Merge pull request 'feat/refund' (#27) from feat/refund into development
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #27
pull/28/head devel_10.6.12
aswin 2024-07-12 10:52:01 +00:00
commit 2a8d5e87cf
54 changed files with 1940 additions and 22 deletions

View File

@ -55,6 +55,9 @@ import { ReportBookmarkModel } from './modules/reports/shared/models/report-book
import { ExportReportHistoryModel } from './modules/reports/shared/models/export-report-history.model';
import { CronModule } from './modules/configuration/cron/cron.module';
import { MidtransModule } from './modules/configuration/midtrans/midtrans.module';
import { RefundModule } from './modules/transaction/refund/refund.module';
import { RefundModel } from './modules/transaction/refund/data/models/refund.model';
import { RefundItemModel } from './modules/transaction/refund/data/models/refund-item.model';
@Module({
imports: [
@ -78,6 +81,8 @@ import { MidtransModule } from './modules/configuration/midtrans/midtrans.module
ItemRateModel,
LogModel,
PaymentMethodModel,
RefundModel,
RefundItemModel,
SalesPriceFormulaModel,
SeasonPeriodModel,
SeasonTypeModel,
@ -119,6 +124,7 @@ import { MidtransModule } from './modules/configuration/midtrans/midtrans.module
PaymentMethodModule,
ProfitShareFormulaModule,
ReconciliationModule,
RefundModule,
SalesPriceFormulaModule,
TaxModule,
TransactionModule,

View File

@ -8,6 +8,7 @@ import * as _ from 'lodash';
export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
protected dataIds: string[];
protected relations: string[] = [];
protected result: BatchResult;
protected dataStatus: STATUS;
protected oldData: Entity;
@ -37,6 +38,7 @@ export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
where: {
id: id,
},
relations: this.relations,
});
if (!entity) {

View File

@ -67,7 +67,7 @@ export abstract class BaseDeleteManager<Entity> extends BaseManager {
this.eventBus.publishAll([
new topic.topic({
id: topic.data['id'],
old: null,
old: this.data,
data: topic.data,
user: this.user,
description: '',

View File

@ -6,7 +6,9 @@ export enum STATUS {
DRAFT = 'draft',
EXPIRED = 'expired',
INACTIVE = 'inactive',
PARTIAL_REFUND = 'partial refund',
PENDING = 'pending',
PROCESS_REFUND = 'proses refund',
REFUNDED = 'refunded',
REJECTED = 'rejected',
SETTLED = 'settled',

View File

@ -4,6 +4,7 @@ export enum MODULE_NAME {
ITEM_RATE = 'item-rates',
PAYMENT_METHOD = 'payment-methods',
RECONCILIATION = 'reconciliations',
REFUND = 'refunds',
SEASON_TYPE = 'season-types',
SEASON_PERIOD = 'season-periods',
TAX = 'taxes',

View File

@ -6,6 +6,8 @@ export enum TABLE_NAME {
LOG = 'logs',
PAYMENT_METHOD = 'payment_methods',
PRICE_FORMULA = 'price_formulas',
REFUND = 'refunds',
REFUND_ITEM = 'refund_items',
SEASON_TYPE = 'season_types',
SEASON_PERIOD = 'season_periods',
TAX = 'taxes',

View File

@ -9,7 +9,7 @@ import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
import { Public } from 'src/core/guards';
@ApiTags(`${MODULE_NAME.{{constantCase name}}.split('-').join(' ')} - read`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}}}`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}} }`)
@Public(false)
@ApiBearerAuth('JWT')
export class {{pascalCase name}}ReadController {

View File

@ -17,7 +17,7 @@ import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'
import { Public } from 'src/core/guards';
@ApiTags(`${MODULE_NAME.{{constantCase name}}.split('-').join(' ')} - data`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}}}`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}} }`)
@Public(false)
@ApiBearerAuth('JWT')
export class {{pascalCase name}}DataController {

View File

@ -16,7 +16,7 @@ import {
import { Public } from 'src/core/guards';
@ApiTags(`${MODULE_NAME.{{constantCase name}}.split('-').join(' ')} - data`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}}}`)
@Controller(`v1/${MODULE_NAME.{{constantCase name}} }`)
@Public(false)
@ApiBearerAuth('JWT')
export class {{pascalCase name}}DataController {

View File

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

View File

@ -0,0 +1,45 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class Refund1720768975877 implements MigrationInterface {
name = 'Refund1720768975877';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."refunds_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`CREATE TYPE "public"."refunds_type_enum" AS ENUM('pengembalian booking', 'pengembalian wahana')`,
);
await queryRunner.query(
`CREATE TABLE "refunds" ("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, "status" "public"."refunds_status_enum" NOT NULL DEFAULT 'draft', "type" "public"."refunds_type_enum" NOT NULL DEFAULT 'pengembalian booking', "code" character varying, "request_date" date, "refund_date" date, "refund_total" numeric, "bank_name" character varying, "bank_account_name" character varying, "bank_account_number" character varying, "transaction_id" uuid, CONSTRAINT "REL_8bb3b7579f49990d2e77684acd" UNIQUE ("transaction_id"), CONSTRAINT "PK_5106efb01eeda7e49a78b869738" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`CREATE TABLE "refund_items" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "qty_refund" numeric, "refund_total" numeric, "refund_item_id" uuid, "transaction_item_id" uuid, CONSTRAINT "REL_07b481a163c219f5de8fb1c90b" UNIQUE ("transaction_item_id"), CONSTRAINT "PK_ef892918375a6101948b90f1140" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ADD CONSTRAINT "FK_8bb3b7579f49990d2e77684acd4" FOREIGN KEY ("transaction_id") REFERENCES "transactions"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "refund_items" ADD CONSTRAINT "FK_2a4bd60fb8a9c37f902f4f3da67" FOREIGN KEY ("refund_item_id") REFERENCES "refunds"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "refund_items" ADD CONSTRAINT "FK_07b481a163c219f5de8fb1c90b3" FOREIGN KEY ("transaction_item_id") REFERENCES "transaction_items"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "refund_items" DROP CONSTRAINT "FK_07b481a163c219f5de8fb1c90b3"`,
);
await queryRunner.query(
`ALTER TABLE "refund_items" DROP CONSTRAINT "FK_2a4bd60fb8a9c37f902f4f3da67"`,
);
await queryRunner.query(
`ALTER TABLE "refunds" DROP CONSTRAINT "FK_8bb3b7579f49990d2e77684acd4"`,
);
await queryRunner.query(`DROP TABLE "refund_items"`);
await queryRunner.query(`DROP TABLE "refunds"`);
await queryRunner.query(`DROP TYPE "public"."refunds_type_enum"`);
await queryRunner.query(`DROP TYPE "public"."refunds_status_enum"`);
}
}

View File

@ -0,0 +1,461 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateEnumStatus1720774145470 implements MigrationInterface {
name = 'UpdateEnumStatus1720774145470';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TYPE "public"."item_categories_status_enum" RENAME TO "item_categories_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."item_categories_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" TYPE "public"."item_categories_status_enum" USING "status"::"text"::"public"."item_categories_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."item_categories_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."season_types_status_enum" RENAME TO "season_types_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."season_types_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" TYPE "public"."season_types_status_enum" USING "status"::"text"::"public"."season_types_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."season_types_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."season_periods_status_enum" RENAME TO "season_periods_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."season_periods_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" TYPE "public"."season_periods_status_enum" USING "status"::"text"::"public"."season_periods_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."season_periods_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."items_status_enum" RENAME TO "items_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."items_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" TYPE "public"."items_status_enum" USING "status"::"text"::"public"."items_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."items_status_enum_old"`);
await queryRunner.query(
`ALTER TYPE "public"."users_status_enum" RENAME TO "users_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."users_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" TYPE "public"."users_status_enum" USING "status"::"text"::"public"."users_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."users_status_enum_old"`);
await queryRunner.query(
`ALTER TYPE "public"."user_privileges_status_enum" RENAME TO "user_privileges_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."user_privileges_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" TYPE "public"."user_privileges_status_enum" USING "status"::"text"::"public"."user_privileges_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."user_privileges_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."refunds_status_enum" RENAME TO "refunds_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."refunds_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" TYPE "public"."refunds_status_enum" USING "status"::"text"::"public"."refunds_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."refunds_status_enum_old"`);
await queryRunner.query(
`ALTER TYPE "public"."transactions_status_enum" RENAME TO "transactions_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" TYPE "public"."transactions_status_enum" USING "status"::"text"::"public"."transactions_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_reconciliation_status_enum" RENAME TO "transactions_reconciliation_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_reconciliation_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" TYPE "public"."transactions_reconciliation_status_enum" USING "reconciliation_status"::"text"::"public"."transactions_reconciliation_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_reconciliation_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_sending_invoice_status_enum" RENAME TO "transactions_sending_invoice_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_sending_invoice_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "sending_invoice_status" TYPE "public"."transactions_sending_invoice_status_enum" USING "sending_invoice_status"::"text"::"public"."transactions_sending_invoice_status_enum"`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_sending_invoice_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_sending_qr_status_enum" RENAME TO "transactions_sending_qr_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_sending_qr_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "sending_qr_status" TYPE "public"."transactions_sending_qr_status_enum" USING "sending_qr_status"::"text"::"public"."transactions_sending_qr_status_enum"`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_sending_qr_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."vip_categories_status_enum" RENAME TO "vip_categories_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."vip_categories_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" TYPE "public"."vip_categories_status_enum" USING "status"::"text"::"public"."vip_categories_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."vip_categories_status_enum_old"`,
);
await queryRunner.query(
`ALTER TYPE "public"."taxes_status_enum" RENAME TO "taxes_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."taxes_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" TYPE "public"."taxes_status_enum" USING "status"::"text"::"public"."taxes_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."taxes_status_enum_old"`);
await queryRunner.query(
`ALTER TYPE "public"."payment_methods_status_enum" RENAME TO "payment_methods_status_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."payment_methods_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" TYPE "public"."payment_methods_status_enum" USING "status"::"text"::"public"."payment_methods_status_enum"`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."payment_methods_status_enum_old"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."payment_methods_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" TYPE "public"."payment_methods_status_enum_old" USING "status"::"text"::"public"."payment_methods_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "payment_methods" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."payment_methods_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."payment_methods_status_enum_old" RENAME TO "payment_methods_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."taxes_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" TYPE "public"."taxes_status_enum_old" USING "status"::"text"::"public"."taxes_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "taxes" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."taxes_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."taxes_status_enum_old" RENAME TO "taxes_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."vip_categories_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" TYPE "public"."vip_categories_status_enum_old" USING "status"::"text"::"public"."vip_categories_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "vip_categories" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."vip_categories_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."vip_categories_status_enum_old" RENAME TO "vip_categories_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_sending_qr_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "sending_qr_status" TYPE "public"."transactions_sending_qr_status_enum_old" USING "sending_qr_status"::"text"::"public"."transactions_sending_qr_status_enum_old"`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_sending_qr_status_enum"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_sending_qr_status_enum_old" RENAME TO "transactions_sending_qr_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_sending_invoice_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "sending_invoice_status" TYPE "public"."transactions_sending_invoice_status_enum_old" USING "sending_invoice_status"::"text"::"public"."transactions_sending_invoice_status_enum_old"`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_sending_invoice_status_enum"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_sending_invoice_status_enum_old" RENAME TO "transactions_sending_invoice_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_reconciliation_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" TYPE "public"."transactions_reconciliation_status_enum_old" USING "reconciliation_status"::"text"::"public"."transactions_reconciliation_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "reconciliation_status" SET DEFAULT 'draft'`,
);
await queryRunner.query(
`DROP TYPE "public"."transactions_reconciliation_status_enum"`,
);
await queryRunner.query(
`ALTER TYPE "public"."transactions_reconciliation_status_enum_old" RENAME TO "transactions_reconciliation_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."transactions_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" TYPE "public"."transactions_status_enum_old" USING "status"::"text"::"public"."transactions_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "transactions" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."transactions_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."transactions_status_enum_old" RENAME TO "transactions_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."refunds_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" TYPE "public"."refunds_status_enum_old" USING "status"::"text"::"public"."refunds_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "refunds" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."refunds_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."refunds_status_enum_old" RENAME TO "refunds_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."user_privileges_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" TYPE "public"."user_privileges_status_enum_old" USING "status"::"text"::"public"."user_privileges_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "user_privileges" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."user_privileges_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."user_privileges_status_enum_old" RENAME TO "user_privileges_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."users_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" TYPE "public"."users_status_enum_old" USING "status"::"text"::"public"."users_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."users_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."users_status_enum_old" RENAME TO "users_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."items_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" TYPE "public"."items_status_enum_old" USING "status"::"text"::"public"."items_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "items" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."items_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."items_status_enum_old" RENAME TO "items_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."season_periods_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" TYPE "public"."season_periods_status_enum_old" USING "status"::"text"::"public"."season_periods_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "season_periods" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."season_periods_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."season_periods_status_enum_old" RENAME TO "season_periods_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."season_types_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" TYPE "public"."season_types_status_enum_old" USING "status"::"text"::"public"."season_types_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "season_types" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."season_types_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."season_types_status_enum_old" RENAME TO "season_types_status_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."item_categories_status_enum_old" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" TYPE "public"."item_categories_status_enum_old" USING "status"::"text"::"public"."item_categories_status_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "item_categories" ALTER COLUMN "status" SET DEFAULT 'draft'`,
);
await queryRunner.query(`DROP TYPE "public"."item_categories_status_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."item_categories_status_enum_old" RENAME TO "item_categories_status_enum"`,
);
}
}

View File

@ -29,8 +29,6 @@ export class SeedDefaultFormula implements Seeder {
.into(SalesPriceFormulaModel)
.values([sales_formula, profit_formula])
.execute();
} catch (error) {
console.log(error, 'er');
}
} catch (error) {}
}
}

