diff --git a/env/env.development b/env/env.development index 4a94509..db61ef4 100644 --- a/env/env.development +++ b/env/env.development @@ -22,10 +22,15 @@ CRON_MIDNIGHT="55 11 * * *" CRON_EVERY_MINUTE="55 11 * * *" CRON_EVERY_HOUR="0 * * * *" +EMAIL_HOST="sandbox.smtp.mailtrap.io" +EMAIL_POST=465 +EMAIL_USER="developer@eigen.co.id" +EMAIL_TOKEN="bitqkbkzjzfywxqx" + MIDTRANS_URL=https://app.sandbox.midtrans.com MIDTRANS_PRODUCTION=false -MIDTRANS_SERVER_KEY=SB-Mid-server-ITmSD6C0nXfIcmgi4TXm6J7i -MIDTRANS_CLIENT_KEY=SB-Mid-client-VFaU_cPL6kh2DKir +MIDTRANS_SERVER_KEY= +MIDTRANS_CLIENT_KEY= EXPORT_LIMIT_PARTITION=200 ASSETS="https://asset.sky.eigen.co.id/" \ No newline at end of file diff --git a/env/env.production b/env/env.production index e0019f2..b389dbc 100644 --- a/env/env.production +++ b/env/env.production @@ -22,10 +22,15 @@ CRON_MIDNIGHT="55 11 * * *" CRON_EVERY_MINUTE="55 11 * * *" CRON_EVERY_HOUR="0 * * * *" +EMAIL_HOST="sandbox.smtp.mailtrap.io" +EMAIL_POST=465 +EMAIL_USER= +EMAIL_TOKEN= + MIDTRANS_URL=https://app.midtrans.com MIDTRANS_PRODUCTION=true -MIDTRANS_SERVER_KEY=Mid-server-6lA4Nnmov2BSOcwVq1sLSOpC -MIDTRANS_CLIENT_KEY=Mid-client-JiPIkIPd_RGooF8U +MIDTRANS_SERVER_KEY= +MIDTRANS_CLIENT_KEY= EXPORT_LIMIT_PARTITION=200 ASSETS="https://asset.sky.eigen.co.id/" \ No newline at end of file diff --git a/package.json b/package.json index f97ceb7..944ef0f 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,12 @@ "elastic-apm-node": "^4.5.4", "exceljs": "^4.4.0", "googleapis": "^140.0.0", + "handlebars": "^4.7.8", "mathjs": "^13.0.2", "midtrans-client": "^1.3.1", "moment": "^2.30.1", "nano": "^10.1.3", + "nodemailer": "^6.9.14", "pg": "^8.11.5", "plop": "^4.0.1", "reflect-metadata": "^0.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 36258c3..08b50d9 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -68,6 +68,7 @@ import { NewsModule } from './modules/web-information/news/news.module'; import { NewsModel } from './modules/web-information/news/data/models/news.model'; import { BannerModule } from './modules/web-information/banner/banner.module'; import { BannerModel } from './modules/web-information/banner/data/models/banner.model'; +import { MailModule } from './modules/configuration/mail/mail.module'; @Module({ imports: [ @@ -122,6 +123,7 @@ import { BannerModel } from './modules/web-information/banner/data/models/banner CronModule, GoogleCalendarModule, LogModule, + MailModule, MidtransModule, SessionModule, UploadModule, diff --git a/src/core/modules/domain/usecase/managers/base-update-status.manager.ts b/src/core/modules/domain/usecase/managers/base-update-status.manager.ts index f3aa9a2..3e4e0a9 100644 --- a/src/core/modules/domain/usecase/managers/base-update-status.manager.ts +++ b/src/core/modules/domain/usecase/managers/base-update-status.manager.ts @@ -9,6 +9,7 @@ export abstract class BaseUpdateStatusManager extends BaseManager { protected result: Entity; protected oldData: Entity; protected dataStatus: STATUS; + protected relations = []; protected duplicateColumn: string[]; abstract get entityTarget(): any; @@ -22,6 +23,7 @@ export abstract class BaseUpdateStatusManager extends BaseManager { where: { id: this.dataId, }, + relations: this.relations, }); this.oldData = _.cloneDeep(this.data); diff --git a/src/database/migrations/1721216510569-update-table-transactions.ts b/src/database/migrations/1721216510569-update-table-transactions.ts new file mode 100644 index 0000000..5e6380a --- /dev/null +++ b/src/database/migrations/1721216510569-update-table-transactions.ts @@ -0,0 +1,25 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateTableTransactions1721216510569 + implements MigrationInterface +{ + name = 'UpdateTableTransactions1721216510569'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "transactions" ADD "payment_midtrans_token" character varying`, + ); + await queryRunner.query( + `ALTER TABLE "transactions" ADD "payment_midtrans_url" character varying`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "transactions" DROP COLUMN "payment_midtrans_url"`, + ); + await queryRunner.query( + `ALTER TABLE "transactions" DROP COLUMN "payment_midtrans_token"`, + ); + } +} diff --git a/src/modules/configuration/mail/domain/email-template/payment-confirmation-bank.html b/src/modules/configuration/mail/domain/email-template/payment-confirmation-bank.html new file mode 100644 index 0000000..daa023e --- /dev/null +++ b/src/modules/configuration/mail/domain/email-template/payment-confirmation-bank.html @@ -0,0 +1,413 @@ + + + + + + + Email Ibunda + + + + + + + + + + +
  +
