Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details

pull/34/head devel_10.6.22
Firman Ramdhani 2024-07-22 11:56:42 +07:00
commit 2f9c96bdec
31 changed files with 356 additions and 128 deletions

View File

@ -10,39 +10,14 @@ export function setQueryFilterDefault(
baseFilter: BaseFilterEntity,
tableName: TABLE_NAME,
): SelectQueryBuilder<any> {
// filter berdasarkan statuses
if (!!baseFilter.statuses) {
queryBuilder.andWhere(
new Brackets((qb) => {
baseFilter.statuses.map((status) => {
// trim search
const statusData = status.includes("'")
? status.trim().replace(/'/g, "''").replace(/\s+/g, ' ')
: status.trim().replace(/\s+/g, ' ');
// jika searching status terdapat dalam enum, maka dia mencari specific data
// ? karena jika tidak, ketika dia search "active" maka "inactive" juga ikut
if (STATUS[statusData.toUpperCase()])
qb.orWhere(`${tableName}.status = :statusData`, {
statusData: statusData,
});
else
qb['orWhere'](
`${tableName}.status::text ILIKE '%${[statusData]}%'`,
);
});
}),
);
}
// filter berdasarkan id pembuat
if (!!baseFilter.created_ids)
new WhereInQueryHelper(
queryBuilder,
tableName,
'created_id',
'creator_id',
baseFilter.created_ids,
'created_ids',
'creator_ids',
).getQuery();
// filter berdasarkan tanggal terakhir dibuat

View File

@ -107,7 +107,7 @@ export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (!topic.relations) {
if (topic.relations?.length) {
data = await this.dataService.getOneByOptions({
where: {
id: dataNew.id,

View File

@ -8,6 +8,7 @@ import {
} from 'src/core/helpers/query/default-filter.helper';
import { Param } from '../../entities/base-filter.entity';
import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
import { STATUS } from 'src/core/strings/constants/base.constants';
export abstract class BaseIndexManager<Entity> extends BaseReadManager {
protected result: PaginationResponse<Entity>;
@ -19,6 +20,7 @@ export abstract class BaseIndexManager<Entity> extends BaseReadManager {
}
async process(): Promise<void> {
const specificFilter = this.specificFilter;
const { joinRelations, selectRelations, countRelations } = this.relations;
if (joinRelations?.length)
@ -40,10 +42,26 @@ export abstract class BaseIndexManager<Entity> extends BaseReadManager {
if (this.selects?.length) this.queryBuilder.select(this.selects);
if (this.filterParam.statuses?.length > 0) {
const data = this.filterParam.statuses.map((status) => {
const statusData = status.includes("'")
? status.trim().replace(/'/g, "''").replace(/\s+/g, ' ')
: status.trim().replace(/\s+/g, ' ');
// jika searching status terdapat dalam enum, maka dia mencari specific data
// ? karena jika tidak, ketika dia search "active" maka "inactive" juga ikut
return STATUS[statusData.toUpperCase()] ?? statusData;
});
specificFilter.push({
cols: `${this.tableName}.status::text`,
data: data,
});
}
new SpecificSearchFilter<Entity>(
this.queryBuilder,
this.tableName,
this.specificFilter,
specificFilter,
).getFilter();
getOrderBy(this.filterParam, this.queryBuilder, this.tableName);

View File

@ -1,25 +0,0 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateMidtransColumnTransaction1721284234428
implements MigrationInterface
{
name = 'UpdateMidtransColumnTransaction1721284234428';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "payment_midtrans_url"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "payment_midtrans_token"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" ADD "payment_midtrans_token" character varying`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ADD "payment_midtrans_url" character varying`,
);
}
}

View File

@ -0,0 +1,25 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateColumnTransaction1721385120750
implements MigrationInterface
{
name = 'UpdateColumnTransaction1721385120750';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "discount_percentage"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ADD "discount_percentage" numeric`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "discount_percentage"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ADD "discount_percentage" integer`,
);
}
}

View File

@ -24,7 +24,8 @@ export class PaymentTransactionHandler
if (
old_data.status == STATUS.DRAFT &&
current_data.status == STATUS.PENDING &&
current_data.payment_type != TransactionPaymentType.COUNTER
current_data.payment_type != TransactionPaymentType.COUNTER &&
!!current_data.customer_email
) {
if (current_data.payment_type != TransactionPaymentType.MIDTRANS) {
payments = await this.paymentService.getManyByOptions({

View File

@ -72,6 +72,7 @@ export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.status`,
`${this.tableName}.created_at`,
`${this.tableName}.name`,
`${this.tableName}.base_price`,
@ -126,6 +127,9 @@ export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
});
}
queryBuilder.andWhere(`${this.tableName}.status In (:...statuses)`, {
statuses: [STATUS.ACTIVE],
});
return queryBuilder;
}
}

View File

@ -85,6 +85,8 @@ export class IndexItemManager extends BaseIndexManager<ItemEntity> {
queryBuilder.andWhere(`${this.tableName}.tenant_id In (:...tenantIds)`, {
tenantIds: this.filterParam.tenant_ids,
});
} else if (!this.filterParam.all_item) {
queryBuilder.andWhere(`${this.tableName}.tenant_id Is Null`);
}
return queryBuilder;

View File

@ -11,6 +11,7 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class CurrentSeasonPeriodManager extends BaseIndexManager<SeasonPeriodEntity> {
async prepareData(): Promise<void> {
this.filterParam.limit = 10;
return;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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 {}

View File

@ -11,10 +11,25 @@ import {
} from '@nestjs/common';
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
validateData(data: TransactionEntity): Promise<void> {
async validateData(data: TransactionEntity): Promise<void> {
const transaction = await this.dataService.getOneByOptions({
where: {
id: data.id,
},
});
if (transaction.status != STATUS.SETTLED) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! cant cancel transaction not settled`,
error: 'Unprocessable Entity',
});
}
Object.assign(data, {
reconciliation_mdr: this.data.reconciliation_mdr ?? null,
reconciliation_confirm_by: this.user.name,

View File

@ -4,6 +4,7 @@ import {
UnprocessableEntityException,
} from '@nestjs/common';
import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager';
import { STATUS } from 'src/core/strings/constants/base.constants';
import {
EventTopics,
validateRelations,
@ -18,7 +19,20 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager<Transac
}
async validateProcess(): Promise<void> {
if (this.data.is_recap_transaction) {
// untuk dapat current status
const transaction = await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
});
if (transaction.status != STATUS.SETTLED) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! cant cancel transaction not settled`,
error: 'Unprocessable Entity',
});
} else if (this.data.is_recap_transaction) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! cant cancel recap data`,

View File

@ -16,8 +16,14 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class BatchConfirmRefundManager extends BaseBatchUpdateStatusManager<RefundEntity> {
validateData(data: RefundEntity): Promise<void> {
if (![STATUS.DRAFT, STATUS.PENDING].includes(data.status)) {
async validateData(data: RefundEntity): Promise<void> {
if (data?.['transaction']?.status != STATUS.SETTLED) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,
error: 'Unprocessable Entity',
});
} else if (![STATUS.DRAFT, STATUS.PENDING].includes(data.status)) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only data with status ${STATUS.DRAFT} and ${STATUS.PENDING} can be confirmed`,

View File

@ -38,6 +38,14 @@ export class ConfirmRefundManager extends BaseUpdateStatusManager<RefundEntity>
relations: ['transaction'],
});
if (data.transaction.status != STATUS.SETTLED) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,
error: 'Unprocessable Entity',
});
}
if (data.status == STATUS.DRAFT) {
Object.assign(this.data, {
code: `RF-${data.transaction?.invoice_code?.split('-')[1]}`,

View File

@ -30,7 +30,14 @@ export class CreateRefundManager extends BaseCreateManager<RefundEntity> {
refund_items: refund_items,
});
if (this.data.transaction?.status != STATUS.SETTLED) {
const transaction = await this.dataServiceFirstOpt.getOneByOptions({
where: {
id: this.data.transaction.id,
status: STATUS.SETTLED,
},
});
if (!transaction) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,

View File

@ -17,7 +17,14 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class UpdateRefundManager extends BaseUpdateManager<RefundEntity> {
async validateProcess(): Promise<void> {
if (this.data.transaction?.status != STATUS.SETTLED) {
const transaction = await this.dataServiceFirstOpt.getOneByOptions({
where: {
id: this.data.transaction.id,
status: STATUS.SETTLED,
},
});
if (!transaction) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,

View File

@ -12,6 +12,7 @@ import { BatchDeleteRefundManager } from './managers/batch-delete-refund.manager
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { CancelRefundManager } from './managers/cancel-refund.manager';
import { BatchCancelRefundManager } from './managers/batch-cancel-refund.manager';
import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service';
@Injectable()
export class RefundDataOrchestrator {
@ -25,18 +26,27 @@ export class RefundDataOrchestrator {
private batchCancelManager: BatchCancelRefundManager,
private batchConfirmManager: BatchConfirmRefundManager,
private serviceData: RefundDataService,
private transactionDataService: TransactionDataService,
) {}
async create(data): Promise<RefundEntity> {
this.createManager.setData(data);
this.createManager.setService(this.serviceData, TABLE_NAME.REFUND);
this.createManager.setService(
this.serviceData,
TABLE_NAME.REFUND,
this.transactionDataService,
);
await this.createManager.execute();
return this.createManager.getResult();
}
async update(dataId, data): Promise<RefundEntity> {
this.updateManager.setData(dataId, data);
this.updateManager.setService(this.serviceData, TABLE_NAME.REFUND);
this.updateManager.setService(
this.serviceData,
TABLE_NAME.REFUND,
this.transactionDataService,
);
await this.updateManager.execute();
return this.updateManager.getResult();
}

View File

@ -21,12 +21,14 @@ import { RefundModel } from './data/models/refund.model';
import { BatchCancelRefundManager } from './domain/usecases/managers/batch-cancel-refund.manager';
import { CancelRefundManager } from './domain/usecases/managers/cancel-refund.manager';
import { RefundItemModel } from './data/models/refund-item.model';
import { TransactionDataService } from '../transaction/data/services/transaction-data.service';
import { TransactionModel } from '../transaction/data/models/transaction.model';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature(
[RefundModel, RefundItemModel],
[RefundModel, RefundItemModel, TransactionModel],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,
@ -46,6 +48,7 @@ import { RefundItemModel } from './data/models/refund-item.model';
RefundDataService,
RefundReadService,
TransactionDataService,
RefundDataOrchestrator,
RefundReadOrchestrator,

View File

@ -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,
};
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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,

View File

@ -93,7 +93,7 @@ export class TransactionModel
@Column('varchar', { name: 'discount_code', nullable: true })
discount_code: string;
@Column('int', { name: 'discount_percentage', nullable: true })
@Column('decimal', { name: 'discount_percentage', nullable: true })
discount_percentage: number;
@Column('decimal', { name: 'discount_value', nullable: true })

View File

@ -18,7 +18,7 @@ export class RefundUpdatedHandler
if (
old_data.status != current_data.data ||
event.data.op == OPERATION.DELETE
(event.data.op == OPERATION.DELETE && current_data.status != STATUS.DRAFT)
) {
const queryRunner = this.dataService
.getRepository()

View File

@ -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,
};
}
}

View File

@ -56,7 +56,10 @@ export class ConfirmTransactionManager extends BaseUpdateStatusManager<Transacti
}
Object.assign(this.data, {
invoice_code: await generateInvoiceCodeHelper(this.dataService),
invoice_code:
this.data.payment_type == TransactionPaymentType.COUNTER
? null
: await generateInvoiceCodeHelper(this.dataService),
status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING,
});
return;

View File

@ -35,11 +35,14 @@ export class DetailTransactionManager extends BaseDetailManager<TransactionEntit
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.creator_counter_no`,
`${this.tableName}.creator_name`,
`${this.tableName}.created_at`,
`${this.tableName}.updated_at`,
`${this.tableName}.editor_name`,
`${this.tableName}.invoice_code`,
`${this.tableName}.invoice_date`,
`${this.tableName}.settlement_date`,
`${this.tableName}.season_period_id`,
`${this.tableName}.season_period_name`,

View File

@ -1,5 +1,8 @@
import { STATUS } from 'src/core/strings/constants/base.constants';
import { TransactionType } from 'src/modules/transaction/transaction/constants';
import {
TransactionPaymentType,
TransactionType,
} from 'src/modules/transaction/transaction/constants';
export function mappingTransaction(data) {
let payment_type_bank: any = null;
@ -73,15 +76,31 @@ export function mappingTransaction(data) {
export function mappingRevertTransaction(data, type) {
if (type == TransactionType.COUNTER) {
if (data.booking_id) {
Object.assign(data, {
editor_id: data.pos_admin?.id,
editor_name: data.pos_admin?.name,
edited_at: new Date(data.created_at),
});
} else {
Object.assign(data, {
creator_id: data.pos_admin?.id,
creator_name: data.pos_admin?.name,
});
}
Object.assign(data, {
id: data._id,
creator_counter_no: data.pos_number,
creator_id: data.pos_admin?.id,
creator_name: data.pos_admin?.name,
id: data.booking_id ?? data._id,
invoice_code: data.code,
creator_counter_no: Number(data.pos_number),
status: STATUS.SETTLED,
booking_date: data.created_at,
settlement_date: data.created_at,
payment_type: data.payment_type,
settlement_date: new Date(data.created_at),
payment_date: new Date(data.created_at),
invoice_date: new Date(data.created_at),
payment_type:
data.payment_type == 'cc'
? TransactionPaymentType.CC
: data.payment_type,
payment_card_information: data.card_information,
payment_code_reference: data.payment_code,
discount_code_id: data.discount_code?.id,
@ -116,7 +135,8 @@ export function mappingRevertTransaction(data, type) {
});
data.items?.map((item) => {
const total_price = Number(item.item.base_price) * Number(item.qty);
const total_price =
Number(item.item.price ?? item.item.base_price) * Number(item.qty);
const share_margin = item.item.tenant?.share_margin ?? 0;
const total_share_tenant =
share_margin > 0 ? (Number(share_margin) / 100) * total_price : 0;

View File

@ -48,6 +48,7 @@ export class IndexTransactionManager extends BaseIndexManager<TransactionEntity>
`${this.tableName}.id`,
`${this.tableName}.status`,
`${this.tableName}.invoice_code`,
`${this.tableName}.creator_counter_no`,
`${this.tableName}.booking_date`,
`${this.tableName}.no_of_group`,
`${this.tableName}.type`,