diff --git a/env/env.development b/env/env.development index 6fefe96..db3a60d 100644 --- a/env/env.development +++ b/env/env.development @@ -24,8 +24,11 @@ CRON_EVERY_HOUR="0 * * * *" EMAIL_HOST=smtp.gmail.com EMAIL_POST=465 -EMAIL_USER=developer@eigen.co.id -EMAIL_TOKEN=bitqkbkzjzfywxqx +EMAIL_USER=weplayground.app@gmail.com +EMAIL_TOKEN=sonvvwiukhsevtmv + +// nama email yang akan muncul ke user sebagai pengirim +EMAIL_SENDER=no-reply@eigen.co.id MIDTRANS_URL=https://app.sandbox.midtrans.com MIDTRANS_PRODUCTION=false diff --git a/src/core/modules/domain/entities/base-filter.entity.ts b/src/core/modules/domain/entities/base-filter.entity.ts index 357412d..c447c41 100644 --- a/src/core/modules/domain/entities/base-filter.entity.ts +++ b/src/core/modules/domain/entities/base-filter.entity.ts @@ -22,6 +22,7 @@ export interface Param { data: string[]; additional?: any[]; leftJoin?: any[]; + isStatus?: boolean; } export interface RelationParam { diff --git a/src/core/modules/domain/usecase/managers/base-index.manager.ts b/src/core/modules/domain/usecase/managers/base-index.manager.ts index 63a7c56..fb5ece5 100644 --- a/src/core/modules/domain/usecase/managers/base-index.manager.ts +++ b/src/core/modules/domain/usecase/managers/base-index.manager.ts @@ -52,10 +52,14 @@ export abstract class BaseIndexManager extends BaseReadManager { // ? karena jika tidak, ketika dia search "active" maka "inactive" juga ikut return `'${STATUS[statusData.toUpperCase()]}'` ?? `'%${statusData}%'`; }); - specificFilter.push({ - cols: `${this.tableName}.status::text`, - data: data, - }); + + const exist = specificFilter.find((item) => item.isStatus); + if (!exist) { + specificFilter.push({ + cols: `${this.tableName}.status::text`, + data: data, + }); + } } new SpecificSearchFilter( diff --git a/src/core/strings/constants/privilege.constants.ts b/src/core/strings/constants/privilege.constants.ts index 1f7b5e6..f03b32f 100644 --- a/src/core/strings/constants/privilege.constants.ts +++ b/src/core/strings/constants/privilege.constants.ts @@ -145,7 +145,6 @@ export const PrivilegePOSConstant = [ actions: [ PrivilegeAction.VIEW, PrivilegeAction.CREATE, - PrivilegeAction.DELETE, PrivilegeAction.EDIT, PrivilegeAction.CANCEL, ], diff --git a/src/database/migrations/1722581313837-update-relation-table-transaction.ts b/src/database/migrations/1722581313837-update-relation-table-transaction.ts new file mode 100644 index 0000000..8fa4911 --- /dev/null +++ b/src/database/migrations/1722581313837-update-relation-table-transaction.ts @@ -0,0 +1,49 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateRelationTableTransaction1722581313837 + implements MigrationInterface +{ + name = 'UpdateRelationTableTransaction1722581313837'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "refunds" DROP CONSTRAINT "FK_8bb3b7579f49990d2e77684acd4"`, + ); + await queryRunner.query( + `ALTER TABLE "refunds" DROP CONSTRAINT "REL_8bb3b7579f49990d2e77684acd"`, + ); + await queryRunner.query( + `ALTER TABLE "refund_items" DROP CONSTRAINT "FK_07b481a163c219f5de8fb1c90b3"`, + ); + await queryRunner.query( + `ALTER TABLE "refund_items" DROP CONSTRAINT "REL_07b481a163c219f5de8fb1c90b"`, + ); + 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_07b481a163c219f5de8fb1c90b3" FOREIGN KEY ("transaction_item_id") REFERENCES "transaction_items"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "refund_items" DROP CONSTRAINT "FK_07b481a163c219f5de8fb1c90b3"`, + ); + await queryRunner.query( + `ALTER TABLE "refunds" DROP CONSTRAINT "FK_8bb3b7579f49990d2e77684acd4"`, + ); + await queryRunner.query( + `ALTER TABLE "refund_items" ADD CONSTRAINT "REL_07b481a163c219f5de8fb1c90b" UNIQUE ("transaction_item_id")`, + ); + 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`, + ); + await queryRunner.query( + `ALTER TABLE "refunds" ADD CONSTRAINT "REL_8bb3b7579f49990d2e77684acd" UNIQUE ("transaction_id")`, + ); + await queryRunner.query( + `ALTER TABLE "refunds" ADD CONSTRAINT "FK_8bb3b7579f49990d2e77684acd4" FOREIGN KEY ("transaction_id") REFERENCES "transactions"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } +} diff --git a/src/database/migrations/1722587128195-update-type-column-item-table.ts b/src/database/migrations/1722587128195-update-type-column-item-table.ts new file mode 100644 index 0000000..d19e50d --- /dev/null +++ b/src/database/migrations/1722587128195-update-type-column-item-table.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateTypeColumnItemTable1722587128195 + implements MigrationInterface +{ + name = 'UpdateTypeColumnItemTable1722587128195'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "sales_margin"`); + await queryRunner.query(`ALTER TABLE "items" ADD "sales_margin" numeric`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "sales_margin"`); + await queryRunner.query(`ALTER TABLE "items" ADD "sales_margin" integer`); + } +} diff --git a/src/database/migrations/1722595038215-update-table-transaction.ts b/src/database/migrations/1722595038215-update-table-transaction.ts new file mode 100644 index 0000000..f4a69bc --- /dev/null +++ b/src/database/migrations/1722595038215-update-table-transaction.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateTableTransaction1722595038215 implements MigrationInterface { + name = 'UpdateTableTransaction1722595038215'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."transactions_payment_type_counter_enum" AS ENUM('midtrans', 'bank transfer', 'qris', 'counter', 'cash', 'credit card', 'debit', 'e-money')`, + ); + await queryRunner.query( + `ALTER TABLE "transactions" ADD "payment_type_counter" "public"."transactions_payment_type_counter_enum"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "transactions" DROP COLUMN "payment_type_counter"`, + ); + await queryRunner.query( + `DROP TYPE "public"."transactions_payment_type_counter_enum"`, + ); + } +} diff --git a/src/modules/configuration/couch/domain/managers/booking.handler.ts b/src/modules/configuration/couch/domain/managers/booking.handler.ts index 6380435..2809b23 100644 --- a/src/modules/configuration/couch/domain/managers/booking.handler.ts +++ b/src/modules/configuration/couch/domain/managers/booking.handler.ts @@ -38,36 +38,41 @@ export class BookingHandler const old_data = event.data.old; const data = event.data.data; - if (data.payment_type != TransactionPaymentType.COUNTER) return; - - const booking = await this.bookingService.getOneByOptions({ - where: { - id: data.id, - }, - relations: ['items'], - }); - - mappingTransaction(booking); - if ( - old_data?.status != data.status && - [STATUS.PENDING, STATUS.ACTIVE].includes(data.status) + data.payment_type == TransactionPaymentType.COUNTER || + ([STATUS.ACTIVE, STATUS.SETTLED].includes(data.status) && + data.payment_type != TransactionPaymentType.COUNTER) ) { - await this.couchService.createDoc( - { - _id: booking.id, - ...booking, + const booking = await this.bookingService.getOneByOptions({ + where: { + id: data.id, }, - 'booking', - ); - } else { - await this.couchService.updateDoc( - { - _id: booking.id, - ...booking, - }, - 'booking', - ); + relations: ['items'], + }); + + mappingTransaction(booking); + + if ( + (old_data?.status != data.status || + data.payment_type != TransactionPaymentType.COUNTER) && + [STATUS.PENDING, STATUS.ACTIVE, STATUS.SETTLED].includes(data.status) + ) { + await this.couchService.createDoc( + { + _id: booking.id, + ...booking, + }, + 'booking', + ); + } else { + await this.couchService.updateDoc( + { + _id: booking.id, + ...booking, + }, + 'booking', + ); + } } } } diff --git a/src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper.ts b/src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper.ts index 14e35d4..8f674fd 100644 --- a/src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper.ts +++ b/src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper.ts @@ -61,8 +61,12 @@ export async function CreateEventCalendarHelper( function mappingData(transaction) { return { - summary: transaction.invoice_code, - description: `Booking for invoice ${transaction.invoice_code}`, + summary: transaction.customer_name ?? transaction.invoice_code, + description: `Booking for invoice ${ + transaction.invoice_code + }

