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 { 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 { 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 { 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()
|
@Injectable()
|
||||||
export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
||||||
async validateProcess(): Promise<void> {
|
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;
|
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 { 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 { 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 { 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()
|
@Injectable()
|
||||||
export class ProfitShareFormulaDataOrchestrator {
|
export class ProfitShareFormulaDataOrchestrator {
|
||||||
constructor(
|
constructor(
|
||||||
private updateManager: UpdateProfitShareFormulaManager,
|
private updateManager: UpdateProfitShareFormulaManager,
|
||||||
private serviceData: SalesPriceFormulaDataService,
|
private serviceData: SalesPriceFormulaDataService,
|
||||||
|
private taxService: TaxDataService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async update(data): Promise<SalesPriceFormulaEntity> {
|
async update(data): Promise<SalesPriceFormulaEntity> {
|
||||||
|
@ -20,7 +22,11 @@ export class ProfitShareFormulaDataOrchestrator {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateManager.setData(formula.id, data);
|
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();
|
await this.updateManager.execute();
|
||||||
return this.updateManager.getResult();
|
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 { UpdateProfitShareFormulaManager } from './domain/usecases/managers/update-profit-share-formula.manager';
|
||||||
import { DetailProfitShareFormulaManager } from './domain/usecases/managers/detail-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 { 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({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
TypeOrmModule.forFeature([SalesPriceFormulaModel], CONNECTION_NAME.DEFAULT),
|
TypeOrmModule.forFeature(
|
||||||
|
[SalesPriceFormulaModel, TaxModel],
|
||||||
|
CONNECTION_NAME.DEFAULT,
|
||||||
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
|
@ -27,6 +32,8 @@ import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales
|
||||||
|
|
||||||
ProfitShareFormulaDataOrchestrator,
|
ProfitShareFormulaDataOrchestrator,
|
||||||
ProfitShareFormulaReadOrchestrator,
|
ProfitShareFormulaReadOrchestrator,
|
||||||
|
|
||||||
|
TaxDataService,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ProfitShareFormulaModule {}
|
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,
|
columnUniques,
|
||||||
validateRelations,
|
validateRelations,
|
||||||
} from 'src/core/strings/constants/interface.constants';
|
} 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()
|
@Injectable()
|
||||||
export class UpdateSalesPriceFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
export class UpdateSalesPriceFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
|
||||||
async validateProcess(): Promise<void> {
|
async validateProcess(): Promise<void> {
|
||||||
|
const taxes = await this.dataServiceFirstOpt.getManyByOptions({
|
||||||
|
where: {
|
||||||
|
status: In([STATUS.ACTIVE]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
calculateSalesFormula(this.data.formula_string, taxes, 10000, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,14 @@ import { SalesPriceFormulaEntity } from '../entities/sales-price-formula.entity'
|
||||||
import { UpdateSalesPriceFormulaManager } from './managers/update-sales-price-formula.manager';
|
import { UpdateSalesPriceFormulaManager } from './managers/update-sales-price-formula.manager';
|
||||||
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
||||||
import { FormulaType } from '../../constants';
|
import { FormulaType } from '../../constants';
|
||||||
|
import { TaxDataService } from 'src/modules/transaction/tax/data/services/tax-data.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SalesPriceFormulaDataOrchestrator {
|
export class SalesPriceFormulaDataOrchestrator {
|
||||||
constructor(
|
constructor(
|
||||||
private updateManager: UpdateSalesPriceFormulaManager,
|
private updateManager: UpdateSalesPriceFormulaManager,
|
||||||
private serviceData: SalesPriceFormulaDataService,
|
private serviceData: SalesPriceFormulaDataService,
|
||||||
|
private taxService: TaxDataService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async update(data): Promise<SalesPriceFormulaEntity> {
|
async update(data): Promise<SalesPriceFormulaEntity> {
|
||||||
|
@ -20,7 +22,11 @@ export class SalesPriceFormulaDataOrchestrator {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateManager.setData(formula.id, data);
|
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();
|
await this.updateManager.execute();
|
||||||
return this.updateManager.getResult();
|
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 { UpdateSalesPriceFormulaManager } from './domain/usecases/managers/update-sales-price-formula.manager';
|
||||||
import { DetailSalesPriceFormulaManager } from './domain/usecases/managers/detail-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 { 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()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
TypeOrmModule.forFeature([SalesPriceFormulaModel], CONNECTION_NAME.DEFAULT),
|
TypeOrmModule.forFeature(
|
||||||
|
[SalesPriceFormulaModel, TaxModel],
|
||||||
|
CONNECTION_NAME.DEFAULT,
|
||||||
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
|
@ -28,6 +33,7 @@ import { SalesPriceFormulaModel } from './data/models/sales-price-formula.model'
|
||||||
DetailSalesPriceFormulaManager,
|
DetailSalesPriceFormulaManager,
|
||||||
UpdateSalesPriceFormulaManager,
|
UpdateSalesPriceFormulaManager,
|
||||||
|
|
||||||
|
TaxDataService,
|
||||||
SalesPriceFormulaDataService,
|
SalesPriceFormulaDataService,
|
||||||
SalesPriceFormulaReadService,
|
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 { 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 { TaxDataService } from 'src/modules/transaction/tax/data/services/tax-data.service';
|
||||||
import { FormulaType } from 'src/modules/transaction/sales-price-formula/constants';
|
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 { STATUS } from 'src/core/strings/constants/base.constants';
|
||||||
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
||||||
import { TransactionModel } from '../../../data/models/transaction.model';
|
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)
|
@EventsHandler(TransactionChangeStatusEvent)
|
||||||
export class SettledTransactionHandler
|
export class SettledTransactionHandler
|
||||||
|
@ -59,7 +58,7 @@ export class SettledTransactionHandler
|
||||||
.manager.connection.createQueryRunner();
|
.manager.connection.createQueryRunner();
|
||||||
|
|
||||||
// const profit_share_value = this.calculateFormula(profit_formula.formula_string, taxes, data.payment_total_net_profit ?? 0);
|
// 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,
|
sales_price.formula_string,
|
||||||
taxes,
|
taxes,
|
||||||
data.payment_total_net_profit ?? 0,
|
data.payment_total_net_profit ?? 0,
|
||||||
|
@ -74,49 +73,4 @@ export class SettledTransactionHandler
|
||||||
|
|
||||||
await this.dataService.create(queryRunner, TransactionModel, data);
|
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