Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/fix-couch-transaction

feat/fix-couch-transaction
Firman Ramdhani 2024-09-04 18:20:13 +07:00
commit db57b1973e
29 changed files with 16511 additions and 7 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
assets/image/we.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -76,6 +76,7 @@ import { PosLogModel } from './modules/configuration/log/data/models/pos-log.mod
import { ExportModule } from './modules/configuration/export/export.module';
import { TransactionDemographyModel } from './modules/transaction/transaction/data/models/transaction-demography.model';
import { SupersetModule } from './modules/configuration/superset/superset.module';
import { GateScanModule } from './modules/gates/gate.module';
@Module({
imports: [
@ -178,6 +179,8 @@ import { SupersetModule } from './modules/configuration/superset/superset.module
// superset
SupersetModule,
GateScanModule,
],
controllers: [],
providers: [

View File

@ -1 +1,2 @@
export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE';
export const GATE_RESPONSE = 'GATE_RESPONSE';

View File

@ -1,5 +1,5 @@
import { SetMetadata } from '@nestjs/common';
import { PAGINATION_RESPONSE } from '../../constants';
import { GATE_RESPONSE, PAGINATION_RESPONSE } from '../../constants';
/**
* This decorator will tell the response,
@ -7,3 +7,5 @@ import { PAGINATION_RESPONSE } from '../../constants';
*/
export const Pagination = (isPagination = true) =>
SetMetadata(PAGINATION_RESPONSE, isPagination);
export const Gate = () => SetMetadata(GATE_RESPONSE, true);

View File

@ -8,13 +8,20 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
import { PAGINATION_RESPONSE } from '../constants';
import { GATE_RESPONSE, PAGINATION_RESPONSE } from '../constants';
import { createPaginationResponse } from './utils/pagination-meta.helper';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
constructor(protected readonly reflector: Reflector) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const isGate = this.reflector.getAllAndOverride<boolean>(GATE_RESPONSE, [
context.getHandler(),
context.getClass(),
]);
if (isGate) return next.handle();
const isPagination = this.reflector.getAllAndOverride<boolean>(
PAGINATION_RESPONSE,
[context.getHandler(), context.getClass()],

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddValueVariableFormula1724926316235
implements MigrationInterface
{
name = 'AddValueVariableFormula1724926316235';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "price_formulas" ADD "value_for" character varying NOT NULL DEFAULT 'dpp'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "price_formulas" DROP COLUMN "value_for"`,
);
}
}

View File

@ -32,7 +32,6 @@ export class PaymentTransactionHandler
const current_data = event.data.data;
const data_id = current_data.transaction_id ?? event.data.id;
const from_refund = event.data.module == TABLE_NAME.REFUND;
console.log('payment handlet', { data_id });
const payments = await this.paymentService.getManyByOptions({
where: {
@ -106,6 +105,15 @@ export class PaymentTransactionHandler
`;
})}
</ul>`,
refund_items_data: transaction?.['refund']?.refund_items
?.filter((item) => Number(item.qty_refund) > 0)
.map((item) => {
return {
qty_refund: item.qty_refund,
item_name: item.transaction_item.item_name,
};
}),
});
}

View File

@ -17,7 +17,7 @@ export async function sendEmail(receivers, invoiceType, attachment?) {
for (const receiver of receivers) {
try {
const templateName = getTemplate(receiver.payment_type, invoiceType);
const templatePath = `./assets/email-template/${templateName}.html`;
const templatePath = `./assets/email-template/redesign/${templateName}.html`;
const templateSource = fs.readFileSync(templatePath, 'utf8');
const template = handlebars.compile(templateSource);

View File

@ -0,0 +1,5 @@
export interface GateScanEntity {
gate_id: string;
type: string;
uuid: string;
}

View File

@ -0,0 +1,8 @@
export interface GateResponseEntity {
code: number;
message: string;
}
export interface GateMasterEntity {
codes: string[];
}

View File

@ -0,0 +1,17 @@
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GateController } from './infrastructure/gate.controller';
@Global()
@Module({
imports: [
ConfigModule.forRoot(),
// TypeOrmModule.forFeature(
// [],
// CONNECTION_NAME.DEFAULT,
// ),
],
controllers: [GateController],
providers: [],
})
export class GateScanModule {}

View File

@ -0,0 +1,94 @@
import { Body, Controller, Get, Param, Post, Res } from '@nestjs/common';
import { Response } from 'express';
import { ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
import { GateScanEntity } from '../domain/entity/gate-request.entity';
import {
GateMasterEntity,
GateResponseEntity,
} from '../domain/entity/gate-response.entity';
import { Gate } from 'src/core/response';
const masterGates = [
'319b6d3e-b661-4d19-8695-0dd6fb76465e',
'9afdb79d-7162-43e6-8ac6-f1941adea7ba',
'7e4c0281-8cf2-420e-aba1-c8ff834de450',
'19318ac8-caa0-47e4-8a41-2aac238d3665',
'495bc25f-42c4-4007-8e79-3747fa1054b6',
'b90fc9a9-efd9-4216-a8af-7ed120b141de',
'4399e93c-a839-4802-a49d-f933c72b1433',
'970673a7-6370-444a-931a-9784220dd35d',
'151ab50e-4e54-4252-b3ab-f5c0817b27a0',
'4c0e6924-baf5-47fb-a15b-fd1cd0958cc0',
];
const failedGates = [
'b3c3ae7b-daf5-4340-998b-ee35ed41323d',
'be157609-92b8-4989-920d-a81769bcb05a',
];
const gateResponses = [
{
statusCode: 200,
code: 1,
message: 'Berhasil Check In',
},
{
statusCode: 403,
code: 2,
message: 'Gagal melakukan Check In. Karena tiket telah kadaluarsa',
},
{
statusCode: 403,
code: 3,
message: 'Gagal melakukan Check In. Tiket tidak tersedia',
},
];
@ApiTags(`Gate - read`)
@Controller(`v1/gate`)
@Public(true)
@Gate()
export class GateController {
@Post('scan')
async scan(
@Body() data: GateScanEntity,
@Res({ passthrough: true }) res: Response,
): Promise<GateResponseEntity> {
console.log(data);
if (masterGates.includes(data.uuid)) {
res.status(200);
return gateResponses[0];
}
if (failedGates.includes(data.uuid)) {
res.status(403);
return gateResponses[2];
}
const response = Math.floor(Math.random() * 3);
const responseValue = gateResponses[response];
res.status(responseValue.statusCode);
return responseValue;
}
@Get(':id/master')
async detail(@Param('id') id: string): Promise<GateMasterEntity> {
if (id == '1') return { codes: masterGates };
return {
codes: this.createRandomStringArray(masterGates),
};
}
createRandomStringArray(inputArray: string[]): string[] {
const randomLength = Math.floor(Math.random() * 4) + 2; // Random length between 2 and 5
const outputArray: string[] = [];
while (outputArray.length < randomLength) {
const randomIndex = Math.floor(Math.random() * inputArray.length);
outputArray.push(inputArray[randomIndex]);
}
return outputArray;
}
}

View File

@ -0,0 +1,340 @@
import {
DATA_FORMAT,
DATA_TYPE,
FILTER_FIELD_TYPE,
FILTER_TYPE,
REPORT_GROUP,
} from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity';
import { TransactionType } from 'src/modules/transaction/transaction/constants';
import { STATUS } from 'src/core/strings/constants/base.constants';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__income_per_item_master`,
label: 'Pendapatan Per Item Master',
table_schema: `transactions main
LEFT JOIN transaction_items tr_item ON tr_item.transaction_id::text = main.id::text
LEFT JOIN transaction_item_breakdowns tr_item_bundling ON tr_item_bundling.transaction_item_id::text = tr_item.id::text
LEFT JOIN refunds refund ON refund.transaction_id = main.id
LEFT JOIN items item ON item.id::text = tr_item.item_id::text
LEFT JOIN users tenant ON tenant.id::text = item.tenant_id::text
LEFT JOIN refund_items refund_item ON refund_item.refund_item_id::text = tr_item.item_id::text`,
main_table_alias: 'main',
whereDefaultConditions: [
{
column: 'main.status',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [STATUS.SETTLED, STATUS.REFUNDED, STATUS.PROCESS_REFUND],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
column_configs: [
{
column: 'main__settlement_date',
query: 'main.settlement_date',
label: 'Tanggal Pendapatan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
},
{
column: 'item_owner',
query: `CASE WHEN tenant.name is not null THEN tenant.name ELSE 'Company' END`,
label: 'Kepemilikan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__type',
query: 'main.type',
label: 'Sumber',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__invoice_code',
query: 'main.invoice_code',
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code',
query: 'main.payment_code',
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_category_name',
query: 'tr_item.item_category_name',
label: 'Kategori Item',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_name',
query: 'tr_item.item_name',
label: 'Nama Item',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__breakdown_bundling',
query: 'tr_item.breakdown_bundling',
label: 'Breakdown Bundling',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.BOOLEAN,
},
{
column: 'tr_item_bundling__item_name',
query: 'tr_item_bundling.item_name',
label: 'Nama Item Bundling',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_type',
query: 'main.customer_type',
label: 'Tipe Pelanggan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_counter_no',
query: 'main.creator_counter_no',
label: 'No.PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__qty',
query: 'tr_item.qty',
label: 'Qty',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.NUMBER,
},
{
column: 'tr_item__total_hpp',
query: 'tr_item.total_hpp',
label: 'Total HPP',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
// TODO => tambahkan total dpp per item
// TODO => tambahkan total tax
{
column: 'tr_item__total_price',
query: 'tr_item.total_price',
label: 'Total Penjualan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'refund__refund_date',
query: 'refund.refund_date',
label: 'Tanggal Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
},
{
column: 'refund__status',
query: 'refund.status',
label: 'Status Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__code',
query: 'refund.code',
label: 'Kode Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund_item__qty_refund',
query: 'refund_item.qty_refund',
label: 'Qty Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.NUMBER,
},
{
column: 'refund_item__refund_total',
query: '(refund_item.refund_total * -1)',
label: 'Total Pengembalian',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'transaction_balance',
query: `CASE WHEN refund.id is null THEN tr_item.total_price ELSE tr_item.total_price - refund_item.refund_total END`,
label: 'Balance',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__item_tenant_share_margin',
query: 'tr_item.item_tenant_share_margin',
label: 'Profile Share (IDR)',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tenant_income',
query: 'tr_item.total_price - tr_item.item_tenant_share_margin',
label: 'Pendapatan Tenant',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__customer_name',
query: 'main.customer_name',
label: 'Nama Pelanggan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_description',
query: 'main.customer_description',
label: 'Deskripsi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_phone',
query: 'main.customer_phone',
label: 'Telepon',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_name',
query: 'main.creator_name',
label: 'Dibuat Oleh',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
],
whereCondition(filterModel) {
const queryFilter = [];
const breakdown = filterModel.tr_item__breakdown_bundling;
if (breakdown) {
const value = breakdown.filter.map((item) => {
return item === 'Yes' ? true : false;
});
queryFilter.push(`tr_item.breakdown_bundling in (${value.join()})`);
}
return queryFilter;
},
ignore_filter_keys: ['tr_item__breakdown_bundling'],
filter_configs: [
{
filed_label: 'Tanggal Pendapatan',
filter_column: 'main__settlement_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
},
{
filed_label: 'Kepemilikan',
filter_column: 'item_owner',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Sumber',
filter_column: 'main__type',
field_type: FILTER_FIELD_TYPE.select,
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
select_custom_options: [...Object.values(TransactionType)],
},
{
filed_label: 'Kode Booking',
filter_column: 'main__invoice_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Kode Pembayaran',
filter_column: 'main__payment_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Kategori Item',
filter_column: 'tr_item__item_category_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Item',
filter_column: 'tr_item__item_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Breakdown Item',
filter_column: 'tr_item__breakdown_bundling',
field_type: FILTER_FIELD_TYPE.select,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
select_custom_options: ['Yes', 'No'],
},
{
filed_label: 'Nama Item Bundling',
filter_column: 'tr_item_bundling__item_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tipe Pelanggan',
filter_column: 'main__customer_type',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'No. PoS',
filter_column: 'main__creator_counter_no',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tanggal Pengembalian',
filter_column: 'refund__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
},
{
filed_label: 'Kode Pengembalian',
filter_column: 'refund__code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Pelanggan',
filter_column: 'main__customer_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Bank/Issuer',
filter_column: 'main__payment_type_method_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Dibuat Oleh',
filter_column: 'main__creator_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
],
};

View File

@ -2,6 +2,7 @@ import { ReportConfigEntity } from '../../entities/report-config.entity';
import IncomeReport from './configs/income';
import IncomeReportPerItem from './configs/income-per-item';
import IncomeReportPerItemMaster from './configs/income-per-item-master';
import GivingDiscount from './configs/giving-discounts';
import VisitorsPerRideReport from './configs/visitors-per-ride';
import TimePerRideReport from './configs/time-per-ride';
@ -14,6 +15,7 @@ import ReconciliationReport from './configs/reconciliation';
export const TransactionReportConfig: ReportConfigEntity[] = [
IncomeReport,
IncomeReportPerItem,
IncomeReportPerItemMaster,
GivingDiscount,
// VisitorsPerRideReport,
// TimePerRideReport,

View File

@ -0,0 +1,56 @@
import { Injectable } from '@nestjs/common';
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';
@Injectable()
export class IndexProfitShareFormulaManager extends BaseIndexManager<SalesPriceFormulaEntity> {
setQueryFilter(
queryBuilder: SelectQueryBuilder<SalesPriceFormulaEntity>,
): SelectQueryBuilder<SalesPriceFormulaEntity> {
return queryBuilder;
}
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.type::text`,
data: [FormulaType.PROFIT_SHARE],
},
];
}
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
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 [];
}
}

View File

@ -11,6 +11,7 @@ import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-for
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';
@Injectable()
export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
@ -30,6 +31,35 @@ export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPric
}
async afterProcess(): Promise<void> {
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);
}
return;
}

View File

@ -3,14 +3,24 @@ import { DetailProfitShareFormulaManager } from './managers/detail-profit-share-
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';
@Injectable()
export class ProfitShareFormulaReadOrchestrator {
constructor(
private detailManager: DetailProfitShareFormulaManager,
private indexManager: IndexProfitShareFormulaManager,
private serviceData: SalesPriceFormulaReadService,
) {}
async index(): Promise<SalesPriceFormulaEntity[]> {
this.indexManager.setFilterParam({});
this.indexManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);
await this.indexManager.execute();
const { data } = this.indexManager.getResult();
return data;
}
async detail(): Promise<SalesPriceFormulaEntity> {
this.detailManager.setData('');
this.detailManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);

View File

@ -1,4 +1,4 @@
import { Controller, Get, Param } from '@nestjs/common';
import { Controller, Get } from '@nestjs/common';
import { ProfitShareFormulaReadOrchestrator } from '../domain/usecases/profit-share-formula-read.orchestrator';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
@ -15,4 +15,9 @@ export class ProfitShareFormulaReadController {
async detail(): Promise<SalesPriceFormulaEntity> {
return await this.orchestrator.detail();
}
@Get('detail')
async breakdown(): Promise<SalesPriceFormulaEntity[]> {
return await this.orchestrator.index();
}
}

View File

@ -12,6 +12,7 @@ import { DetailProfitShareFormulaManager } from './domain/usecases/managers/deta
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';
import { IndexProfitShareFormulaManager } from './domain/usecases/managers/index-profit-share-formula.manager';
@Module({
imports: [
@ -29,6 +30,7 @@ import { TaxModel } from '../tax/data/models/tax.model';
providers: [
DetailProfitShareFormulaManager,
UpdateProfitShareFormulaManager,
IndexProfitShareFormulaManager,
ProfitShareFormulaDataOrchestrator,
ProfitShareFormulaReadOrchestrator,

View File

@ -22,6 +22,9 @@ export class SalesPriceFormulaModel
@Column('varchar', { name: 'formula_string', nullable: true })
formula_string: string;
@Column('varchar', { default: 'dpp' })
value_for: string;
@Column('varchar', { name: 'example_formula', nullable: true })
example_formula: string;

View File

@ -6,5 +6,13 @@ export interface SalesPriceFormulaEntity extends BaseEntity {
formula_string: string; // digunakan untuk menyimpan string dari formula
example_formula: string;
example_result: number;
value_for: string;
type: FormulaType;
additional?: AdditionalFormula[];
}
export interface AdditionalFormula {
formula_render: any;
formula_string: string;
value_for: string;
}

View File

@ -1,11 +1,37 @@
import { BaseDto } from 'src/core/modules/infrastructure/dto/base.dto';
import { SalesPriceFormulaEntity } from '../../domain/entities/sales-price-formula.entity';
import {
AdditionalFormula,
SalesPriceFormulaEntity,
} from '../../domain/entities/sales-price-formula.entity';
import { ApiProperty } from '@nestjs/swagger';
import { ValidateIf } from 'class-validator';
import { ValidateIf, ValidateNested } from 'class-validator';
import { Exclude } from 'class-transformer';
import { Any } from 'typeorm';
import { FormulaType } from '../../constants';
export class AdditionalFormulaDto implements AdditionalFormula {
@ApiProperty({
type: Any,
required: false,
})
@ValidateIf((body) => body.formula_render)
formula_render: any;
@ApiProperty({
type: String,
required: false,
})
@ValidateIf((body) => body.formula_string)
formula_string: string;
@ApiProperty({
type: String,
required: false,
})
@ValidateIf((body) => body.value_for)
value_for: string;
}
export class SalesPriceFormulaDto
extends BaseDto
implements SalesPriceFormulaEntity
@ -30,6 +56,19 @@ export class SalesPriceFormulaDto
@Exclude()
example_result: number;
@Exclude()
value_for: string;
@Exclude()
type: FormulaType;
@ApiProperty({
type: [AdditionalFormulaDto],
default: AdditionalFormulaDto,
})
@ValidateIf(({ additional }) => {
return additional != null;
})
@ValidateNested({ each: true })
additional: AdditionalFormulaDto[];
}