Merge pull request 'fix/data' (#40) from fix/data into development
continuous-integration/drone/tag Build is passing
Details
continuous-integration/drone/tag Build is passing
Details
Reviewed-on: #40pull/41/head devel_10.6.28
commit
c7fa402663
|
@ -97,7 +97,7 @@ export abstract class BaseCreateManager<Entity> extends BaseManager {
|
|||
|
||||
this.eventBus.publishAll([
|
||||
new topic.topic({
|
||||
id: data?.['id'] ?? topic?.data?.['id'],
|
||||
id: this.result['id'],
|
||||
old: null,
|
||||
data: data ?? topic.data,
|
||||
user: this.user,
|
||||
|
|
|
@ -20,6 +20,16 @@ export enum ORDER_TYPE {
|
|||
DESC = 'DESC',
|
||||
}
|
||||
|
||||
export const DAY = [
|
||||
'minggu',
|
||||
'senin',
|
||||
'selasa',
|
||||
'rabu',
|
||||
'kamis',
|
||||
'jumat',
|
||||
'sabtu',
|
||||
];
|
||||
|
||||
export enum CONNECTION_NAME {
|
||||
DEFAULT = 'default',
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
|
||||
import { EMPTY_UUID } from 'src/core/strings/constants/base.constants';
|
||||
import { ItemCreatedEvent } from 'src/modules/item-related/item/domain/entities/event/item-created.event';
|
||||
import { SeasonPeriodDataService } from 'src/modules/season-related/season-period/data/services/season-period-data.service';
|
||||
import { Not } from 'typeorm';
|
||||
import { ItemRateModel } from '../../../data/models/item-rate.model';
|
||||
import { ItemRateDataService } from '../../../data/services/item-rate-data.service';
|
||||
|
||||
@EventsHandler(ItemCreatedEvent)
|
||||
export class SeasonPeriodHolidayHandler
|
||||
implements IEventHandler<ItemCreatedEvent>
|
||||
{
|
||||
constructor(
|
||||
private seasonService: SeasonPeriodDataService,
|
||||
private dataService: ItemRateDataService,
|
||||
) {}
|
||||
|
||||
async handle(event: ItemCreatedEvent) {
|
||||
const rates = [];
|
||||
const seasons = await this.seasonService.getManyByOptions({
|
||||
where: {
|
||||
id: Not(EMPTY_UUID),
|
||||
},
|
||||
});
|
||||
|
||||
const queryRunner = this.dataService
|
||||
.getRepository()
|
||||
.manager.connection.createQueryRunner();
|
||||
|
||||
if (seasons.length) {
|
||||
for (const season of seasons) {
|
||||
const rate = new ItemRateModel();
|
||||
rate.item_id = event.data.id;
|
||||
rate.season_period_id = season.id;
|
||||
|
||||
rates.push(rate);
|
||||
}
|
||||
}
|
||||
|
||||
// create batch
|
||||
await this.dataService.createBatch(queryRunner, ItemRateModel, rates);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import {
|
|||
RelationParam,
|
||||
} from 'src/core/modules/domain/entities/base-filter.entity';
|
||||
import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { DAY, STATUS } from 'src/core/strings/constants/base.constants';
|
||||
|
||||
@Injectable()
|
||||
export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
|
||||
|
@ -26,18 +26,32 @@ export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
|
|||
d <= new Date(this.filterParam.end_date);
|
||||
d.setDate(d.getDate() + 1)
|
||||
) {
|
||||
const rate = item['item_rates']?.find(
|
||||
(rate) =>
|
||||
rate.season_period?.status == STATUS.ACTIVE &&
|
||||
d >= new Date(rate.season_period.start_date) &&
|
||||
d <= new Date(rate.season_period.end_date),
|
||||
);
|
||||
const day: string = DAY[d.getDay()];
|
||||
const rates = item['item_rates']
|
||||
?.filter((rate) => {
|
||||
const days: string[] = rate.season_period.days ?? [];
|
||||
if (rate.season_period.priority == 2) {
|
||||
return (
|
||||
rate.season_period?.status == STATUS.ACTIVE &&
|
||||
d >= new Date(rate.season_period.start_date) &&
|
||||
d <= new Date(rate.season_period.end_date) &&
|
||||
days.includes(day)
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
rate.season_period?.status == STATUS.ACTIVE &&
|
||||
d >= new Date(rate.season_period.start_date) &&
|
||||
d <= new Date(rate.season_period.end_date)
|
||||
);
|
||||
}
|
||||
})
|
||||
.sort((a, b) => a.season_period.priority - b.season_period.priority);
|
||||
|
||||
prices.push({
|
||||
date: new Date(d),
|
||||
price: rate?.price ?? item.base_price,
|
||||
season_type: rate?.season_period?.season_type ?? null,
|
||||
holiday_name: rate?.season_period?.holiday_name ?? null,
|
||||
price: rates[0]?.price ?? item.base_price,
|
||||
season_type: rates[0]?.season_period?.season_type ?? null,
|
||||
holiday_name: rates[0]?.season_period?.holiday_name ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -91,6 +105,8 @@ export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
|
|||
'season_period.holiday_name',
|
||||
'season_period.start_date',
|
||||
'season_period.end_date',
|
||||
'season_period.priority',
|
||||
'season_period.days',
|
||||
|
||||
'season_type.id',
|
||||
'season_type.name',
|
||||
|
|
|
@ -16,16 +16,24 @@ import { UpdateItemRateManager } from './domain/usecases/managers/update-item-ra
|
|||
import { DetailItemRateManager } from './domain/usecases/managers/detail-item-rate.manager';
|
||||
import { BatchDeleteItemRateManager } from './domain/usecases/managers/batch-delete-item-rate.manager';
|
||||
import { ItemRateModel } from './data/models/item-rate.model';
|
||||
import { SeasonPeriodHolidayHandler } from './domain/usecases/handlers/item-created.handler';
|
||||
import { SeasonPeriodDataService } from 'src/modules/season-related/season-period/data/services/season-period-data.service';
|
||||
import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
TypeOrmModule.forFeature([ItemRateModel], CONNECTION_NAME.DEFAULT),
|
||||
TypeOrmModule.forFeature(
|
||||
[ItemRateModel, SeasonPeriodModel],
|
||||
CONNECTION_NAME.DEFAULT,
|
||||
),
|
||||
CqrsModule,
|
||||
],
|
||||
controllers: [ItemRateDataController, ItemRateReadController],
|
||||
providers: [
|
||||
SeasonPeriodHolidayHandler,
|
||||
|
||||
IndexItemRateManager,
|
||||
DetailItemRateManager,
|
||||
CreateItemRateManager,
|
||||
|
@ -33,6 +41,7 @@ import { ItemRateModel } from './data/models/item-rate.model';
|
|||
UpdateItemRateManager,
|
||||
BatchDeleteItemRateManager,
|
||||
|
||||
SeasonPeriodDataService,
|
||||
ItemRateDataService,
|
||||
ItemRateReadService,
|
||||
|
||||
|
|
|
@ -7,7 +7,11 @@ import {
|
|||
import { ItemModel } from '../../../data/models/item.model';
|
||||
import { ItemDeletedEvent } from '../../entities/event/item-deleted.event';
|
||||
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class BatchDeleteItemManager extends BaseBatchDeleteManager<ItemEntity> {
|
||||
|
@ -16,6 +20,21 @@ export class BatchDeleteItemManager extends BaseBatchDeleteManager<ItemEntity> {
|
|||
}
|
||||
|
||||
async validateData(data: ItemEntity): Promise<void> {
|
||||
const haveRelation = await this.dataService.getOneByOptions({
|
||||
where: {
|
||||
bundling_items: {
|
||||
id: data.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (haveRelation) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! this data already connected to bunding item`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -24,7 +43,7 @@ export class BatchDeleteItemManager extends BaseBatchDeleteManager<ItemEntity> {
|
|||
}
|
||||
|
||||
get validateRelations(): validateRelations[] {
|
||||
return [{ relation: 'bundling_items' }];
|
||||
return [];
|
||||
}
|
||||
|
||||
get entityTarget(): any {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager';
|
||||
import { ItemEntity } from '../../entities/item.entity';
|
||||
import {
|
||||
|
@ -15,6 +19,21 @@ export class DeleteItemManager extends BaseDeleteManager<ItemEntity> {
|
|||
}
|
||||
|
||||
async validateProcess(): Promise<void> {
|
||||
const haveRelation = await this.dataService.getOneByOptions({
|
||||
where: {
|
||||
bundling_items: {
|
||||
id: this.dataId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (haveRelation) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! this data already connected to bunding item`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27,7 +46,7 @@ export class DeleteItemManager extends BaseDeleteManager<ItemEntity> {
|
|||
}
|
||||
|
||||
get validateRelations(): validateRelations[] {
|
||||
return [{ relation: 'bundling_items' }];
|
||||
return [];
|
||||
}
|
||||
|
||||
get entityTarget(): any {
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
Param,
|
||||
RelationParam,
|
||||
} from 'src/core/modules/domain/entities/base-filter.entity';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { DAY, STATUS } from 'src/core/strings/constants/base.constants';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentSeasonPeriodManager extends BaseIndexManager<SeasonPeriodEntity> {
|
||||
|
@ -20,8 +20,19 @@ export class CurrentSeasonPeriodManager extends BaseIndexManager<SeasonPeriodEnt
|
|||
}
|
||||
|
||||
async afterProcess(): Promise<void> {
|
||||
const date = new Date(this.filterParam.date);
|
||||
const day = DAY[date.getDay()];
|
||||
Object.assign(this.result, {
|
||||
data: this.result.data.sort((a, b) => a.priority - b.priority),
|
||||
data: this.result.data
|
||||
.filter((data) => {
|
||||
const days: string[] = data.days ?? [];
|
||||
if (data.priority == 2) {
|
||||
return days.includes(day);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.sort((a, b) => a.priority - b.priority),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export class SeasonPeriodDataOrchestrator extends BaseDataTransactionOrchestrato
|
|||
async update(dataId, data, updatePrice = false): Promise<SeasonPeriodEntity> {
|
||||
this.updateManager.setData(dataId, {
|
||||
...data,
|
||||
isUpdatePrice: updatePrice
|
||||
isUpdatePrice: updatePrice,
|
||||
});
|
||||
this.updateManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD);
|
||||
await this.updateManager.execute();
|
||||
|
|
|
@ -23,7 +23,7 @@ export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManag
|
|||
},
|
||||
});
|
||||
|
||||
if (transaction.status != STATUS.SETTLED) {
|
||||
if ([STATUS.SETTLED, STATUS.WAITING].includes(transaction.status)) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! cant cancel transaction not settled`,
|
||||
|
|
|
@ -9,22 +9,20 @@ import { TransactionEntity } from 'src/modules/transaction/transaction/domain/en
|
|||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||
import { generateInvoiceCodeHelper } from 'src/modules/transaction/transaction/domain/usecases/managers/helpers/generate-invoice-code.helper';
|
||||
|
||||
@Injectable()
|
||||
export class BatchConfirmReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
||||
async validateData(data: TransactionEntity): Promise<void> {
|
||||
const net_profit = data.reconciliation_mdr
|
||||
? Number(this.data.payment_total) - Number(this.data.reconciliation_mdr)
|
||||
: null;
|
||||
|
||||
Object.assign(data, {
|
||||
reconciliation_mdr: this.data.reconciliation_mdr ?? null,
|
||||
reconciliation_confirm_by: this.user.name,
|
||||
reconciliation_confirm_date: new Date().getTime(),
|
||||
status: STATUS.SETTLED,
|
||||
reconciliation_status: this.dataStatus,
|
||||
payment_total_net_profit: net_profit,
|
||||
payment_date: this.data.payment_date,
|
||||
payment_code_reference: await generateInvoiceCodeHelper(
|
||||
this.dataService,
|
||||
'PMY',
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager<Transac
|
|||
},
|
||||
});
|
||||
|
||||
if (transaction.status != STATUS.SETTLED) {
|
||||
if ([STATUS.SETTLED, STATUS.WAITING].includes(transaction.status)) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! cant cancel transaction not settled`,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||
import { generateInvoiceCodeHelper } from 'src/modules/transaction/transaction/domain/usecases/managers/helpers/generate-invoice-code.helper';
|
||||
|
||||
@Injectable()
|
||||
export class ConfirmReconciliationManager extends BaseUpdateStatusManager<TransactionEntity> {
|
||||
|
@ -25,6 +26,10 @@ export class ConfirmReconciliationManager extends BaseUpdateStatusManager<Transa
|
|||
reconciliation_confirm_date: new Date().getTime(),
|
||||
status: STATUS.SETTLED,
|
||||
reconciliation_status: this.dataStatus,
|
||||
payment_code_reference: await generateInvoiceCodeHelper(
|
||||
this.dataService,
|
||||
'PMY',
|
||||
),
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
} from 'src/core/modules/domain/entities/base-filter.entity';
|
||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||
import { BetweenQueryHelper } from 'src/core/helpers/query/between-query.helper';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
|
||||
@Injectable()
|
||||
export class IndexReconciliationManager extends BaseIndexManager<TransactionEntity> {
|
||||
|
@ -145,7 +146,10 @@ export class IndexReconciliationManager extends BaseIndexManager<TransactionEnti
|
|||
}
|
||||
|
||||
queryBuilder.andWhere(
|
||||
`${this.tableName}.reconciliation_status Is Not Null`,
|
||||
`${this.tableName}.reconciliation_status Not In (:...statuses)`,
|
||||
{
|
||||
statuses: [STATUS.DRAFT],
|
||||
},
|
||||
);
|
||||
return queryBuilder;
|
||||
}
|
||||
|
|
|
@ -18,12 +18,29 @@ import { TransactionPaymentType } from '../../../constants';
|
|||
@Injectable()
|
||||
export class BatchConfirmDataTransactionManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
||||
validateData(data: TransactionEntity): Promise<void> {
|
||||
if (
|
||||
[
|
||||
TransactionPaymentType.BANK_TRANSFER,
|
||||
TransactionPaymentType.QRIS,
|
||||
].includes(this.data.payment_type) &&
|
||||
(!this.data.payment_date ||
|
||||
!this.data.payment_total ||
|
||||
!this.data.payment_type_method_number ||
|
||||
!this.data.payment_type_method_name)
|
||||
) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Gagal! tolong lengkapi data terlebih dahulu`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
![STATUS.PENDING, STATUS.REJECTED, STATUS.EXPIRED].includes(data.status)
|
||||
) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! only data booking with status ${STATUS.PENDING}, ${STATUS.REJECTED}, ${STATUS.EXPIRED} can be confirm`,
|
||||
message: `Gagal! hanya pemesanan dengan status ${STATUS.PENDING}, ${STATUS.REJECTED}, ${STATUS.EXPIRED} dapat dikonfirmasi`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ export class BatchConfirmTransactionManager extends BaseBatchUpdateStatusManager
|
|||
}
|
||||
|
||||
Object.assign(data, {
|
||||
invoice_code: await generateInvoiceCodeHelper(this.dataService),
|
||||
invoice_code: await generateInvoiceCodeHelper(this.dataService, 'INV'),
|
||||
status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING,
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -21,6 +21,23 @@ export class ConfirmDataTransactionManager extends BaseUpdateStatusManager<Trans
|
|||
}
|
||||
|
||||
async validateProcess(): Promise<void> {
|
||||
if (
|
||||
[
|
||||
TransactionPaymentType.BANK_TRANSFER,
|
||||
TransactionPaymentType.QRIS,
|
||||
].includes(this.data.payment_type) &&
|
||||
(!this.data.payment_date ||
|
||||
!this.data.payment_total ||
|
||||
!this.data.payment_type_method_number ||
|
||||
!this.data.payment_type_method_name)
|
||||
) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Gagal! tolong lengkapi data terlebih dahulu`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -32,7 +49,7 @@ export class ConfirmDataTransactionManager extends BaseUpdateStatusManager<Trans
|
|||
) {
|
||||
throw new UnprocessableEntityException({
|
||||
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
message: `Failed! only data booking with status ${STATUS.PENDING}, ${STATUS.REJECTED}, ${STATUS.EXPIRED} can be confirm`,
|
||||
message: `Gagal! hanya pemesanan dengan status ${STATUS.PENDING}, ${STATUS.REJECTED}, ${STATUS.EXPIRED} dapat dikonfirmasi`,
|
||||
error: 'Unprocessable Entity',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ export class ConfirmTransactionManager extends BaseUpdateStatusManager<Transacti
|
|||
invoice_code:
|
||||
this.data.payment_type == TransactionPaymentType.COUNTER
|
||||
? null
|
||||
: await generateInvoiceCodeHelper(this.dataService),
|
||||
: await generateInvoiceCodeHelper(this.dataService, 'INV'),
|
||||
status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING,
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -4,19 +4,26 @@ import {
|
|||
} from 'src/modules/transaction/vip-code/domain/usecases/managers/helpers/generate-random.helper';
|
||||
import { ILike } from 'typeorm';
|
||||
|
||||
export async function generateInvoiceCodeHelper(dataService) {
|
||||
export async function generateInvoiceCodeHelper(dataService, code) {
|
||||
const month_year = generateCodeDate();
|
||||
const char = generateRandom(1);
|
||||
const number = generateRandom(1, true);
|
||||
let query: any = {
|
||||
invoice_code: ILike(`%${month_year}%`),
|
||||
};
|
||||
|
||||
if (code == 'PYM') {
|
||||
query = {
|
||||
payment_code_reference: ILike(`%${month_year}%`),
|
||||
};
|
||||
}
|
||||
|
||||
const invoice_code = await dataService.getManyByOptions({
|
||||
where: {
|
||||
invoice_code: ILike(`%${month_year}%`),
|
||||
},
|
||||
where: query,
|
||||
});
|
||||
const current_number = invoice_code.length + 1;
|
||||
|
||||
return `INV-${month_year}${char}${number}/${current_number
|
||||
return `${code}-${month_year}${char}${number}/${current_number
|
||||
.toString()
|
||||
.padStart(5, '0')}`;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ export function mappingTransaction(data) {
|
|||
season_period: season_period,
|
||||
items: items,
|
||||
payment_type_bank: payment_type_bank,
|
||||
payment_code: data.payment_code_reference,
|
||||
});
|
||||
|
||||
delete data.season_period_id;
|
||||
|
|
Loading…
Reference in New Issue