From 3f57e574a686f328c36d7dd30481a2f72b0d4040 Mon Sep 17 00:00:00 2001 From: ilham Date: Wed, 22 Dec 2021 22:56:44 +0700 Subject: [PATCH] add: parser upload product --- package.json | 2 + src/helper/csv-parser.ts | 28 +++++++ src/product/product-sub-categories.service.ts | 8 ++ src/product/product.controller.ts | 5 +- src/product/product.service.ts | 82 ++++++++++++++++++- src/transaction/transaction.controller.ts | 13 ++- src/users/dto/create-partner.dto.ts | 3 + src/users/entities/partner.entity.ts | 5 ++ src/users/partner/partner.service.ts | 22 ++++- src/users/users.module.ts | 2 +- src/users/users.service.ts | 9 +- yarn.lock | 12 +++ 12 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 src/helper/csv-parser.ts diff --git a/package.json b/package.json index 291af1f..05a3a9b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,9 @@ "class-transformer": "^0.4.0", "class-validator": "^0.13.1", "crypto": "^1.0.1", + "csv-parser": "^3.0.0", "decimal.js": "^10.3.1", + "fs": "^0.0.1-security", "fs-extra": "^10.0.0", "joi": "^17.4.2", "lodash": "^4.17.21", diff --git a/src/helper/csv-parser.ts b/src/helper/csv-parser.ts new file mode 100644 index 0000000..63c08f3 --- /dev/null +++ b/src/helper/csv-parser.ts @@ -0,0 +1,28 @@ +import { createReadStream } from 'fs'; +import * as csvParser from 'csv-parser'; +import * as path from 'path'; + +export async function parsingFile(dataFile) { + const parsingData: any = await new Promise((resolve, reject) => { + const results = []; + + const file = createReadStream( + path.join( + process.cwd(), + './files/Template Upload Product - Sheet1-a532.csv', + ), + ); + + file + .pipe( + csvParser({ + headers: false, + }), + ) + .on('data', (data) => results.push(data)) + .on('end', () => { + resolve(results); + }); + }); + return parsingData; +} diff --git a/src/product/product-sub-categories.service.ts b/src/product/product-sub-categories.service.ts index 98a5b22..9890ef7 100644 --- a/src/product/product-sub-categories.service.ts +++ b/src/product/product-sub-categories.service.ts @@ -105,6 +105,14 @@ export class ProductSubCategoriesService { } } + async findOneForCSVParser(code: string) { + return await this.productSubCategoriesRepository.findOne({ + where: { + code: code, + }, + }); + } + async update( id: string, updateCategoriesProductDto: UpdateSubCategoriesProductDto, diff --git a/src/product/product.controller.ts b/src/product/product.controller.ts index 6c012c4..de6443e 100644 --- a/src/product/product.controller.ts +++ b/src/product/product.controller.ts @@ -92,10 +92,7 @@ export class ProductController { @Get('test') async test(@Request() req) { - const data = await this.productHistoryPriceService.findOne( - '4d3b328c-3ce4-4c84-84bb-cd9c36e85a45', - '27effb3e-0351-428a-ba7f-08a21c54e16a', - ); + const data = await this.productService.processUploadCSV(); return { data, diff --git a/src/product/product.service.ts b/src/product/product.service.ts index e1fa8db..f98fdc4 100644 --- a/src/product/product.service.ts +++ b/src/product/product.service.ts @@ -1,5 +1,5 @@ import { HttpException, HttpStatus } from '@nestjs/common'; -import { EntityNotFoundError, Repository } from 'typeorm'; +import { EntityNotFoundError, IsNull, Repository } from 'typeorm'; import { Product } from './entities/product.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { CreateProductDto } from './dto/product/create-product.dto'; @@ -10,6 +10,8 @@ import { productType } from '../helper/enum-list'; import { UpdatePriceProductDto } from './dto/product/update-price-product.dto'; import { UsersService } from '../users/users.service'; import { SupplierService } from '../users/supplier/supplier.service'; +import { parsingFile } from '../helper/csv-parser'; +import { PartnerService } from '../users/partner/partner.service'; export class ProductService { constructor( @@ -20,6 +22,7 @@ export class ProductService { private productSubCategoriesService: ProductSubCategoriesService, private usersService: UsersService, private supplierService: SupplierService, + private partnerService: PartnerService, ) {} async create(createProductDto: CreateProductDto) { @@ -47,6 +50,83 @@ export class ProductService { return this.productRepository.findOneOrFail(result.identifiers[0].id); } + async processUploadCSV() { + const data = await parsingFile(''); + data.shift(); + await Promise.all( + data.map(async (it) => { + let dataHistoryPrice; + let partnerData; + + const subCategories = + await this.productSubCategoriesService.findOneForCSVParser(it[2]); + + if (!subCategories) { + return; + } + + const productData = await this.productRepository.findOne({ + code: it[0], + }); + if (productData) { + //TODO : Handle Update Product + productData.name = it[1]; + productData.status = it[5] == 'active' ? 'ACTIVE' : 'NOT ACTIVE'; + await this.productRepository.save(productData); + + //TODO : Handle History Price + if (it[6] != '-' && it[6] != '') { + partnerData = await this.partnerService.findOne(it[6]); + dataHistoryPrice = await this.productHistoryPrice.findOne({ + product: productData, + partner: partnerData, + }); + } else { + dataHistoryPrice = await this.productHistoryPrice.findOne({ + product: productData, + }); + } + + dataHistoryPrice.endDate = new Date(); + await this.productHistoryPrice.save(dataHistoryPrice); + + await this.productHistoryPrice.insert({ + product: productData, + mark_up_price: it[4], + price: it[3], + type: productType.NORMAL, + startDate: new Date(), + endDate: null, + partner: it[6] != '-' ? partnerData : null, + }); + } else { + let partnerData; + if (it[6] != '-' && it[6] != '') { + partnerData = await this.partnerService.findOne(it[6]); + } + const savedProduct = await this.productRepository.insert({ + name: it[1], + code: it[0], + status: it[5] == 'active' ? 'ACTIVE' : 'NOT ACTIVE', + sub_categories: subCategories, + }); + + await this.productHistoryPrice.insert({ + product: savedProduct.identifiers[0], + mark_up_price: it[4], + price: it[3], + type: productType.NORMAL, + startDate: new Date(), + endDate: null, + partner: it[6] != '-' ? partnerData : null, + }); + } + }), + ); + + return data; + } + async findAll( page: number, supplier: string, diff --git a/src/transaction/transaction.controller.ts b/src/transaction/transaction.controller.ts index f415960..453dc23 100644 --- a/src/transaction/transaction.controller.ts +++ b/src/transaction/transaction.controller.ts @@ -1,4 +1,15 @@ -import { Body, Controller, Get, HttpStatus, Param, ParseUUIDPipe, Post, Put, Query, Request } from '@nestjs/common'; +import { + Body, + Controller, + Get, + HttpStatus, + Param, + ParseUUIDPipe, + Post, + Put, + Query, + Request, +} from '@nestjs/common'; import { TransactionService } from './transaction.service'; import { DistributeTransactionDto } from './dto/distribute-transaction.dto'; import { OrderTransactionDto } from './dto/order-transaction.dto'; diff --git a/src/users/dto/create-partner.dto.ts b/src/users/dto/create-partner.dto.ts index a53785f..a4f1bc9 100644 --- a/src/users/dto/create-partner.dto.ts +++ b/src/users/dto/create-partner.dto.ts @@ -10,6 +10,9 @@ export class CreatePartnerDto { @IsNotEmpty() owner: string; + @IsNotEmpty() + code: string; + @IsNotEmpty() npwp: string; diff --git a/src/users/entities/partner.entity.ts b/src/users/entities/partner.entity.ts index 7601e41..dba4b0e 100644 --- a/src/users/entities/partner.entity.ts +++ b/src/users/entities/partner.entity.ts @@ -11,6 +11,11 @@ export class Partner extends BaseModel { @Column() name: string; + @Column({ + nullable: true, + }) + code: string; + @Column() npwp: string; diff --git a/src/users/partner/partner.service.ts b/src/users/partner/partner.service.ts index 1cae2f5..cf2422f 100644 --- a/src/users/partner/partner.service.ts +++ b/src/users/partner/partner.service.ts @@ -1,6 +1,12 @@ -import { forwardRef, HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; +import { + forwardRef, + HttpException, + HttpStatus, + Inject, + Injectable, +} from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Connection, Not, Repository } from 'typeorm'; +import { Connection, EntityNotFoundError, Not, Repository } from 'typeorm'; import { CoaService } from '../../transaction/coa.service'; import { CreatePartnerDto } from '../dto/create-partner.dto'; import { Partner } from '../entities/partner.entity'; @@ -9,6 +15,7 @@ import { UsersService } from '../users.service'; import { CreateUserDto } from '../dto/create-user.dto'; import { UpdatePartnerDto } from '../dto/update-partner.dto'; import { UpdateUserDto } from '../dto/update-user.dto'; +import { when } from 'joi'; @Injectable() export class PartnerService { @@ -41,10 +48,12 @@ export class PartnerService { } const partnerData = new Partner(); + partnerData.id = uuid.v4(); partnerData.name = createPartnerDto.name; partnerData.npwp = createPartnerDto.npwp; partnerData.address = createPartnerDto.address; + partnerData.code = createPartnerDto.code; partnerData.status = true; await this.connection.transaction(async (manager) => { @@ -52,6 +61,7 @@ export class PartnerService { }); const dataUser = new CreateUserDto(); + dataUser.username = `admin_${partnerData.name}`; dataUser.name = partnerData.name; dataUser.phone_number = partnerData.phone_number; @@ -129,6 +139,14 @@ export class PartnerService { return partnerData; }; + async findOne(code: string) { + return await this.partnerRepository.findOne({ + where: { + code: code, + }, + }); + } + findAllPartner(page, pageSize?) { return this.partnerRepository.findAndCount({ skip: page * (pageSize || 10), diff --git a/src/users/users.module.ts b/src/users/users.module.ts index 523735e..449f2cc 100644 --- a/src/users/users.module.ts +++ b/src/users/users.module.ts @@ -19,6 +19,6 @@ import { UserDetail } from './entities/user_detail.entity'; ], controllers: [UsersController], providers: [UsersService, SupplierService, PartnerService], - exports: [UsersService, SupplierService], + exports: [UsersService, SupplierService, PartnerService], }) export class UsersModule {} diff --git a/src/users/users.service.ts b/src/users/users.service.ts index b823a26..7ade7a4 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -1,4 +1,10 @@ -import { forwardRef, HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; +import { + forwardRef, + HttpException, + HttpStatus, + Inject, + Injectable, +} from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { Connection, EntityNotFoundError, Not, Repository } from 'typeorm'; @@ -383,6 +389,7 @@ export class UsersService { return this.usersRepository.findOneOrFail({ where: { username, + isActive: true, }, relations: ['roles', 'partner'], }); diff --git a/yarn.lock b/yarn.lock index 5a03b46..24f3843 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2110,6 +2110,13 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +csv-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/csv-parser/-/csv-parser-3.0.0.tgz#b88a6256d79e090a97a1b56451f9327b01d710e7" + integrity sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ== + dependencies: + minimist "^1.2.0" + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -2867,6 +2874,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= +fs@^0.0.1-security: + version "0.0.1-security" + resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" + integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ= + fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"