List Items :

    ${transaction.items.map( + (item) => `
  • ${item.item_name}
  • `, + )}
`, start: { dateTime: new Date(transaction.booking_date).toISOString(), timeZone: 'Asia/Jakarta', diff --git a/src/modules/configuration/mail/domain/email-template/change-date-information.html b/src/modules/configuration/mail/domain/email-template/change-date-information.html new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/mail/domain/email-template/invoice-expired.html b/src/modules/configuration/mail/domain/email-template/invoice-expired.html new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/mail/domain/email-template/invoice.html b/src/modules/configuration/mail/domain/email-template/invoice.html new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/mail/domain/email-template/refund-confirmation.html b/src/modules/configuration/mail/domain/email-template/refund-confirmation.html new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/mail/domain/email-template/refund-request.html b/src/modules/configuration/mail/domain/email-template/refund-request.html new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/mail/domain/helpers/send-email.helper.ts b/src/modules/configuration/mail/domain/helpers/send-email.helper.ts index c242887..bae519c 100644 --- a/src/modules/configuration/mail/domain/helpers/send-email.helper.ts +++ b/src/modules/configuration/mail/domain/helpers/send-email.helper.ts @@ -20,9 +20,9 @@ export async function sendEmail(receivers, subject) { if (receiver.payment_type == TransactionPaymentType.MIDTRANS) templateName = 'payment-confirmation-midtrans'; - let templatePath = path.resolve( + let templatePath = path.join( __dirname, - `../email-template/${ templateName }.html`, + `../email-template/${templateName}.html`, ); templatePath = templatePath.replace(/dist/g, 'src'); const templateSource = fs.readFileSync(templatePath, 'utf8'); @@ -31,7 +31,7 @@ export async function sendEmail(receivers, subject) { const htmlToSend = template(receiver); const emailContext = { - from: 'no-reply@eigen.co.id', + from: process.env.EMAIL_SENDER ?? 'no-reply@weplayground.app', to: receiver.email, subject: subject, html: htmlToSend, @@ -42,13 +42,13 @@ export async function sendEmail(receivers, subject) { smtpTransport.sendMail(emailContext, function (err, data) { if (err) { - console.log(err, `Error occurs on send to ${ receiver.email }`); + console.log(err, `Error occurs on send to ${receiver.email}`); } else { - console.log(`Email sent to ${ receiver.email }`); + console.log(`Email sent to ${receiver.email}`); } }); } catch (error) { - console.log(error, `Error occurs on send to ${ receiver.email }`) + console.log(error, `Error occurs on send to ${receiver.email}`); } } } diff --git a/src/modules/configuration/mail/infrastructure/mail.controller.ts b/src/modules/configuration/mail/infrastructure/mail.controller.ts new file mode 100644 index 0000000..75e6d82 --- /dev/null +++ b/src/modules/configuration/mail/infrastructure/mail.controller.ts @@ -0,0 +1,57 @@ +import { Controller, Get, Injectable } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Public } from 'src/core/guards'; +import * as path from 'path'; +import * as fs from 'fs'; + +@ApiTags(`email templates`) +@Controller('v1/email-templates') +@Public() +@Injectable() +export class MailTemplateController { + constructor() {} + + getTemplate(templateName) { + const templatePath = path.join( + __dirname, + '../../../../../', + `src/modules/configuration/mail/domain/email-template/${templateName}.html`, + ); + return fs.readFileSync(templatePath, 'utf8'); + } + + @Get('date-change') + async getDateChange() { + return this.getTemplate('change-date'); + } + + @Get('invoice') + async getBookingInvoice() { + return this.getTemplate('invoice'); + } + + @Get('payment-confirmation-bank') + async getPaymentConfirmation() { + return this.getTemplate('payment-confirmation-bank'); + } + + @Get('payment-confirmation-midtrans') + async getPaymentConfirmationMidtrans() { + return this.getTemplate('payment-confirmation-midtrans'); + } + + @Get('invoice-expired') + async getInvoiceExpired() { + return this.getTemplate('invoice-expired'); + } + + @Get('refund-confirmation') + async getRefundConfirmation() { + return this.getTemplate('refund-confirmation'); + } + + @Get('refund-request') + async getRefundRequest() { + return this.getTemplate('refunr-request'); + } +} diff --git a/src/modules/configuration/mail/mail.module.ts b/src/modules/configuration/mail/mail.module.ts index 597fc9c..c45d49c 100644 --- a/src/modules/configuration/mail/mail.module.ts +++ b/src/modules/configuration/mail/mail.module.ts @@ -8,6 +8,7 @@ import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model'; import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service'; import { PaymentTransactionHandler } from './domain/handlers/payment-transaction.handler'; +import { MailTemplateController } from './infrastructure/mail.controller'; @Module({ imports: [ @@ -18,7 +19,7 @@ import { PaymentTransactionHandler } from './domain/handlers/payment-transaction ), CqrsModule, ], - controllers: [], + controllers: [MailTemplateController], providers: [ PaymentTransactionHandler, PaymentMethodDataService, diff --git a/src/modules/configuration/midtrans/infrastructure/midtrans.controller.ts b/src/modules/configuration/midtrans/infrastructure/midtrans.controller.ts index a00867a..cd19a56 100644 --- a/src/modules/configuration/midtrans/infrastructure/midtrans.controller.ts +++ b/src/modules/configuration/midtrans/infrastructure/midtrans.controller.ts @@ -18,7 +18,20 @@ export class MidtransController { @Get(':id/status') async getStatus(@Param('id') id: string) { - return await this.dataService.getStatus(id); + try { + const data = await this.dataService.getStatus(id); + this.eventBus.publishAll([ + new MidtransCallbackEvent({ + id: id, + data: data, + }), + ]); + + return 'Berhasil update status transaksi'; + } catch (error) { + console.log(error.message); + throw new Error('Gagal update status transaksi'); + } } @Post('callback') diff --git a/src/modules/item-related/item-rate/domain/usecases/handlers/item-created.handler.ts b/src/modules/item-related/item-rate/domain/usecases/handlers/item-created.handler.ts index 12b7fb6..f0b1351 100644 --- a/src/modules/item-related/item-rate/domain/usecases/handlers/item-created.handler.ts +++ b/src/modules/item-related/item-rate/domain/usecases/handlers/item-created.handler.ts @@ -32,7 +32,10 @@ export class SeasonPeriodHolidayHandler const rate = new ItemRateModel(); rate.item_id = event.data.id; rate.season_period_id = season.id; - rate.price = event.data.data.total_price ?? event.data.data.base_price; + rate.price = + Number(event.data.data.total_price) != 0 + ? event.data.data.total_price + : event.data.data.base_price; rates.push(rate); } diff --git a/src/modules/item-related/item/data/models/item.model.ts b/src/modules/item-related/item/data/models/item.model.ts index 61b645e..1ad37d5 100644 --- a/src/modules/item-related/item/data/models/item.model.ts +++ b/src/modules/item-related/item/data/models/item.model.ts @@ -38,7 +38,7 @@ export class ItemModel @Column('bigint', { name: 'hpp', nullable: true }) hpp: number; - @Column('int', { name: 'sales_margin', nullable: true }) + @Column('decimal', { name: 'sales_margin', nullable: true }) sales_margin: number; @Column('bigint', { name: 'total_price', nullable: true }) diff --git a/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts index d7a1c9a..59da47d 100644 --- a/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts +++ b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts @@ -36,7 +36,12 @@ export class ActiveItemManager extends BaseUpdateStatusManager { { relation: 'tenant', singleQuery: ['status', '!=', STATUS.ACTIVE], - message: `Gagal! Belum ada item yang aktif`, + message: `Gagal! tenant tidak aktif`, + }, + { + relation: 'bundling_items', + singleQuery: ['status', '!=', STATUS.ACTIVE], + message: `Gagal! Terdapat item yang belum aktif`, }, ]; } diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts index 3b20b1a..a36460d 100644 --- a/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts +++ b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts @@ -7,11 +7,7 @@ import { 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 { - HttpStatus, - Injectable, - UnprocessableEntityException, -} from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() @@ -33,7 +29,12 @@ export class BatchActiveItemManager extends BaseBatchUpdateStatusManager parseFloat(recap.payment_total), @@ -112,7 +110,8 @@ export class RecapReconciliationManager extends BaseCustomManager TransactionItemModel, (model) => model.refund, { + @ManyToOne(() => TransactionItemModel, (model) => model.refunds, { onDelete: 'CASCADE', onUpdate: 'CASCADE', }) diff --git a/src/modules/transaction/refund/data/models/refund.model.ts b/src/modules/transaction/refund/data/models/refund.model.ts index e50043a..014a016 100644 --- a/src/modules/transaction/refund/data/models/refund.model.ts +++ b/src/modules/transaction/refund/data/models/refund.model.ts @@ -1,6 +1,6 @@ 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 { Column, Entity, JoinColumn, ManyToOne, OneToMany } 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'; @@ -64,7 +64,7 @@ export class RefundModel // relation to transaction @Column('varchar', { name: 'transaction_id', nullable: true }) transaction_id: string; - @OneToOne(() => TransactionModel, (model) => model.refund, { + @ManyToOne(() => TransactionModel, (model) => model.refunds, { onDelete: 'CASCADE', onUpdate: 'CASCADE', }) diff --git a/src/modules/transaction/refund/domain/usecases/managers/batch-confirm-refund.manager.ts b/src/modules/transaction/refund/domain/usecases/managers/batch-confirm-refund.manager.ts index 99f1cf5..8add7f4 100644 --- a/src/modules/transaction/refund/domain/usecases/managers/batch-confirm-refund.manager.ts +++ b/src/modules/transaction/refund/domain/usecases/managers/batch-confirm-refund.manager.ts @@ -38,7 +38,6 @@ export class BatchConfirmRefundManager extends BaseBatchUpdateStatusManager if (data.status == STATUS.DRAFT) { Object.assign(this.data, { - code: `RF-${data.transaction?.invoice_code?.split('-')[1]}`, request_date: new Date(), status: STATUS.PENDING, }); diff --git a/src/modules/transaction/refund/domain/usecases/managers/create-refund.manager.ts b/src/modules/transaction/refund/domain/usecases/managers/create-refund.manager.ts index c78ecd7..2d49c00 100644 --- a/src/modules/transaction/refund/domain/usecases/managers/create-refund.manager.ts +++ b/src/modules/transaction/refund/domain/usecases/managers/create-refund.manager.ts @@ -13,6 +13,8 @@ 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'; +import { In, Not } from 'typeorm'; +import { generateInvoiceCodeHelper } from 'src/modules/transaction/transaction/domain/usecases/managers/helpers/generate-invoice-code.helper'; @Injectable() export class CreateRefundManager extends BaseCreateManager { @@ -26,13 +28,10 @@ export class CreateRefundManager extends BaseCreateManager { }; }); - Object.assign(this.data, { - refund_items: refund_items, - }); - const exist = await this.dataService.getOneByOptions({ where: { transaction_id: this.data.transaction.id, + status: Not(In([STATUS.CANCEL])), }, }); if (exist) { @@ -57,6 +56,11 @@ export class CreateRefundManager extends BaseCreateManager { error: 'Unprocessable Entity', }); } + + Object.assign(this.data, { + refund_items: refund_items, + code: await generateInvoiceCodeHelper(this.dataService, 'RF'), + }); return; } diff --git a/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts b/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts index 486e581..b5f332e 100644 --- a/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts +++ b/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts @@ -15,7 +15,7 @@ export class DetailRefundManager extends BaseDetailManager { } async afterProcess(): Promise { - mappingTransaction(this.result['transaction']); + mappingTransaction(this.result['transaction'], this.dataId); return; } @@ -25,7 +25,12 @@ export class DetailRefundManager extends BaseDetailManager { joinRelations: [], // relation join and select (relasi yang ingin ditampilkan), - selectRelations: ['transaction', 'transaction.items', 'items.refund'], + selectRelations: [ + 'transaction', + 'transaction.items', + 'items.refunds item_refunds', + 'item_refunds.refund item_refunds_refund', + ], // relation yang hanya ingin dihitung (akan return number) countRelations: [], @@ -55,7 +60,9 @@ export class DetailRefundManager extends BaseDetailManager { 'transaction', 'items', - 'refund', + 'item_refunds', + 'item_refunds_refund.id', + 'item_refunds_refund.status', ]; } diff --git a/src/modules/transaction/refund/domain/usecases/managers/update-refund.manager.ts b/src/modules/transaction/refund/domain/usecases/managers/update-refund.manager.ts index fdedbc2..7d12668 100644 --- a/src/modules/transaction/refund/domain/usecases/managers/update-refund.manager.ts +++ b/src/modules/transaction/refund/domain/usecases/managers/update-refund.manager.ts @@ -12,25 +12,10 @@ import { columnUniques, validateRelations, } from 'src/core/strings/constants/interface.constants'; -import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class UpdateRefundManager extends BaseUpdateManager { async validateProcess(): Promise { - const transaction = await this.dataServiceFirstOpt.getOneByOptions({ - where: { - id: this.data.transaction.id, - status: STATUS.SETTLED, - }, - }); - - if (!transaction) { - throw new UnprocessableEntityException({ - statusCode: HttpStatus.UNPROCESSABLE_ENTITY, - message: `Gagal! hanya pemesanan dengan status ${STATUS.SETTLED} yang dapat dikembalikan`, - error: 'Unprocessable Entity', - }); - } return; } diff --git a/src/modules/transaction/transaction/data/models/transaction-item.model.ts b/src/modules/transaction/transaction/data/models/transaction-item.model.ts index dc5b278..78807dd 100644 --- a/src/modules/transaction/transaction/data/models/transaction-item.model.ts +++ b/src/modules/transaction/transaction/data/models/transaction-item.model.ts @@ -1,5 +1,5 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; -import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from 'typeorm'; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } 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'; @@ -80,10 +80,10 @@ export class TransactionItemModel transaction: TransactionModel; // relations to refund - @OneToOne(() => RefundItemModel, (model) => model.transaction_item, { + @OneToMany(() => RefundItemModel, (model) => model.transaction_item, { cascade: true, onDelete: 'CASCADE', onUpdate: 'CASCADE', }) - refund: RefundItemModel; + refunds: RefundItemModel[]; } diff --git a/src/modules/transaction/transaction/data/models/transaction.model.ts b/src/modules/transaction/transaction/data/models/transaction.model.ts index e8c93a2..565b543 100644 --- a/src/modules/transaction/transaction/data/models/transaction.model.ts +++ b/src/modules/transaction/transaction/data/models/transaction.model.ts @@ -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, OneToOne } from 'typeorm'; +import { Column, Entity, OneToMany } from 'typeorm'; import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { TransactionType, @@ -107,6 +107,13 @@ export class TransactionModel }) payment_type: TransactionPaymentType; + @Column('enum', { + name: 'payment_type_counter', + enum: TransactionPaymentType, + nullable: true, + }) + payment_type_counter: TransactionPaymentType; + @Column('varchar', { name: 'payment_code', nullable: true }) payment_code: string; @@ -233,10 +240,10 @@ export class TransactionModel taxes: TransactionTaxModel[]; // relations to refund - @OneToOne(() => RefundModel, (model) => model.transaction, { + @OneToMany(() => RefundModel, (model) => model.transaction, { cascade: true, onDelete: 'CASCADE', onUpdate: 'CASCADE', }) - refund: RefundModel; + refunds: RefundModel[]; } diff --git a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts index 18761df..4b1ba0f 100644 --- a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts +++ b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts @@ -41,6 +41,7 @@ export interface TransactionEntity extends BaseStatusEntity { // payment data payment_type: TransactionPaymentType; + payment_type_counter: TransactionPaymentType; payment_type_method_id: string; payment_type_method_name: string; payment_type_method_number: string; diff --git a/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts b/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts index 827d347..8d38740 100644 --- a/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts +++ b/src/modules/transaction/transaction/domain/usecases/handlers/settled-transaction.handler.ts @@ -37,57 +37,59 @@ export class SettledTransactionHandler relations: ['items'], }); - if (!settled || !oldSettled) return; + if (settled || oldSettled) { + const queryRunner = this.dataService + .getRepository() + .manager.connection.createQueryRunner(); - const queryRunner = this.dataService - .getRepository() - .manager.connection.createQueryRunner(); + if (settled) { + const profit_formula = await this.formulaService.getOneByOptions({ + where: { + type: FormulaType.PROFIT_SHARE, + }, + }); - if (settled) { - const profit_formula = await this.formulaService.getOneByOptions({ - where: { - type: FormulaType.PROFIT_SHARE, - }, - }); + const sales_price = await this.formulaService.getOneByOptions({ + where: { + type: FormulaType.SALES_PRICE, + }, + }); - const sales_price = await this.formulaService.getOneByOptions({ - where: { - type: FormulaType.SALES_PRICE, - }, - }); + const taxes = await this.taxService.getManyByOptions({ + where: { + status: STATUS.ACTIVE, + }, + }); - const taxes = await this.taxService.getManyByOptions({ - where: { - status: STATUS.ACTIVE, - }, - }); + // const profit_share_value = this.calculateFormula(profit_formula.formula_string, taxes, data.payment_total_net_profit ?? 0); + const { dpp_value, tax_datas } = calculateSalesFormula( + sales_price.formula_string, + taxes, + data.payment_total_net_profit ?? 0, + ); - // const profit_share_value = this.calculateFormula(profit_formula.formula_string, taxes, data.payment_total_net_profit ?? 0); - const { dpp_value, tax_datas } = calculateSalesFormula( - sales_price.formula_string, - taxes, - data.payment_total_net_profit ?? 0, - ); + console.log(data, 'dsa'); + const google_calendar = await CreateEventCalendarHelper(data); - const google_calendar = await CreateEventCalendarHelper(data); + Object.assign(data, { + payment_total_dpp: dpp_value, + profit_share_formula: profit_formula.formula_string, + sales_price_formula: sales_price.formula_string, + taxes: tax_datas, + calendar_id: google_calendar?.id, + calendar_link: google_calendar?.htmlLink, + }); + } else if (oldSettled) { + console.log(data, 'data oldSettled'); + const google_calendar = await CreateEventCalendarHelper(data); - Object.assign(data, { - payment_total_dpp: dpp_value, - profit_share_formula: profit_formula.formula_string, - sales_price_formula: sales_price.formula_string, - taxes: tax_datas, - calendar_id: google_calendar?.id, - calendar_link: google_calendar?.htmlLink, - }); - } else if (oldSettled) { - const google_calendar = await CreateEventCalendarHelper(data); + Object.assign(data, { + calendar_id: null, + calendar_link: null, + }); + } - Object.assign(data, { - calendar_id: null, - calendar_link: null, - }); + await this.dataService.create(queryRunner, TransactionModel, data); } - - await this.dataService.create(queryRunner, TransactionModel, data); } } diff --git a/src/modules/transaction/transaction/domain/usecases/managers/active-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/active-transaction.manager.ts index 8287849..de433cd 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/active-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/active-transaction.manager.ts @@ -11,7 +11,7 @@ import { TransactionChangeStatusEvent } from '../../entities/event/transaction-c @Injectable() export class ActiveTransactionManager extends BaseUpdateStatusManager { getResult(): string { - return `Success active data ${this.result.invoice_code}`; + return `Success ${this.dataStatus} data ${this.result.invoice_code}`; } async validateProcess(): Promise { diff --git a/src/modules/transaction/transaction/domain/usecases/managers/cancel-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/cancel-transaction.manager.ts index 4e5de9d..5499d86 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/cancel-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/cancel-transaction.manager.ts @@ -16,11 +16,11 @@ import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class CancelTransactionManager extends BaseUpdateStatusManager { getResult(): string { - return `Success active data ${this.result.invoice_code}`; + return `Success ${this.dataStatus} data ${this.result.invoice_code}`; } async validateProcess(): Promise { - if (![STATUS.EXPIRED, STATUS.PENDING].includes(this.data.status)) { + if (![STATUS.EXPIRED, STATUS.PENDING].includes(this.oldData.status)) { throw new UnprocessableEntityException({ statusCode: HttpStatus.UNPROCESSABLE_ENTITY, message: `Gagal! hanya tranksaksi dengan status ${STATUS.PENDING} dan ${STATUS.EXPIRED} yang dapat di${this.dataStatus}`, diff --git a/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts index 0453916..49a7213 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts @@ -25,7 +25,12 @@ export class DetailTransactionManager extends BaseDetailManager { let tenant; + let refund = itemData.refunds?.find( + (item) => ![STATUS.CANCEL].includes(item.refund.status), + ); if (itemData.item_tenant_id) { tenant = { @@ -35,6 +38,9 @@ export function mappingTransaction(data) { }; } + if (refundId) + refund = itemData.refunds?.find((item) => item.refund.id == refundId); + return { item: { id: itemData.item_id, @@ -49,20 +55,27 @@ export function mappingTransaction(data) { }, }, id: itemData.id, - refund: itemData.refund, + refund: refund, qty: itemData.qty, qty_remaining: itemData.qty_remaining, - total_price_refund: itemData.refund?.refund_total ?? 0, + total_price_refund: refund?.refund_total ?? 0, total_price: itemData.total_price, }; }); + const refund = data.refunds?.find( + (refund) => ![STATUS.CANCEL].includes(refund.status), + ); + Object.assign(data, { season_period: season_period, items: items, payment_type_bank: payment_type_bank, + refund: refund, }); + delete data.refunds; + delete data.season_period_id; delete data.season_period_name; delete data.season_period_type_id; @@ -85,6 +98,7 @@ export function mappingRevertTransaction(data, type) { }); } else { Object.assign(data, { + type: type, creator_id: data.pos_admin?.id, creator_name: data.pos_admin?.name, invoice_code: data.code, @@ -94,11 +108,11 @@ export function mappingRevertTransaction(data, type) { Object.assign(data, { id: data.booking_id ?? data._id, creator_counter_no: Number(data.pos_number), - status: STATUS.SETTLED, settlement_date: new Date(data.created_at), payment_date: new Date(data.created_at), invoice_date: new Date(data.created_at), - payment_type: + payment_type: TransactionPaymentType.COUNTER, + payment_type_counter: data.payment_type == 'cc' ? TransactionPaymentType.CC : data.payment_type, @@ -109,13 +123,12 @@ export function mappingRevertTransaction(data, type) { discount_percentage: data.discount_code?.discount, }); } else { - // Object.assign(data, { - // payment_type: - // }) + Object.assign(data, { + type: type, + }); } Object.assign(data, { - type: type, payment_total_net_profit: data.payment_total, customer_category_id: data.customer_category?.id ?? null, customer_category_name: data.customer_category?.name ?? null, diff --git a/src/modules/transaction/transaction/domain/usecases/managers/index-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/index-transaction.manager.ts index dbed026..055bad9 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/index-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/index-transaction.manager.ts @@ -7,6 +7,7 @@ import { RelationParam, } from 'src/core/modules/domain/entities/base-filter.entity'; import { BetweenQueryHelper } from 'src/core/helpers/query/between-query.helper'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class IndexTransactionManager extends BaseIndexManager { @@ -20,12 +21,16 @@ export class IndexTransactionManager extends BaseIndexManager async afterProcess(): Promise { this.result?.data?.map((item) => { + const activeRefund = item['refunds'].find( + (refund) => ![STATUS.CANCEL].includes(refund.status), + ); + Object.assign(item, { - refund_code: item['refund']?.code ?? null, - refund_date: item['refund']?.refund_date ?? null, + refund_code: activeRefund?.code ?? null, + refund_date: activeRefund?.refund_date ?? null, }); - delete item['refund']; + delete item['refunds']; }); return; } @@ -36,7 +41,7 @@ export class IndexTransactionManager extends BaseIndexManager joinRelations: [], // relation join and select (relasi yang ingin ditampilkan), - selectRelations: ['items', 'refund'], + selectRelations: ['items', 'refunds'], // relation yang hanya ingin dihitung (akan return number) countRelations: [], @@ -70,16 +75,17 @@ export class IndexTransactionManager extends BaseIndexManager `${this.tableName}.payment_code`, `${this.tableName}.payment_card_information`, `${this.tableName}.payment_type`, + `${this.tableName}.payment_type_counter`, `${this.tableName}.payment_date`, `${this.tableName}.payment_total_pay`, `${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`, - `refund.request_date`, + `refunds.id`, + `refunds.code`, + `refunds.refund_date`, + `refunds.request_date`, ]; }