View File

@ -5,6 +5,7 @@ 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';
@ApiTags('configuration - constant')
@Controller('v1/constant')
@ -44,4 +45,9 @@ export class ConstantController {
async transactionType(): Promise<any> {
return ['counter', 'admin', 'online'];
}
@Get('refund-type')
async refundType(): Promise<any> {
return Object.values(RefundType);
}
}

View File

@ -23,9 +23,7 @@ export class CouchDataController {
try {
const n = this.nanoInstance;
await n.db.create(entity.name);
} catch (error) {
console.log(error, 'dsa');
}
} catch (error) {}
}
@Post('doc')
@ -33,7 +31,6 @@ export class CouchDataController {
try {
const nano = this.nanoInstance;
const people = nano.db.use('string');
console.log(await people.info(), entity);
// const data = {
// id: '1212',
// name: 'dsadas',
@ -54,9 +51,7 @@ export class CouchDataController {
.on('error', (e) => {
console.error('error', e);
});
} catch (error) {
console.log(error, 'dsa');
}
} catch (error) {}
}
@Get()
@ -67,8 +62,6 @@ export class CouchDataController {
return people;
// return people.get();
} catch (error) {
console.log(error, 'dsa');
}
} catch (error) {}
}
}

View File

@ -34,7 +34,6 @@ export class SeasonPeriodDataController {
@Post('/update-price')
async updatePrice(@Body() body: UpdateSeasonPriceDto): Promise<BatchResult> {
console.log('here');
return await this.orchestrator.updatePrice(body);
}

View File

@ -0,0 +1,4 @@
export enum RefundType {
BOOKING = 'pengembalian booking',
WAHANA = 'pengembalian wahana',
}

View File

@ -0,0 +1,38 @@
import { BaseCoreModel } from 'src/core/modules/data/model/base-core.model';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from 'typeorm';
import { RefundItemEntity } from '../../domain/entities/refund-item.entity';
import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model';
import { RefundModel } from './refund.model';
@Entity(TABLE_NAME.REFUND_ITEM)
export class RefundItemModel
extends BaseCoreModel<RefundItemEntity>
implements RefundItemEntity
{
@Column('decimal', { name: 'qty_refund', nullable: true })
qty_refund: number;
@Column('decimal', { name: 'refund_total', nullable: true })
refund_total: number;
// transaction to refund
@Column('decimal', { name: 'refund_item_id', nullable: true })
refund_item_id: number;
@ManyToOne(() => RefundModel, (model) => model.refund_items, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
@JoinColumn({ name: 'refund_item_id' })
refund: RefundModel;
// transaction to transaction item
@Column('varchar', { name: 'transaction_item_id', nullable: true })
transaction_item_id: string;
@OneToOne(() => TransactionItemModel, (model) => model.refund, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
@JoinColumn({ name: 'transaction_item_id' })
transaction_item: TransactionItemModel;
}

View File

@ -0,0 +1,60 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { RefundEntity } from '../../domain/entities/refund.entity';
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';
@Entity(TABLE_NAME.REFUND)
export class RefundModel
extends BaseStatusModel<RefundEntity>
implements RefundEntity
{
@Column('enum', {
name: 'type',
enum: RefundType,
default: RefundType.BOOKING,
})
type: RefundType;
@Column('varchar', { name: 'code', nullable: true })
code: string;
@Column('date', { name: 'request_date', nullable: true })
request_date: Date;
@Column('date', { name: 'refund_date', nullable: true })
refund_date: Date;
@Column('decimal', { name: 'refund_total', nullable: true })
refund_total: number;
// bank info
@Column('varchar', { name: 'bank_name', nullable: true })
bank_name: string;
@Column('varchar', { name: 'bank_account_name', nullable: true })
bank_account_name: string;
@Column('varchar', { name: 'bank_account_number', nullable: true })
bank_account_number: string;
// relations to item
@OneToMany(() => RefundItemModel, (model) => model.refund, {
cascade: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
refund_items: RefundItemModel[];
// relation to transaction
@Column('varchar', { name: 'transaction_id', nullable: true })
transaction_id: string;
@OneToOne(() => TransactionModel, (model) => model.refund, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
@JoinColumn({ name: 'transaction_id' })
transaction: TransactionModel;
}

View File

@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
import { RefundEntity } from '../../domain/entities/refund.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { RefundModel } from '../models/refund.model';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { Repository } from 'typeorm';
@Injectable()
export class RefundDataService extends BaseDataService<RefundEntity> {
constructor(
@InjectRepository(RefundModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<RefundModel>,
) {
super(repo);
}
}

View File

@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import { RefundEntity } from '../../domain/entities/refund.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { RefundModel } from '../models/refund.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';
@Injectable()
export class RefundReadService extends BaseReadService<RefundEntity> {
constructor(
@InjectRepository(RefundModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<RefundModel>,
) {
super(repo);
}
}

View File

@ -0,0 +1,5 @@
import { IEvent } from 'src/core/strings/constants/interface.constants';
export class RefundChangeStatusEvent {
constructor(public readonly data: IEvent) {}
}

View File

@ -0,0 +1,5 @@
import { IEvent } from 'src/core/strings/constants/interface.constants';
export class RefundCreatedEvent {
constructor(public readonly data: IEvent) {}
}

View File

@ -0,0 +1,5 @@
import { IEvent } from 'src/core/strings/constants/interface.constants';
export class RefundDeletedEvent {
constructor(public readonly data: IEvent) {}
}

View File

@ -0,0 +1,5 @@
import { IEvent } from 'src/core/strings/constants/interface.constants';
export class RefundUpdatedEvent {
constructor(public readonly data: IEvent) {}
}

View File

@ -0,0 +1,18 @@
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
export interface FilterRefundEntity extends BaseFilterEntity {
codes: string[];
invoice_codes: string[];
bank_names: string[];
bank_account_names: string[];
bank_account_numbers: string[];
contact_names: string[];
creator_names: string[];
refund_date_from: Date;
refund_date_to: Date;
request_date_from: Date;
request_date_to: Date;
settlement_date_from: Date;
settlement_date_to: Date;
}

View File

@ -0,0 +1,7 @@
import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entity';
export interface RefundItemEntity extends BaseCoreEntity {
qty_refund: number;
transaction_item_id?: string;
}

View File

@ -0,0 +1,16 @@
import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity';
import { RefundType } from '../../constants';
export interface RefundEntity extends BaseStatusEntity {
type: RefundType;
code: string;
request_date: Date;
refund_date: Date;
refund_total: number;
bank_name: string;
bank_account_name: string;
bank_account_number: string;
transaction_id: string;
}

View File

@ -0,0 +1,57 @@
import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundChangeStatusEvent } from '../../entities/event/refund-change-status.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class BatchCancelRefundManager extends BaseBatchUpdateStatusManager<RefundEntity> {
validateData(data: RefundEntity): Promise<void> {
if (![STATUS.REFUNDED, STATUS.PENDING].includes(data.status)) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only data with status ${STATUS.REFUNDED} and ${STATUS.PENDING} can be cancelled`,
error: 'Unprocessable Entity',
});
}
return;
}
beforeProcess(): Promise<void> {
return;
}
afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundChangeStatusEvent,
},
];
}
getResult(): BatchResult {
return this.result;
}
}

View File

@ -0,0 +1,72 @@
import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundChangeStatusEvent } from '../../entities/event/refund-change-status.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
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)) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only data with status ${STATUS.DRAFT} and ${STATUS.PENDING} can be confirmed`,
error: 'Unprocessable Entity',
});
}
if (this.data.status == STATUS.DRAFT) {
Object.assign(this.data, {
code: `RF-${data?.['transaction']?.invoice_code.split('-')[1]}`,
request_date: new Date(),
status: STATUS.PENDING,
});
} else if (this.data.status == STATUS.PENDING) {
Object.assign(this.data, {
refund_date: new Date(),
status: STATUS.REFUNDED,
});
}
return;
}
beforeProcess(): Promise<void> {
this.relations = ['transaction'];
return;
}
afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundChangeStatusEvent,
relations: ['transaction'],
},
];
}
getResult(): BatchResult {
return this.result;
}
}

