fix(SPG-620) Sales Price & Profit Share Formula - Tambahkan warning/validasi jika formula menyebabkan error
parent
0b236cb879
commit
fba7b9aae5
|
@ -8,10 +8,20 @@ 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';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
||||
async validateProcess(): Promise<void> {
|
||||
const taxes = await this.dataServiceFirstOpt.getManyByOptions({
|
||||
where: {
|
||||
status: In([STATUS.ACTIVE]),
|
||||
},
|
||||
});
|
||||
|
||||
calculateProfitFormula(this.data.formula_string, taxes, 10000, 50, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
|||
import { SalesPriceFormulaDataService } from 'src/modules/transaction/sales-price-formula/data/services/sales-price-formula-data.service';
|
||||
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 { TaxDataService } from 'src/modules/transaction/tax/data/services/tax-data.service';
|
||||
|
||||
@Injectable()
|
||||
export class ProfitShareFormulaDataOrchestrator {
|
||||
constructor(
|
||||
private updateManager: UpdateProfitShareFormulaManager,
|
||||
private serviceData: SalesPriceFormulaDataService,
|
||||
private taxService: TaxDataService,
|
||||
) {}
|
||||
|
||||
async update(data): Promise<SalesPriceFormulaEntity> {
|
||||
|
@ -20,7 +22,11 @@ export class ProfitShareFormulaDataOrchestrator {
|
|||
});
|
||||
|
||||
this.updateManager.setData(formula.id, data);
|
||||
this.updateManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);
|
||||
this.updateManager.setService(
|
||||
this.serviceData,
|
||||
TABLE_NAME.PRICE_FORMULA,
|
||||
this.taxService,
|
||||
);
|
||||
await this.updateManager.execute();
|
||||
return this.updateManager.getResult();
|
||||
}
|
||||
|
|
|
@ -10,11 +10,16 @@ import { CqrsModule } from '@nestjs/cqrs';
|
|||
import { UpdateProfitShareFormulaManager } from './domain/usecases/managers/update-profit-share-formula.manager';
|
||||
import { DetailProfitShareFormulaManager } from './domain/usecases/managers/detail-profit-share-formula.manager';
|
||||
import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales-price-formula.model';
|
||||
import { TaxDataService } from '../tax/data/services/tax-data.service';
|
||||
import { TaxModel } from '../tax/data/models/tax.model';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
TypeOrmModule.forFeature([SalesPriceFormulaModel], CONNECTION_NAME.DEFAULT),
|
||||
TypeOrmModule.forFeature(
|
||||
[SalesPriceFormulaModel, TaxModel],
|
||||
CONNECTION_NAME.DEFAULT,
|
||||
),
|
||||
CqrsModule,
|
||||
],
|
||||
controllers: [
|
||||
|
@ -27,6 +32,8 @@ import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales
|
|||
|
||||
ProfitShareFormulaDataOrchestrator,
|
||||
ProfitShareFormulaReadOrchestrator,
|
||||
|
||||
TaxDataService,
|
||||
],
|
||||
})
|
||||
export class ProfitShareFormulaModule {}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import * as math from 'mathjs';
|
||||
import { Equation, parse } from 'algebra.js';
|
||||
import { HttpStatus, UnprocessableEntityException } from '@nestjs/common';
|
||||
|
||||
export function calculateSalesFormula(
|
||||
formula: string,
|
||||
taxes: object[],
|
||||
total: number,
|
||||
throwError = false,
|
||||
) {
|
||||
try {
|
||||
let { value, variable, tax_datas } = mappingTaxes(taxes, formula, total);
|
||||
|
||||
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('dpp').toString();
|
||||
console.log(result, 'formula');
|
||||
|
||||
value = math.evaluate(result);
|
||||
console.log(value, 'value');
|
||||
|
||||
return {
|
||||
dpp_value: value,
|
||||
tax_datas: tax_datas,
|
||||
};
|
||||
} catch (e) {
|
||||
returnError(throwError, e, taxes);
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateProfitFormula(
|
||||
formula: string,
|
||||
taxes: object[],
|
||||
total: number,
|
||||
profit_share = 0,
|
||||
throwError = false,
|
||||
) {
|
||||
try {
|
||||
let { value, variable, tax_datas } = mappingTaxes(
|
||||
taxes,
|
||||
formula,
|
||||
total,
|
||||
profit_share,
|
||||
);
|
||||
|
||||
const result = math.simplify(formula, variable).toString();
|
||||
console.log(result, 'formula');
|
||||
|
||||
value = math.evaluate(result);
|
||||
console.log(value, 'value');
|
||||
|
||||
return {
|
||||
dpp_value: value,
|
||||
tax_datas: tax_datas,
|
||||
};
|
||||
} catch (e) {
|
||||
returnError(throwError, e, taxes);
|
||||
}
|
||||
}
|
||||
|
||||
function mappingTaxes(taxes, formula, total, profit_share = 0) {
|
||||
let value = 0;
|
||||
const variable = {};
|
||||
let tax_datas = [];
|
||||
const const_variable = ['profit_share', 'item_share', 'dpp'];
|
||||
|
||||
const regex = /([a-zA-Z0-9_]+)/g;
|
||||
|
||||
const matches: string[] = formula.match(regex);
|
||||
const uniqueMatches = new Set(matches);
|
||||
const keys = Array.from(uniqueMatches);
|
||||
|
||||
for (const key of keys) {
|
||||
if (!const_variable.includes(key)) {
|
||||
const keyData = taxes.find((tax) => tax.name == key);
|
||||
variable[key] = keyData.value / 100;
|
||||
|
||||
tax_datas.push({
|
||||
tax_id: keyData.id,
|
||||
tax_name: keyData.name,
|
||||
tax_value: keyData.value,
|
||||
tax_total_value: (keyData.value / 100) * Number(total),
|
||||
});
|
||||
} else {
|
||||
switch (key) {
|
||||
case 'profit_share':
|
||||
variable[key] = profit_share / 100;
|
||||
break;
|
||||
|
||||
case 'item_share':
|
||||
variable[key] = profit_share / 100;
|
||||
break;
|
||||
|
||||
case 'dpp':
|
||||
if (profit_share > 0) variable[key] = total;
|
||||
break;
|
||||
default:
|
||||
variable[key] = profit_share;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value: value,
|
||||
variable: variable,
|
||||
tax_datas: tax_datas,
|
||||
};
|
||||
}
|
||||
|
||||
function returnError(throwError, e, taxes) {
|
||||
if (throwError) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! Formula error`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
} else {
|
||||
console.log(e);
|
||||
|
||||
return {
|
||||
dpp_value: 0,
|
||||
tax_datas: taxes,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -8,10 +8,20 @@ import {
|
|||
columnUniques,
|
||||
validateRelations,
|
||||
} from 'src/core/strings/constants/interface.constants';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { In } from 'typeorm';
|
||||
import { calculateSalesFormula } from './helpers/calculation-formula.helper';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateSalesPriceFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
||||
async validateProcess(): Promise<void> {
|
||||
const taxes = await this.dataServiceFirstOpt.getManyByOptions({
|
||||
where: {
|
||||
status: In([STATUS.ACTIVE]),
|
||||
},
|
||||
});
|
||||
|
||||
calculateSalesFormula(this.data.formula_string, taxes, 10000, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ import { SalesPriceFormulaEntity } from '../entities/sales-price-formula.entity'
|
|||
import { UpdateSalesPriceFormulaManager } from './managers/update-sales-price-formula.manager';
|
||||
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
||||
import { FormulaType } from '../../constants';
|
||||
import { TaxDataService } from 'src/modules/transaction/tax/data/services/tax-data.service';
|
||||
|
||||
@Injectable()
|
||||
export class SalesPriceFormulaDataOrchestrator {
|
||||
constructor(
|
||||
private updateManager: UpdateSalesPriceFormulaManager,
|
||||
private serviceData: SalesPriceFormulaDataService,
|
||||
private taxService: TaxDataService,
|
||||
) {}
|
||||
|
||||
async update(data): Promise<SalesPriceFormulaEntity> {
|
||||
|
@ -20,7 +22,11 @@ export class SalesPriceFormulaDataOrchestrator {
|
|||
});
|
||||
|
||||
this.updateManager.setData(formula.id, data);
|
||||
this.updateManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);
|
||||
this.updateManager.setService(
|
||||
this.serviceData,
|
||||
TABLE_NAME.PRICE_FORMULA,
|
||||
this.taxService,
|
||||
);
|
||||
await this.updateManager.execute();
|
||||
return this.updateManager.getResult();
|
||||
}
|
||||
|
|
|
@ -12,12 +12,17 @@ import { CqrsModule } from '@nestjs/cqrs';
|
|||
import { UpdateSalesPriceFormulaManager } from './domain/usecases/managers/update-sales-price-formula.manager';
|
||||
import { DetailSalesPriceFormulaManager } from './domain/usecases/managers/detail-sales-price-formula.manager';
|
||||
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';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
TypeOrmModule.forFeature([SalesPriceFormulaModel], CONNECTION_NAME.DEFAULT),
|
||||
TypeOrmModule.forFeature(
|
||||
[SalesPriceFormulaModel, TaxModel],
|
||||
CONNECTION_NAME.DEFAULT,
|
||||
),
|
||||
CqrsModule,
|
||||
],
|
||||
controllers: [
|
||||
|
@ -28,6 +33,7 @@ import { SalesPriceFormulaModel } from './data/models/sales-price-formula.model'
|
|||
DetailSalesPriceFormulaManager,
|
||||
UpdateSalesPriceFormulaManager,
|
||||
|
||||
TaxDataService,
|
||||
SalesPriceFormulaDataService,
|
||||
SalesPriceFormulaReadService,
|
||||
|
||||
|
|
|
@ -3,11 +3,10 @@ import { TransactionChangeStatusEvent } from '../../entities/event/transaction-c
|
|||
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 { FormulaType } from 'src/modules/transaction/sales-price-formula/constants';
|
||||
import * as math from 'mathjs';
|
||||
import { Equation, parse } from 'algebra.js';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
||||
import { TransactionModel } from '../../../data/models/transaction.model';
|
||||
import { calculateSalesFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper';
|
||||
|
||||
@EventsHandler(TransactionChangeStatusEvent)
|
||||
export class SettledTransactionHandler
|
||||
|
@ -59,7 +58,7 @@ export class SettledTransactionHandler
|
|||
.manager.connection.createQueryRunner();
|
||||
|
||||
// const profit_share_value = this.calculateFormula(profit_formula.formula_string, taxes, data.payment_total_net_profit ?? 0);
|
||||
const { dpp_value, tax_datas } = this.calculateSalesFormula(
|
||||
const { dpp_value, tax_datas } = calculateSalesFormula(
|
||||
sales_price.formula_string,
|
||||
taxes,
|
||||
data.payment_total_net_profit ?? 0,
|
||||
|
@ -74,49 +73,4 @@ export class SettledTransactionHandler
|
|||
|
||||
await this.dataService.create(queryRunner, TransactionModel, data);
|
||||
}
|
||||
|
||||
calculateSalesFormula(formula, taxes, total) {
|
||||
let value = 0;
|
||||
let tax_datas = [];
|
||||
const regex = /([a-zA-Z0-9_]+)/g;
|
||||
const variable = {};
|
||||
|
||||
const matches: string[] = formula.match(regex);
|
||||
const uniqueMatches = new Set(matches);
|
||||
const keys = Array.from(uniqueMatches).filter((key) => key != 'dpp');
|
||||
|
||||
for (const key of keys) {
|
||||
const keyData = taxes.find((tax) => tax.name == key);
|
||||
variable[key] = keyData.value / 100;
|
||||
|
||||
tax_datas.push({
|
||||
tax_id: keyData.id,
|
||||
tax_name: keyData.name,
|
||||
tax_value: keyData.value,
|
||||
tax_total_value: (keyData.value / 100) * Number(total),
|
||||
});
|
||||
}
|
||||
|
||||
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('dpp').toString();
|
||||
console.log(result);
|
||||
|
||||
value = math.evaluate(result);
|
||||
console.log(value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
return {
|
||||
dpp_value: value,
|
||||
tax_datas: tax_datas,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue