Compare commits

...

4 Commits

Author SHA1 Message Date
shancheas e92f325807 fix: make transaction setting public 2025-05-02 11:25:33 +07:00
shancheas 66d76634b7 fix: find transactionSettingData with parameter 2025-05-02 09:02:45 +07:00
shancheas b91080906e feat: change save factor formula 2025-05-02 07:33:08 +07:00
shancheas 714b075e1d fix: add transaction setting api 2025-04-30 13:06:36 +07:00
17 changed files with 298 additions and 23 deletions

View File

@ -33,7 +33,10 @@ import { SeasonTypeModel } from './modules/season-related/season-type/data/model
import { TaxModule } from './modules/transaction/tax/tax.module';
import { TaxModel } from './modules/transaction/tax/data/models/tax.model';
import { SalesPriceFormulaModule } from './modules/transaction/sales-price-formula/sales-price-formula.module';
import { SalesPriceFormulaModel } from './modules/transaction/sales-price-formula/data/models/sales-price-formula.model';
import {
SalesPriceFormulaModel,
TransactionSettingModel,
} from './modules/transaction/sales-price-formula/data/models/sales-price-formula.model';
import { ProfitShareFormulaModule } from './modules/transaction/profit-share-formula/profit-share-formula.module';
import { PaymentMethodModule } from './modules/transaction/payment-method/payment-method.module';
import { PaymentMethodModel } from './modules/transaction/payment-method/data/models/payment-method.model';
@ -137,6 +140,7 @@ import { QueueBucketModel } from './modules/queue/data/models/queue-bucket.model
TransactionItemBreakdownModel,
TransactionItemTaxModel,
TransactionBreakdownTaxModel,
TransactionSettingModel,
UserModel,
UserLoginModel,

View File

@ -12,6 +12,7 @@ export enum TABLE_NAME {
NEWS = 'news',
PAYMENT_METHOD = 'payment_methods',
PRICE_FORMULA = 'price_formulas',
TRANSACTION_SETTING = 'transaction_settings',
REFUND = 'refunds',
REFUND_ITEM = 'refund_items',
SEASON_TYPE = 'season_types',

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class TransactionSettingModel1745991391299
implements MigrationInterface
{
name = 'TransactionSettingModel1745991391299';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "transaction_settings" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "creator_id" character varying(36), "creator_name" character varying(125), "editor_id" character varying(36), "editor_name" character varying(125), "created_at" bigint NOT NULL, "updated_at" bigint NOT NULL, "value" numeric NOT NULL DEFAULT '100', CONSTRAINT "PK_db7fb38a439358b499ebdee4761" PRIMARY KEY ("id"))`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "transaction_settings"`);
}
}

View File

@ -97,6 +97,36 @@ export class CouchService {
}
}
public async totalTodayTransactions(database = 'transaction') {
try {
const nano = this.nanoInstance;
const db = nano.use(database);
// Get today's start timestamp (midnight)
const today = new Date();
today.setHours(0, 0, 0, 0);
const todayTimestamp = today.getTime();
// Query for documents created today
const selector = {
created_at: {
$gte: todayTimestamp,
},
};
const result = await db.find({
selector: selector,
fields: ['_id'],
});
return result.docs.length;
} catch (error) {
console.log(error);
apm.captureError(error);
return 0;
}
}
getUnixTimestampLast7Days() {
const date = new Date();
date.setDate(date.getDate() - 4);

View File

@ -1,5 +1,8 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { SalesPriceFormulaEntity } from '../../domain/entities/sales-price-formula.entity';
import {
SalesPriceFormulaEntity,
TransactionSetting,
} from '../../domain/entities/sales-price-formula.entity';
import { Column, Entity } from 'typeorm';
import { BaseModel } from 'src/core/modules/data/model/base.model';
import { FormulaType } from '../../constants';
@ -31,3 +34,12 @@ export class SalesPriceFormulaModel
@Column('numeric', { name: 'example_result', nullable: true })
example_result: number;
}
@Entity(TABLE_NAME.TRANSACTION_SETTING)
export class TransactionSettingModel
extends BaseModel<TransactionSetting>
implements TransactionSetting
{
@Column('numeric', { default: 100 })
value: number;
}

View File

@ -1,13 +1,25 @@
import { Injectable, UnprocessableEntityException } from '@nestjs/common';
import {
Injectable,
Logger,
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 {
SalesPriceFormulaEntity,
TransactionSetting,
} from '../../domain/entities/sales-price-formula.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { SalesPriceFormulaModel } from '../models/sales-price-formula.model';
import {
SalesPriceFormulaModel,
TransactionSettingModel,
} from '../models/sales-price-formula.model';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { Repository } from 'typeorm';
import { MoreThan, 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';
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
import { CouchService } from 'src/modules/configuration/couch/data/services/couch.service';
@Injectable()
export class SalesPriceFormulaDataService extends BaseDataService<SalesPriceFormulaEntity> {
@ -18,6 +30,11 @@ export class SalesPriceFormulaDataService extends BaseDataService<SalesPriceForm
private tax: Repository<TaxModel>,
@InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT)
private item: Repository<ItemModel>,
@InjectRepository(TransactionSettingModel, CONNECTION_NAME.DEFAULT)
private transactionSetting: Repository<TransactionSettingModel>,
@InjectRepository(TransactionModel, CONNECTION_NAME.DEFAULT)
private transaction: Repository<TransactionModel>,
private couchService: CouchService,
) {
super(repo);
}
@ -31,11 +48,38 @@ export class SalesPriceFormulaDataService extends BaseDataService<SalesPriceForm
}
async sentToBlackHole() {
const percentage = 80;
const transactionSettingData = await this.transactionSetting.findOne({
where: {},
});
const percentage = transactionSettingData?.value ?? 100;
const randomValue = Math.floor(Math.random() * 100) + 1;
// const transactionPercentage = Math.floor(Math.random() * 100) + 1;
const transactionPercentage = await this.dataSaveFactor();
return randomValue > percentage;
Logger.log(`Factor ${transactionPercentage} from ${percentage}`);
return transactionPercentage > percentage;
}
async dataSaveFactor() {
const today = new Date();
today.setHours(0, 0, 0, 0);
const todayTimestamp = today.getTime();
const totalTransactions = await this.transaction.count({
where: {
created_at: MoreThan(todayTimestamp),
},
});
const couchTransaction = await this.couchService.totalTodayTransactions();
if (couchTransaction == 0) return 0;
const factor = (totalTransactions / couchTransaction) * 100;
return factor;
}
async itemTax(id: string) {
@ -98,3 +142,13 @@ export class SalesPriceFormulaDataService extends BaseDataService<SalesPriceForm
return salesFormula;
}
}
@Injectable()
export class TransactionSettingDataService extends BaseDataService<TransactionSetting> {
constructor(
@InjectRepository(TransactionSettingModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<TransactionSettingModel>,
) {
super(repo);
}
}

View File

@ -1,7 +1,10 @@
import { Injectable } from '@nestjs/common';
import { SalesPriceFormulaEntity } from '../../domain/entities/sales-price-formula.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { SalesPriceFormulaModel } from '../models/sales-price-formula.model';
import {
SalesPriceFormulaModel,
TransactionSettingModel,
} from '../models/sales-price-formula.model';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { Repository } from 'typeorm';
import { BaseReadService } from 'src/core/modules/data/service/base-read.service';
@ -11,7 +14,25 @@ export class SalesPriceFormulaReadService extends BaseReadService<SalesPriceForm
constructor(
@InjectRepository(SalesPriceFormulaModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<SalesPriceFormulaModel>,
@InjectRepository(TransactionSettingModel, CONNECTION_NAME.DEFAULT)
private transactionSetting: Repository<TransactionSettingModel>,
) {
super(repo);
}
async getTransactionSetting(): Promise<any> {
try {
const data = await this.transactionSetting.findOne({
where: {},
order: {
created_at: 'DESC',
},
});
return data;
} catch (error) {
throw error;
}
}
}

View File

@ -1,5 +1,6 @@
import { BaseEntity } from 'src/core/modules/domain/entities/base.entity';
import { FormulaType } from '../../constants';
import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entity';
export interface SalesPriceFormulaEntity extends BaseEntity {
formula_render: any; // json type
@ -16,3 +17,7 @@ export interface AdditionalFormula {
formula_string: string;
value_for: string;
}
export interface TransactionSetting extends BaseCoreEntity {
value: number;
}

View File

@ -0,0 +1,40 @@
import { Injectable } from '@nestjs/common';
import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager';
import { TransactionSetting } from '../../entities/sales-price-formula.entity';
import { TransactionSettingModel } from '../../../data/models/sales-price-formula.model';
import {
EventTopics,
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
@Injectable()
export class UpdateTransactionSettingManager extends BaseUpdateManager<TransactionSetting> {
async validateProcess(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get uniqueColumns(): columnUniques[] {
return [];
}
get entityTarget(): any {
return TransactionSettingModel;
}
get eventTopics(): EventTopics[] {
return [];
}
}

View File

@ -1,10 +1,17 @@
import { Injectable } from '@nestjs/common';
import { SalesPriceFormulaDataService } from '../../data/services/sales-price-formula-data.service';
import { SalesPriceFormulaEntity } from '../entities/sales-price-formula.entity';
import {
SalesPriceFormulaDataService,
TransactionSettingDataService,
} from '../../data/services/sales-price-formula-data.service';
import {
SalesPriceFormulaEntity,
TransactionSetting,
} 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';
import { UpdateTransactionSettingManager } from './managers/update-transaction-setting.manager';
@Injectable()
export class SalesPriceFormulaDataOrchestrator {
@ -12,6 +19,8 @@ export class SalesPriceFormulaDataOrchestrator {
private updateManager: UpdateSalesPriceFormulaManager,
private serviceData: SalesPriceFormulaDataService,
private taxService: TaxDataService,
private transactionSettingService: TransactionSettingDataService,
private transactionSettingManager: UpdateTransactionSettingManager,
) {}
async update(data): Promise<SalesPriceFormulaEntity> {
@ -30,4 +39,14 @@ export class SalesPriceFormulaDataOrchestrator {
await this.updateManager.execute();
return this.updateManager.getResult();
}
async updateTransactionSetting(data): Promise<TransactionSetting> {
this.transactionSettingManager.setData(data.id, data);
this.transactionSettingManager.setService(
this.transactionSettingService,
TABLE_NAME.TRANSACTION_SETTING,
);
await this.transactionSettingManager.execute();
return this.transactionSettingManager.getResult();
}
}

View File

@ -17,4 +17,12 @@ export class SalesPriceFormulaReadOrchestrator {
await this.detailManager.execute();
return this.detailManager.getResult();
}
async getTransactionSetting(): Promise<any> {
try {
return await this.serviceData.getTransactionSetting();
} catch (error) {
throw error;
}
}
}

View File

@ -2,6 +2,7 @@ import { BaseDto } from 'src/core/modules/infrastructure/dto/base.dto';
import {
AdditionalFormula,
SalesPriceFormulaEntity,
TransactionSetting,
} from '../../domain/entities/sales-price-formula.entity';
import { ApiProperty } from '@nestjs/swagger';
import { ValidateIf, ValidateNested } from 'class-validator';
@ -32,6 +33,21 @@ export class AdditionalFormulaDto implements AdditionalFormula {
value_for: string;
}
export class TransactionSettingDto implements TransactionSetting {
@ApiProperty({
type: String,
required: true,
})
@ValidateIf((body) => body.id)
id?: string;
@ApiProperty({
type: Number,
required: true,
})
value: number;
}
export class SalesPriceFormulaDto
extends BaseDto
implements SalesPriceFormulaEntity

View File

@ -1,12 +1,18 @@
import { Body, Controller, Post } from '@nestjs/common';
import { Body, Controller, Post, Put } from '@nestjs/common';
import { SalesPriceFormulaDataOrchestrator } from '../domain/usecases/sales-price-formula-data.orchestrator';
import { SalesPriceFormulaDto } from './dto/sales-price-formula.dto';
import {
SalesPriceFormulaDto,
TransactionSettingDto,
} from './dto/sales-price-formula.dto';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { SalesPriceFormulaEntity } from '../domain/entities/sales-price-formula.entity';
import {
SalesPriceFormulaEntity,
TransactionSetting,
} from '../domain/entities/sales-price-formula.entity';
import { Public } from 'src/core/guards';
@ApiTags(`sales price formulas - data`)
@Controller('v1/sales-price-formula')
@Controller(['v1/sales-price-formula', 'v1/transaction-setting'])
@Public(false)
@ApiBearerAuth('JWT')
export class SalesPriceFormulaDataController {
@ -18,4 +24,12 @@ export class SalesPriceFormulaDataController {
): Promise<SalesPriceFormulaEntity> {
return await this.orchestrator.update(data);
}
@Public(true)
@Put()
async updateTransactionSetting(
@Body() data: TransactionSettingDto,
): Promise<TransactionSetting> {
return await this.orchestrator.updateTransactionSetting(data);
}
}

View File

@ -5,7 +5,7 @@ import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
@ApiTags(`sales price formulas - read`)
@Controller('v1/sales-price-formula')
@Controller(['v1/sales-price-formula', 'v1/transaction-setting'])
@Public(false)
@ApiBearerAuth('JWT')
export class SalesPriceFormulaReadController {
@ -15,4 +15,10 @@ export class SalesPriceFormulaReadController {
async detail(): Promise<SalesPriceFormulaEntity> {
return await this.orchestrator.detail();
}
@Public(true)
@Get('detail')
async getTransactionSetting(): Promise<any> {
return await this.orchestrator.getTransactionSetting();
}
}

View File

@ -2,7 +2,10 @@ import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { SalesPriceFormulaDataService } from './data/services/sales-price-formula-data.service';
import {
SalesPriceFormulaDataService,
TransactionSettingDataService,
} from './data/services/sales-price-formula-data.service';
import { SalesPriceFormulaReadService } from './data/services/sales-price-formula-read.service';
import { SalesPriceFormulaReadController } from './infrastructure/sales-price-formula-read.controller';
import { SalesPriceFormulaReadOrchestrator } from './domain/usecases/sales-price-formula-read.orchestrator';
@ -11,17 +14,29 @@ import { SalesPriceFormulaDataOrchestrator } from './domain/usecases/sales-price
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 {
SalesPriceFormulaModel,
TransactionSettingModel,
} 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';
import { UpdateTransactionSettingManager } from './domain/usecases/managers/update-transaction-setting.manager';
import { TransactionModel } from '../transaction/data/models/transaction.model';
import { CouchService } from 'src/modules/configuration/couch/data/services/couch.service';
@Global()
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature(
[SalesPriceFormulaModel, TaxModel, ItemModel],
[
SalesPriceFormulaModel,
TransactionSettingModel,
TransactionModel,
TaxModel,
ItemModel,
],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,
@ -33,13 +48,16 @@ import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'
providers: [
DetailSalesPriceFormulaManager,
UpdateSalesPriceFormulaManager,
UpdateTransactionSettingManager,
TaxDataService,
SalesPriceFormulaDataService,
SalesPriceFormulaReadService,
TransactionSettingDataService,
SalesPriceFormulaDataOrchestrator,
SalesPriceFormulaReadOrchestrator,
CouchService,
],
exports: [SalesPriceFormulaDataService, SalesPriceFormulaReadService],
})

View File

@ -23,14 +23,17 @@ import { BatchConfirmTaxManager } from './domain/usecases/managers/batch-confirm
import { BatchInactiveTaxManager } from './domain/usecases/managers/batch-inactive-tax.manager';
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 {
SalesPriceFormulaModel,
TransactionSettingModel,
} from '../sales-price-formula/data/models/sales-price-formula.model';
import { IndexTaxFormulaManager } from './domain/usecases/managers/index-tax-formula.manager';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature(
[TaxModel, SalesPriceFormulaModel],
[TaxModel, SalesPriceFormulaModel, TransactionSettingModel],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,

View File

@ -32,7 +32,10 @@ import { BatchConfirmDataTransactionManager } from './domain/usecases/managers/b
import { PosTransactionHandler } from './domain/usecases/handlers/pos-transaction.handler';
import { TaxDataService } from '../tax/data/services/tax-data.service';
import { SalesPriceFormulaDataService } from '../sales-price-formula/data/services/sales-price-formula-data.service';
import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales-price-formula.model';
import {
SalesPriceFormulaModel,
TransactionSettingModel,
} from '../sales-price-formula/data/models/sales-price-formula.model';
import { TaxModel } from '../tax/data/models/tax.model';
import { SettledTransactionHandler } from './domain/usecases/handlers/settled-transaction.handler';
import { RefundUpdatedHandler } from './domain/usecases/handlers/refund-update.handler';
@ -43,6 +46,7 @@ import { PaymentMethodModel } from '../payment-method/data/models/payment-method
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';
import { CouchService } from 'src/modules/configuration/couch/data/services/couch.service';
@Module({
exports: [TransactionReadService],
@ -57,6 +61,7 @@ import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'
TransactionTaxModel,
TransactionItemTaxModel,
TransactionBreakdownTaxModel,
TransactionSettingModel,
TaxModel,
SalesPriceFormulaModel,
PaymentMethodModel,
@ -96,6 +101,8 @@ import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'
TransactionDataOrchestrator,
TransactionReadOrchestrator,
CouchService,
],
})
export class TransactionModule {}