View File

@ -0,0 +1,45 @@
import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundDeletedEvent } from '../../entities/event/refund-deleted.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common';
@Injectable()
export class BatchDeleteRefundManager extends BaseBatchDeleteManager<RefundEntity> {
async beforeProcess(): Promise<void> {
return;
}
async validateData(data: RefundEntity): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundDeletedEvent,
},
];
}
getResult(): BatchResult {
return this.result;
}
}

View File

@ -0,0 +1,57 @@
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundChangeStatusEvent } from '../../entities/event/refund-change-status.event';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class CancelRefundManager extends BaseUpdateStatusManager<RefundEntity> {
getResult(): string {
return `Success active data ${this.result.code}`;
}
async validateProcess(): Promise<void> {
if (![STATUS.REFUNDED, STATUS.PENDING].includes(this.data.status)) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only data with status ${STATUS.REFUNDED} and ${STATUS.PENDING} can be cancelled`,
error: 'Unprocessable Entity',
});
}
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundChangeStatusEvent,
data: this.data,
},
];
}
}

View File

@ -0,0 +1,77 @@
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundChangeStatusEvent } from '../../entities/event/refund-change-status.event';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class ConfirmRefundManager extends BaseUpdateStatusManager<RefundEntity> {
getResult(): string {
return `Success active data ${this.result.code}`;
}
async validateProcess(): Promise<void> {
if (![STATUS.DRAFT, STATUS.PENDING].includes(this.oldData.status)) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only data with status ${STATUS.DRAFT} and ${STATUS.PENDING} can be confirmed`,
error: 'Unprocessable Entity',
});
}
return;
}
async beforeProcess(): Promise<void> {
const data = await this.dataService.getOneByOptions({
where: {
id: this.data.id,
},
relations: ['transaction'],
});
if (data.status == STATUS.DRAFT) {
Object.assign(this.data, {
code: `RF-${data.transaction?.invoice_code?.split('-')[1]}`,
request_date: new Date(),
status: STATUS.PENDING,
});
} else if (data.status == STATUS.PENDING) {
Object.assign(this.data, {
refund_date: new Date(),
status: STATUS.REFUNDED,
});
}
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundChangeStatusEvent,
relations: ['transaction'],
},
];
}
}

