From 53575f36d6af0d6b200d34621ad6d0d449723e1b Mon Sep 17 00:00:00 2001 From: ilham Date: Wed, 15 Dec 2021 08:51:05 +0700 Subject: [PATCH 1/2] fix: order product --- src/configurable/commission.service.ts | 24 ++++- src/configurable/configurable.controller.ts | 2 +- src/configurable/configurable.module.ts | 2 +- src/product/product.controller.ts | 16 +++ src/product/product.module.ts | 4 +- src/product/product.service.ts | 8 +- src/transaction/transaction.module.ts | 2 + src/transaction/transaction.service.ts | 103 ++++++++++++-------- src/users/users.service.ts | 18 ++-- 9 files changed, 125 insertions(+), 54 deletions(-) diff --git a/src/configurable/commission.service.ts b/src/configurable/commission.service.ts index 3765970..491e929 100644 --- a/src/configurable/commission.service.ts +++ b/src/configurable/commission.service.ts @@ -12,7 +12,7 @@ export class CommissionService { private commissionRepository: Repository, ) {} - findAllRoles(page) { + findAllCommission(page) { return this.commissionRepository.findAndCount({ skip: page * 10, take: 10, @@ -22,6 +22,28 @@ export class CommissionService { }); } + async findOne(role: string) { + try { + return await this.commissionRepository.findOneOrFail({ + where: { + role: role, + }, + }); + } catch (e) { + if (e instanceof EntityNotFoundError) { + throw new HttpException( + { + statusCode: HttpStatus.NOT_FOUND, + error: 'Data not found', + }, + HttpStatus.NOT_FOUND, + ); + } else { + throw e; + } + } + } + async updateCommission(id: string, request) { try { await this.commissionRepository.findOneOrFail(id); diff --git a/src/configurable/configurable.controller.ts b/src/configurable/configurable.controller.ts index 63d6006..fe94a6e 100644 --- a/src/configurable/configurable.controller.ts +++ b/src/configurable/configurable.controller.ts @@ -37,7 +37,7 @@ export class ConfigurableController { @Get('/commission') async findCommission(@Query('page') page: number) { - const [data, count] = await this.commissionService.findAllRoles(page); + const [data, count] = await this.commissionService.findAllCommission(page); return { data, diff --git a/src/configurable/configurable.module.ts b/src/configurable/configurable.module.ts index 58d0459..45c0081 100644 --- a/src/configurable/configurable.module.ts +++ b/src/configurable/configurable.module.ts @@ -10,6 +10,6 @@ import { CommissionSetting } from './entities/commission_setting.entity'; imports: [TypeOrmModule.forFeature([Roles, CommissionSetting])], controllers: [ConfigurableController], providers: [RoleService, CommissionService], - exports: [RoleService], + exports: [RoleService, CommissionService], }) export class ConfigurableModule {} diff --git a/src/product/product.controller.ts b/src/product/product.controller.ts index d3a2753..a9eea82 100644 --- a/src/product/product.controller.ts +++ b/src/product/product.controller.ts @@ -20,6 +20,7 @@ import { ProductSubCategoriesService } from './product-sub-categories.service'; import { CreateSubCategoriesProductDto } from './dto/sub-categories/create-sub-categories-product.dto'; import { CreateProductDto } from './dto/product/create-product.dto'; import { UpdateProductDto } from './dto/product/update-product.dto'; +import { ProductHistoryPriceService } from './history-price/history-price.service'; @Controller({ path: 'product', @@ -30,6 +31,7 @@ export class ProductController { private readonly productService: ProductService, private readonly productCategoriesService: ProductCategoriesService, private readonly productSubCategoriesService: ProductSubCategoriesService, + private readonly productHistoryPriceService: ProductHistoryPriceService, ) {} @Post() @@ -79,6 +81,20 @@ 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', + ); + + return { + data, + statusCode: HttpStatus.OK, + message: 'success', + }; + } + @Get('by-categories-all') async findByCategoriesAll( @Query('page') page: number, diff --git a/src/product/product.module.ts b/src/product/product.module.ts index b0fc683..231478e 100644 --- a/src/product/product.module.ts +++ b/src/product/product.module.ts @@ -9,6 +9,7 @@ import { ProductHistoryPrice } from './entities/product-history-price.entity'; import { ProductSubCategories } from './entities/product-sub-category.entity'; import { ProductSubCategoriesService } from './product-sub-categories.service'; import { UsersModule } from '../users/users.module'; +import { ProductHistoryPriceService } from './history-price/history-price.service'; @Module({ imports: [ @@ -25,7 +26,8 @@ import { UsersModule } from '../users/users.module'; ProductService, ProductCategoriesService, ProductSubCategoriesService, + ProductHistoryPriceService, ], - exports: [ProductService], + exports: [ProductService, ProductHistoryPriceService], }) export class ProductModule {} diff --git a/src/product/product.service.ts b/src/product/product.service.ts index 7ea059a..a74f24a 100644 --- a/src/product/product.service.ts +++ b/src/product/product.service.ts @@ -13,7 +13,6 @@ import { UpdateProductDto } from './dto/product/update-product.dto'; import { ProductHistoryPrice } from './entities/product-history-price.entity'; import { productType } from '../helper/enum-list'; import { UpdatePriceProductDto } from './dto/product/update-price-product.dto'; -import { Raw } from 'typeorm/browser'; import { UsersService } from '../users/users.service'; import { SupplierService } from '../users/supplier/supplier.service'; @@ -132,7 +131,12 @@ export class ProductService { async findOne(code: string) { try { - return await this.productRepository.findOneOrFail({ code: code }); + return await this.productRepository.findOneOrFail({ + relations: ['supplier'], + where: { + code: code, + }, + }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( diff --git a/src/transaction/transaction.module.ts b/src/transaction/transaction.module.ts index 698ef2b..13bae9e 100644 --- a/src/transaction/transaction.module.ts +++ b/src/transaction/transaction.module.ts @@ -9,11 +9,13 @@ import { Transactions } from './entities/transactions.entity'; import { CoaService } from './coa.service'; import { ProductModule } from '../product/product.module'; import { UsersModule } from 'src/users/users.module'; +import { ConfigurableModule } from '../configurable/configurable.module'; @Module({ imports: [ TypeOrmModule.forFeature([COA, TransactionJournal, Transactions]), ProductModule, + ConfigurableModule, forwardRef(() => UsersModule), ], controllers: [TransactionController, PpobCallbackController], diff --git a/src/transaction/transaction.service.ts b/src/transaction/transaction.service.ts index 86e609b..fe598ca 100644 --- a/src/transaction/transaction.service.ts +++ b/src/transaction/transaction.service.ts @@ -21,6 +21,8 @@ import { CreateJournalDto } from './dto/create-journal.dto'; import { UsersService } from 'src/users/users.service'; import { AddSaldoSupplier } from './dto/add-saldo-supplier.dto'; import { SupplierService } from '../users/supplier/supplier.service'; +import { ProductHistoryPriceService } from '../product/history-price/history-price.service'; +import { CommissionService } from '../configurable/commission.service'; interface JournalEntry { coa_id: string; @@ -39,7 +41,9 @@ export class TransactionService { private coaRepository: Repository, private coaService: CoaService, private productService: ProductService, + private productHistoryPriceService: ProductHistoryPriceService, private userService: UsersService, + private commissionService: CommissionService, private supplierService: SupplierService, private connection: Connection, ) {} @@ -268,33 +272,30 @@ export class TransactionService { orderTransactionDto: OrderTransactionDto, currentUser: any, ) { + //GET USER + const userData = await this.userService.findByUsername( + currentUser.username, + ); + //GET PRODUCT const product = await this.productService.findOne( orderTransactionDto.productCode, ); - //GET USER - const userData = await this.userService.findByUsername( - currentUser.username, + const product_price = await this.productHistoryPriceService.findOne( + product.id, + userData.partner?.id, ); + let supervisorData = []; - if (userData.superior != null) { - supervisorData.push( - await this.userService.findByUsername(currentUser.username), + if (!userData.partner) { + //GET SALES + supervisorData = await this.calculateCommission( + supervisorData, + product_price.mark_up_price - product_price.price, + userData, ); - - if (supervisorData[0].superior != null) { - supervisorData.push( - await this.userService.findByUsername(currentUser.username), - ); - - if (supervisorData[0].superior != null) { - supervisorData.push( - await this.userService.findByUsername(currentUser.username), - ); - } - } } //GET COA @@ -304,11 +305,11 @@ export class TransactionService { ); const coaInventory = await this.coaService.findByName( - `${coaType[coaType.INVENTORY]}-IRS`, + `${coaType[coaType.INVENTORY]}-${product.supplier.code}`, ); const coaCostOfSales = await this.coaService.findByName( - `${coaType[coaType.COST_OF_SALES]}-SYSTEM`, + `${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`, ); const coaSales = await this.coaService.findByName( @@ -319,18 +320,6 @@ export class TransactionService { `${coaType[coaType.EXPENSE]}-SYSTEM`, ); - supervisorData = supervisorData.map(async (it) => { - const coaAccount = await this.coaService.findByUser( - it.id, - coaType.WALLET, - ); - - return { - coa_id: coaAccount.id, - credit: 0, - }; - }); - if (coaAccount.amount <= product.price) { throw new HttpException( { @@ -346,10 +335,10 @@ export class TransactionService { const transactionData = new Transactions(); transactionData.id = uuid.v4(); - transactionData.amount = product.price; + transactionData.amount = product_price.mark_up_price; transactionData.user = userData.id; transactionData.status = statusTransaction.SUCCESS; - transactionData.type = typeTransaction.DISTRIBUTION; + transactionData.type = typeTransaction.ORDER; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ @@ -360,23 +349,25 @@ export class TransactionService { journals: [ { coa_id: coaInventory.id, - credit: product.basePrice, + credit: product_price.price, }, { coa_id: coaCostOfSales.id, - debit: product.basePrice, + debit: product_price.price, }, { coa_id: coaAccount.id, - debit: product.price, + debit: product_price.mark_up_price, }, { coa_id: coaSales.id, - credit: product.price, + credit: product_price.mark_up_price, }, { coa_id: coaExpense.id, - credit: 0, + credit: userData.partner + ? 0 + : product_price.mark_up_price - product_price.price, }, ].concat(supervisorData), }); @@ -388,6 +379,40 @@ export class TransactionService { return true; } + async calculateCommission(data, totalPrice, userData) { + let supervisorData = []; + supervisorData.push( + await this.userService.findByUsername(userData.superior.username), + ); + + //GET Supervisor + supervisorData.push( + await this.userService.findByUsername( + supervisorData[0].superior.username, + ), + ); + + //GET Admin + supervisorData.push( + await this.userService.findByUsername( + supervisorData[1].superior.username, + ), + ); + + return supervisorData.map(async (it) => { + const coaAccount = await this.coaService.findByUser( + it.id, + coaType.WALLET, + ); + const commissionValue = await this.commissionService.findOne(it.role.id); + + return { + coa_id: coaAccount.id, + credit: totalPrice * commissionValue.commission, + }; + }); + } + async accountingTransaction(createJournalDto: CreateJournalDto) { const creditSum = createJournalDto.journals .map((it) => { diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 74edf69..04106ba 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -83,6 +83,14 @@ export class UsersService { dataCoaWallet.coaEntityManager = manager; await this.coaService.create(dataCoaWallet); + const dataCoaAR = new InputCoaDto(); + dataCoaAR.user = userData; + dataCoaAR.balanceType = balanceType.DEBIT; + dataCoaAR.relatedUserId = superior.id; + dataCoaAR.type = coaType.ACCOUNT_RECEIVABLE; + dataCoaAR.coaEntityManager = manager; + await this.coaService.create(dataCoaAR); + if (createUserDto.superior) { const dataCoaAP = new InputCoaDto(); dataCoaAP.user = userData; @@ -91,14 +99,6 @@ export class UsersService { dataCoaAP.type = coaType.ACCOUNT_PAYABLE; dataCoaAP.coaEntityManager = manager; await this.coaService.create(dataCoaAP); - - const dataCoaAR = new InputCoaDto(); - dataCoaAR.user = userData; - dataCoaAR.balanceType = balanceType.DEBIT; - dataCoaAR.relatedUserId = superior.id; - dataCoaAR.type = coaType.ACCOUNT_RECEIVABLE; - dataCoaAR.coaEntityManager = manager; - await this.coaService.create(dataCoaAR); } }); @@ -169,7 +169,7 @@ export class UsersService { where: { username: username, }, - relations: ['roles'], + relations: ['superior', 'roles', 'partner'], }); } catch (e) { if (e instanceof EntityNotFoundError) { From 8c5e944cc82e385c5bb6c7c73c767c429ec987d4 Mon Sep 17 00:00:00 2001 From: ilham Date: Wed, 15 Dec 2021 15:17:59 +0700 Subject: [PATCH 2/2] fix: get tranasction history by user --- .../history-price.service.spec.ts | 18 +++++++ .../history-price/history-price.service.ts | 37 +++++++++++++ .../entities/transactions.entity.ts | 7 +++ src/transaction/transaction.controller.ts | 15 ++++++ src/transaction/transaction.service.ts | 52 ++++++++++++++++--- 5 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 src/product/history-price/history-price.service.spec.ts create mode 100644 src/product/history-price/history-price.service.ts diff --git a/src/product/history-price/history-price.service.spec.ts b/src/product/history-price/history-price.service.spec.ts new file mode 100644 index 0000000..0a9952d --- /dev/null +++ b/src/product/history-price/history-price.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { HistoryPriceService } from './history-price.service'; + +describe('HistoryPriceService', () => { + let service: HistoryPriceService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [HistoryPriceService], + }).compile(); + + service = module.get(HistoryPriceService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/product/history-price/history-price.service.ts b/src/product/history-price/history-price.service.ts new file mode 100644 index 0000000..eb0a183 --- /dev/null +++ b/src/product/history-price/history-price.service.ts @@ -0,0 +1,37 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { EntityNotFoundError, IsNull, Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ProductCategories } from '../entities/product-category.entity'; +import { ProductHistoryPrice } from '../entities/product-history-price.entity'; + +@Injectable() +export class ProductHistoryPriceService { + constructor( + @InjectRepository(ProductHistoryPrice) + private productHistoryPriceService: Repository, + ) {} + + async findOne(product: string, partner: string) { + try { + return await this.productHistoryPriceService.findOneOrFail({ + where: { + product: product, + endDate: IsNull(), + partner: partner ? partner : IsNull(), + }, + }); + } catch (e) { + if (e instanceof EntityNotFoundError) { + throw new HttpException( + { + statusCode: HttpStatus.NOT_FOUND, + error: 'Data not found', + }, + HttpStatus.NOT_FOUND, + ); + } else { + throw e; + } + } + } +} diff --git a/src/transaction/entities/transactions.entity.ts b/src/transaction/entities/transactions.entity.ts index 5627735..0a3d34e 100644 --- a/src/transaction/entities/transactions.entity.ts +++ b/src/transaction/entities/transactions.entity.ts @@ -12,6 +12,8 @@ import { } from 'typeorm'; import { BaseModel } from '../../config/basemodel.entity'; import { statusTransaction, typeTransaction } from '../../helper/enum-list'; +import { Partner } from '../../users/entities/partner.entity'; +import { ProductHistoryPrice } from '../../product/entities/product-history-price.entity'; @Entity() export class Transactions extends BaseModel { @@ -31,4 +33,9 @@ export class Transactions extends BaseModel { nullable: true, }) user_destination: string; + + @ManyToOne(() => ProductHistoryPrice, (product) => product.id) + product_price: ProductHistoryPrice; + + mark_up_price: number; } diff --git a/src/transaction/transaction.controller.ts b/src/transaction/transaction.controller.ts index 9d95332..d93fad0 100644 --- a/src/transaction/transaction.controller.ts +++ b/src/transaction/transaction.controller.ts @@ -8,6 +8,7 @@ import { Delete, Request, HttpStatus, + Query, } from '@nestjs/common'; import { TransactionService } from './transaction.service'; import { DistributeTransactionDto } from './dto/distribute-transaction.dto'; @@ -73,4 +74,18 @@ export class TransactionController { req.user, ); } + + @Get('history') + async findByCategories(@Query('page') page: number, @Request() req) { + const data = await this.transactionService.transactionHistoryByUser( + page, + req.user.userId, + ); + + return { + ...data, + statusCode: HttpStatus.OK, + message: 'success', + }; + } } diff --git a/src/transaction/transaction.service.ts b/src/transaction/transaction.service.ts index fe598ca..eaa232b 100644 --- a/src/transaction/transaction.service.ts +++ b/src/transaction/transaction.service.ts @@ -123,6 +123,7 @@ export class TransactionService { const userData = await this.userService.findByUsername( currentUser.username, ); + if (userData.roles.name != 'Admin') { throw new HttpException( { @@ -289,11 +290,13 @@ export class TransactionService { let supervisorData = []; + const profit = product_price.mark_up_price - product_price.price; + if (!userData.partner) { //GET SALES supervisorData = await this.calculateCommission( supervisorData, - product_price.mark_up_price - product_price.price, + profit, userData, ); } @@ -339,6 +342,7 @@ export class TransactionService { transactionData.user = userData.id; transactionData.status = statusTransaction.SUCCESS; transactionData.type = typeTransaction.ORDER; + transactionData.product_price = product_price; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ @@ -365,9 +369,7 @@ export class TransactionService { }, { coa_id: coaExpense.id, - credit: userData.partner - ? 0 - : product_price.mark_up_price - product_price.price, + credit: userData.partner ? 0 : profit, }, ].concat(supervisorData), }); @@ -379,8 +381,39 @@ export class TransactionService { return true; } + async transactionHistoryByUser(page: number, user: string) { + const baseQuery = this.transactionRepository + .createQueryBuilder('transaction') + .select('transaction.id', 'id') + .addSelect('transaction.created_at', 'created_at') + .where('transaction.user = :id and transaction.type = 1', { + id: user, + }) + .leftJoin('transaction.product_price', 'product_price') + .leftJoin('product_price.product', 'product') + .addSelect('product_price.mark_up_price', 'mark_up_price') + .addSelect('product.name', 'name') + .addSelect('product.id', 'product_id'); + + // .leftJoinAndSelect('transaction.product_price', 'product_price') + // .leftJoinAndSelect('product_price.product', 'product'); + + const data = await baseQuery + .skip(page * 10) + .take(10) + .getRawMany(); + + const totalData = await baseQuery.getCount(); + + return { + data, + count: totalData, + }; + } + async calculateCommission(data, totalPrice, userData) { - let supervisorData = []; + const supervisorData = []; + supervisorData.push( await this.userService.findByUsername(userData.superior.username), ); @@ -498,17 +531,20 @@ export class TransactionService { return a.plus(b); }, new Decimal(0)); - let coa = coas.find( - (it) => it.id.toLowerCase() === coaId.toLowerCase(), - ); + const coa = coas.find((it) => { + return it.id.toLowerCase() === coaId.toLowerCase(); + }); let balance = new Decimal(coa.amount); + if (coa.balanceType == balanceType.DEBIT) { balance = balance.plus(debitSum.minus(creditSum)); } else if (coa.balanceType == balanceType.CREDIT) { balance = balance.plus(creditSum.minus(debitSum)); } + const diff = balance.minus(new Decimal(coa.amount)); + return createJournalDto.transactionalEntityManager .createQueryBuilder() .update(COA)