diff --git a/src/app.module.ts b/src/app.module.ts index c346f5a..e552023 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -45,8 +45,10 @@ import { GoogleCalendarModule } from './modules/configuration/google-calendar/go import { TransactionModule } from './modules/transaction/transaction/transaction.module'; import { TransactionModel } from './modules/transaction/transaction/data/models/transaction.model'; import { + TransactionBreakdownTaxModel, TransactionItemBreakdownModel, TransactionItemModel, + TransactionItemTaxModel, } from './modules/transaction/transaction/data/models/transaction-item.model'; import { TransactionTaxModel } from './modules/transaction/transaction/data/models/transaction-tax.model'; import { ReconciliationModule } from './modules/transaction/reconciliation/reconciliation.module'; @@ -121,6 +123,8 @@ import { AuthService } from './core/guards/domain/services/auth.service'; TransactionTaxModel, TransactionDemographyModel, TransactionItemBreakdownModel, + TransactionItemTaxModel, + TransactionBreakdownTaxModel, UserModel, UserLoginModel, diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index f6d4b21..990c4cb 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -22,6 +22,8 @@ export enum TABLE_NAME { TRANSACTION_ITEM = 'transaction_items', TRANSACTION_ITEM_BREAKDOWN = 'transaction_item_breakdowns', TRANSACTION_TAX = 'transaction_taxes', + TRANSACTION_ITEM_TAX = 'transaction_item_taxes', + TRANSACTION_ITEM_BREAKDOWN_TAX = 't_breakdown_item_taxes', TRANSACTION_DEMOGRAPHY = 'transaction_demographies', USER = 'users', USER_LOGIN = 'users_login', diff --git a/src/database/migrations/1726045820711-add-tax-item-transaction.ts b/src/database/migrations/1726045820711-add-tax-item-transaction.ts new file mode 100644 index 0000000..7dffa6a --- /dev/null +++ b/src/database/migrations/1726045820711-add-tax-item-transaction.ts @@ -0,0 +1,73 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddTaxItemTransaction1726045820711 implements MigrationInterface { + name = 'AddTaxItemTransaction1726045820711'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "transaction_item_taxes" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "tax_id" character varying, "tax_name" character varying, "taxt_value" numeric, "tax_total_value" numeric, "transaction_id" uuid, CONSTRAINT "PK_fc5f6da61b24eb5bfdd503b0a0d" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "t_breakdown_item_taxes" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "tax_id" character varying, "tax_name" character varying, "taxt_value" numeric, "tax_total_value" numeric, "transaction_id" uuid, CONSTRAINT "PK_a1ef08d2c68169a50102aa70eca" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" ADD "total_profit_share" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" ADD "total_profit_share" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_taxes" ADD CONSTRAINT "FK_f5c4966a381d903899cafb4b5ba" FOREIGN KEY ("transaction_id") REFERENCES "transaction_items"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE "t_breakdown_item_taxes" ADD CONSTRAINT "FK_74bedce7e94f6707ddf26ef0c0f" FOREIGN KEY ("transaction_id") REFERENCES "transaction_item_breakdowns"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" ADD "payment_total_dpp" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" ADD "payment_total_dpp" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" ADD "payment_total_tax" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" ADD "payment_total_tax" numeric`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" ADD "total_share_tenant" numeric`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "t_breakdown_item_taxes" DROP CONSTRAINT "FK_74bedce7e94f6707ddf26ef0c0f"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_taxes" DROP CONSTRAINT "FK_f5c4966a381d903899cafb4b5ba"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "total_profit_share"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" DROP COLUMN "total_profit_share"`, + ); + await queryRunner.query(`DROP TABLE "t_breakdown_item_taxes"`); + await queryRunner.query(`DROP TABLE "transaction_item_taxes"`); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "payment_total_dpp"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" DROP COLUMN "payment_total_dpp"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "payment_total_tax"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_items" DROP COLUMN "payment_total_tax"`, + ); + await queryRunner.query( + `ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "total_share_tenant"`, + ); + } +} diff --git a/src/database/migrations/1726365023179-add-formula-to-tax.ts b/src/database/migrations/1726365023179-add-formula-to-tax.ts new file mode 100644 index 0000000..4654d9b --- /dev/null +++ b/src/database/migrations/1726365023179-add-formula-to-tax.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddFormulaToTax1726365023179 implements MigrationInterface { + name = 'AddFormulaToTax1726365023179'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "taxes" ADD "formula_render" json`); + await queryRunner.query( + `ALTER TABLE "taxes" ADD "formula_string" character varying`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "formula_string"`); + await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "formula_render"`); + } +} diff --git a/src/modules/transaction/profit-share-formula/domain/usecases/managers/index-profit-share-formula.manager.ts b/src/modules/transaction/profit-share-formula/domain/usecases/managers/index-profit-share-formula.manager.ts index f03482e..8936608 100644 --- a/src/modules/transaction/profit-share-formula/domain/usecases/managers/index-profit-share-formula.manager.ts +++ b/src/modules/transaction/profit-share-formula/domain/usecases/managers/index-profit-share-formula.manager.ts @@ -3,7 +3,6 @@ import { Param, RelationParam, } from 'src/core/modules/domain/entities/base-filter.entity'; -import { FormulaType } from 'src/modules/transaction/sales-price-formula/constants'; import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity'; import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; import { SelectQueryBuilder } from 'typeorm'; @@ -17,12 +16,7 @@ export class IndexProfitShareFormulaManager extends BaseIndexManager { @@ -51,6 +45,12 @@ export class IndexProfitShareFormulaManager extends BaseIndexManager { + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.status::text`, + isStatus: true, + data: [`'active'`], + }, + ]; + } + + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + // return []; + return [ + `${this.tableName}.id`, + `${this.tableName}.formula_render`, + `${this.tableName}.formula_string`, + `${this.tableName}.name`, + ]; + } +} diff --git a/src/modules/transaction/profit-share-formula/domain/usecases/managers/update-profit-share-formula.manager.ts b/src/modules/transaction/profit-share-formula/domain/usecases/managers/update-profit-share-formula.manager.ts index 7a22c6c..52da542 100644 --- a/src/modules/transaction/profit-share-formula/domain/usecases/managers/update-profit-share-formula.manager.ts +++ b/src/modules/transaction/profit-share-formula/domain/usecases/managers/update-profit-share-formula.manager.ts @@ -8,21 +8,21 @@ import { import { SalesPriceFormulaModel } from 'src/modules/transaction/sales-price-formula/data/models/sales-price-formula.model'; import { ProfitShareFormulaUpdatedEvent } from '../../entities/event/profit-share-formula-updated.event'; import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity'; -import { In } from 'typeorm'; -import { STATUS } from 'src/core/strings/constants/base.constants'; -import { calculateProfitFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper'; -import { FormulaType } from 'src/modules/transaction/sales-price-formula/constants'; +// import { In } from 'typeorm'; +// import { STATUS } from 'src/core/strings/constants/base.constants'; +// import { calculateProfitFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper'; @Injectable() export class UpdateProfitShareFormulaManager extends BaseUpdateManager { async validateProcess(): Promise { - const taxes = await this.dataServiceFirstOpt.getManyByOptions({ - where: { - status: In([STATUS.ACTIVE]), - }, - }); + // const taxes = await this.dataServiceFirstOpt.getManyByOptions({ + // where: { + // status: In([STATUS.ACTIVE]), + // }, + // }); - calculateProfitFormula(this.data.formula_string, taxes, 10000, 50, true); + // TODO: Save Validation + // calculateProfitFormula(this.data.formula_string, taxes, 10000, 50, true); return; } @@ -32,34 +32,9 @@ export class UpdateProfitShareFormulaManager extends BaseUpdateManager { const additionalFormula = this.data.additional; - for (const additional of additionalFormula) { - /** - * Find formula for variable - * If the formula doesn't exist, then create data for save - */ - const formula = (await this.dataService.getOneByOptions({ - where: { - value_for: additional.value_for, - }, - })) ?? { - editor_id: this.user.id, - editor_name: this.user.name, - updated_at: new Date().getTime(), - created_at: new Date().getTime(), - type: FormulaType.PROFIT_SHARE, - }; - - // Update formula value to exist formula or new formula - formula.formula_render = additional.formula_render; - formula.formula_string = additional.formula_string; - formula.value_for = additional.value_for; - - /** - * This function is create, but inside function is save - * So, if the id is provide, the data will be update instead create new data - */ - this.dataService.create(null, null, formula); - } + const taxFormula = this.data.taxes; + this.dataService.create(null, null, additionalFormula); + this.dataServiceFirstOpt.create(null, null, taxFormula); return; } diff --git a/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-data.orchestrator.ts b/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-data.orchestrator.ts index a1d68df..0bf359d 100644 --- a/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-data.orchestrator.ts +++ b/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-data.orchestrator.ts @@ -17,7 +17,7 @@ export class ProfitShareFormulaDataOrchestrator { async update(data): Promise { const formula = await this.serviceData.getOneByOptions({ where: { - type: FormulaType.PROFIT_SHARE, + type: FormulaType.SALES_PRICE, }, }); diff --git a/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-read.orchestrator.ts b/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-read.orchestrator.ts index 9dffdab..0659b8e 100644 --- a/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-read.orchestrator.ts +++ b/src/modules/transaction/profit-share-formula/domain/usecases/profit-share-formula-read.orchestrator.ts @@ -4,13 +4,17 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { SalesPriceFormulaReadService } from 'src/modules/transaction/sales-price-formula/data/services/sales-price-formula-read.service'; import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity'; import { IndexProfitShareFormulaManager } from './managers/index-profit-share-formula.manager'; +import { IndexTaxFormulaManager } from './managers/tax-formula.manager'; +import { TaxReadService } from 'src/modules/transaction/tax/data/services/tax-read.service'; @Injectable() export class ProfitShareFormulaReadOrchestrator { constructor( private detailManager: DetailProfitShareFormulaManager, private indexManager: IndexProfitShareFormulaManager, + private taxManager: IndexTaxFormulaManager, private serviceData: SalesPriceFormulaReadService, + private taxServiceData: TaxReadService, ) {} async index(): Promise { @@ -21,6 +25,19 @@ export class ProfitShareFormulaReadOrchestrator { return data; } + async tax(): Promise[]> { + this.taxManager.setFilterParam({}); + this.taxManager.setService(this.taxServiceData, TABLE_NAME.TAX); + await this.taxManager.execute(); + const { data } = this.taxManager.getResult(); + return data.map((tax) => { + return { + ...tax, + value_for: tax.name, + }; + }); + } + async detail(): Promise { this.detailManager.setData(''); this.detailManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA); diff --git a/src/modules/transaction/profit-share-formula/infrastructure/profit-share-formula-read.controller.ts b/src/modules/transaction/profit-share-formula/infrastructure/profit-share-formula-read.controller.ts index aa4c92d..c98f929 100644 --- a/src/modules/transaction/profit-share-formula/infrastructure/profit-share-formula-read.controller.ts +++ b/src/modules/transaction/profit-share-formula/infrastructure/profit-share-formula-read.controller.ts @@ -20,4 +20,9 @@ export class ProfitShareFormulaReadController { async breakdown(): Promise { return await this.orchestrator.index(); } + + @Get('tax') + async tax(): Promise[]> { + return await this.orchestrator.tax(); + } } diff --git a/src/modules/transaction/profit-share-formula/profit-share-formula.module.ts b/src/modules/transaction/profit-share-formula/profit-share-formula.module.ts index 51b8947..4637dd4 100644 --- a/src/modules/transaction/profit-share-formula/profit-share-formula.module.ts +++ b/src/modules/transaction/profit-share-formula/profit-share-formula.module.ts @@ -13,6 +13,8 @@ import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales import { TaxDataService } from '../tax/data/services/tax-data.service'; import { TaxModel } from '../tax/data/models/tax.model'; import { IndexProfitShareFormulaManager } from './domain/usecases/managers/index-profit-share-formula.manager'; +import { IndexTaxFormulaManager } from './domain/usecases/managers/tax-formula.manager'; +import { TaxReadService } from '../tax/data/services/tax-read.service'; @Module({ imports: [ @@ -31,11 +33,13 @@ import { IndexProfitShareFormulaManager } from './domain/usecases/managers/index DetailProfitShareFormulaManager, UpdateProfitShareFormulaManager, IndexProfitShareFormulaManager, + IndexTaxFormulaManager, ProfitShareFormulaDataOrchestrator, ProfitShareFormulaReadOrchestrator, TaxDataService, + TaxReadService, ], }) export class ProfitShareFormulaModule {} diff --git a/src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service.ts b/src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service.ts index 5ed3752..8e23965 100644 --- a/src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service.ts +++ b/src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service.ts @@ -1,17 +1,91 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnprocessableEntityException } from '@nestjs/common'; import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; import { SalesPriceFormulaEntity } from '../../domain/entities/sales-price-formula.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { SalesPriceFormulaModel } from '../models/sales-price-formula.model'; import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; import { Repository } from 'typeorm'; +import { FormulaType } from '../../constants'; +import { TaxModel } from 'src/modules/transaction/tax/data/models/tax.model'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Injectable() export class SalesPriceFormulaDataService extends BaseDataService { constructor( @InjectRepository(SalesPriceFormulaModel, CONNECTION_NAME.DEFAULT) private repo: Repository, + @InjectRepository(TaxModel, CONNECTION_NAME.DEFAULT) + private tax: Repository, + @InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT) + private item: Repository, ) { super(repo); } + + profitShareFormula() { + return this.repo.find({ + where: { + type: FormulaType.PROFIT_SHARE, + }, + }); + } + + async itemTax(id: string) { + const item = await this.item.findOne({ + relations: ['tenant'], + where: { + id, + }, + }); + + const profitShare = (item?.share_profit ?? 0) / 100; + const tenantShare = (item?.tenant?.share_margin ?? 0) / 100; + + return { profitShare, tenantShare }; + } + + async salesPriceFormula() { + const salesFormula = await this.repo.findOne({ + where: { + type: FormulaType.SALES_PRICE, + }, + }); + + const taxes = await this.tax.find(); + + for (const tax of taxes) { + salesFormula.formula_string = salesFormula.formula_string.replace( + tax.name, + `(${tax.formula_string})`, + ); + } + + const counter = {}; + do { + let isInfinite = false; + for (const tax of taxes) { + salesFormula.formula_string = salesFormula.formula_string.replace( + `${tax.name}_value`, + `(${tax.formula_string})`, + ); + + if (salesFormula.formula_string.includes(`${tax.name}_value`)) + counter[tax.name] = counter[tax.name] ? counter[tax.name] + 1 : 1; + + for (const count of Object.keys(counter)) { + if (!isInfinite && counter[count] > 50) isInfinite = true; + } + } + + if (isInfinite) { + throw new UnprocessableEntityException({ + message: 'Infinity Loop Formula, please fix formula', + error: 'Infinity Loop Formula', + meta: counter, + }); + } + } while (salesFormula.formula_string.includes('_value')); + + return salesFormula; + } } diff --git a/src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper.ts b/src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper.ts index f83e7b0..aff347c 100644 --- a/src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper.ts +++ b/src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper.ts @@ -1,6 +1,46 @@ import * as math from 'mathjs'; import { Equation, parse } from 'algebra.js'; -import { HttpStatus, UnprocessableEntityException } from '@nestjs/common'; +import { + BadRequestException, + HttpStatus, + UnprocessableEntityException, +} from '@nestjs/common'; +import { apm } from 'src/core/apm'; + +export function calculateFormula( + formula: string, + variable: object, + total: number, + solveFor = 'dpp', +) { + try { + const x1 = math.simplify(formula, variable).toString(); + // console.log('Formula ', x1); + const dppFormula = parse(x1); + const totalFormula = parse(total.toString()); + const equation = new Equation(totalFormula, dppFormula); + + // console.log(equation.toString()); + const result = equation.solveFor(solveFor).toString(); + // console.log(result, 'formula'); + + const value = math.evaluate(result); + // console.log(value, 'value'); + + return value; + } catch (e) { + apm.captureError(e); + throw new BadRequestException({ + message: 'Wrong value', + meta: { + formula, + variable, + total, + solveFor, + }, + }); + } +} export function calculateSalesFormula( formula: string, diff --git a/src/modules/transaction/sales-price-formula/sales-price-formula.module.ts b/src/modules/transaction/sales-price-formula/sales-price-formula.module.ts index accd83c..02be135 100644 --- a/src/modules/transaction/sales-price-formula/sales-price-formula.module.ts +++ b/src/modules/transaction/sales-price-formula/sales-price-formula.module.ts @@ -14,13 +14,14 @@ import { DetailSalesPriceFormulaManager } from './domain/usecases/managers/detai import { SalesPriceFormulaModel } from './data/models/sales-price-formula.model'; import { TaxDataService } from '../tax/data/services/tax-data.service'; import { TaxModel } from '../tax/data/models/tax.model'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Global() @Module({ imports: [ ConfigModule.forRoot(), TypeOrmModule.forFeature( - [SalesPriceFormulaModel, TaxModel], + [SalesPriceFormulaModel, TaxModel, ItemModel], CONNECTION_NAME.DEFAULT, ), CqrsModule, diff --git a/src/modules/transaction/tax/data/models/tax.model.ts b/src/modules/transaction/tax/data/models/tax.model.ts index cad7509..108d4f2 100644 --- a/src/modules/transaction/tax/data/models/tax.model.ts +++ b/src/modules/transaction/tax/data/models/tax.model.ts @@ -10,4 +10,10 @@ export class TaxModel extends BaseStatusModel implements TaxEntity { @Column('float', { name: 'value', default: 0 }) value: number; + + @Column('json', { name: 'formula_render', nullable: true }) + formula_render: any; + + @Column('varchar', { name: 'formula_string', nullable: true }) + formula_string: string; } diff --git a/src/modules/transaction/tax/data/services/tax-data.service.ts b/src/modules/transaction/tax/data/services/tax-data.service.ts index 87d4967..7b5d70c 100644 --- a/src/modules/transaction/tax/data/services/tax-data.service.ts +++ b/src/modules/transaction/tax/data/services/tax-data.service.ts @@ -3,7 +3,10 @@ import { BaseDataService } from 'src/core/modules/data/service/base-data.service import { TaxEntity } from '../../domain/entities/tax.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { TaxModel } from '../models/tax.model'; -import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { + CONNECTION_NAME, + STATUS, +} from 'src/core/strings/constants/base.constants'; import { Repository } from 'typeorm'; @Injectable() @@ -14,4 +17,21 @@ export class TaxDataService extends BaseDataService { ) { super(repo); } + + async taxKeyValue(): Promise { + const taxes = await this.getManyByOptions({ + where: { + status: STATUS.ACTIVE, + }, + }); + + const keyVal = {}; + + for (const tax of taxes) { + const { name, value } = tax; + keyVal[name] = value / 100; + } + + return keyVal; + } } diff --git a/src/modules/transaction/tax/domain/entities/tax.entity.ts b/src/modules/transaction/tax/domain/entities/tax.entity.ts index 9873d88..12bdf95 100644 --- a/src/modules/transaction/tax/domain/entities/tax.entity.ts +++ b/src/modules/transaction/tax/domain/entities/tax.entity.ts @@ -3,4 +3,5 @@ import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.e export interface TaxEntity extends BaseStatusEntity { name: string; value: number; + formula_string?: string; } diff --git a/src/modules/transaction/tax/domain/usecases/managers/index-tax-formula.manager.ts b/src/modules/transaction/tax/domain/usecases/managers/index-tax-formula.manager.ts new file mode 100644 index 0000000..642c3fa --- /dev/null +++ b/src/modules/transaction/tax/domain/usecases/managers/index-tax-formula.manager.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@nestjs/common'; +import { IndexTaxManager } from './index-tax.manager'; +import { Param } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexTaxFormulaManager extends IndexTaxManager { + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.name`, + `${this.tableName}.value`, + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.status::text`, + data: [`'active'`], + isStatus: true, + }, + ...super.specificFilter, + ]; + } +} diff --git a/src/modules/transaction/tax/domain/usecases/tax-read.orchestrator.ts b/src/modules/transaction/tax/domain/usecases/tax-read.orchestrator.ts index 80a0297..059eeac 100644 --- a/src/modules/transaction/tax/domain/usecases/tax-read.orchestrator.ts +++ b/src/modules/transaction/tax/domain/usecases/tax-read.orchestrator.ts @@ -6,11 +6,13 @@ import { PaginationResponse } from 'src/core/response/domain/ok-response.interfa import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; import { DetailTaxManager } from './managers/detail-tax.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { IndexTaxFormulaManager } from './managers/index-tax-formula.manager'; @Injectable() export class TaxReadOrchestrator extends BaseReadOrchestrator { constructor( private indexManager: IndexTaxManager, + private formulaManager: IndexTaxFormulaManager, private detailManager: DetailTaxManager, private serviceData: TaxReadService, ) { @@ -24,6 +26,13 @@ export class TaxReadOrchestrator extends BaseReadOrchestrator { return this.indexManager.getResult(); } + async formula(params): Promise> { + this.formulaManager.setFilterParam(params); + this.formulaManager.setService(this.serviceData, TABLE_NAME.TAX); + await this.formulaManager.execute(); + return this.formulaManager.getResult(); + } + async detail(dataId: string): Promise { this.detailManager.setData(dataId); this.detailManager.setService(this.serviceData, TABLE_NAME.TAX); diff --git a/src/modules/transaction/tax/infrastructure/tax-read.controller.ts b/src/modules/transaction/tax/infrastructure/tax-read.controller.ts index 773f2a0..b1c6ae2 100644 --- a/src/modules/transaction/tax/infrastructure/tax-read.controller.ts +++ b/src/modules/transaction/tax/infrastructure/tax-read.controller.ts @@ -23,6 +23,14 @@ export class TaxReadController { return await this.orchestrator.index(params); } + @Get('formula') + @Pagination() + async formula( + @Query() params: FilterTaxDto, + ): Promise> { + return await this.orchestrator.formula(params); + } + @Get(':id') async detail(@Param('id') id: string): Promise { return await this.orchestrator.detail(id); diff --git a/src/modules/transaction/tax/tax.module.ts b/src/modules/transaction/tax/tax.module.ts index 46682b4..97be019 100644 --- a/src/modules/transaction/tax/tax.module.ts +++ b/src/modules/transaction/tax/tax.module.ts @@ -24,6 +24,7 @@ import { BatchInactiveTaxManager } from './domain/usecases/managers/batch-inacti import { TaxModel } from './data/models/tax.model'; import { SalesPriceFormulaReadService } from '../sales-price-formula/data/services/sales-price-formula-read.service'; import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales-price-formula.model'; +import { IndexTaxFormulaManager } from './domain/usecases/managers/index-tax-formula.manager'; @Module({ imports: [ @@ -37,6 +38,7 @@ import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales controllers: [TaxDataController, TaxReadController], providers: [ IndexTaxManager, + IndexTaxFormulaManager, DetailTaxManager, CreateTaxManager, DeleteTaxManager, diff --git a/src/modules/transaction/transaction/data/models/transaction-item.model.ts b/src/modules/transaction/transaction/data/models/transaction-item.model.ts index 01eab5a..e472982 100644 --- a/src/modules/transaction/transaction/data/models/transaction-item.model.ts +++ b/src/modules/transaction/transaction/data/models/transaction-item.model.ts @@ -7,6 +7,7 @@ import { } from '../../domain/entities/transaction-item.entity'; import { TransactionModel } from './transaction.model'; import { RefundItemModel } from 'src/modules/transaction/refund/data/models/refund-item.model'; +import { TransactionTaxEntity } from '../../domain/entities/transaction-tax.entity'; @Entity(TABLE_NAME.TRANSACTION_ITEM) export class TransactionItemModel @@ -64,6 +65,15 @@ export class TransactionItemModel @Column('decimal', { name: 'total_share_tenant', nullable: true }) total_share_tenant: number; + @Column('decimal', { name: 'total_profit_share', nullable: true }) + total_profit_share: number; + + @Column('decimal', { nullable: true }) + payment_total_dpp: number; + + @Column('decimal', { nullable: true }) + payment_total_tax: number; + @Column('int', { name: 'qty', nullable: true }) qty: number; @@ -103,6 +113,13 @@ export class TransactionItemModel }, ) bundling_items: TransactionItemBreakdownModel[]; + + @OneToMany(() => TransactionItemTaxModel, (model) => model.transaction, { + cascade: true, + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + item_taxes: TransactionItemTaxModel[]; } @Entity(TABLE_NAME.TRANSACTION_ITEM_BREAKDOWN) @@ -122,10 +139,83 @@ export class TransactionItemBreakdownModel extends BaseCoreModel TransactionItemModel, (model) => model.bundling_items, { onDelete: 'CASCADE', onUpdate: 'CASCADE', }) @JoinColumn({ name: 'transaction_item_id' }) transaction_item: TransactionItemModel; + + @OneToMany(() => TransactionBreakdownTaxModel, (model) => model.transaction, { + cascade: true, + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + item_taxes: TransactionBreakdownTaxModel[]; +} + +@Entity(TABLE_NAME.TRANSACTION_ITEM_TAX) +export class TransactionItemTaxModel + extends BaseCoreModel + implements TransactionTaxEntity +{ + @Column('varchar', { name: 'tax_id', nullable: true }) + tax_id: string; + + @Column('varchar', { name: 'tax_name', nullable: true }) + tax_name: string; + + @Column('decimal', { name: 'taxt_value', nullable: true }) + taxt_value: number; + + @Column('decimal', { name: 'tax_total_value', nullable: true }) + tax_total_value: number; + + @Column('varchar', { name: 'transaction_id', nullable: true }) + transaction_id: string; + @ManyToOne(() => TransactionItemModel, (model) => model.taxes, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'transaction_id' }) + transaction: TransactionItemModel; +} + +@Entity(TABLE_NAME.TRANSACTION_ITEM_BREAKDOWN_TAX) +export class TransactionBreakdownTaxModel + extends BaseCoreModel + implements TransactionTaxEntity +{ + @Column('varchar', { name: 'tax_id', nullable: true }) + tax_id: string; + + @Column('varchar', { name: 'tax_name', nullable: true }) + tax_name: string; + + @Column('decimal', { name: 'taxt_value', nullable: true }) + taxt_value: number; + + @Column('decimal', { name: 'tax_total_value', nullable: true }) + tax_total_value: number; + + @Column('varchar', { name: 'transaction_id', nullable: true }) + transaction_id: string; + @ManyToOne(() => TransactionItemBreakdownModel, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'transaction_id' }) + transaction: TransactionItemBreakdownModel; } diff --git a/src/modules/transaction/transaction/domain/entities/transaction-item.entity.ts b/src/modules/transaction/transaction/domain/entities/transaction-item.entity.ts index 9d3a575..ba31418 100644 --- a/src/modules/transaction/transaction/domain/entities/transaction-item.entity.ts +++ b/src/modules/transaction/transaction/domain/entities/transaction-item.entity.ts @@ -34,4 +34,5 @@ export interface TransactionBundlingItemEntity extends BaseCoreEntity { hpp: number; base_price: number; item_rates: number; + total_price?: number; } diff --git a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts index 0f32849..8aa0b55 100644 --- a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts +++ b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts @@ -6,6 +6,7 @@ import { } from '../../constants'; import { STATUS } from 'src/core/strings/constants/base.constants'; import { TransactionItemEntity } from './transaction-item.entity'; +import { TransactionTaxEntity } from './transaction-tax.entity'; export interface TransactionEntity extends BaseStatusEntity { // general info @@ -89,4 +90,5 @@ export interface TransactionEntity extends BaseStatusEntity { calendar_link?: string; items: TransactionItemEntity[]; + taxes?: TransactionTaxEntity[]; } diff --git a/src/modules/transaction/transaction/domain/usecases/calculator/price.calculator.ts b/src/modules/transaction/transaction/domain/usecases/calculator/price.calculator.ts new file mode 100644 index 0000000..88d8619 --- /dev/null +++ b/src/modules/transaction/transaction/domain/usecases/calculator/price.calculator.ts @@ -0,0 +1,272 @@ +import { Injectable } from '@nestjs/common'; +import { SalesPriceFormulaDataService } from 'src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service'; +import { TaxDataService } from 'src/modules/transaction/tax/data/services/tax-data.service'; +import { TransactionEntity } from '../../entities/transaction.entity'; +import { calculateFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper'; +import * as math from 'mathjs'; +import { + TransactionBundlingItemEntity, + TransactionItemEntity, +} from '../../entities/transaction-item.entity'; + +@Injectable() +export class PriceCalculator { + constructor( + private formulaService: SalesPriceFormulaDataService, + private taxService: TaxDataService, + ) {} + + private initialValue(formulas: any[]) { + const tax = {}; + for (const formula of formulas) { + tax[`${formula.name}_value`] = null; + } + + return tax; + } + + async calculate(transaction: TransactionEntity) { + const prices = []; + const transaction_taxes = []; + + for (let i = 0; i < transaction.items.length; i++) { + const item = transaction.items[i]; + const price = await this.calculateItem(item); + const priceValues = this.calculatePrice(price); + prices.push(priceValues); + transaction_taxes.push(price.taxesValue); + + if (item.bundling_items) { + for (let b = 0; b < item.bundling_items.length; b++) { + const bundling = item.bundling_items[b]; + bundling.total_price = bundling.item_rates ?? bundling.base_price; + + const bundlingPrice = await this.calculateItem(bundling); + const bundlingValues = this.calculatePrice(bundlingPrice); + + const item_taxes = { item_taxes: bundlingPrice.taxesValue }; + Object.assign(bundling, bundlingValues, item_taxes); + item.bundling_items[b] = bundling; + } + } + + const item_taxes = { item_taxes: price.taxesValue }; + Object.assign(item, priceValues, item_taxes); + transaction.items[i] = item; + } + + const tatal_taxes = this.mergeAndSumArrays(transaction_taxes); + transaction.taxes = tatal_taxes; + const { payment_total_dpp, ...otherValue } = + this.sumArrayBasedOnObjectKey(prices); + + return { + dpp_value: payment_total_dpp, + other: otherValue, + tax_datas: tatal_taxes, + }; + } + + async calculateItem( + transaction: TransactionItemEntity | TransactionBundlingItemEntity, + ) { + // const itemShare = 20 / 100; + // const profitShare = 10 / 100; + + const { profitShare, tenantShare } = await this.formulaService.itemTax( + transaction.item_id, + ); + + const tax = await this.taxService.taxKeyValue(); + /* Update constant from + - profit_share -> tenant_share + - item_share -> profit_share + */ + const taxes = { + ...tax, + tenant_share: tenantShare, + profit_share: profitShare, + }; + const dpp = await this.formulaService.salesPriceFormula(); + const taxFormula = await this.taxService.getManyByOptions({}); + const shareFormulas = await this.formulaService.profitShareFormula(); + const taxShareFormulas = shareFormulas.map((formula) => { + return { + ...formula, + name: formula.value_for, + }; + }); + const formulas = [...taxFormula, ...taxShareFormulas]; + const values = { + total: transaction.total_price, + ...this.initialValue(formulas), + ...taxes, + }; + + // const dpp = formulas.find((formula) => formula.value_for == 'dpp'); + + const dppValue = calculateFormula( + dpp.formula_string, + taxes, + transaction.total_price, + ); + + values['dpp'] = dppValue; + values['dpp_value'] = dppValue; + + let calledVariable = []; + const taxesValue = []; + do { + const valueFor = this.withNullValue(values, calledVariable); + + const formula = formulas.find((formula) => { + const name = formula['name'] ?? formula['value_for']; + return `${name}_value` == valueFor; + }); + let result = null; + + try { + result = math.evaluate(formula.formula_string, values); + calledVariable = []; + } catch (error) { + calledVariable.push(valueFor); + console.log(error); + } + + values[valueFor] = result; + if (result != null) { + const tax = taxFormula.find(({ id }) => id == formula.id); + if (tax != null) { + taxesValue.push({ + tax_id: tax?.id, + tax_name: tax?.name, + taxt_value: result, + tax_total_value: result, + transaction_id: transaction.id, + }); + } + } + // values[`${valueFor}_value`] = result; + } while (this.containsNullValue(values)); + + // const itemShareFormula = shareFormulas.find( + // (f) => f.value_for == 'tenant_share', + // ); + // values['tenant_share_value'] = math.evaluate( + // itemShareFormula.formula_string, + // values, + // ); + + // const profitShareFormula = shareFormulas.find( + // (f) => f.value_for == 'profit_share', + // ); + // values['profit_share_value'] = math.evaluate( + // profitShareFormula.formula_string, + // values, + // ); + + return { dpp_value: dppValue, tax_datas: values, taxesValue }; + } + + calculatePrice(prices: any) { + const data = prices.tax_datas; + const filteredObject: any = Object.keys(data) + .filter((key) => key.endsWith('_value')) + .reduce((acc, key) => ({ ...acc, [key]: data[key] }), {}); + + const { dpp_value, tenant_share_value, profit_share_value, ...tax } = + filteredObject; + const taxes = this.sumPriceObject(tax); + return { + total_profit_share: profit_share_value, + total_share_tenant: tenant_share_value, + payment_total_tax: taxes, + payment_total_dpp: dpp_value, + tax, + }; + } + + sumArrayBasedOnObjectKey(arr) { + return arr.reduce((acc, cur) => { + Object.keys(cur).forEach((key) => { + if (!acc[key]) { + acc[key] = 0; + } + acc[key] += cur[key]; + }); + return acc; + }, {}); + } + + sumPriceObject(taxes: any): number { + let total = 0; + for (const tax in taxes) { + total += taxes[tax] ?? 0; + } + + return total; + } + + containsNullValue(obj) { + if (typeof obj !== 'object' || obj === null) { + return obj === null; // Return true if the value itself is null + } + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (this.containsNullValue(obj[key])) { + return true; // If any nested value is null, return true + } + } + } + + return false; // If no null values are found, return false + } + + mergeAndSumArrays(arrays): any { + const mergedData = {}; + + arrays.forEach((arr) => { + arr.forEach((item) => { + if (!mergedData[item.tax_id]) { + mergedData[item.tax_id] = { + tax_name: item.tax_name, + taxt_value: 0, + tax_total_value: 0, + transaction_id: item.transaction_id, + }; + } + + mergedData[item.tax_id].taxt_value += item.taxt_value; + mergedData[item.tax_id].tax_total_value += item.tax_total_value; + }); + }); + + return Object.values(mergedData); + } + + withNullValue(mainObj, called = []) { + const obj = { ...mainObj }; + for (const variable of called) { + delete obj[variable]; + } + if (typeof obj !== 'object' || obj === null) { + return null; // Return null for non-object values + } + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (obj[key] === null) { + return key; // Found a null value, return the key + } else if (typeof obj[key] === 'object') { + const nestedKey = this.withNullValue(obj[key]); + if (nestedKey !== null) { + return `${key}.${nestedKey}`; // Found null in nested object, return nested key path + } + } + } + } + + return null; // No null values found, return null + } +} diff --git a/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts b/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts index 0bf4e4d..9217f1b 100644 --- a/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts +++ b/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts @@ -9,6 +9,7 @@ import { TransactionModel } from '../../../data/models/transaction.model'; import { calculateSalesFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper'; import { CreateEventCalendarHelper } from 'src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper'; import { TransactionUpdatedEvent } from '../../entities/event/transaction-updated.event'; +import { PriceCalculator } from '../calculator/price.calculator'; @EventsHandler(TransactionChangeStatusEvent, TransactionUpdatedEvent) export class SettledTransactionHandler @@ -18,6 +19,7 @@ export class SettledTransactionHandler private formulaService: SalesPriceFormulaDataService, private taxService: TaxDataService, private dataService: TransactionDataService, + private calculator: PriceCalculator, ) {} async handle(event: TransactionChangeStatusEvent) { @@ -62,12 +64,16 @@ export class SettledTransactionHandler }); // const profit_share_value = this.calculateFormula(profit_formula.formula_string, taxes, data.payment_total_net_profit ?? 0); - const { dpp_value, tax_datas } = calculateSalesFormula( - sales_price.formula_string, - taxes, - data.payment_total_net_profit ?? 0, + const { dpp_value, tax_datas, other } = await this.calculator.calculate( + data, ); + // calculateSalesFormula( + // sales_price.formula_string, + // taxes, + // data.payment_total_net_profit ?? 0, + // ); + // console.log(data, 'dsa'); const google_calendar = await CreateEventCalendarHelper(data); @@ -78,6 +84,8 @@ export class SettledTransactionHandler taxes: tax_datas, calendar_id: google_calendar?.id, calendar_link: google_calendar?.htmlLink, + payment_total_share: other.total_profit_share, + payment_total_tax: other.payment_total_tax, }); } else if (oldSettled) { // console.log(data, 'data oldSettled'); diff --git a/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts b/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts index 8496379..c717131 100644 --- a/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts +++ b/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts @@ -99,6 +99,7 @@ export class TransactionDataOrchestrator { return this.batchCancelManager.getResult(); } + // Confirm from draft to pending async confirm(dataId): Promise { this.confirmManager.setData(dataId, STATUS.ACTIVE); this.confirmManager.setService( @@ -111,7 +112,7 @@ export class TransactionDataOrchestrator { } async batchConfirm(dataIds: string[]): Promise { - this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setData(dataIds, STATUS.PENDING); this.batchConfirmManager.setService( this.serviceData, TABLE_NAME.TRANSACTION, diff --git a/src/modules/transaction/transaction/domain/usecases/transaction-read.orchestrator.ts b/src/modules/transaction/transaction/domain/usecases/transaction-read.orchestrator.ts index 4f39239..cbc1912 100644 --- a/src/modules/transaction/transaction/domain/usecases/transaction-read.orchestrator.ts +++ b/src/modules/transaction/transaction/domain/usecases/transaction-read.orchestrator.ts @@ -6,6 +6,7 @@ import { PaginationResponse } from 'src/core/response/domain/ok-response.interfa import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; import { DetailTransactionManager } from './managers/detail-transaction.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { PriceCalculator } from './calculator/price.calculator'; @Injectable() export class TransactionReadOrchestrator extends BaseReadOrchestrator { @@ -13,6 +14,7 @@ export class TransactionReadOrchestrator extends BaseReadOrchestrator { + const transaction = await this.serviceData.getOneByOptions({ + where: { + id, + }, + relations: ['items', 'items.bundling_items'], + }); + + const price = await this.calculator.calculate(transaction); + transaction.payment_total_profit = + transaction.payment_total - + price.other.total_profit_share - + price.other.payment_total_tax - + price.other.total_share_tenant; + transaction.payment_total_dpp = price.dpp_value; + transaction.payment_total_share = price.other.total_profit_share; + transaction.payment_total_tax = price.other.payment_total_tax; + console.log({ price }, transaction.payment_total); + } + + async calculatePrice(): Promise { + const transactions = await this.serviceData.getManyByOptions({ + where: { + is_recap_transaction: false, + }, + relations: ['items', 'items.bundling_items'], + }); + + for (const transaction of transactions) { + try { + const price = await this.calculator.calculate(transaction); + transaction.payment_total_profit = + transaction.payment_total - + price.other.total_profit_share - + price.other.payment_total_tax - + price.other.total_share_tenant; + transaction.payment_total_dpp = price.dpp_value; + transaction.payment_total_share = price.other.total_profit_share; + transaction.payment_total_tax = price.other.payment_total_tax; + console.log(transaction.id); + await this.serviceData.getRepository().save(transaction); + + // break; + } catch (error) { + console.log(error); + } + } + } } diff --git a/src/modules/transaction/transaction/infrastructure/transaction-read.controller.ts b/src/modules/transaction/transaction/infrastructure/transaction-read.controller.ts index 099cc0d..8446857 100644 --- a/src/modules/transaction/transaction/infrastructure/transaction-read.controller.ts +++ b/src/modules/transaction/transaction/infrastructure/transaction-read.controller.ts @@ -27,4 +27,18 @@ export class TransactionReadController { async detail(@Param('id') id: string): Promise { return await this.orchestrator.detail(id); } + + @Public(true) + @Get('dummy/:id') + async calculate(@Param('id') id: string): Promise { + this.orchestrator.dummyCalculate(id); + return 'OK'; + } + + @Public(true) + @Get('dummy2/calculate') + async calculateAll(): Promise { + this.orchestrator.calculatePrice(); + return 'OK'; + } } diff --git a/src/modules/transaction/transaction/transaction.module.ts b/src/modules/transaction/transaction/transaction.module.ts index f4a2e61..e08f2db 100644 --- a/src/modules/transaction/transaction/transaction.module.ts +++ b/src/modules/transaction/transaction/transaction.module.ts @@ -19,8 +19,10 @@ import { BatchDeleteTransactionManager } from './domain/usecases/managers/batch- import { BatchConfirmTransactionManager } from './domain/usecases/managers/batch-confirm-transaction.manager'; import { TransactionModel } from './data/models/transaction.model'; import { + TransactionBreakdownTaxModel, TransactionItemBreakdownModel, TransactionItemModel, + TransactionItemTaxModel, } from './data/models/transaction-item.model'; import { TransactionTaxModel } from './data/models/transaction-tax.model'; import { CancelTransactionManager } from './domain/usecases/managers/cancel-transaction.manager'; @@ -39,6 +41,8 @@ import { PdfMakeManager } from 'src/modules/configuration/export/domain/managers import { PaymentMethodDataService } from '../payment-method/data/services/payment-method-data.service'; import { PaymentMethodModel } from '../payment-method/data/models/payment-method.model'; import { TransactionDemographyModel } from './data/models/transaction-demography.model'; +import { PriceCalculator } from './domain/usecases/calculator/price.calculator'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Module({ exports: [TransactionReadService], @@ -51,9 +55,12 @@ import { TransactionDemographyModel } from './data/models/transaction-demography TransactionDemographyModel, TransactionItemBreakdownModel, TransactionTaxModel, + TransactionItemTaxModel, + TransactionBreakdownTaxModel, TaxModel, SalesPriceFormulaModel, PaymentMethodModel, + ItemModel, ], CONNECTION_NAME.DEFAULT, ), @@ -61,6 +68,7 @@ import { TransactionDemographyModel } from './data/models/transaction-demography ], controllers: [TransactionDataController, TransactionReadController], providers: [ + PriceCalculator, RefundUpdatedHandler, PosTransactionHandler, MidtransCallbackHandler,