View File

@ -0,0 +1,54 @@
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import {
EventTopics,
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundEntity } from '../../entities/refund.entity';
import { RefundModel } from '../../../data/models/refund.model';
import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager';
import { RefundCreatedEvent } from '../../entities/event/refund-created.event';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class CreateRefundManager extends BaseCreateManager<RefundEntity> {
async beforeProcess(): Promise<void> {
// if (this.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',
// });
// }
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get uniqueColumns(): columnUniques[] {
return [];
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundCreatedEvent,
data: this.data,
},
];
}
get entityTarget(): any {
return RefundModel;
}
}

View File

@ -0,0 +1,45 @@
import { Injectable } from '@nestjs/common';
import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager';
import { RefundEntity } from '../../entities/refund.entity';
import {
EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundDeletedEvent } from '../../entities/event/refund-deleted.event';
@Injectable()
export class DeleteRefundManager extends BaseDeleteManager<RefundEntity> {
getResult(): string {
return `Success`;
}
async validateProcess(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundDeletedEvent,
data: this.data,
},
];
}
}

View File

@ -0,0 +1,65 @@
import { Injectable } from '@nestjs/common';
import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager';
import { RefundEntity } from '../../entities/refund.entity';
import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity';
import { mappingTransaction } from 'src/modules/transaction/transaction/domain/usecases/managers/helpers/mapping-transaction.helper';
@Injectable()
export class DetailRefundManager extends BaseDetailManager<RefundEntity> {
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
mappingTransaction(this.result['transaction']);
return;
}
get relations(): RelationParam {
return {
// relation only join (for query purpose)
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: ['transaction', 'transaction.items', 'items.refund'],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
};
}
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.code`,
`${this.tableName}.status`,
`${this.tableName}.type`,
`${this.tableName}.request_date`,
`${this.tableName}.refund_date`,
`${this.tableName}.created_at`,
`${this.tableName}.updated_at`,
`${this.tableName}.creator_name`,
`${this.tableName}.editor_name`,
`${this.tableName}.refund_total`,
`${this.tableName}.bank_name`,
`${this.tableName}.bank_account_name`,
`${this.tableName}.bank_account_number`,
'transaction',
'items',
'refund',
];
}
get setFindProperties(): any {
return {
id: this.dataId,
};
}
}

View File

@ -0,0 +1,145 @@
import { Injectable } from '@nestjs/common';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { RefundEntity } from '../../entities/refund.entity';
import { SelectQueryBuilder } from 'typeorm';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
import { BetweenQueryHelper } from 'src/core/helpers/query/between-query.helper';
@Injectable()
export class IndexRefundManager extends BaseIndexManager<RefundEntity> {
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
this.result?.data?.map((item) => {
delete item['transaction']?.id;
Object.assign(item, {
...item['transaction'],
});
delete item['transaction'];
});
return;
}
get relations(): RelationParam {
return {
// relation only join (for query purpose)
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: ['transaction'],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
};
}
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.code`,
`${this.tableName}.status`,
`${this.tableName}.type`,
`${this.tableName}.request_date`,
`${this.tableName}.refund_date`,
`${this.tableName}.created_at`,
`${this.tableName}.updated_at`,
`${this.tableName}.creator_name`,
`${this.tableName}.editor_name`,
`${this.tableName}.refund_total`,
`${this.tableName}.bank_name`,
`${this.tableName}.bank_account_name`,
`${this.tableName}.bank_account_number`,
`transaction.id`,
`transaction.invoice_code`,
`transaction.settlement_date`,
`transaction.payment_total`,
`transaction.customer_name`,
`transaction.customer_phone`,
`transaction.customer_email`,
`transaction.customer_description`,
];
}
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.code`,
data: this.filterParam.codes,
},
{
cols: `transaction.invoice_code`,
data: this.filterParam.invoice_codes,
},
{
cols: `${this.tableName}.bank_name`,
data: this.filterParam.bank_names,
},
{
cols: `${this.tableName}.bank_account_name`,
data: this.filterParam.bank_account_names,
},
{
cols: `${this.tableName}.bank_account_number`,
data: this.filterParam.bank_account_numbers,
},
{
cols: `transaction.customer_name`,
data: this.filterParam.contact_names,
},
{
cols: `${this.tableName}.creator_name`,
data: this.filterParam.creator_names,
},
];
}
setQueryFilter(
queryBuilder: SelectQueryBuilder<RefundEntity>,
): SelectQueryBuilder<RefundEntity> {
if (!!this.filterParam.refund_date_from)
new BetweenQueryHelper(
queryBuilder,
this.tableName,
'refund_date',
this.filterParam.refund_date_from,
this.filterParam.refund_date_to ?? this.filterParam.refund_date_from,
'refund_date',
).getQuery();
if (!!this.filterParam.request_date_from)
new BetweenQueryHelper(
queryBuilder,
this.tableName,
'request_date',
this.filterParam.request_date_from,
this.filterParam.request_date_to ?? this.filterParam.request_date_from,
'request_date',
).getQuery();
if (!!this.filterParam.settlement_date_from)
new BetweenQueryHelper(
queryBuilder,
'transaction',
'settlement_date',
this.filterParam.settlement_date_from,
this.filterParam.settlement_date_to ??
this.filterParam.settlement_date_from,
'settlement_date',
).getQuery();
return queryBuilder;
}
}

View File

@ -0,0 +1,58 @@
import {
HttpStatus,
Injectable,
UnprocessableEntityException,
} from '@nestjs/common';
import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager';
import { RefundEntity } from '../../entities/refund.entity';
import { RefundModel } from '../../../data/models/refund.model';
import { RefundUpdatedEvent } from '../../entities/event/refund-updated.event';
import {
EventTopics,
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
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) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! only transaction with status ${STATUS.SETTLED} can be refund`,
error: 'Unprocessable Entity',
});
}
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get validateRelations(): validateRelations[] {
return [];
}
get uniqueColumns(): columnUniques[] {
return [];
}
get entityTarget(): any {
return RefundModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: RefundUpdatedEvent,
data: this.data,
},
];
}
}

