diff --git a/package-lock.json b/package-lock.json index 1b2d0f2..2e9f31c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.2", "dayjs": "^1.11.19", + "decimal.js": "^10.6.0", "fastify": "^5.6.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", @@ -8480,6 +8481,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://mirror-npm.runflare.com/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, "node_modules/dedent": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", diff --git a/package.json b/package.json index 5162e1f..5cf6407 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.2", "dayjs": "^1.11.19", + "decimal.js": "^10.6.0", "fastify": "^5.6.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", diff --git a/src/modules/invoice/entities/invoice.entity.ts b/src/modules/invoice/entities/invoice.entity.ts index 37c92f3..c3fda32 100644 --- a/src/modules/invoice/entities/invoice.entity.ts +++ b/src/modules/invoice/entities/invoice.entity.ts @@ -52,7 +52,7 @@ export class Invoice extends BaseEntity { type: 'int', unique: true }) - invoiceNumber: number; + invoiceNumber!: number | Opt; @Property({ type: 'int' }) diff --git a/src/modules/invoice/invoice.service.ts b/src/modules/invoice/invoice.service.ts index c2ec260..c6ba069 100644 --- a/src/modules/invoice/invoice.service.ts +++ b/src/modules/invoice/invoice.service.ts @@ -51,7 +51,7 @@ export class InvoiceService { ? new Date(dto.approvalDeadline) : undefined; - const discount = dto.items.reduce((acc, item) => acc + (item.discount ?? 0), 0); + // const discount = dto.items.reduce((acc, item) => acc + (item.discount ?? 0), 0); const invoice = await this.em.transactional(async (em) => { const invoice = em.create(Invoice, { @@ -59,12 +59,12 @@ export class InvoiceService { ...(request && { request }), enableTax, approvalDeadline, - discount, + // discount, paidAmount: 0, // balance: 0, attachments: [], paymentMethod: dto.paymentMethod, - invoiceNumber: 20, + invoiceNumber: 20, // TODO : invoice number description: dto.description }); em.persist(invoice); @@ -75,7 +75,7 @@ export class InvoiceService { const product = await this.productService.findOneOrFail(item.productId); const unitPrice = item.unitPrice; const itemDiscount = item.discount ?? 0; - const itemTotal = Math.max(0, unitPrice * item.quantity - itemDiscount); + // const itemTotal = Math.max(0, unitPrice * item.quantity - itemDiscount); // subTotal += itemTotal; const invoiceItem = em.create(InvoiceItem, { @@ -114,7 +114,7 @@ export class InvoiceService { await em.flush(); return invoice; }); - +// TODO : maybe it is needed to get a fresh instance. this.eventEmitter.emit( InvoiceCreatedEvent.name, new InvoiceCreatedEvent( @@ -231,13 +231,13 @@ export class InvoiceService { ); } const product = await this.productService.findOneOrFail(item.productId); - const itemDiscount = item.discount ?? 0; + // const itemDiscount = item.discount ?? 0; const invoiceItem = this.em.create(InvoiceItem, { invoice, product, quantity: item.quantity, unitPrice: item.unitPrice, - discount: itemDiscount || undefined, + // discount: itemDiscount || undefined,` description: item.description, }); invoice.items.add(invoiceItem); @@ -245,25 +245,25 @@ export class InvoiceService { } const allItems = invoice.items.getItems(); - let subTotal = 0; - let discount = 0; - for (const item of allItems) { - const itemTotal = Math.max( - 0, - item.unitPrice * item.quantity - (item.discount ?? 0), - ); - subTotal += itemTotal; - discount += item.discount ?? 0; - } - invoice.discount = discount; - const taxAmount = invoice.enableTax - ? Math.round((subTotal - discount) * TAX_RATE) - : 0; - const total = Math.max(0, subTotal - discount + taxAmount); - invoice.subTotal = subTotal; - invoice.taxAmount = taxAmount; - invoice.total = total; - invoice.balance = total - invoice.paidAmount; + // let subTotal = 0; + // let discount = 0; + // for (const item of allItems) { + // const itemTotal = Math.max( + // 0, + // item.unitPrice * item.quantity - (item.discount ?? 0), + // ); + // subTotal += itemTotal; + // discount += item.discount ?? 0; + // } + // invoice.discount = discount; + // const taxAmount = invoice.enableTax + // ? Math.round((subTotal - discount) * TAX_RATE) + // : 0; + // const total = Math.max(0, subTotal - discount + taxAmount); + // invoice.subTotal = subTotal; + // invoice.taxAmount = taxAmount; + // invoice.total = total; + // invoice.balance = total - invoice.paidAmount; } await this.em.flush(); return invoice; diff --git a/src/modules/payment/services/payments.service.ts b/src/modules/payment/services/payments.service.ts index e2772e4..a1bfe07 100644 --- a/src/modules/payment/services/payments.service.ts +++ b/src/modules/payment/services/payments.service.ts @@ -7,7 +7,6 @@ import { OrderPaymentContext } from '../interface/payment'; import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { onlinePaymentSucceedEvent, newCashPaymentEvent } from '../events/payment.events'; -import { OrderService } from 'src/modules/order/providers/order.service'; import { PayOrderDto } from '../dto/pay-order.dto'; import { PaymentRepository } from '../repositories/payment.repository'; import { CreditRepository } from 'src/modules/user/repositories/credit.repository'; @@ -20,6 +19,7 @@ import { AdminRepository } from 'src/modules/admin/repositories/admin.repository import { CreditTransaction } from 'src/modules/user/entities/credit-transaction.entity'; import { InvoiceService } from 'src/modules/invoice/invoice.service'; import { ConfigService } from '@nestjs/config'; +import { Decimal } from 'decimal.js' @@ -41,7 +41,7 @@ export class PaymentService { private readonly adminRepository: AdminRepository, private readonly invoiceService: InvoiceService, private readonly configService: ConfigService, - ) { + ) { this.frontUrl = this.configService.get('FRONT_URL') || 'https://negareh-console.dev.danakcorp.com/' } @@ -84,11 +84,11 @@ export class PaymentService { } } - if (amount <= 0) { + if (new Decimal(amount).lte(0)) { throw new BadRequestException(PaymentMessage.AMOUNT_MUST_BE_GREATER_THAN_ZERO); } - if (amount > invoice.balance) { + if (new Decimal(amount).gte(invoice.balance)) { throw new BadRequestException(`You cant pay more than ${invoice.balance}`); } @@ -125,13 +125,13 @@ export class PaymentService { await this.em.transactional(async em => { // 1. get User remained Credit - const remainedCredit = await this.creditService.getCurrentCredit(user.id) + const remainedCredit = new Decimal(await this.creditService.getCurrentCredit(user.id)) - if (remainedCredit < amount) { + if (remainedCredit.lt(amount)) { throw new BadRequestException("You Dont have enough Credit") } - const newBalance = remainedCredit - amount; + const newBalance = remainedCredit.minus(amount) // 2. Create payment record const payment = em.create(Payment, { creator: admin, @@ -147,7 +147,7 @@ export class PaymentService { user: invoice.user, amount, type: CreditTransactionType.WITHDRAW, - balance: newBalance, + balance: newBalance.toNumber(), invoiceId: invoice.id, }); diff --git a/src/modules/user/providers/credit.service.ts b/src/modules/user/providers/credit.service.ts index f1d39dd..ed7fa0c 100644 --- a/src/modules/user/providers/credit.service.ts +++ b/src/modules/user/providers/credit.service.ts @@ -6,6 +6,7 @@ import { FindWalletTransactionsDto } from '../dto/find-wallet-transactions.dto'; import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; import { CreditTransaction } from '../entities/credit-transaction.entity'; import { UserRepository } from '../repositories/user.repository'; +import Decimal from 'decimal.js'; @Injectable() @@ -24,7 +25,7 @@ export class CreditService { throw new BadRequestException("User not found") } - const maxCredit = user.maxCredit + const maxCredit = new Decimal(user.maxCredit) const latestTransaction = await this.creditRepository.findOne( { @@ -32,11 +33,11 @@ export class CreditService { }, { orderBy: { createdAt: 'desc' } }, ); - const balance = latestTransaction?.balance || 0 + const balance = new Decimal(latestTransaction?.balance || 0) - const remained = maxCredit - balance + const remained = maxCredit.minus(balance) - return remained + return remained.toNumber() } // async getUserWalletTransactions( // userId: string,