2767 lines
82 KiB
TypeScript
2767 lines
82 KiB
TypeScript
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';
|
|
import moment from "moment";
|
|
|
|
@Injectable()
|
|
export class TransactionService {
|
|
private readonly logger = new Logger(TransactionService.name);
|
|
|
|
constructor(
|
|
@InjectRepository(Transactions)
|
|
private transactionRepository: Repository<Transactions>,
|
|
@InjectRepository(TransactionJournal)
|
|
private transactionJournalRepository: Repository<TransactionJournal>,
|
|
@InjectRepository(ProductHistoryPrice)
|
|
private productPriceRepository: Repository<ProductHistoryPrice>,
|
|
@InjectRepository(COA)
|
|
private coaRepository: Repository<COA>,
|
|
@InjectRepository(CheckBillHistory)
|
|
private checkBillHistoryRepository: Repository<CheckBillHistory>,
|
|
@InjectRepository(CallbackPartner)
|
|
private callbackPartnerRepository: Repository<CallbackPartner>,
|
|
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('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, currentUser: 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('supplier.name', 'supplier_name')
|
|
.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");
|
|
if (currentUser.username == 'admin') {
|
|
dataSorted.push({
|
|
product_name: item.product_name,
|
|
product_code: item.product_code,
|
|
supplier_name: item.supplier_name,
|
|
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,
|
|
});
|
|
} else {
|
|
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
|
|
if (currentUser.username == 'admin') {
|
|
sheet.columns = [
|
|
{header: 'Nama Produk', key: 'product_name'},
|
|
{header: 'Kode Produk', key: 'product_code'},
|
|
{header: 'Supplier', key: 'supplier_name'},
|
|
{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'},
|
|
];
|
|
} else {
|
|
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'}}
|
|
}
|
|
|
|
}
|
|
}
|
|
|