View File

@ -0,0 +1,85 @@
import { Injectable } from '@nestjs/common';
import { CreateRefundManager } from './managers/create-refund.manager';
import { RefundDataService } from '../../data/services/refund-data.service';
import { RefundEntity } from '../entities/refund.entity';
import { DeleteRefundManager } from './managers/delete-refund.manager';
import { UpdateRefundManager } from './managers/update-refund.manager';
import { ConfirmRefundManager } from './managers/confirm-refund.manager';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BatchConfirmRefundManager } from './managers/batch-confirm-refund.manager';
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';
@Injectable()
export class RefundDataOrchestrator {
constructor(
private createManager: CreateRefundManager,
private updateManager: UpdateRefundManager,
private deleteManager: DeleteRefundManager,
private cancelManager: CancelRefundManager,
private confirmManager: ConfirmRefundManager,
private batchDeleteManager: BatchDeleteRefundManager,
private batchCancelManager: BatchCancelRefundManager,
private batchConfirmManager: BatchConfirmRefundManager,
private serviceData: RefundDataService,
) {}
async create(data): Promise<RefundEntity> {
this.createManager.setData(data);
this.createManager.setService(this.serviceData, TABLE_NAME.REFUND);
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);
await this.updateManager.execute();
return this.updateManager.getResult();
}
async delete(dataId): Promise<string> {
this.deleteManager.setData(dataId);
this.deleteManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.deleteManager.execute();
return this.deleteManager.getResult();
}
async batchDelete(dataIds: string[]): Promise<BatchResult> {
this.batchDeleteManager.setData(dataIds);
this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.batchDeleteManager.execute();
return this.batchDeleteManager.getResult();
}
async cancel(dataId): Promise<string> {
this.cancelManager.setData(dataId, STATUS.CANCEL);
this.cancelManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.cancelManager.execute();
return this.cancelManager.getResult();
}
async batchCancel(dataIds: string[]): Promise<BatchResult> {
this.batchCancelManager.setData(dataIds, STATUS.CANCEL);
this.batchCancelManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.batchCancelManager.execute();
return this.batchCancelManager.getResult();
}
async confirm(dataId): Promise<string> {
this.confirmManager.setData(dataId, STATUS.PENDING);
this.confirmManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.confirmManager.execute();
return this.confirmManager.getResult();
}
async batchConfirm(dataIds: string[]): Promise<BatchResult> {
this.batchConfirmManager.setData(dataIds, STATUS.PENDING);
this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.batchConfirmManager.execute();
return this.batchConfirmManager.getResult();
}
}