+ + + + + + + +
+ + + + +
+

Halo {{customer_name}}

+

Pemesanan tiket telah berhasil dengan nomor invoice {{invoice_code}}, Silahkan lakukan pembayaran

+
+

+ PEMBAYARAN DAPAT MELALUI +

    + {{#each payment_methods}} +
  • +

    + {{issuer_name}}
    + Name: {{account_name}}
    + Number: {{account_number}} +

    +
  • + {{/each}} +
+

+
+
+ + + + + + +
+
 
+ + + \ No newline at end of file diff --git a/src/modules/configuration/mail/domain/email-template/payment-confirmation-midtrans.html b/src/modules/configuration/mail/domain/email-template/payment-confirmation-midtrans.html new file mode 100644 index 0000000..b1cc797 --- /dev/null +++ b/src/modules/configuration/mail/domain/email-template/payment-confirmation-midtrans.html @@ -0,0 +1,404 @@ + + + + + + + Email Ibunda + + + + + + + + + + +
  +
+ + + + + + + +
+ + + + + + + +
+

Halo {{customer_name}}

+

Pemesanan tiket telah berhasil dengan nomor invoice {{invoice_code}}, Silahkan lakukan pembayaran dengan klik button dibawah ini

+
+ Lanjutkan Pembayaran +
+
+ + + + + + +
+
 
+ + + \ No newline at end of file diff --git a/src/modules/configuration/mail/domain/handlers/payment-transaction.handler.ts b/src/modules/configuration/mail/domain/handlers/payment-transaction.handler.ts new file mode 100644 index 0000000..f050ba1 --- /dev/null +++ b/src/modules/configuration/mail/domain/handlers/payment-transaction.handler.ts @@ -0,0 +1,60 @@ +import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { PaymentMethodDataService } from 'src/modules/transaction/payment-method/data/services/payment-method-data.service'; +import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service'; +import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event'; +import { sendEmail } from '../helpers/send-email.helper'; +import { TransactionPaymentType } from 'src/modules/transaction/transaction/constants'; + +@EventsHandler(TransactionChangeStatusEvent) +export class PaymentTransactionHandler + implements IEventHandler +{ + constructor( + private dataService: TransactionDataService, + private paymentService: PaymentMethodDataService, + ) {} + + async handle(event: TransactionChangeStatusEvent) { + const data_id = event.data.id; + const old_data = event.data.old; + const current_data = event.data.data; + let payments = []; + + if ( + old_data.status == STATUS.DRAFT && + current_data.status == STATUS.PENDING && + current_data.payment_type != TransactionPaymentType.COUNTER + ) { + if (current_data.payment_type != TransactionPaymentType.MIDTRANS) { + payments = await this.paymentService.getManyByOptions({ + where: { + status: STATUS.ACTIVE, + }, + }); + } + + const transaction = await this.dataService.getOneByOptions({ + where: { + id: data_id, + }, + relations: ['items'], + }); + + try { + sendEmail( + [ + { + ...transaction, + email: transaction.customer_email, + payment_methods: payments, + }, + ], + 'Payment Confirmation', + ); + } catch (error) { + console.log(error); + } + } + } +} diff --git a/src/modules/configuration/mail/domain/helpers/send-email.helper.ts b/src/modules/configuration/mail/domain/helpers/send-email.helper.ts new file mode 100644 index 0000000..87dd1ee --- /dev/null +++ b/src/modules/configuration/mail/domain/helpers/send-email.helper.ts @@ -0,0 +1,50 @@ +import * as nodemailer from 'nodemailer'; +import * as handlebars from 'handlebars'; +import * as path from 'path'; +import * as fs from 'fs'; +import { TransactionPaymentType } from 'src/modules/transaction/transaction/constants'; + +export async function sendEmail(receivers, subject) { + const smtpTransport = nodemailer.createTransport({ + host: process.env.EMAIL_HOST, + port: process.env.EMAIL_POST, + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_TOKEN, + }, + }); + let templateName = 'payment-confirmation-bank'; + + for (const receiver of receivers) { + if (receiver.payment_type == TransactionPaymentType.MIDTRANS) + templateName = 'payment-confirmation-midtrans'; + + let templatePath = path.resolve( + __dirname, + `../email-template/${templateName}.html`, + ); + templatePath = templatePath.replace(/dist/g, 'src'); + const templateSource = fs.readFileSync(templatePath, 'utf8'); + + const template = handlebars.compile(templateSource); + const htmlToSend = template(receiver); + + const emailContext = { + from: 'no-reply@eigen.co.id', + to: receiver.email, + subject: subject, + html: htmlToSend, + attachDataUrls: true, + }; + + await new Promise((f) => setTimeout(f, 2000)); + + smtpTransport.sendMail(emailContext, function (err, data) { + if (err) { + console.log(`Error occurs on send to ${receiver.email}`); + } else { + console.log(`Email sent to ${receiver.email}`); + } + }); + } +} diff --git a/src/modules/configuration/mail/mail.module.ts b/src/modules/configuration/mail/mail.module.ts new file mode 100644 index 0000000..597fc9c --- /dev/null +++ b/src/modules/configuration/mail/mail.module.ts @@ -0,0 +1,28 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { CqrsModule } from '@nestjs/cqrs'; +import { PaymentMethodModel } from 'src/modules/transaction/payment-method/data/models/payment-method.model'; +import { PaymentMethodDataService } from 'src/modules/transaction/payment-method/data/services/payment-method-data.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +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'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature( + [PaymentMethodModel, TransactionModel], + CONNECTION_NAME.DEFAULT, + ), + CqrsModule, + ], + controllers: [], + providers: [ + PaymentTransactionHandler, + PaymentMethodDataService, + TransactionDataService, + ], +}) +export class MailModule {} diff --git a/src/modules/configuration/midtrans/data/services/midtrans.service.ts b/src/modules/configuration/midtrans/data/services/midtrans.service.ts index 568cf19..5a3d658 100644 --- a/src/modules/configuration/midtrans/data/services/midtrans.service.ts +++ b/src/modules/configuration/midtrans/data/services/midtrans.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@nestjs/common'; import { EventBus } from '@nestjs/cqrs'; +import { mappingMidtransTransaction } from '../../domain/usecases/helpers/mapping-transaction.helper'; const midtransClient = require('midtrans-client'); @Injectable() @@ -19,20 +20,7 @@ export class MidtransService { } async create(body): Promise { - return await this.midtransInstance.createTransaction({ - transaction_details: { - order_id: '123', - gross_amount: 10000, - }, - credit_card: { - secure: true, - }, - customer_details: { - first_name: 'budd', - last_name: 'pratama', - email: 'budi.pra@mail.com', - phone: '0822111111', - }, - }); + const data = mappingMidtransTransaction(body); + return await this.midtransInstance.createTransaction(data); } } diff --git a/src/modules/configuration/midtrans/domain/usecases/helpers/mapping-transaction.helper.ts b/src/modules/configuration/midtrans/domain/usecases/helpers/mapping-transaction.helper.ts new file mode 100644 index 0000000..0e6cb4c --- /dev/null +++ b/src/modules/configuration/midtrans/domain/usecases/helpers/mapping-transaction.helper.ts @@ -0,0 +1,31 @@ +export function mappingMidtransTransaction(transaction) { + const item_details = transaction.items?.map((item) => { + return { + quantity: Number(item.qty), + price: Number(item.total_price), + name: item.item_name, + category: item.item_category_name, + }; + }); + + if (transaction.payment_discount_total) { + item_details.push({ + quantity: 1, + price: -Number(transaction.payment_discount_total), + name: 'discount', + }); + } + + return { + transaction_details: { + order_id: transaction.id, + gross_amount: Number(transaction.payment_total), + }, + item_details: item_details, + customer_details: { + first_name: transaction.customer_name, + email: transaction.customer_email, + phone: transaction.customer_phone, + }, + }; +} diff --git a/src/modules/configuration/midtrans/midtrans.module.ts b/src/modules/configuration/midtrans/midtrans.module.ts index ae5abf1..38d22f5 100644 --- a/src/modules/configuration/midtrans/midtrans.module.ts +++ b/src/modules/configuration/midtrans/midtrans.module.ts @@ -2,19 +2,16 @@ import { ConfigModule } from '@nestjs/config'; import { CqrsModule } from '@nestjs/cqrs'; import { MidtransController } from './infrastructure/midtrans.controller'; import { MidtransService } from './data/services/midtrans.service'; -import { Module } from '@nestjs/common'; +import { Global, Module } from '@nestjs/common'; +@Global() @Module({ imports: [ ConfigModule.forRoot(), - // TypeOrmModule.forFeature( - // [ - // ], - // CONNECTION_NAME.DEFAULT, - // ), CqrsModule, ], controllers: [MidtransController], providers: [MidtransService], + exports: [MidtransService], }) export class MidtransModule {} diff --git a/src/modules/transaction/transaction/data/models/transaction.model.ts b/src/modules/transaction/transaction/data/models/transaction.model.ts index 7ca536f..786623f 100644 --- a/src/modules/transaction/transaction/data/models/transaction.model.ts +++ b/src/modules/transaction/transaction/data/models/transaction.model.ts @@ -125,6 +125,12 @@ export class TransactionModel @Column('varchar', { name: 'payment_code_reference', nullable: true }) payment_code_reference: string; + @Column('varchar', { name: 'payment_midtrans_token', nullable: true }) + payment_midtrans_token: string; + + @Column('varchar', { name: 'payment_midtrans_url', nullable: true }) + payment_midtrans_url: string; + @Column('date', { name: 'payment_date', nullable: true }) payment_date: Date; diff --git a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts index c340dbc..09f1f54 100644 --- a/src/modules/transaction/transaction/domain/entities/transaction.entity.ts +++ b/src/modules/transaction/transaction/domain/entities/transaction.entity.ts @@ -47,6 +47,8 @@ export interface TransactionEntity extends BaseStatusEntity { payment_type_method_qr: string; payment_card_information: string; payment_code_reference: string; + payment_midtrans_token: string; + payment_midtrans_url: string; payment_date: Date; // calculation data diff --git a/src/modules/transaction/transaction/domain/usecases/handlers/midtrans-transaction-callback.handler.ts b/src/modules/transaction/transaction/domain/usecases/handlers/midtrans-transaction-callback.handler.ts new file mode 100644 index 0000000..ec0d46b --- /dev/null +++ b/src/modules/transaction/transaction/domain/usecases/handlers/midtrans-transaction-callback.handler.ts @@ -0,0 +1,44 @@ +import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; +import { MidtransCallbackEvent } from 'src/modules/configuration/midtrans/domain/entities/midtrans-callback.event'; +import { TransactionDataService } from '../../../data/services/transaction-data.service'; +import { TransactionModel } from '../../../data/models/transaction.model'; +import { STATUS } from 'src/core/strings/constants/base.constants'; + +@EventsHandler(MidtransCallbackEvent) +export class MidtransCallbackHandler + implements IEventHandler +{ + constructor(private dataService: TransactionDataService) {} + + async handle(event: MidtransCallbackEvent) { + const data_id = event.data.id; + const data = event.data.data; + const transaction = await this.dataService.getOneByOptions({ + where: { + id: data_id, + }, + }); + + if (['capture', 'settlement'].includes(data.transaction_status)) { + Object.assign(transaction, { + status: STATUS.SETTLED, + settlement_date: new Date(data.settlement_time), + payment_code_reference: data.approval_code, + }); + } else if (['pending'].includes(data['transaction_status'])) { + Object.assign(transaction, { + status: STATUS.PENDING, + }); + } else { + Object.assign(transaction, { + status: STATUS.EXPIRED, + }); + } + + const queryRunner = this.dataService + .getRepository() + .manager.connection.createQueryRunner(); + + await this.dataService.create(queryRunner, TransactionModel, transaction); + } +} diff --git a/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-data-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-data-transaction.manager.ts index 301e158..d3e593a 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-data-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-data-transaction.manager.ts @@ -30,10 +30,12 @@ export class BatchConfirmDataTransactionManager extends BaseBatchUpdateStatusMan Object.assign(data, { status: STATUS.WAITING, - reconciliation_status: - data.payment_type == TransactionPaymentType.COUNTER - ? null - : STATUS.PENDING, + reconciliation_status: [ + TransactionPaymentType.COUNTER, + TransactionPaymentType.MIDTRANS, + ].includes(data.payment_type) + ? null + : STATUS.PENDING, }); return; diff --git a/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-transaction.manager.ts index de10bb9..47606d4 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/batch-confirm-transaction.manager.ts @@ -13,9 +13,13 @@ import { UnprocessableEntityException, } from '@nestjs/common'; import { STATUS } from 'src/core/strings/constants/base.constants'; +import { generateInvoiceCodeHelper } from './helpers/generate-invoice-code.helper'; +import { TransactionPaymentType } from '../../../constants'; @Injectable() export class BatchConfirmTransactionManager extends BaseBatchUpdateStatusManager { + protected relations = ['items']; + async validateData(data: TransactionEntity): Promise { if (data.status != STATUS.DRAFT) { throw new UnprocessableEntityException({ @@ -26,7 +30,26 @@ export class BatchConfirmTransactionManager extends BaseBatchUpdateStatusManager } const freeTransaction = data.payment_total < 1; + if (data.payment_type == TransactionPaymentType.MIDTRANS) { + try { + const { token, redirect_url } = await this.dataServiceFirstOpt.create( + data, + ); + Object.assign(data, { + payment_midtrans_token: token, + payment_midtrans_url: redirect_url, + }); + } catch (error) { + throw new UnprocessableEntityException({ + statusCode: HttpStatus.UNPROCESSABLE_ENTITY, + message: `Failed! this transaction already created, please check your email to continue payment`, + error: 'Unprocessable Entity', + }); + } + } + Object.assign(data, { + invoice_code: await generateInvoiceCodeHelper(this.dataService), status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING, }); return; diff --git a/src/modules/transaction/transaction/domain/usecases/managers/confirm-data-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/confirm-data-transaction.manager.ts index 07361d8..f860f9e 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/confirm-data-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/confirm-data-transaction.manager.ts @@ -39,10 +39,12 @@ export class ConfirmDataTransactionManager extends BaseUpdateStatusManager { + protected relations = ['items']; + getResult(): string { return `Success active data ${this.result.invoice_code}`; } @@ -33,6 +36,25 @@ export class ConfirmTransactionManager extends BaseUpdateStatusManager { const freeTransaction = this.data.payment_total < 1; + + if (this.data.payment_type == TransactionPaymentType.MIDTRANS) { + try { + const { token, redirect_url } = await this.dataServiceFirstOpt.create( + this.oldData, + ); + Object.assign(this.data, { + payment_midtrans_token: token, + payment_midtrans_url: redirect_url, + }); + } catch (error) { + throw new UnprocessableEntityException({ + statusCode: HttpStatus.UNPROCESSABLE_ENTITY, + message: `Failed! this transaction already created, please check your email to continue payment`, + error: 'Unprocessable Entity', + }); + } + } + Object.assign(this.data, { invoice_code: await generateInvoiceCodeHelper(this.dataService), status: freeTransaction ? STATUS.ACTIVE : STATUS.PENDING, diff --git a/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts b/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts index 477fd1e..3aa32a8 100644 --- a/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts +++ b/src/modules/transaction/transaction/domain/usecases/transaction-data.orchestrator.ts @@ -14,6 +14,7 @@ import { CancelTransactionManager } from './managers/cancel-transaction.manager' import { BatchCancelTransactionManager } from './managers/batch-cancel-transaction.manager'; import { ConfirmDataTransactionManager } from './managers/confirm-data-transaction.manager'; import { BatchConfirmDataTransactionManager } from './managers/batch-confirm-data-transaction.manager'; +import { MidtransService } from 'src/modules/configuration/midtrans/data/services/midtrans.service'; @Injectable() export class TransactionDataOrchestrator { @@ -29,6 +30,7 @@ export class TransactionDataOrchestrator { private cancelManager: CancelTransactionManager, private batchCancelManager: BatchCancelTransactionManager, private serviceData: TransactionDataService, + private midtransService: MidtransService, ) {} async create(data): Promise { @@ -81,7 +83,11 @@ export class TransactionDataOrchestrator { async confirm(dataId): Promise { this.confirmManager.setData(dataId, STATUS.ACTIVE); - this.confirmManager.setService(this.serviceData, TABLE_NAME.TRANSACTION); + this.confirmManager.setService( + this.serviceData, + TABLE_NAME.TRANSACTION, + this.midtransService, + ); await this.confirmManager.execute(); return this.confirmManager.getResult(); } @@ -91,6 +97,7 @@ export class TransactionDataOrchestrator { this.batchConfirmManager.setService( this.serviceData, TABLE_NAME.TRANSACTION, + this.midtransService, ); await this.batchConfirmManager.execute(); return this.batchConfirmManager.getResult(); diff --git a/src/modules/transaction/transaction/transaction.module.ts b/src/modules/transaction/transaction/transaction.module.ts index 1ce5612..a626078 100644 --- a/src/modules/transaction/transaction/transaction.module.ts +++ b/src/modules/transaction/transaction/transaction.module.ts @@ -31,6 +31,7 @@ import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales 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'; +import { MidtransCallbackHandler } from './domain/usecases/handlers/midtrans-transaction-callback.handler'; @Module({ imports: [ @@ -51,6 +52,7 @@ import { RefundUpdatedHandler } from './domain/usecases/handlers/refund-update.h providers: [ RefundUpdatedHandler, PosTransactionHandler, + MidtransCallbackHandler, SettledTransactionHandler, IndexTransactionManager, diff --git a/yarn.lock b/yarn.lock index 382e0c6..cc75c97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5364,6 +5364,11 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +nodemailer@^6.9.14: + version "6.9.14" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.14.tgz#845fda981f9fd5ac264f4446af908a7c78027f75" + integrity sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA== + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"