import { BadRequestException, HttpException, HttpStatus, Injectable, Logger, NotFoundException, } from '@nestjs/common'; import { DistributeTransactionDto } from './dto/distribute-transaction.dto'; import { OrderTransactionDto } from './dto/order-transaction.dto'; import { InjectRepository } from '@nestjs/typeorm'; import { Transactions } from './entities/transactions.entity'; import { Between, Connection, EntityNotFoundError, In, Repository, } from 'typeorm'; import { COA } from './entities/coa.entity'; import { TransactionJournal } from './entities/transaction-journal.entity'; import { CoaService } from './coa.service'; import * as uuid from 'uuid'; import { uniq } from 'lodash'; import { Decimal } from 'decimal.js'; import { balanceType, coaType, statusTransaction, typeTransaction, } from '../helper/enum-list'; import { ProductService } from '../product/product.service'; 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'; import { DepositReturnDto } from './dto/deposit_return.dto'; import { UserDetail } from '../users/entities/user_detail.entity'; import { doTransaction } from '../helper/irs-api'; import { ProductHistoryPrice } from '../product/entities/product-history-price.entity'; import axios from 'axios'; import { CheckBillHistory } from './entities/check-bill-history.entity'; import { CallbackPartner } from './entities/callback-partner.entity'; import { doAuthorizeHemat } from '../helper/sihemat-authorization'; import { ProductHistoryStatusService } from '../product/history-status/history-status.service'; import { Workbook } from 'exceljs'; @Injectable() export class TransactionService { private readonly logger = new Logger(TransactionService.name); constructor( @InjectRepository(Transactions) private transactionRepository: Repository, @InjectRepository(TransactionJournal) private transactionJournalRepository: Repository, @InjectRepository(ProductHistoryPrice) private productPriceRepository: Repository, @InjectRepository(COA) private coaRepository: Repository, @InjectRepository(CheckBillHistory) private checkBillHistoryRepository: Repository, @InjectRepository(CallbackPartner) private callbackPartnerRepository: Repository, private coaService: CoaService, private productService: ProductService, private productHistoryPriceService: ProductHistoryPriceService, private productHistoryStatusService: ProductHistoryStatusService, private userService: UsersService, private commissionService: CommissionService, private supplierService: SupplierService, private connection: Connection, ) {} async addSupplierSaldo(addSaldoSupplier: AddSaldoSupplier, currentUser: any) { const supplier = await this.supplierService.findByCode( addSaldoSupplier.supplier, ); // GET COA const coaBank = await this.coaService.findByName( `${coaType[coaType.BANK]}-SYSTEM`, ); const coaInventory = await this.coaService.findByName( `${coaType[coaType.INVENTORY]}-${supplier.code}`, ); const coaBudget = await this.coaService.findByName( `${coaType[coaType.BUDGET]}-${supplier.code}`, ); const coaContraBudget = await this.coaService.findByName( `${coaType[coaType.CONTRA_BUDGET]}-${supplier.code}`, ); //GET USER const userData = await this.userService.findByUsername( currentUser.username, ); await this.connection.transaction(async (manager) => { //INSERT TRANSACTION const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = addSaldoSupplier.amount; transactionData.user = userData.id; transactionData.status = statusTransaction.SUCCESS; transactionData.type = typeTransaction.DEPOSIT_SUPPLIER; transactionData.balance_remaining = 0; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaBank.id, credit: transactionData.amount, }, { coa_id: coaInventory.id, debit: transactionData.amount, }, { coa_id: coaBudget.id, debit: transactionData.amount, }, { coa_id: coaContraBudget.id, credit: transactionData.amount, }, ], }); }); return true; } async distributeFromAdmin( distributeTransactionDto: DistributeTransactionDto, currentUser: any, ) { //GET USER const userData = await this.userService.findByUsername( currentUser.username, ); const supplier = await this.supplierService.findByActive(); try { if (userData.roles.name != 'Admin') { throw new HttpException( { statusCode: HttpStatus.NOT_ACCEPTABLE, error: 'Roles Not Admin', }, HttpStatus.NOT_ACCEPTABLE, ); } console.log('suppliercodedist', supplier.code); // GET COA const coaBudget = await this.coaService.findByName( `${coaType[coaType.BUDGET]}-${supplier.code}`, ); console.log('coabudgetdist', coaBudget.amount); console.log('amounttotaldist', distributeTransactionDto.amount); if (coaBudget.amount < distributeTransactionDto.amount) { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction failed due to insufficient balance`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } const coaContraBudget = await this.coaService.findByName( `${coaType[coaType.CONTRA_BUDGET]}-${supplier.code}`, ); const coaAR = await this.coaService.findByTwoUser( distributeTransactionDto.destination, currentUser.userId, coaType.ACCOUNT_RECEIVABLE, ); console.log('coamsk1', 'coa'); const coaWallet = await this.coaService.findByUser( distributeTransactionDto.destination, coaType.WALLET, ); await this.connection.transaction(async (manager) => { //INSERT TRANSACTION const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = distributeTransactionDto.amount; transactionData.user = userData.id; transactionData.user_destination = distributeTransactionDto.destination; transactionData.status = statusTransaction.SUCCESS; transactionData.type = typeTransaction.DISTRIBUTION; transactionData.balance_remaining = 0; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaAR.id, debit: transactionData.amount, }, { coa_id: coaWallet.id, credit: transactionData.amount, }, { coa_id: coaBudget.id, credit: transactionData.amount, }, { coa_id: coaContraBudget.id, debit: transactionData.amount, }, ], }); }); return true; } catch (e) { throw e; } } async distributeDeposit( distributeTransactionDto: DistributeTransactionDto, currentUser: any, ) { //GET USER const userData = await this.userService.findByUsername( currentUser.username, ); // GET COA console.log('coamsk2', 'coa'); const coaSenderWallet = await this.coaService.findByUser( userData.id, coaType.WALLET, ); const coaAP = await this.coaService.findByUserWithRelated( distributeTransactionDto.destination, userData.id, coaType.ACCOUNT_PAYABLE, ); console.log('coamsk3', 'coa'); const coaReceiverWallet = await this.coaService.findByUser( distributeTransactionDto.destination, coaType.WALLET, ); const coaAR = await this.coaService.findByUserWithRelated( distributeTransactionDto.destination, userData.id, coaType.ACCOUNT_RECEIVABLE, ); if (coaSenderWallet.amount < distributeTransactionDto.amount) { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction failed due to insufficient balance`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } await this.connection.transaction(async (manager) => { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = distributeTransactionDto.amount; transactionData.user = userData.id; transactionData.user_destination = distributeTransactionDto.destination; transactionData.status = statusTransaction.SUCCESS; transactionData.type = typeTransaction.DISTRIBUTION; transactionData.balance_remaining = 0; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaSenderWallet.id, debit: transactionData.amount, }, { coa_id: coaReceiverWallet.id, credit: transactionData.amount, }, { coa_id: coaAR.id, debit: transactionData.amount, }, { coa_id: coaAP.id, credit: transactionData.amount, }, ], }); }); return true; } async orderTransaction( orderTransactionDto: OrderTransactionDto, currentUser: any, ) { const productData = await this.productService.findOne( orderTransactionDto.productCode, 'prepaid', orderTransactionDto.productId ); // if (!productData.statusHistory.status.includes('ACTIVE')) { // throw new HttpException( // { // statusCode: HttpStatus.INTERNAL_SERVER_ERROR, // error: `Transaction Failed because product is not active`, // }, // HttpStatus.INTERNAL_SERVER_ERROR, // ); // } else { const trxId = Array(11) .fill(null) .map(() => { return Math.round(Math.random() * 16).toString(16); }) .join(''); //GET USER const userData = await this.userService.findByUsername( currentUser.username, ); // const supplierData = await this.supplierService.findByCode('IRS'); //GET PRODUCT const product = await this.productService.findOneActive( orderTransactionDto.productCode, 'prepaid', orderTransactionDto.productId, ); const product_price = await this.productHistoryPriceService.findOne( product.id, userData.partner?.id, ); let costInventory = product_price.price; let supervisorData = []; let profit = product_price.mark_up_price; //GET COA console.log('coamsk4', 'coa'); const coaAccount = await this.coaService.findByUser( userData.id, coaType.WALLET, ); const coaInventory = await this.coaService.findByName( `${coaType[coaType.INVENTORY]}-${product.supplier.code}`, ); const coaCostOfSales = await this.coaService.findByName( `${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`, ); const coaSales = await this.coaService.findByName( `${coaType[coaType.SALES]}-SYSTEM`, ); const coaExpense = await this.coaService.findByName( `${coaType[coaType.EXPENSE]}-SYSTEM`, ); if (!userData.partner) { //GET SALES supervisorData = await this.calculateCommission( supervisorData, profit, userData, ); profit = supervisorData .map((item) => { return item.credit; }) .reduce((prev, curr) => { return prev + curr; }, 0); supervisorData = supervisorData.concat([ { coa_id: coaExpense.id, debit: profit, }, ]); } if (coaAccount.amount < product_price.mark_up_price + product_price.price) { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction failed due to insufficient balance`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } try { await this.connection.transaction(async (manager) => { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = product_price.mark_up_price + product_price.price; transactionData.user = userData.id; transactionData.status = statusTransaction.SUCCESS; transactionData.type = typeTransaction.ORDER; transactionData.product_price = product_price; transactionData.destination = orderTransactionDto.destination; transactionData.partner_trx_id = orderTransactionDto.trx_id; transactionData.supplier_trx_id = trxId; transactionData.balance_remaining = coaAccount.amount - product_price.mark_up_price - costInventory; await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaInventory.id, credit: product_price.price, }, { coa_id: coaCostOfSales.id, debit: product_price.price, }, { coa_id: coaAccount.id, debit: product_price.mark_up_price + product_price.price, }, { // eslint-disable-next-line camelcase coa_id: coaSales.id, credit: product_price.mark_up_price + product_price.price, }, ].concat(supervisorData), }); }); } catch (e) { throw e; } return { trx_id: trxId, client_trx_id: orderTransactionDto.trx_id, product: orderTransactionDto.productCode, amount: product_price.mark_up_price + product_price.price, status: statusTransaction[statusTransaction.SUCCESS], }; // } } async orderTransactionProd( orderTransactionDto: OrderTransactionDto, currentUser: any, ) { const productData = await this.productService.findOne( orderTransactionDto.productCode, 'prepaid', orderTransactionDto.productId ); // if (!productData.statusHistory.status.includes('ACTIVE')) { // throw new HttpException( // { // statusCode: HttpStatus.INTERNAL_SERVER_ERROR, // error: `Transaction Failed because product is not active`, // }, // HttpStatus.INTERNAL_SERVER_ERROR, // ); // } else { let status; const amount = 0; //GET USER DATA const userData = await this.userService.findByUsername( currentUser.username, ); // const supplierData = await this.supplierService.findByCode('IRS'); //GET PRODUCT AND PRICE const product = await this.productService.findOneActive( orderTransactionDto.productCode, 'prepaid', orderTransactionDto.productId, ); const supplier = await this.supplierService.findByCode( product.supplier.code, ); const statusProduct = await this.productHistoryStatusService.findOneActive( product.id, userData.partner == null ? null : userData.partner.id, ); if (statusProduct.status == 'NOT ACTIVE') { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction Failed because product is not active`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } else { console.log('userdatapartnerid', userData.partner?.id); let product_price = null; product_price = await this.productHistoryPriceService.findOne( product.id, userData.partner?.id, ); //GET COA console.log('coamsk5', product_price.id); const coaAccount = await this.coaService.findByUser( userData.id, coaType.WALLET, ); const coaInventory = await this.coaService.findByName( `${coaType[coaType.INVENTORY]}-${product.supplier.code}`, ); const coaCostOfSales = await this.coaService.findByName( `${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`, ); const coaSales = await this.coaService.findByName( `${coaType[coaType.SALES]}-SYSTEM`, ); if (orderTransactionDto.bill_trx_id) { try { const billId = await this.checkBillHistoryRepository.findOneOrFail({ where: { trx_id: orderTransactionDto.bill_trx_id, }, }); product_price.price = billId.amount; } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'Bill not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } if (coaAccount.amount < product_price.mark_up_price + product_price.price) { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction failed due to insufficient balance`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } //HIT API SUPPLIER const trxId = Array(11) .fill(null) .map(() => { return Math.round(Math.random() * 16).toString(16); }) .join(''); let hitLoginHemat; if (supplier.code == 'Hemat') { hitLoginHemat = await doAuthorizeHemat(supplier.irs_user, supplier.irs_pass, supplier); } let hitSupplier = supplier.code == 'Hemat' ? await doTransaction( orderTransactionDto.productCode, orderTransactionDto.destination, trxId, supplier, hitLoginHemat.data, product.type == 'prepaid' ? 'PURCHASE' : 'PAYMENT', ) : await doTransaction( orderTransactionDto.productCode, orderTransactionDto.destination, trxId, supplier, "", product.type == 'prepaid' ? 'PURCHASE' : 'PAYMENT', ); // let hitSupplier; console.log('iniresponsupplierharga', hitSupplier) console.log('iniresponsupplier', hitSupplier.harga) console.log(supplier.code, 'sdkfjsd'); console.log(product_price, 'price'); if (supplier.code == 'metro') { const parsingResponse = hitSupplier.split(' '); console.log('parsingResponse', parsingResponse) const newHitSupplier = { success: hitSupplier.includes('diproses'), harga: parseInt( parsingResponse[parsingResponse.length - 2].replace(/\./g, ' '), ), msg: hitSupplier, }; hitSupplier = newHitSupplier; if (orderTransactionDto.bill_trx_id !== null) { hitSupplier.harga = product_price.price; } } else if (supplier.code == 'Hemat') { const newHitSupplier = { success: hitSupplier.success, harga: product_price.price, msg: hitSupplier.msg, }; hitSupplier = newHitSupplier; if (orderTransactionDto.bill_trx_id !== null) { hitSupplier.harga = product_price.price; } } console.log(hitSupplier, 'newhitSupplier'); // const hitSupplier = { // harga: 2000, // success: true, // msg: 'Berhasil', // }; this.logger.log({ responseAPISupplier: hitSupplier, }); let costInventory = product_price.price; if (hitSupplier.harga != undefined) { if (hitSupplier.harga != product_price.price) { console.log('priceupdate1supplier', hitSupplier.harga); console.log('priceupdate1normal', product_price.price); product_price.endDate = new Date(); costInventory = hitSupplier.harga; const listActivePrice = await this.productHistoryPriceService.getAllActivePriceByProduct( product.id, ); await this.productHistoryPriceService.updateEndDate(product.id); listActivePrice.map(async (x) => { const newProductPrice = new ProductHistoryPrice(); newProductPrice.id = uuid.v4(); newProductPrice.type = x.type; newProductPrice.price = hitSupplier.harga; newProductPrice.mark_up_price = x.mark_up_price; newProductPrice.startDate = new Date(); newProductPrice.product = product; newProductPrice.partner = x.partner; await this.productHistoryPriceService.create(newProductPrice); product_price = newProductPrice; }); } } try { //TRANSACTION DATA await this.connection.transaction(async (manager) => { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = product_price.mark_up_price + product_price.price; transactionData.user = userData.id; transactionData.type = typeTransaction.ORDER; transactionData.product_price = product_price; transactionData.destination = orderTransactionDto.destination; transactionData.partner_trx_id = orderTransactionDto.trx_id; transactionData.supplier_trx_id = trxId; transactionData.check_bill = orderTransactionDto.bill_trx_id; transactionData.balance_remaining = coaAccount.amount - product_price.mark_up_price - costInventory; if (!hitSupplier.success) { transactionData.status = statusTransaction.FAILED; status = statusTransaction[transactionData.status]; await this.transactionRepository.insert(transactionData); throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: hitSupplier.msg, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } else { transactionData.status = statusTransaction.PENDING; status = statusTransaction[transactionData.status]; } await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaInventory.id, credit: costInventory, }, { coa_id: coaCostOfSales.id, debit: costInventory, }, { coa_id: coaAccount.id, debit: product_price.mark_up_price + costInventory, }, { // eslint-disable-next-line camelcase coa_id: coaSales.id, credit: product_price.mark_up_price + costInventory, }, ], }); }); } catch (e) { throw e; } return { trx_id: trxId, client_trx_id: orderTransactionDto.trx_id, product: orderTransactionDto.productCode, amount: product_price.mark_up_price + product_price.price, status: status, }; } } async orderTransactionBillProd( orderTransactionDto: OrderTransactionDto, currentUser: any, ) { let status; const amount = 0; //GET USER DATA const userData = await this.userService.findByUsername( currentUser.username, ); //GET PRODUCT AND PRICE const product = await this.productService.findOne( orderTransactionDto.productCode, 'postpaid', orderTransactionDto.productId ); const supplier = await this.supplierService.findByCode( product.supplier.code, ); const product_price = await this.productHistoryPriceService.findOne( product.id, userData.partner?.id, ); //GET COA console.log('coamsk6', 'coa'); const coaAccount = await this.coaService.findByUser( userData.id, coaType.WALLET, ); const coaInventory = await this.coaService.findByName( `${coaType[coaType.INVENTORY]}-${product.supplier.code}`, ); const coaCostOfSales = await this.coaService.findByName( `${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`, ); const coaSales = await this.coaService.findByName( `${coaType[coaType.SALES]}-SYSTEM`, ); if (coaAccount.amount < product_price.mark_up_price + product_price.price) { throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: `Transaction failed due to insufficient balance`, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } //HIT API SUPPLIER const trxId = Array(11) .fill(null) .map(() => { return Math.round(Math.random() * 16).toString(16); }) .join(''); let hitLoginHemat; if (supplier.code == 'Hemat') { hitLoginHemat = await doAuthorizeHemat(supplier.irs_user, supplier.irs_pass, supplier); } let hitSupplier = supplier.code == 'Hemat' ? await doTransaction( orderTransactionDto.productCode, orderTransactionDto.destination, trxId, supplier, hitLoginHemat.data, product.type == 'prepaid' ? 'PURCHASE' : 'PAYMENT', ) : await doTransaction( orderTransactionDto.productCode, orderTransactionDto.destination, trxId, supplier, "", product.type == 'prepaid' ? 'PURCHASE' : 'PAYMENT', ); if (supplier.code != 'IRS') { const parsingResponse = hitSupplier.split(' '); hitSupplier = { success: hitSupplier.includes('diproses'), harga: parseInt( parsingResponse[parsingResponse.length - 2].replaceAll('.', ''), ), msg: hitSupplier, }; } // const hitSupplier = { // harga: 2000, // success: true, // msg: 'Berhasil', // }; this.logger.log({ responseAPISupplier: hitSupplier, }); let costInventory = product_price.price; if (hitSupplier.harga != product_price.price) { product_price.endDate = new Date(); costInventory = hitSupplier.harga; } try { //TRANSACTION DATA await this.connection.transaction(async (manager) => { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = product_price.mark_up_price + product_price.price; transactionData.user = userData.id; transactionData.type = typeTransaction.ORDER; transactionData.product_price = product_price; transactionData.destination = orderTransactionDto.destination; transactionData.partner_trx_id = orderTransactionDto.trx_id; transactionData.supplier_trx_id = trxId; if (!hitSupplier.success) { transactionData.status = statusTransaction.FAILED; status = statusTransaction[transactionData.status]; await this.transactionRepository.insert(transactionData); throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: hitSupplier.msg, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } else { transactionData.status = statusTransaction.PENDING; status = statusTransaction[transactionData.status]; } await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaInventory.id, credit: costInventory, }, { coa_id: coaCostOfSales.id, debit: costInventory, }, { coa_id: coaAccount.id, debit: product_price.mark_up_price + costInventory, }, { // eslint-disable-next-line camelcase coa_id: coaSales.id, credit: product_price.mark_up_price + costInventory, }, ], }); }); } catch (e) { throw e; } return { trx_id: trxId, client_trx_id: orderTransactionDto.trx_id, product: orderTransactionDto.productCode, amount: product_price.mark_up_price + product_price.price, status: status, }; } async checkBill(orderTransactionDto: OrderTransactionDto, currentUser: any) { //GET USER DATA const userData = await this.userService.findByUsername( currentUser.username, ); //GET PRODUCT AND PRICE const product = await this.productService.findOne( orderTransactionDto.productCode, 'postpaid', orderTransactionDto.productId ); const supplier = await this.supplierService.findByCode( product.supplier.code, ); const product_price = await this.productHistoryPriceService.findOne( product.id, userData.partner?.id, ); //HIT API SUPPLIER const trxId = Array(11) .fill(null) .map(() => { return Math.round(Math.random() * 16).toString(16); }) .join(''); let status; try { let hitLoginHemat; if (supplier.code == 'Hemat') { hitLoginHemat = await doAuthorizeHemat(supplier.irs_user, supplier.irs_pass, supplier); } let hitSupplier = supplier.code == 'Hemat' ? await doTransaction( orderTransactionDto.productCode, orderTransactionDto.destination, trxId, supplier, hitLoginHemat.data, 'INQUIRY' ) : await doTransaction( `CEK${orderTransactionDto.productCode.slice(3)}`, orderTransactionDto.destination, trxId, supplier, "", 'INQUIRY' ); // const parsingResponse = hitSupplier.split(' '); if (supplier.code == 'Hemat') { hitSupplier = { success: hitSupplier.success == true, msg: hitSupplier.msg, }; } else { hitSupplier = { success: hitSupplier.includes('diproses') || hitSupplier.includes('dalam proses'), msg: hitSupplier, }; } console.log('inidatacheckbill', hitSupplier) console.log('statushitsupplier', hitSupplier.success) if (!hitSupplier.success) { status = statusTransaction[statusTransaction.FAILED]; throw new HttpException( { statusCode: HttpStatus.INTERNAL_SERVER_ERROR, error: hitSupplier.msg, }, HttpStatus.INTERNAL_SERVER_ERROR, ); } else { status = statusTransaction[statusTransaction.SUCCESS]; await this.checkBillHistoryRepository.insert({ trx_id: trxId, user: userData.id, callback_json: JSON.stringify(hitSupplier), destination: orderTransactionDto.destination, product_code: orderTransactionDto.productCode, partner_trx_id: orderTransactionDto.trx_id, product_price: product_price, status: 'PENDING', }); } } catch (e) { throw e; } return { trx_id: trxId, client_trx_id: orderTransactionDto.trx_id, product: orderTransactionDto.productCode, status: status, }; } async createDepositReturn(currentUser, depositReturnDto: DepositReturnDto) { const userData = await this.userService.findByUsername( currentUser.username, ); try { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = depositReturnDto.amount; transactionData.user = userData.id; transactionData.user_destination = depositReturnDto.destination; transactionData.status = statusTransaction.PENDING; transactionData.type = typeTransaction.DEPOSIT_RETURN; transactionData.image_prove = depositReturnDto.image_prove; await this.connection.transaction(async (manager) => { await manager.insert(Transactions, transactionData); }); return transactionData; } catch (e) { throw e; } } async confirmationDepositReturn( id: string, userData, statusApproval: string, ) { const transactionData = await this.findApprovalDepositReturn(id); // const coaSenderWallet = await this.coaService.findByUser( // transactionData.user, // coaType.WALLET, // ); // // const coaAP = await this.coaService.findByUserWithRelated( // transactionData.user, // userData.userId, // coaType.ACCOUNT_PAYABLE, // ); // // const coaReceiverWallet = await this.coaService.findByUser( // transactionData.user, // coaType.WALLET, // ); // // const coaAR = await this.coaService.findByUserWithRelated( // transactionData.user, // userData.userId, // coaType.ACCOUNT_RECEIVABLE, // ); const userFind = await this.userService.findByUsername(userData.username); try { await this.connection.transaction(async (manager) => { if (statusApproval === 'accept') { if (userFind.roles.name != 'Admin') { transactionData.user_destination = userFind.superior.id; } else { transactionData.status = statusTransaction.APPROVED; } // await this.accountingTransaction({ // createTransaction: false, // transactionalEntityManager: manager, // transaction: transactionData, // amount: transactionData.amount, // journals: [ // { // coa_id: coaSenderWallet.id, // credit: transactionData.amount, // }, // { // coa_id: coaReceiverWallet.id, // debit: transactionData.amount, // }, // { // coa_id: coaAR.id, // credit: transactionData.amount, // }, // { // coa_id: coaAP.id, // debit: transactionData.amount, // }, // ], // }); } else { transactionData.status = statusTransaction.REJECTED; } await manager.save(transactionData); }); return transactionData; } catch (e) { throw e; } return transactionData; } async confirmationAdminDepositReturn( id: string, userData, statusApproval: string, ) { const transactionData = await this.findApprovalDepositReturn(id); const coaAR = await this.coaService.findByUserWithRelated( userData.userId, transactionData.user_destination, coaType.ACCOUNT_RECEIVABLE, ); const coaBank = await this.coaService.findByName( `${coaType[coaType.BANK]}-SYSTEM`, ); try { await this.connection.transaction(async (manager) => { transactionData.status = statusApproval === 'Accept' ? statusTransaction.APPROVED : statusTransaction.REJECTED; await manager.save(transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaAR.id, credit: transactionData.amount, }, { coa_id: coaBank.id, debit: transactionData.amount, }, ], }); }); return transactionData; } catch (e) { throw e; } return transactionData; } async checkCallbackOrderFailed(supplier_trx_id: string, callback: any) { const transactionData = await this.findDataTransactionBySupplierTrxId( supplier_trx_id, ); // if (transactionData.status == statusTransaction.FAILED) { // throw new HttpException( // { // statusCode: HttpStatus.BAD_REQUEST, // error: 'failed to update, the transaction already failed', // }, // HttpStatus.BAD_REQUEST, // ); // } else if (transactionData.status == statusTransaction.SUCCESS) { // throw new HttpException( // { // statusCode: HttpStatus.BAD_REQUEST, // error: 'failed to update, the transaction already success', // }, // HttpStatus.BAD_REQUEST, // ); // } else { const updateTransaction = await this.callbackOrderFailed( supplier_trx_id, callback, ); throw new HttpException( { updateTransaction, statusCode: HttpStatus.BAD_REQUEST, error: 'updated transaction to failed', }, HttpStatus.BAD_REQUEST, ); // } } async checkCallbackOrderSuccess(supplier_trx_id: string, callback: any) { const transactionData = await this.findDataTransactionBySupplierTrxId( supplier_trx_id, ); // if (transactionData.status == statusTransaction.FAILED) { // throw new HttpException( // { // statusCode: HttpStatus.BAD_REQUEST, // error: 'failed to update, the transaction already failed', // }, // HttpStatus.BAD_REQUEST, // ); // } else if (transactionData.status == statusTransaction.SUCCESS) { // throw new HttpException( // { // statusCode: HttpStatus.BAD_REQUEST, // error: 'failed to update, the transaction already success', // }, // HttpStatus.BAD_REQUEST, // ); // } else { const updateTransaction = await this.callbackOrderSuccess( supplier_trx_id, callback, ); throw new HttpException( { updateTransaction, statusCode: HttpStatus.OK, error: 'success', }, HttpStatus.OK, ); // } } async findDataTransactionBySupplierTrxId(supplier_trx_id: string) { try { return await this.transactionRepository.findOneOrFail({ where: { supplier_trx_id: supplier_trx_id, }, relations: ['product_price'], }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'data not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async callbackOrderFailed(supplier_trx_id: string, callback: any) { const dataTransaction = await this.transactionRepository.findOne({ where: { supplier_trx_id: supplier_trx_id, }, relations: ['product_price'], }); const dataProductHistoryPrice = await this.productPriceRepository.findOne({ where: { id: dataTransaction.product_price.id, }, }); // const dataMsg = callback.msg; // const failedReason = dataMsg.split('.'); const userData = await this.userService.findExist(dataTransaction.user); const product_price = await this.productHistoryPriceService.findById( dataTransaction.product_price.id, ); const product = await this.productService.findOneById( product_price.product.id, ); if (callback['message']) { if (callback['message'].includes('METRO')) { if (callback['price'] != dataTransaction.product_price.price) { dataTransaction.product_price.price = parseInt(callback['price']); } } } //GET COA console.log('coamsk7', 'coa'); const coaAccount = await this.coaService.findByUser( userData.id, coaType.WALLET, ); dataTransaction.status = statusTransaction.FAILED; dataTransaction.callback_json = callback; dataTransaction.failed_reason = `Trx ${product.code} ke ${dataTransaction.destination} gagal`; dataTransaction.balance_remaining = parseInt(coaAccount.amount.toString()) + parseInt(dataTransaction.amount.toString()); const coaInventory = await this.coaService.findByName( `${coaType[coaType.INVENTORY]}-${product.supplier.code}`, ); const coaCostOfSales = await this.coaService.findByName( `${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`, ); const coaSales = await this.coaService.findByName( `${coaType[coaType.SALES]}-SYSTEM`, ); try { await this.connection.transaction(async (manager) => { await manager.save(dataTransaction); await manager.save(dataProductHistoryPrice); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: dataTransaction, amount: dataTransaction.amount, journals: [ { coa_id: coaInventory.id, debit: product_price.price, }, { coa_id: coaCostOfSales.id, credit: product_price.price, }, { coa_id: coaAccount.id, credit: product_price.mark_up_price + product_price.price, }, { coa_id: coaSales.id, debit: product_price.mark_up_price + product_price.price, }, ], }); }); } catch (e) { throw e; } if (userData.partner) { const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah gagal.`; this.callbackToPartner( userData.partner.id, message, dataTransaction.partner_trx_id, dataTransaction.amount, product.code, dataTransaction.destination, '-', 'gagal', ); } } async callbackOrderSuccess(supplier_trx_id: string, callback: any) { const dataTransaction = await this.transactionRepository.findOne({ where: { supplier_trx_id: supplier_trx_id, }, relations: ['product_price'], }); const dataProductHistoryPrice = await this.productPriceRepository.findOne({ where: { id: dataTransaction.product_price.id, }, }); const product_price = await this.productHistoryPriceService.findById( dataTransaction.product_price.id, ); const product = await this.productService.findOneById( product_price.product.id, ); const supplier = await this.supplierService.findByCode( product.supplier.code, ); dataTransaction.status = statusTransaction.SUCCESS; if (supplier.code == 'Hemat') { if (callback['sn']) { dataTransaction.seri_number = callback['sn']; } else { dataTransaction.seri_number = callback['data']['serial_number']; } if (callback['hrg']) { dataProductHistoryPrice.price = callback['hrg']; } else { dataProductHistoryPrice.price = parseInt(callback['data']['additional']['harga']); } } else { if (callback['sn']) { dataTransaction.seri_number = callback['sn']; console.log('msksn1', dataTransaction.seri_number); } else { console.log('entnewsn', 'msk'); const response = callback['message']; const responseBaru = response.split(' '); if (supplier.code == 'metro' && response.includes('PLN')) { const s = 'SN: ' const index = response.indexOf(s); const subIndex = index + s.length; const newRes = response.substring(subIndex); console.log('newres1', newRes); if (newRes.includes(' .')) { const splitRes = newRes.split(' .') const serialNumber = splitRes[0]; console.log('msknewsn', serialNumber); dataTransaction.seri_number = serialNumber } } else { dataTransaction.seri_number = responseBaru[10].length > 1 ? responseBaru[10] : responseBaru[9]; console.log('isisn', dataTransaction.seri_number); if (dataTransaction.seri_number == 'SN:') { dataTransaction.seri_number = responseBaru[11]; console.log('msknewsn2', responseBaru[11]); } } } if (callback['message']) { if (callback['message'].includes('METRO')) { if (callback['price'] != dataTransaction.product_price.price) { dataProductHistoryPrice.price = parseInt(callback['price']); } } } } dataTransaction.callback_json = callback; const userData = await this.userService.findExist(dataTransaction.user); let supervisorData = []; let profit = product_price.mark_up_price; //GET COA const coaExpense = await this.coaService.findByName( `${coaType[coaType.EXPENSE]}-SYSTEM`, ); // dataTransaction.balance_remaining = coaAccount.amount - product_price.mark_up_price - costInventory; try { console.log('updatestatustrans', 'update'); await this.connection.transaction(async (manager) => { await manager.save(dataTransaction); await manager.save(dataProductHistoryPrice); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: dataTransaction, amount: dataTransaction.amount, journals: supervisorData, }); }); } catch (e) { console.log('errupdatestatus', e); throw e; } if (userData.partner == null) { console.log('partnernull', 'masuk'); //GET SALES supervisorData = await this.calculateCommission( supervisorData, profit, userData, ); profit = supervisorData .map((item) => { return item.credit; }) .reduce((prev, curr) => { return prev + curr; }, 0); supervisorData = supervisorData.concat([ { coa_id: coaExpense.id, debit: profit, }, ]); } if (userData.partner != null) { if (userData.partner) { console.log('partnernotnull', 'masuk'); const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah berhasil.`; this.callbackToPartner( userData.partner.id, message, dataTransaction.partner_trx_id, dataTransaction.amount, product.code, dataTransaction.destination, dataTransaction.seri_number, 'berhasil', ); } } } async resendOrderToPartner(supplier_trx_id: string, status: boolean) { const dataTransaction = await this.transactionRepository.findOne({ where: { supplier_trx_id: supplier_trx_id, }, relations: ['product_price'], }); const userData = await this.userService.findExist(dataTransaction.user); const product_price = await this.productHistoryPriceService.findById( dataTransaction.product_price.id, ); const product = await this.productService.findOneById( product_price.product.id, ); if (status) { const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah berhasil.`; await this.callbackToPartner( userData.partner.id, message, dataTransaction.partner_trx_id, dataTransaction.amount, product.code, dataTransaction.destination, dataTransaction.seri_number, 'berhasil', ); } else { const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah gagal.`; this.callbackToPartner( userData.partner.id, message, dataTransaction.partner_trx_id, dataTransaction.amount, product.code, dataTransaction.destination, '-', 'gagal', ); } } async callbackToPartner( partnerId: string, message: string, trxId: string, harga: number, productCode: string, destination: string, seriNumber: string, status: string, ) { const partnerData = await this.userService.findPartner(partnerId); const userData = await this.userService.findOneByPartner(partnerId); console.log('coamsk8', 'coa'); const coaAccount = await this.coaService.findByUser( userData.id, coaType.WALLET, ); if (!partnerData.callback_url) { console.log('nopartnerurl', 'msk'); this.logger.error(`Call to partner failed, reason: no callback url`); return false; } const url = `${partnerData.callback_url}?status=${status}&memberID=${partnerData.code}&trxid=${trxId}&harga=${harga}&product=${productCode}&dest=${destination}&seriNumber=${seriNumber}&message=${message}&saldo=${coaAccount.amount}`; const result = await this.callbackPartnerRepository.insert({ partner_trx_id: partnerId, trx_id: trxId, url: url, }); try { const res = await axios.get(url); console.log('successcallback', res); return res; } catch (e) { console.log('errorsendcallback', 'msk'); this.logger.error(`Call to partner failed, reason: ${e.message}`); return false; } } async rollbackJurnal(trxId: string[]) { // const dataTransaction = await this.transactionRepository.findOne({ // where: { // id: trxId, // }, // relations: ['product_price'], // }); if (trxId.length % 2 != 0) { throw Error('Not Balance'); } const dataTransactionJurnal = await this.transactionJournalRepository.find({ where: { id: In(trxId), }, relations: ['coa'], }); const dataRollbackJurnal = []; dataTransactionJurnal.map((it) => { const data = { coa_id: it.coa.id, }; if (it.type == 0) { data['credit'] = it.amount; } else { data['debit'] = it.amount; } dataRollbackJurnal.push(data); }); const dataTransaction = new Transactions(); try { await this.connection.transaction(async (manager) => { await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: dataTransaction, amount: dataTransaction.amount, journals: dataRollbackJurnal, }); }); } catch (e) { throw e; } } async withdrawBenefit(user) { const userData = await this.userService.findExist(user); console.log('coamsk9', 'coa'); const coaProfit = await this.coaService.findByUser(user, coaType.PROFIT); const coaBank = await this.coaService.findByName( `${coaType[coaType.BANK]}-SYSTEM`, ); try { const transactionData = new Transactions(); transactionData.id = uuid.v4(); transactionData.amount = coaProfit.amount; transactionData.user = userData.id; transactionData.status = statusTransaction.APPROVED; transactionData.type = typeTransaction.WITHDRAW; await this.connection.transaction(async (manager) => { await manager.insert(Transactions, transactionData); await this.accountingTransaction({ createTransaction: false, transactionalEntityManager: manager, transaction: transactionData, amount: transactionData.amount, journals: [ { coa_id: coaBank.id, credit: transactionData.amount, }, { coa_id: coaProfit.id, debit: transactionData.amount, }, ], }); }); return transactionData; } catch (e) { throw e; } } async transactionHistoryByUser( page: number, user: string, startDate: string, endDate: string, pageSize?: number, ) { const userData = await this.userService.findExist(user); let userBySupperior = []; if ( userData.roles.id != 'e4dfb6a3-2338-464a-8fb8-5cbc089d4209' && userData.roles.id != '21dceea2-416e-4b55-b74c-12605e1f8d1b' ) { let roleNumber; if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72321') { roleNumber = 3; } else if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72322') { roleNumber = 2; } else if (userData.roles.id == 'e4dfb6a3-2348-464a-8fb8-5cbc089d4209') { roleNumber = 1; } const listUser = await this.userService.findAllSubordinate( userData.id, roleNumber, ); if (listUser.length < 1) { userBySupperior.push(userData.id); } else { userBySupperior = listUser; } } else { userBySupperior.push(userData.id); } const baseQuery = this.transactionRepository .createQueryBuilder('transaction') .select('transaction.id', 'id') .addSelect('transaction.created_at', 'created_at') .where('transaction.user IN (:...id) and transaction.type = 1', { id: userBySupperior, }) .leftJoinAndMapOne( 'transaction.userData', UserDetail, 'userData', 'userData.user = transaction.user', ) .leftJoin('transaction.product_price', 'product_price') .leftJoin('product_price.product', 'product') .leftJoin('product.supplier', 'supplier') .addSelect('transaction.amount', 'price') .addSelect('transaction.destination') .addSelect('transaction.balance_remaining', 'balance_remaining') .addSelect('transaction.seri_number', 'seri_number') .addSelect('transaction.supplier_trx_id', 'transaction_code') .addSelect('transaction.status', 'status') .addSelect('transaction.partner_trx_id', 'partner_transaction_code') .addSelect('transaction.failed_reason', 'failed_reason') .addSelect('userData.name', 'buyer') .addSelect('product.name', 'name') .addSelect('product_price.price', 'product_price') .addSelect('product_price.mark_up_price', 'mark_up_price') .addSelect('product.name', 'supplier_name') .addSelect('supplier.name', 'supplier_name') .orderBy('transaction.created_at', 'DESC'); if (startDate && endDate) { baseQuery.andWhere( 'transaction.created_at between :startDate and :enDate', { startDate: new Date(startDate), enDate: new Date(endDate), }, ); } const data = await baseQuery .offset(page * (pageSize || 10)) .limit(pageSize || 10) .getRawMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findOne(user: string, id: string) { try { return this.checkBillHistoryRepository.findOneOrFail({ where: { trx_id: id, user: user, }, }); } catch (e) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'Billing not found', }, HttpStatus.NOT_FOUND, ); } } async findAll(user: string, page, pageSize?) { try { return await this.checkBillHistoryRepository.findAndCount({ where: { user: user, }, select: [ 'amount', 'admin_price', 'product_code', 'destination', 'trx_id', 'partner_trx_id', 'status', 'createdAt', ], skip: page * (pageSize || 10), take: pageSize || 10, order: { createdAt: 'DESC', }, }); } catch (e) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'Billing not found', }, HttpStatus.NOT_FOUND, ); } } async topUpHistoryByUser( page: number, user: string, destinationUser: string, type: string, pageSize?: number, ) { const userData = await this.userService.findExist(user); const baseQuery = this.transactionRepository .createQueryBuilder('transaction') .leftJoinAndMapOne( 'transaction.userData', UserDetail, 'userData', 'userData.user = transaction.user', ); if ( userData.roles.name == 'Admin' || userData.roles.name == 'Customer Service' || type == 'profile' ) { baseQuery.where( 'transaction.type = 0 and transaction.user_destination = :destinationId', { destinationId: destinationUser, }, ); } else { baseQuery.where( 'transaction.user = :id and transaction.type = 0 and transaction.user_destination = :destinationId', { id: user, destinationId: destinationUser, }, ); } baseQuery .select([ 'transaction.id', 'transaction.created_at as transaction_date', 'amount', 'userData.name as sender_name', ]) .orderBy('transaction.created_at', 'DESC'); const data = await baseQuery .offset(page * (pageSize || 10)) .limit(pageSize || 10) .getRawMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findApprovalDepositReturn(id: string) { try { return await this.transactionRepository.findOneOrFail({ where: { id: id, type: typeTransaction.DEPOSIT_RETURN, status: statusTransaction.PENDING, }, }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'Return Deposit not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async getAllDepositReturnFromUser( user: string, page: number, startDate: string, endDate: string, pageSize?: number, ) { const filter = { user: user, type: typeTransaction.DEPOSIT_RETURN, }; if (startDate && endDate) { filter['start'] = Between(new Date(startDate), new Date(endDate)); } const baseQuery = this.transactionRepository.findAndCount({ skip: page * (pageSize || 10), take: pageSize || 10, where: filter, order: { createdAt: 'DESC', }, }); return baseQuery; } async getAllDepositReturnToUser( user: string, page: number, sender: string, startDate: string, endDate: string, pageSize?: number, ) { const baseQuery = this.transactionRepository .createQueryBuilder('transaction') .where('transaction.user_destination = :id and transaction.type = 3', { id: user, }) .leftJoinAndMapOne( 'transaction.userData', UserDetail, 'userData', 'userData.user = transaction.user', ) .select('transaction.id', 'id') .addSelect([ 'transaction.created_at', 'image_prove', 'amount', 'status', 'userData.name', ]) .orderBy('transaction.created_at', 'DESC'); if (startDate && endDate) { baseQuery.andWhere( 'transaction.created_at between :startDate and :enDate', { startDate: new Date(startDate), enDate: new Date(endDate), }, ); } if (sender) { baseQuery.andWhere('transaction.user = :sender', { sender, }); } const data = await baseQuery .offset(page * (pageSize || 10)) .limit(pageSize || 10) .getRawMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; return this.transactionRepository.findAndCount({ skip: page * (pageSize || 10), take: pageSize || 10, where: { user_destination: user, type: typeTransaction.DEPOSIT_RETURN, }, order: { createdAt: 'DESC', }, }); } async exportDataExcel(startDate, user: any) { const userData = await this.userService.findExist(user); let userBySupperior = []; if ( userData.roles.id != 'e4dfb6a3-2338-464a-8fb8-5cbc089d4209' && userData.roles.id != '21dceea2-416e-4b55-b74c-12605e1f8d1b' ) { let roleNumber; if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72321') { roleNumber = 3; } else if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72322') { roleNumber = 2; } else if (userData.roles.id == 'e4dfb6a3-2348-464a-8fb8-5cbc089d4209') { roleNumber = 1; } const listUser = await this.userService.findAllSubordinate( userData.id, roleNumber, ); if (listUser.length < 1) { userBySupperior.push(userData.id); } else { userBySupperior = listUser; } } else { userBySupperior.push(userData.id); } const baseQuery = this.transactionRepository .createQueryBuilder('transaction') .select('transaction.id', 'id') .addSelect('transaction.created_at', 'created_at') .where('transaction.user IN (:...id) and transaction.type = 1', { id: userBySupperior, }) .leftJoinAndMapOne( 'transaction.userData', UserDetail, 'userData', 'userData.user = transaction.user', ).select(['userData.user']) .leftJoin('transaction.product_price', 'product_price') .leftJoin('product_price.product', 'product') .leftJoin('product.supplier', 'supplier') .addSelect('product.name', 'product_name') .addSelect('product.code', 'product_code') .addSelect('transaction.amount', 'price') .addSelect('transaction.balance_remaining', 'balance_remaining') .addSelect('userData.name', 'buyer') .addSelect('transaction.destination', 'destination') .addSelect('transaction.supplier_trx_id', 'transaction_code') .addSelect(`CASE WHEN "transaction"."status" = 1 THEN 'Success' WHEN "transaction"."status" = 2 THEN 'Failed' ELSE 'Pending' END`, 'status') .addSelect('transaction.seri_number', 'serial_number') .addSelect('transaction.partner_trx_id', 'partner_trx_id') .addSelect('transaction.created_at', 'transaction_date') .addSelect('transaction.failed_reason', 'failed_reason') .orderBy('transaction.created_at', 'DESC'); if (startDate) { baseQuery.andWhere( 'transaction.created_at between :startDate and :enDate', { startDate: new Date (`${startDate} 00:00:00`), enDate: new Date (`${startDate} 23:59:59`), }, ); } const data = await baseQuery.getRawMany(); // return { // data, // }; try { let rows = []; // First create the array of keys/net_total so that we can sort it: var sort_array = []; for (var key in data) { sort_array.push({key: key, product_name: data[key].product_name}); } // Now sort it: sort_array.sort((x, y) => { return x.product_name - y.product_name; }); let dataSorted = []; // Now process that object with it: for (var i = 0; i < sort_array.length; i++) { var item = data[sort_array[i].key]; // now do stuff with each item const moment = require("moment"); dataSorted.push({ product_name: item.product_name, product_code: item.product_code, price: item.price, balance_remaining: item.balance_remaining, buyer: item.buyer, destination: item.destination, transaction_code: item.transaction_code, status: item.status, serial_number: item.serial_number, partner_trx_id: item.partner_trx_id, transaction_date: moment(new Date (item.transaction_date).toISOString().replace('Z', ' ').replace('T', ' ')).format("MM-DD-YYYY HH:mm:ss"), failed_reason: item.failed_reason, }); } dataSorted.forEach((doc) => { rows.push(Object.values(doc)); }); //creating a workbook let book = new Workbook(); //adding a worksheet to workbook let sheet = book.addWorksheet('Mutasi Transaksi'); //add the header rows.unshift(Object.keys(dataSorted[0])); //adding multiple rows in the sheet sheet.addRows(rows); //customize column sheet.columns = [ {header: 'Nama Produk', key: 'product_name'}, {header: 'Kode Produk', key: 'product_code'}, {header: 'Harga', key: 'price'}, {header: 'Sisa Saldo', key: 'balance_remaining'}, {header: 'Pembeli', key: 'buyer'}, {header: 'Tujuan', key: 'destination'}, {header: 'Kode Transaksi', key: 'transaction_code'}, {header: 'Status', key: 'status'}, {header: 'No Seri', key: 'serial_number'}, {header: 'IDTrx Mitra', key: 'partner_trx_id'}, {header: 'Tanggal Transaksi', key: 'transaction_date'}, {header: 'Alasan Gagal', key: 'failed_reason'}, ]; this.styleSheet(sheet) const tmp = require('tmp'); let File = await new Promise((resolve, reject) => { tmp.file( { discardDescriptor: true, prefix: `Mutasi Transaksi ${userData?.partner.name} ${startDate}`, postfix: '.xlsx', mode: parseInt('0600', 8), }, async (err, file) => { if (err) throw new BadRequestException(err); //writing temporary file book.xlsx .writeFile(file) .then((_) => { resolve(file); }) .catch((err) => { throw new BadRequestException(err); }); }, ); }); //returning the path of file return File; } catch (e) { throw new HttpException('No data to export', HttpStatus.NOT_FOUND); } } async getTotalSell(currentUser) { const baseQuery = this.transactionRepository .createQueryBuilder('transactions') .innerJoin('transactions.product_price', 'product_price') .where( 'transactions.type = 1 and partner_trx_id is NULL and transactions.status = 1', ); const data = await baseQuery .select('SUM(transactions.amount) as total_amount') .addSelect('SUM(product_price.price) as total_modal') .addSelect('SUM(product_price.mark_up_price) as total_profit') .addSelect('COUNT(transactions.id) as total_transaction') .getRawOne(); const { total_expense } = await baseQuery .select('SUM(transaction_journal.amount) as total_expense') .innerJoin('transactions.transactionJournal', 'transaction_journal') .where( `transaction_journal.type = '0' and transaction_journal.amount < product_price.price`, ) .getRawOne(); console.log("totalprofitni", data.total_profit); console.log("totalexpenseni", total_expense); return { total_amount: parseInt(data.total_amount), total_transaction: parseInt(data.total_transaction), total_modal: parseInt(data.total_modal), total_profit: parseInt(data.total_profit), total_commission: parseInt(total_expense) - parseInt(data.total_profit), }; } async getTotalSellB2B(currentUser) { const baseQuery = this.transactionRepository .createQueryBuilder('transactions') .innerJoin('transactions.product_price', 'product_price') .where( 'transactions.type = 1 and partner_trx_id is not NULL and transactions.status = 1', ); const data = await baseQuery .select('SUM(transactions.amount) as total_amount') .addSelect('SUM(product_price.price) as total_modal') .addSelect('SUM(product_price.mark_up_price) as total_profit') .addSelect('COUNT(transactions.id) as total_transaction') .getRawOne(); // const dataCoa = this.coaRepository // .createQueryBuilder('coa') // .innerJoin('user', 'user', 'coa.user = user.id') // .where( // `coa.type = '0' and user.partner_id is not NULL and user.is_active = true and is_rejected = false` // ); // // const coa = await dataCoa // .select('SUM(coa.amount) as total_modal') // .getRawOne(); return { total_modal: parseInt(data.total_modal), total_amount: parseInt(data.total_amount), total_transaction: parseInt(data.total_transaction), total_profit: data.total_amount - data.total_modal, // total_profit: parseInt(data.total_profit), }; } async getTotalSellPartner(currentUser) { const userData = await this.userService.findByUsername( currentUser.username, ); const baseQuery = this.transactionRepository .createQueryBuilder('transactions') .innerJoin('transactions.product_price', 'product_price') .where('transactions.type = 1 and transactions.status = 1') .andWhere('transactions.user = :id', { id: userData.id, }); const data = await baseQuery .select('SUM(transactions.amount) as total_amount') .addSelect('COUNT(transactions.id) as total_transaction') .getRawOne(); return { total_amount: parseInt(data.total_amount), total_transaction: parseInt(data.total_transaction), }; } async calculateCommission(data, totalPrice, userData) { const supervisorData = []; supervisorData.push( await this.userService.findByUsername(userData.superior.username), ); //GET Supervisor supervisorData.push( await this.userService.findByUsername( supervisorData[0].superior.username, ), ); console.log('coamsk10', 'coa'); return Promise.all( supervisorData.map(async (it) => { const coaAccount = await this.coaService.findByUser( it.id, coaType.PROFIT, ); const commissionValue = await this.commissionService.findOne( it.roles.id, ); return { coa_id: coaAccount.id, credit: Math.floor((totalPrice * commissionValue.commission) / 100), }; }), ); } async accountingTransaction(createJournalDto: CreateJournalDto) { const creditSum = createJournalDto.journals .map((it) => { return it.credit; }) .filter((it) => { return it; }) .reduce((a, b) => { return a.plus(b); }, new Decimal(0)); const debitSum = createJournalDto.journals .map((it) => { return it.debit; }) .filter((it) => { return it; }) .reduce((a, b) => { return a.plus(b); }, new Decimal(0)); const coaIds = uniq( createJournalDto.journals.map((it) => { return it.coa_id; }), ); if (!creditSum.equals(debitSum)) { throw new Error(`credit and debit doesn't match`); } const coas = await this.coaRepository.findByIds(coaIds); const transaction = createJournalDto.transaction; await Promise.all( createJournalDto.journals.map((journal) => { const coa = coas.find((it) => { return it.id === journal.coa_id; }); if (!coa) { throw new Error(`coa ${journal.coa_id} not found`); } const journalEntry = new TransactionJournal(); journalEntry.coa = coa; journalEntry.type = journal.debit ? balanceType.DEBIT : balanceType.CREDIT; journalEntry.amount = journal.debit ? journal.debit : journal.credit; journalEntry.transaction_head = transaction; return createJournalDto.transactionalEntityManager.save(journalEntry); }), ); await Promise.all( coaIds.map((coaId) => { const journalPerCoa = createJournalDto.journals.filter((journal) => { return journal.coa_id == coaId; }); const creditSum = journalPerCoa .map((it) => { return it.credit; }) .filter((it) => { return it; }) .reduce((a, b) => { return a.plus(b); }, new Decimal(0)); const debitSum = journalPerCoa .map((it) => { return it.debit; }) .filter((it) => { return it; }) .reduce((a, b) => { return a.plus(b); }, new Decimal(0)); 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) .set({ amount: () => { return `amount + ${diff.toString()}`; }, }) .where('id = :id', { id: coa.id }) .execute(); }), ); return transaction; } async updateBill( trxId: string, amount: number, admin: number, status: boolean, message: string, ) { const billData = await this.findOneBillById(trxId); console.log(billData, 'ini dia'); const userData = await this.userService.findExist(billData.user); const product_price = await this.productHistoryPriceService.findById( billData.product_price.id, ); await this.checkBillHistoryRepository.update( { trx_id: trxId, }, { amount: status ? amount - admin + product_price.partner_fee + product_price.mark_up_price : 0, admin_price: admin, status: status ? 'SUCCESS' : 'FAILED', callback_json: JSON.stringify(message), }, ); if (userData.partner) { const message = status ? `Bill dari ${billData.destination} adalah ${ amount + product_price.partner_fee + product_price.mark_up_price }.` : ''; const statusResponse = status ? 'berhasil' : 'gagal'; this.callbackToPartner( userData.id, message, billData.partner_trx_id, amount + product_price.partner_fee + product_price.mark_up_price, billData.product_code, billData.destination, '-', statusResponse, ); } } async findOneBillById(trxId: string) { try { return await this.checkBillHistoryRepository.findOneOrFail({ relations: ['product_price'], where: { trx_id: trxId, }, }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'Bill not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } private styleSheet(sheet) { //set the width of each column sheet.getColumn(1).width = 40; sheet.getColumn(2).width = 20.5; sheet.getColumn(3).width = 20.5; sheet.getColumn(4).width = 20.5; sheet.getColumn(5).width = 20.5; sheet.getColumn(6).width = 20.5; sheet.getColumn(7).width = 20.5; sheet.getColumn(8).width = 20.5; sheet.getColumn(9).width = 20.5; sheet.getColumn(10).width = 20.5; sheet.getColumn(11).width = 20.5; sheet.getColumn(12).width = 20.5; //set the height of header sheet.getRow(1).height = 30.5; //font color sheet.getRow(1).font = {size: 11.5, bold: true, color: {argb: 'FFFFFF'}} //background color sheet.getRow(1).fill = {type: 'pattern', pattern: 'solid', bgColor: {argb: '000000'}, fgColor: {argb: '000000'}} //alignments sheet.getColumn(1).alignment = {vertical: "start", horizontal: "start", wrapText: true} sheet.getColumn(2).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(3).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(4).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(5).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(6).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(7).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(8).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(9).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(10).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(11).alignment = {vertical: "middle", horizontal: "center", wrapText: true} sheet.getColumn(12).alignment = {vertical: "start", horizontal: "start", wrapText: true} sheet.getRow(1).alignment = {vertical: "middle", horizontal: "center", wrapText: true} //borders const borderStyle = { top: {style: 'double', color: {argb: 'FF00FF00'}}, left: {style: 'double', color: {argb: '000000'}}, bottom: {style: 'double', color: {argb: '000000'}}, right: {style: 'double', color: {argb: '000000'}} } sheet.getColumn(1).border = borderStyle sheet.getColumn(2).border = borderStyle sheet.getColumn(3).border = borderStyle sheet.getColumn(4).border = borderStyle sheet.getColumn(5).border = borderStyle sheet.getColumn(6).border = borderStyle sheet.getColumn(7).border = borderStyle sheet.getColumn(8).border = borderStyle sheet.getColumn(9).border = borderStyle sheet.getColumn(10).border = borderStyle sheet.getColumn(11).border = borderStyle sheet.getColumn(12).border = borderStyle sheet.getRow(1).border = { top: {style: 'thin', color: {argb: '000000'}}, left: {style: 'thin', color: {argb: 'FFFFFF'}}, bottom: {style: 'thin', color: {argb: '000000'}}, right: {style: 'thin', color: {argb: 'FFFFFF'}} } } }