View File

@ -0,0 +1,33 @@
import { Injectable } from '@nestjs/common';
import { IndexRefundManager } from './managers/index-refund.manager';
import { RefundReadService } from '../../data/services/refund-read.service';
import { RefundEntity } from '../entities/refund.entity';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator';
import { DetailRefundManager } from './managers/detail-refund.manager';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
@Injectable()
export class RefundReadOrchestrator extends BaseReadOrchestrator<RefundEntity> {
constructor(
private indexManager: IndexRefundManager,
private detailManager: DetailRefundManager,
private serviceData: RefundReadService,
) {
super();
}
async index(params): Promise<PaginationResponse<RefundEntity>> {
this.indexManager.setFilterParam(params);
this.indexManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.indexManager.execute();
return this.indexManager.getResult();
}
async detail(dataId: string): Promise<RefundEntity> {
this.detailManager.setData(dataId);
this.detailManager.setService(this.serviceData, TABLE_NAME.REFUND);
await this.detailManager.execute();
return this.detailManager.getResult();
}
}

View File

View File

@ -0,0 +1,67 @@
import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto';
import { FilterRefundEntity } from '../../domain/entities/filter-refund.entity';
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
export class FilterRefundDto
extends BaseFilterDto
implements FilterRefundEntity
{
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
codes: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
invoice_codes: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
bank_names: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
bank_account_names: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
bank_account_numbers: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
contact_names: string[];
@ApiProperty({ type: ['string'], required: false })
@Transform((body) => {
return Array.isArray(body.value) ? body.value : [body.value];
})
creator_names: string[];
@ApiProperty({ type: Date, required: false })
refund_date_from: Date;
@ApiProperty({ type: Date, required: false })
refund_date_to: Date;
@ApiProperty({ type: Date, required: false })
request_date_from: Date;
@ApiProperty({ type: Date, required: false })
request_date_to: Date;
@ApiProperty({ type: Date, required: false })
settlement_date_from: Date;
@ApiProperty({ type: Date, required: false })
settlement_date_to: Date;
}

View File

@ -0,0 +1,67 @@
import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto';
import { RefundEntity } from '../../domain/entities/refund.entity';
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';
export class RefundDto extends BaseStatusDto implements RefundEntity {
@ApiProperty({
type: String,
required: true,
example: RefundType.BOOKING,
})
@IsString()
type: RefundType;
@ApiProperty({
type: Number,
example: 1750000,
})
@IsNumber()
refund_total: number;
@ApiProperty({
type: String,
required: false,
example: 'BCA',
})
bank_name: string;
@ApiProperty({
type: String,
required: false,
example: 'andhika',
})
bank_account_name: string;
@ApiProperty({
type: String,
required: false,
example: '64222456',
})
bank_account_number: string;
@ApiProperty({
type: Object,
required: true,
example: {
id: 'uuid',
invoice_code: 'INV-',
},
})
transaction: TransactionEntity;
@Exclude()
code: string;
@Exclude()
request_date: Date;
@Exclude()
refund_date: Date;
@Exclude()
transaction_id: string;
}

