Merge pull request 'fix/data' (#42) from fix/data into development
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #42
pull/44/head devel_12.0.0
aswin 2024-07-30 06:56:07 +00:00
commit e1004b3843
29 changed files with 182 additions and 63 deletions

View File

@ -20,12 +20,16 @@ export class SpecificSearchFilter<Entity = any> {
new Brackets((qb) => {
params.forEach((param) => {
const { cols, data, additional, leftJoin } = param;
const columns = cols.split('.');
let arr = data;
const arr = data?.map((el) =>
if (!columns.includes('status::text')) {
arr = data?.map((el) =>
el.includes("'")
? `'%${el.trim().replace(/'/g, "''").replace(/\s+/g, ' ')}%'`
: `'%${el.trim().replace(/\s+/g, ' ')}%'`,
);
}
const aliases = !cols.match(/\./g)
? this.table.concat(`.${cols}`)

View File

@ -50,7 +50,7 @@ export abstract class BaseIndexManager<Entity> extends BaseReadManager {
// 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;
return `'${STATUS[statusData.toUpperCase()]}'` ?? `'%${statusData}%'`;
});
specificFilter.push({
cols: `${this.tableName}.status::text`,

View File

@ -51,7 +51,6 @@ export const PrivilegeAdminConstant = [
menu_label: 'Rekonsiliasi',
actions: [
PrivilegeAction.VIEW,
PrivilegeAction.CREATE,
PrivilegeAction.CONFIRM,
PrivilegeAction.DELETE,
PrivilegeAction.CANCEL,
@ -160,7 +159,7 @@ export const PrivilegePOSConstant = [
{
menu: 'BOOKING',
menu_label: 'Pemesanan',
actions: [PrivilegeAction.VIEW, PrivilegeAction.CREATE],
actions: [PrivilegeAction.VIEW],
index: 16,
},
{

View File

@ -0,0 +1,27 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddColumnToRefundTable1722318939681 implements MigrationInterface {
name = 'AddColumnToRefundTable1722318939681';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."refunds_refund_reason_type_enum" AS ENUM('weather', 'ride malfunction', 'other')`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ADD "refund_reason_type" "public"."refunds_refund_reason_type_enum" NOT NULL DEFAULT 'ride malfunction'`,
);
await queryRunner.query(`ALTER TABLE "refunds" ADD "refund_reason" text`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "refunds" DROP COLUMN "refund_reason"`,
);
await queryRunner.query(
`ALTER TABLE "refunds" DROP COLUMN "refund_reason_type"`,
);
await queryRunner.query(
`DROP TYPE "public"."refunds_refund_reason_type_enum"`,
);
}
}

View File

@ -5,7 +5,10 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
import { ItemType } from 'src/modules/item-related/item-category/constants';
import { LimitType } from 'src/modules/item-related/item/constants';
import { PaymentMethodType } from 'src/modules/transaction/payment-method/constants';
import { RefundType } from 'src/modules/transaction/refund/constants';
import {
RefundReasonType,
RefundType,
} from 'src/modules/transaction/refund/constants';
import { GateType } from 'src/modules/web-information/gate/constants';
@ApiTags('configuration - constant')
@ -52,6 +55,11 @@ export class ConstantController {
return Object.values(RefundType);
}
@Get('refund-reason-type')
async refundReasonType(): Promise<any> {
return Object.values(RefundReasonType);
}
@Get('gate-type')
async gateType(): Promise<any> {
return Object.values(GateType);

View File

@ -27,7 +27,11 @@ export class UpdateItemCategoryManager extends BaseUpdateManager<ItemCategoryEnt
}
get validateRelations(): validateRelations[] {
return [];
return [
{
relation: 'items',
},
];
}
get uniqueColumns(): columnUniques[] {

View File

@ -1,7 +1,9 @@
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
import { ItemType } from 'src/modules/item-related/item-category/constants';
export interface FilterItemRateEntity extends BaseFilterEntity {
item_ids: string[];
item_types: ItemType[];
season_period_ids: string[];
start_date: Date;
end_date: Date;

View File

@ -86,6 +86,7 @@ export class IndexItemRateManager extends BaseIndexManager<ItemEntity> {
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.item_type`,
`${this.tableName}.status`,
`${this.tableName}.created_at`,
`${this.tableName}.name`,

View File

@ -2,6 +2,7 @@ import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.d
import { FilterItemRateEntity } from '../../domain/entities/filter-item-rate.entity';
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { ItemType } from 'src/modules/item-related/item-category/constants';
export class FilterItemRateDto
extends BaseFilterDto
@ -21,6 +22,16 @@ export class FilterItemRateDto
})
end_date: Date;
@ApiProperty({
type: ['string'],
required: false,
description: `Select ["${Object.values(ItemType)}"]`,
})
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
item_types: ItemType[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];

View File

@ -7,11 +7,8 @@ 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 {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { validateRelation } from './helpers/validasi-relation.helper';
@Injectable()
export class BatchDeleteItemManager extends BaseBatchDeleteManager<ItemEntity> {
@ -20,21 +17,7 @@ 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',
});
}
await validateRelation(this.dataService, data.id);
return;
}

View File

@ -8,10 +8,12 @@ import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common';
import { validateRelation } from './helpers/validasi-relation.helper';
@Injectable()
export class BatchInactiveItemManager extends BaseBatchUpdateStatusManager<ItemEntity> {
validateData(data: ItemEntity): Promise<void> {
async validateData(data: ItemEntity): Promise<void> {
await validateRelation(this.dataService, data.id);
return;
}

View File

@ -1,8 +1,4 @@
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager';
import { ItemEntity } from '../../entities/item.entity';
import {
@ -11,6 +7,7 @@ import {
} from 'src/core/strings/constants/interface.constants';
import { ItemModel } from '../../../data/models/item.model';
import { ItemDeletedEvent } from '../../entities/event/item-deleted.event';
import { validateRelation } from './helpers/validasi-relation.helper';
@Injectable()
export class DeleteItemManager extends BaseDeleteManager<ItemEntity> {
@ -19,21 +16,7 @@ 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',
});
}
await validateRelation(this.dataService, this.dataId);
return;
}

View File

@ -0,0 +1,19 @@
import { HttpStatus, UnprocessableEntityException } from '@nestjs/common';
export async function validateRelation(dataService, id) {
const haveRelation = await dataService.getOneByOptions({
where: {
bundling_items: {
id: id,
},
},
});
if (haveRelation) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! this data already connected to bunding item`,
error: 'Unprocessable Entity',
});
}
}

View File

@ -7,6 +7,7 @@ import {
} from 'src/core/strings/constants/interface.constants';
import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { validateRelation } from './helpers/validasi-relation.helper';
@Injectable()
export class InactiveItemManager extends BaseUpdateStatusManager<ItemEntity> {
@ -15,6 +16,7 @@ export class InactiveItemManager extends BaseUpdateStatusManager<ItemEntity> {
}
async validateProcess(): Promise<void> {
await validateRelation(this.dataService, this.dataId);
return;
}

View File

@ -19,6 +19,16 @@ export class IndexItemRatesManager extends BaseIndexManager<ItemRateEntity> {
}
async afterProcess(): Promise<void> {
this.result.data?.map((item) => {
const item_price =
Number(item['item']?.total_price ?? 0) == 0
? item['item']?.total_price
: item['item']?.base_price;
Object.assign(item, {
price: item.price ?? item_price,
});
});
return;
}
@ -28,7 +38,7 @@ export class IndexItemRatesManager extends BaseIndexManager<ItemRateEntity> {
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: ['season_period', 'season_period.season_type'],
selectRelations: ['season_period', 'season_period.season_type', 'item'],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
@ -41,6 +51,10 @@ export class IndexItemRatesManager extends BaseIndexManager<ItemRateEntity> {
`${this.tableName}.item_id`,
`${this.tableName}.price`,
'item.id',
'item.total_price',
'item.base_price',
`season_period.id`,
`season_period.priority`,
`season_period.created_at`,

View File

@ -2,3 +2,9 @@ export enum RefundType {
BOOKING = 'pengembalian booking',
WAHANA = 'pengembalian wahana',
}
export enum RefundReasonType {
WEATHER = 'weather',
RIDE_MALFUNCTION = 'ride malfunction',
OTHER = 'other',
}

View File

@ -4,7 +4,7 @@ import { Column, Entity, JoinColumn, OneToMany, OneToOne } from 'typeorm';
import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model';
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
import { RefundItemModel } from './refund-item.model';
import { RefundType } from '../../constants';
import { RefundReasonType, RefundType } from '../../constants';
@Entity(TABLE_NAME.REFUND)
export class RefundModel
@ -33,6 +33,16 @@ export class RefundModel
@Column('decimal', { name: 'refund_total', nullable: true })
refund_total: number;
@Column('enum', {
name: 'refund_reason_type',
enum: RefundReasonType,
default: RefundReasonType.RIDE_MALFUNCTION,
})
refund_reason_type: RefundReasonType;
@Column('text', { name: 'refund_reason', nullable: true })
refund_reason: string;
// bank info
@Column('varchar', { name: 'bank_name', nullable: true })
bank_name: string;

View File

@ -1,5 +1,5 @@
import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity';
import { RefundType } from '../../constants';
import { RefundReasonType, RefundType } from '../../constants';
export interface RefundEntity extends BaseStatusEntity {
type: RefundType;
@ -8,6 +8,8 @@ export interface RefundEntity extends BaseStatusEntity {
refund_date: Date;
refund_sub_total: number;
refund_total: number;
refund_reason_type: RefundReasonType;
refund_reason: string;
bank_name: string;
bank_account_name: string;

View File

@ -17,7 +17,12 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class BatchConfirmRefundManager extends BaseBatchUpdateStatusManager<RefundEntity> {
async validateData(data: RefundEntity): Promise<void> {
if (data?.['transaction']?.status != STATUS.SETTLED) {
if (
this.data.status == STATUS.DRAFT &&
data['trnsaction']?.status != STATUS.SETTLED &&
this.data.status == STATUS.PENDING &&
data['trnsaction']?.status != STATUS.PROCESS_REFUND
) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,

View File

@ -38,7 +38,12 @@ export class ConfirmRefundManager extends BaseUpdateStatusManager<RefundEntity>
relations: ['transaction'],
});
if (data.transaction.status != STATUS.SETTLED) {
if (
data.status == STATUS.DRAFT &&
data.transaction.status != STATUS.SETTLED &&
data.status == STATUS.PENDING &&
data.transaction.status != STATUS.PROCESS_REFUND
) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,

View File

@ -39,6 +39,8 @@ export class DetailRefundManager extends BaseDetailManager<RefundEntity> {
`${this.tableName}.status`,
`${this.tableName}.type`,
`${this.tableName}.refund_reason`,
`${this.tableName}.refund_reason_type`,
`${this.tableName}.request_date`,
`${this.tableName}.refund_date`,
`${this.tableName}.created_at`,

View File

@ -50,6 +50,8 @@ export class IndexRefundManager extends BaseIndexManager<RefundEntity> {
`${this.tableName}.status`,
`${this.tableName}.type`,
`${this.tableName}.refund_reason`,
`${this.tableName}.refund_reason_type`,
`${this.tableName}.request_date`,
`${this.tableName}.refund_date`,
`${this.tableName}.created_at`,

View File

@ -4,9 +4,25 @@ import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsString, ValidateIf } from 'class-validator';
import { Exclude } from 'class-transformer';
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
import { RefundType } from '../../constants';
import { RefundReasonType, RefundType } from '../../constants';
export class RefundDto extends BaseStatusDto implements RefundEntity {
@ApiProperty({
type: String,
required: true,
example: RefundReasonType.RIDE_MALFUNCTION,
})
@IsString()
refund_reason_type: RefundReasonType;
@ApiProperty({
type: String,
required: false,
example: '',
})
@ValidateIf((object) => object.refund_reason_type == RefundReasonType.OTHER)
refund_reason: string;
@ApiProperty({
type: String,
required: true,

View File

@ -51,6 +51,7 @@ export class BatchConfirmTransactionManager extends BaseBatchUpdateStatusManager
Object.assign(data, {
invoice_code: await generateInvoiceCodeHelper(this.dataService, 'INV'),
status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING,
invoice_date: new Date(),
});
return;
}

View File

@ -61,6 +61,7 @@ export class ConfirmTransactionManager extends BaseUpdateStatusManager<Transacti
? null
: await generateInvoiceCodeHelper(this.dataService, 'INV'),
status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING,
invoice_date: new Date(),
});
return;
}

View File

@ -103,10 +103,9 @@ export class TransactionDto extends BaseStatusDto {
@ApiProperty({
type: String,
required: true,
required: false,
example: TransactionPaymentType.MIDTRANS,
})
@IsString()
payment_type: TransactionPaymentType;
@ApiProperty({

View File

@ -1,3 +1,5 @@
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
export interface FilterBannerEntity extends BaseFilterEntity {}
export interface FilterBannerEntity extends BaseFilterEntity {
titles: string[];
}

View File

@ -52,8 +52,8 @@ export class IndexBannerManager extends BaseIndexManager<BannerEntity> {
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.name`,
data: this.filterParam.names,
cols: `${this.tableName}.title`,
data: this.filterParam.titles,
},
];
}

View File

@ -1,6 +1,15 @@
import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto';
import { FilterBannerEntity } from '../../domain/entities/filter-banner.entity';
import { Transform } from 'class-transformer';
import { ApiProperty } from '@nestjs/swagger';
export class FilterBannerDto
extends BaseFilterDto
implements FilterBannerEntity {}
implements FilterBannerEntity
{
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
titles: string[];
}