View File

@ -0,0 +1,68 @@
import {
Body,
Controller,
Delete,
Param,
Patch,
Post,
Put,
} from '@nestjs/common';
import { RefundDataOrchestrator } from '../domain/usecases/refund-data.orchestrator';
import { RefundDto } from './dto/refund.dto';
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { RefundEntity } from '../domain/entities/refund.entity';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto';
import { Public } from 'src/core/guards';
@ApiTags(`${MODULE_NAME.REFUND.split('-').join(' ')} - data`)
@Controller(`v1/${MODULE_NAME.REFUND}`)
@Public(false)
@ApiBearerAuth('JWT')
export class RefundDataController {
constructor(private orchestrator: RefundDataOrchestrator) {}
@Post()
async create(@Body() data: RefundDto): Promise<RefundEntity> {
return await this.orchestrator.create(data);
}
@Put('/batch-delete')
async batchDeleted(@Body() body: BatchIdsDto): Promise<BatchResult> {
return await this.orchestrator.batchDelete(body.ids);
}
@Patch(':id/cancel')
async cancel(@Param('id') dataId: string): Promise<string> {
return await this.orchestrator.cancel(dataId);
}
@Put('/batch-cancel')
async batchcancel(@Body() body: BatchIdsDto): Promise<BatchResult> {
return await this.orchestrator.batchCancel(body.ids);
}
@Patch(':id/confirm')
async confirm(@Param('id') dataId: string): Promise<string> {
return await this.orchestrator.confirm(dataId);
}
@Put('/batch-confirm')
async batchConfirm(@Body() body: BatchIdsDto): Promise<BatchResult> {
return await this.orchestrator.batchConfirm(body.ids);
}
@Put(':id')
async update(
@Param('id') dataId: string,
@Body() data: RefundDto,
): Promise<RefundEntity> {
return await this.orchestrator.update(dataId, data);
}
@Delete(':id')
async delete(@Param('id') dataId: string): Promise<string> {
return await this.orchestrator.delete(dataId);
}
}

View File

@ -0,0 +1,30 @@
import { Controller, Get, Param, Query } from '@nestjs/common';
import { FilterRefundDto } from './dto/filter-refund.dto';
import { Pagination } from 'src/core/response';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { RefundEntity } from '../domain/entities/refund.entity';
import { RefundReadOrchestrator } from '../domain/usecases/refund-read.orchestrator';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
import { Public } from 'src/core/guards';
@ApiTags(`${MODULE_NAME.REFUND.split('-').join(' ')} - read`)
@Controller(`v1/${MODULE_NAME.REFUND}`)
@Public(false)
@ApiBearerAuth('JWT')
export class RefundReadController {
constructor(private orchestrator: RefundReadOrchestrator) {}
@Get()
@Pagination()
async index(
@Query() params: FilterRefundDto,
): Promise<PaginationResponse<RefundEntity>> {
return await this.orchestrator.index(params);
}
@Get(':id')
async detail(@Param('id') id: string): Promise<RefundEntity> {
return await this.orchestrator.detail(id);
}
}

View File

@ -0,0 +1,54 @@
import { 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 { RefundDataService } from './data/services/refund-data.service';
import { RefundReadService } from './data/services/refund-read.service';
import { RefundReadController } from './infrastructure/refund-read.controller';
import { RefundReadOrchestrator } from './domain/usecases/refund-read.orchestrator';
import { RefundDataController } from './infrastructure/refund-data.controller';
import { RefundDataOrchestrator } from './domain/usecases/refund-data.orchestrator';
import { CreateRefundManager } from './domain/usecases/managers/create-refund.manager';
import { CqrsModule } from '@nestjs/cqrs';
import { IndexRefundManager } from './domain/usecases/managers/index-refund.manager';
import { DeleteRefundManager } from './domain/usecases/managers/delete-refund.manager';
import { UpdateRefundManager } from './domain/usecases/managers/update-refund.manager';
import { ConfirmRefundManager } from './domain/usecases/managers/confirm-refund.manager';
import { DetailRefundManager } from './domain/usecases/managers/detail-refund.manager';
import { BatchDeleteRefundManager } from './domain/usecases/managers/batch-delete-refund.manager';
import { BatchConfirmRefundManager } from './domain/usecases/managers/batch-confirm-refund.manager';
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';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature(
[RefundModel, RefundItemModel],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,
],
controllers: [RefundDataController, RefundReadController],
providers: [
IndexRefundManager,
DetailRefundManager,
CreateRefundManager,
DeleteRefundManager,
UpdateRefundManager,
ConfirmRefundManager,
CancelRefundManager,
BatchDeleteRefundManager,
BatchConfirmRefundManager,
BatchCancelRefundManager,
RefundDataService,
RefundReadService,
RefundDataOrchestrator,
RefundReadOrchestrator,
],
})
export class RefundModule {}

View File

@ -1,8 +1,9 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from 'typeorm';
import { BaseCoreModel } from 'src/core/modules/data/model/base-core.model';
import { TransactionItemEntity } from '../../domain/entities/transaction-item.entity';
import { TransactionModel } from './transaction.model';
import { RefundItemModel } from 'src/modules/transaction/refund/data/models/refund-item.model';
@Entity(TABLE_NAME.TRANSACTION_ITEM)
export class TransactionItemModel
@ -60,6 +61,12 @@ export class TransactionItemModel
@Column('int', { name: 'qty', nullable: true })
qty: number;
@Column('int', { name: 'qty_remaining', nullable: true })
qty_remaining: number;
@Column('json', { name: 'taxes', nullable: true })
taxes: string;
@Column('varchar', { name: 'transaction_id', nullable: true })
transaction_id: string;
@ManyToOne(() => TransactionModel, (model) => model.items, {
@ -68,4 +75,12 @@ export class TransactionItemModel
})
@JoinColumn({ name: 'transaction_id' })
transaction: TransactionModel;
// relations to refund
@OneToOne(() => RefundItemModel, (model) => model.transaction_item, {
cascade: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
refund: RefundItemModel;
}

View File

@ -1,6 +1,6 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { TransactionEntity } from '../../domain/entities/transaction.entity';
import { Column, Entity, OneToMany } from 'typeorm';
import { Column, Entity, OneToMany, OneToOne } from 'typeorm';
import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model';
import {
TransactionType,
@ -11,6 +11,7 @@ import { TransactionItemEntity } from '../../domain/entities/transaction-item.en
import { TransactionItemModel } from './transaction-item.model';
import { TransactionTaxModel } from './transaction-tax.model';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { RefundModel } from 'src/modules/transaction/refund/data/models/refund.model';
@Entity(TABLE_NAME.TRANSACTION)
export class TransactionModel
@ -214,4 +215,12 @@ export class TransactionModel
onUpdate: 'CASCADE',
})
taxes: TransactionTaxModel[];
// relations to refund
@OneToOne(() => RefundModel, (model) => model.transaction, {
cascade: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
refund: RefundModel;
}

View File

@ -22,4 +22,6 @@ export interface TransactionItemEntity extends BaseCoreEntity {
total_profit: number;
total_share_tenant: number;
qty: number;
qty_remaining: number;
taxes: string;
}

View File

@ -0,0 +1,52 @@
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { RefundChangeStatusEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-change-status.event';
import { TransactionDataService } from '../../../data/services/transaction-data.service';
import { OPERATION, STATUS } from 'src/core/strings/constants/base.constants';
import { TransactionModel } from '../../../data/models/transaction.model';
import { RefundDeletedEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-deleted.event';
@EventsHandler(RefundChangeStatusEvent, RefundDeletedEvent)
export class RefundUpdatedHandler
implements IEventHandler<RefundChangeStatusEvent>
{
constructor(private dataService: TransactionDataService) {}
async handle(event: RefundChangeStatusEvent) {
const old_data = event.data.old;
const current_data = event.data.data;
let status: STATUS;
if (
old_data.status != current_data.data ||
event.data.op == OPERATION.DELETE
) {
const queryRunner = this.dataService
.getRepository()
.manager.connection.createQueryRunner();
const data = new TransactionModel();
const if_full_refund =
Number(current_data.refund_total ?? 0) ==
Number(current_data.transaction?.payment_total);
if (event.data.op == OPERATION.DELETE) status = STATUS.SETTLED;
else if (current_data.status == STATUS.PENDING)
status = STATUS.PROCESS_REFUND;
else if (current_data.status == STATUS.REFUNDED && if_full_refund)
status = STATUS.REFUNDED;
else if (current_data.status == STATUS.REFUNDED && !if_full_refund)
status = STATUS.PARTIAL_REFUND;
else if (current_data.status == STATUS.CANCEL) status = STATUS.SETTLED;
await this.dataService.update(
queryRunner,
TransactionModel,
{ id: current_data.transaction_id },
{
...data,
status: status,
},
);
}
}
}

View File

@ -25,7 +25,7 @@ export class DetailTransactionManager extends BaseDetailManager<TransactionEntit
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: ['items'],
selectRelations: ['items', 'items.refund item_refund', 'refund'],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
@ -72,6 +72,8 @@ export class DetailTransactionManager extends BaseDetailManager<TransactionEntit
`${this.tableName}.payment_total`,
'items',
'item_refund',
'refund',
];
}

View File

@ -17,6 +17,7 @@ export function mappingTransaction(data) {
id: data.payment_type_method_id,
issuer_name: data.payment_type_method_name,
account_number: data.payment_type_method_number,
qr_image: data.payment_type_method_qr,
};
}
@ -44,7 +45,10 @@ export function mappingTransaction(data) {
name: itemData.item_category_name,
},
},
refund: itemData.refund,
qty: itemData.qty,
qty_remaining: itemData.qty_remaining,
total_price_refund: itemData.refund?.refund_total ?? 0,
total_price: itemData.total_price,
};
});
@ -63,6 +67,7 @@ export function mappingTransaction(data) {
delete data.payment_type_method_id;
delete data.payment_type_method_name;
delete data.payment_type_method_number;
delete data.payment_type_method_qr;
}
export function mappingRevertTransaction(data, type) {
@ -124,6 +129,7 @@ export function mappingRevertTransaction(data, type) {
item_type: item.item.item_type,
item_price: item.item.base_price,
item_hpp: item.item.hpp,
qty_remaining: item.qty,
item_category_id: item.item.item_category?.id,
item_category_name: item.item.item_category?.name,

View File

@ -18,6 +18,14 @@ export class IndexTransactionManager extends BaseIndexManager<TransactionEntity>
}
async afterProcess(): Promise<void> {
this.result?.data?.map((item) => {
Object.assign(item, {
refund_code: item['refund']?.code ?? null,
refund_date: item['refund']?.refund_date ?? null,
});
delete item['refund'];
});
return;
}
@ -27,7 +35,7 @@ export class IndexTransactionManager extends BaseIndexManager<TransactionEntity>
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: ['items'],
selectRelations: ['items', 'refund'],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
@ -63,6 +71,10 @@ export class IndexTransactionManager extends BaseIndexManager<TransactionEntity>
`${this.tableName}.payment_type_method_id`,
`${this.tableName}.payment_type_method_name`,
`${this.tableName}.payment_type_method_number`,
`refund.id`,
`refund.code`,
`refund.refund_date`,
];
}

View File

@ -30,6 +30,7 @@ import { SalesPriceFormulaDataService } from '../sales-price-formula/data/servic
import { SalesPriceFormulaModel } 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';
@Module({
imports: [
@ -48,6 +49,7 @@ import { SettledTransactionHandler } from './domain/usecases/handlers/settled-tr
],
controllers: [TransactionDataController, TransactionReadController],
providers: [
RefundUpdatedHandler,
PosTransactionHandler,
SettledTransactionHandler,