feat(SPG-554) BE - Integrasi Booking dengan Google Calendar
parent
00d5eba7ab
commit
a671404947
|
@ -22,10 +22,10 @@ CRON_MIDNIGHT="55 11 * * *"
|
||||||
CRON_EVERY_MINUTE="55 11 * * *"
|
CRON_EVERY_MINUTE="55 11 * * *"
|
||||||
CRON_EVERY_HOUR="0 * * * *"
|
CRON_EVERY_HOUR="0 * * * *"
|
||||||
|
|
||||||
EMAIL_HOST="sandbox.smtp.mailtrap.io"
|
EMAIL_HOST=smtp.gmail.com
|
||||||
EMAIL_POST=465
|
EMAIL_POST=465
|
||||||
EMAIL_USER="developer@eigen.co.id"
|
EMAIL_USER=developer@eigen.co.id
|
||||||
EMAIL_TOKEN="bitqkbkzjzfywxqx"
|
EMAIL_TOKEN=bitqkbkzjzfywxqx
|
||||||
|
|
||||||
MIDTRANS_URL=https://app.sandbox.midtrans.com
|
MIDTRANS_URL=https://app.sandbox.midtrans.com
|
||||||
MIDTRANS_PRODUCTION=false
|
MIDTRANS_PRODUCTION=false
|
||||||
|
@ -34,3 +34,6 @@ MIDTRANS_CLIENT_KEY=
|
||||||
|
|
||||||
EXPORT_LIMIT_PARTITION=200
|
EXPORT_LIMIT_PARTITION=200
|
||||||
ASSETS="https://asset.sky.eigen.co.id/"
|
ASSETS="https://asset.sky.eigen.co.id/"
|
||||||
|
|
||||||
|
GOOGLE_CALENDAR_KEY="AIzaSyCSg4P3uC9Z7kD1P4f3rf1BbBaz4Q-M55o"
|
||||||
|
GOOGLE_CALENDAR_ID=""
|
|
@ -22,10 +22,10 @@ CRON_MIDNIGHT="55 11 * * *"
|
||||||
CRON_EVERY_MINUTE="55 11 * * *"
|
CRON_EVERY_MINUTE="55 11 * * *"
|
||||||
CRON_EVERY_HOUR="0 * * * *"
|
CRON_EVERY_HOUR="0 * * * *"
|
||||||
|
|
||||||
EMAIL_HOST="sandbox.smtp.mailtrap.io"
|
EMAIL_HOST=smtp.gmail.com
|
||||||
EMAIL_POST=465
|
EMAIL_POST=465
|
||||||
EMAIL_USER=
|
EMAIL_USER=weplayground.app@gmail.com
|
||||||
EMAIL_TOKEN=
|
EMAIL_TOKEN=sonvvwiukhsevtmv
|
||||||
|
|
||||||
MIDTRANS_URL=https://app.midtrans.com
|
MIDTRANS_URL=https://app.midtrans.com
|
||||||
MIDTRANS_PRODUCTION=true
|
MIDTRANS_PRODUCTION=true
|
||||||
|
@ -34,3 +34,6 @@ MIDTRANS_CLIENT_KEY=
|
||||||
|
|
||||||
EXPORT_LIMIT_PARTITION=200
|
EXPORT_LIMIT_PARTITION=200
|
||||||
ASSETS="https://asset.sky.eigen.co.id/"
|
ASSETS="https://asset.sky.eigen.co.id/"
|
||||||
|
|
||||||
|
GOOGLE_CALENDAR_KEY="AIzaSyCSg4P3uC9Z7kD1P4f3rf1BbBaz4Q-M55o"
|
||||||
|
GOOGLE_CALENDAR_ID=""
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"type": "service_account",
|
||||||
|
"project_id": "weplayground-app",
|
||||||
|
"private_key_id": "e3ed1a4430140ac589c6e9e7ce125d16d8f7304a",
|
||||||
|
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCmEl90K7ojdx1\nnJv5BKq3THI+l+pgC4dlqOuEV4sc2SFXECgyEgEYAFH6U8eH9TTl5wW5hFhvpiWl\nHSxZA2nMa1ojp97mkufzaGgsJbcB4ni9ydoJyN9Hqs2Wz+JiBtjscGOrmOP1bNyn\nBO9RhHInh0bfTNMrtsIicr4DPNIfM2sl95v6pCDGt7Cfu2NoEnDhId50d73KVONI\n0+rf90WhehEMwoZEzYI0gLmSVbnPEm1j4/OOQfQl7FjaFKyle+A5BWaiRsIqiSue\n0jvZz0DlGmjeHx1yjBIKpq5omOku7aYi4kTNEZKKxzs5HhRFKi2KuYNK/WD5ApQg\ncIhGhhCfAgMBAAECggEANX+LmNjh9VJm/Tigkt4LFxifwgCe8WfKAhNmKHyu5K/3\nIAnzmwxjG5ee8gzNat3pfJk+dCnj7FIHwHScSB6NnCMZZXsV51sVBNC77wMxZIXA\nPyE63fzJEdlt6xvc96k9QweFB1yhs0wJ/6r2JnmcrqxcujBTUA3PIoxcG+TBOc08\ndo5Rcbeq6/3txjGlFM1820WViuFSQQiL6PgNVb+l0JrQ8rAOflKYFOkUb8wux9LX\nnD4vJMwa0j+GRvH5BCcZCguIQZn2JR3rTgcavWtcaHiTNsc49Lsj/hGGOsbkFROo\nGWaSgXE169xiVR/MMEblzqpSXq1qXF2iUeaqyUFIZQKBgQDxxrNlDs1qMfcaQ0S2\nVVtU/f1NfY+kCjQaC4CoYJaaoZINs5ODPs8/2DGnHuhNXMtnPeQ+SzNaK1e1eLbw\nmvq1+n3aGZTvUq2L3b+v7JJ6TQmQ4eBLZBzNjxrxC3EkCULTuROtsAhfzORuE0mE\nwnhR5LpPraEBrPi0re9yDDXVHQKBgQDOCwGw1gNVLh622qR65Zhx5rs2q6ktPxq2\neiUV0KDug6/7QbJzg1pNeoVQmadJR86H0fzKMsN5C7t7z3MIkqXc0+T1NmdN2fPm\ndLthnR1grCDYykoet/CITbAfiip27/o3TJ7YIYItefyZ4GnNH82R/4z3LBDnXB9f\n565hbUj76wKBgEnNMpOFijSBXgFZSU8zDPcLtNeDnWYgazkMC9DZ8v7ulOuzxjKI\n6LB/aOCvsY9z5O712IcfY2SB2HsfhxA47pDADsyVhH3tSeZo4QttdmT4wRPFrza0\nL4qbxUiRCo9KeGiylQwusM+1doEXSBjLV/j/jdOml4AwcZaNhYrVqVUNAoGAU0uD\nzXdXNZJFfGp7X+t9a155hKp05APEyswqPd1vkbzO4eY3PBd35CaJyoGzbR6IUcQE\nS8Gl4ENr8at1t5uBTfqjbrYloQVhYmMCdX3MqI4tYTa2LCD0LkYp0zZJ4Hc3Ui+5\nb2psc/ICujpMy032DvWeiTXZR46oaF8C0gQaIy0CgYEAmKCP4CXmPlWoWqebFp3W\nz2eKWUfASioQ+ZGUVNEge4a6iutciydQJZxBfg9ZXWqDfI0FoRSPfs2zUZFO0AcM\n6oaPGiFnTnH8FGcSHu3p0YysevyoSY6tgsAhb3IiKjJd4e7btsYzpPZbIfyfUVHK\nQFOOSkE+x4J5ts+XO6isQ+w=\n-----END PRIVATE KEY-----\n",
|
||||||
|
"client_email": "weplayground@weplayground-app.iam.gserviceaccount.com",
|
||||||
|
"client_id": "106351339097550564510",
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token",
|
||||||
|
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/weplayground%40weplayground-app.iam.gserviceaccount.com",
|
||||||
|
"universe_domain": "googleapis.com"
|
||||||
|
}
|
|
@ -102,7 +102,7 @@ export abstract class BaseUpdateManager<Entity> extends BaseManager {
|
||||||
|
|
||||||
this.eventBus.publishAll([
|
this.eventBus.publishAll([
|
||||||
new topic.topic({
|
new topic.topic({
|
||||||
id: data?.['id'] ?? topic?.data?.['id'],
|
id: topic.data?.['id'] ?? this.dataId,
|
||||||
old: this.oldData,
|
old: this.oldData,
|
||||||
data: data ?? topic.data,
|
data: data ?? topic.data,
|
||||||
user: this.user,
|
user: this.user,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddCalendarColumnTransaction1721892389807
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = 'AddCalendarColumnTransaction1721892389807';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "transactions" ADD "calendar_id" character varying`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "transactions" ADD "calendar_link" character varying`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "transactions" DROP COLUMN "calendar_id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "transactions" DROP COLUMN "calendar_link"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { google } from 'googleapis';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
|
|
||||||
|
export async function CreateEventCalendarHelper(
|
||||||
|
transaction: TransactionEntity,
|
||||||
|
isDelete = false,
|
||||||
|
) {
|
||||||
|
let result;
|
||||||
|
|
||||||
|
const filePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'../../../../../../../../',
|
||||||
|
'google-credential.json',
|
||||||
|
);
|
||||||
|
const credential = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||||
|
|
||||||
|
const client = new google.auth.JWT({
|
||||||
|
email: credential.client_email,
|
||||||
|
key: credential.private_key,
|
||||||
|
scopes: ['https://www.googleapis.com/auth/calendar'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const calendar = google.calendar({
|
||||||
|
version: 'v3',
|
||||||
|
auth: client,
|
||||||
|
});
|
||||||
|
|
||||||
|
const eventData = mappingData(transaction);
|
||||||
|
|
||||||
|
if (transaction.calendar_id) {
|
||||||
|
result = await calendar.events.update(
|
||||||
|
{
|
||||||
|
calendarId: process.env.GOOGLE_CALENDAR_ID,
|
||||||
|
eventId: transaction.calendar_id,
|
||||||
|
requestBody: eventData,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
} else if (!isDelete) {
|
||||||
|
result = await calendar.events.insert(
|
||||||
|
{
|
||||||
|
calendarId: process.env.GOOGLE_CALENDAR_ID,
|
||||||
|
requestBody: eventData,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
result = await calendar.events.delete(
|
||||||
|
{
|
||||||
|
calendarId: process.env.GOOGLE_CALENDAR_ID,
|
||||||
|
eventId: transaction.calendar_id,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result?.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mappingData(transaction) {
|
||||||
|
return {
|
||||||
|
summary: transaction.invoice_code,
|
||||||
|
description: `Booking for invoice ${transaction.invoice_code}`,
|
||||||
|
start: {
|
||||||
|
dateTime: new Date(transaction.booking_date).toISOString(),
|
||||||
|
timeZone: 'Asia/Jakarta',
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
dateTime: new Date(transaction.booking_date).toISOString(),
|
||||||
|
timeZone: 'Asia/Jakarta',
|
||||||
|
},
|
||||||
|
reminders: {
|
||||||
|
useDefault: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ export class IndexHolidayCalendarManager {
|
||||||
const events = [];
|
const events = [];
|
||||||
const calendar = google.calendar({
|
const calendar = google.calendar({
|
||||||
version: 'v3',
|
version: 'v3',
|
||||||
auth: 'AIzaSyCsCt6PDd6uYLkahvtdvCoMWf-1_QaLiNM',
|
auth: process.env.GOOGLE_CALENDAR_KEY,
|
||||||
});
|
});
|
||||||
const calendarId = 'id.indonesian#holiday@group.v.calendar.google.com';
|
const calendarId = 'id.indonesian#holiday@group.v.calendar.google.com';
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,29 @@ import { CqrsModule } from '@nestjs/cqrs';
|
||||||
import { IndexHolidayCalendarManager } from '../../configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager';
|
import { IndexHolidayCalendarManager } from '../../configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager';
|
||||||
import { GoogleCalendarController } from './infrastructure/google-calendar.controller';
|
import { GoogleCalendarController } from './infrastructure/google-calendar.controller';
|
||||||
import { GoogleCalendarOrchestrator } from './domain/usecases/google-calendar.orchestrator';
|
import { GoogleCalendarOrchestrator } from './domain/usecases/google-calendar.orchestrator';
|
||||||
|
import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service';
|
||||||
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||||
|
import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model';
|
||||||
|
import { TransactionTaxModel } from 'src/modules/transaction/transaction/data/models/transaction-tax.model';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule.forRoot(), CqrsModule],
|
imports: [
|
||||||
|
ConfigModule.forRoot(),
|
||||||
|
TypeOrmModule.forFeature(
|
||||||
|
[TransactionModel, TransactionItemModel, TransactionTaxModel],
|
||||||
|
CONNECTION_NAME.DEFAULT,
|
||||||
|
),
|
||||||
|
CqrsModule,
|
||||||
|
],
|
||||||
controllers: [GoogleCalendarController],
|
controllers: [GoogleCalendarController],
|
||||||
providers: [IndexHolidayCalendarManager, GoogleCalendarOrchestrator],
|
providers: [
|
||||||
|
IndexHolidayCalendarManager,
|
||||||
|
|
||||||
|
TransactionDataService,
|
||||||
|
|
||||||
|
GoogleCalendarOrchestrator,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class GoogleCalendarModule {}
|
export class GoogleCalendarModule {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { GoogleCalendarOrchestrator } from './../domain/usecases/google-calendar.orchestrator';
|
import { GoogleCalendarOrchestrator } from './../domain/usecases/google-calendar.orchestrator';
|
||||||
import { Controller, Get, Query } from '@nestjs/common';
|
import { Controller, Get, Post, Query } from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import { Public } from 'src/core/guards';
|
import { Public } from 'src/core/guards';
|
||||||
import { FilterGoogleCalendarDto } from './dto/filter-google-calendar.dto';
|
import { FilterGoogleCalendarDto } from './dto/filter-google-calendar.dto';
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||||
|
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
||||||
|
@ -67,7 +68,11 @@ export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManag
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventTopics(): EventTopics[] {
|
get eventTopics(): EventTopics[] {
|
||||||
return [];
|
return [
|
||||||
|
{
|
||||||
|
topic: TransactionChangeStatusEvent,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
getResult(): BatchResult {
|
getResult(): BatchResult {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||||
|
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BatchConfirmReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
export class BatchConfirmReconciliationManager extends BaseBatchUpdateStatusManager<TransactionEntity> {
|
||||||
|
@ -45,7 +46,11 @@ export class BatchConfirmReconciliationManager extends BaseBatchUpdateStatusMana
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventTopics(): EventTopics[] {
|
get eventTopics(): EventTopics[] {
|
||||||
return [];
|
return [
|
||||||
|
{
|
||||||
|
topic: TransactionChangeStatusEvent,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
getResult(): BatchResult {
|
getResult(): BatchResult {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
validateRelations,
|
validateRelations,
|
||||||
} from 'src/core/strings/constants/interface.constants';
|
} from 'src/core/strings/constants/interface.constants';
|
||||||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
|
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -68,6 +69,10 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager<Transac
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventTopics(): EventTopics[] {
|
get eventTopics(): EventTopics[] {
|
||||||
return [];
|
return [
|
||||||
|
{
|
||||||
|
topic: TransactionChangeStatusEvent,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
validateRelations,
|
validateRelations,
|
||||||
} from 'src/core/strings/constants/interface.constants';
|
} from 'src/core/strings/constants/interface.constants';
|
||||||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
|
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
|
||||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -42,6 +43,10 @@ export class ConfirmReconciliationManager extends BaseUpdateStatusManager<Transa
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventTopics(): EventTopics[] {
|
get eventTopics(): EventTopics[] {
|
||||||
return [];
|
return [
|
||||||
|
{
|
||||||
|
topic: TransactionChangeStatusEvent,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
validateRelations,
|
validateRelations,
|
||||||
} from 'src/core/strings/constants/interface.constants';
|
} from 'src/core/strings/constants/interface.constants';
|
||||||
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model';
|
||||||
|
import { TransactionUpdatedEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-updated.event';
|
||||||
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -46,6 +47,10 @@ export class UpdateReconciliationManager extends BaseUpdateManager<TransactionEn
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventTopics(): EventTopics[] {
|
get eventTopics(): EventTopics[] {
|
||||||
return [];
|
return [
|
||||||
|
{
|
||||||
|
topic: TransactionUpdatedEvent,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,13 @@ export class TransactionModel
|
||||||
@Column({ name: 'sending_qr_at', type: 'bigint', nullable: true })
|
@Column({ name: 'sending_qr_at', type: 'bigint', nullable: true })
|
||||||
sending_qr_at: number;
|
sending_qr_at: number;
|
||||||
|
|
||||||
|
// calendar
|
||||||
|
@Column('varchar', { name: 'calendar_id', nullable: true })
|
||||||
|
calendar_id: string;
|
||||||
|
|
||||||
|
@Column('varchar', { name: 'calendar_link', nullable: true })
|
||||||
|
calendar_link: string;
|
||||||
|
|
||||||
// relations to item
|
// relations to item
|
||||||
@OneToMany(() => TransactionItemModel, (model) => model.transaction, {
|
@OneToMany(() => TransactionItemModel, (model) => model.transaction, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
|
|
|
@ -78,4 +78,7 @@ export interface TransactionEntity extends BaseStatusEntity {
|
||||||
sending_invoice_status: STATUS;
|
sending_invoice_status: STATUS;
|
||||||
sending_qr_at: number;
|
sending_qr_at: number;
|
||||||
sending_qr_status: STATUS;
|
sending_qr_status: STATUS;
|
||||||
|
|
||||||
|
calendar_id?: string;
|
||||||
|
calendar_link?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,36 @@
|
||||||
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
|
import { EventBus, EventsHandler, IEventHandler } from '@nestjs/cqrs';
|
||||||
import { MidtransCallbackEvent } from 'src/modules/configuration/midtrans/domain/entities/midtrans-callback.event';
|
import { MidtransCallbackEvent } from 'src/modules/configuration/midtrans/domain/entities/midtrans-callback.event';
|
||||||
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
||||||
import { TransactionModel } from '../../../data/models/transaction.model';
|
import { TransactionModel } from '../../../data/models/transaction.model';
|
||||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
import {
|
||||||
|
BLANK_USER,
|
||||||
|
OPERATION,
|
||||||
|
STATUS,
|
||||||
|
} from 'src/core/strings/constants/base.constants';
|
||||||
|
import { TransactionChangeStatusEvent } from '../../entities/event/transaction-change-status.event';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
||||||
|
|
||||||
@EventsHandler(MidtransCallbackEvent)
|
@EventsHandler(MidtransCallbackEvent)
|
||||||
export class MidtransCallbackHandler
|
export class MidtransCallbackHandler
|
||||||
implements IEventHandler<MidtransCallbackEvent>
|
implements IEventHandler<MidtransCallbackEvent>
|
||||||
{
|
{
|
||||||
constructor(private dataService: TransactionDataService) {}
|
constructor(
|
||||||
|
private dataService: TransactionDataService,
|
||||||
|
private eventBus: EventBus,
|
||||||
|
) {}
|
||||||
|
|
||||||
async handle(event: MidtransCallbackEvent) {
|
async handle(event: MidtransCallbackEvent) {
|
||||||
const data_id = event.data.id;
|
const data_id = event.data.id;
|
||||||
const data = event.data.data;
|
const data = event.data.data;
|
||||||
|
let old_data;
|
||||||
|
|
||||||
const transaction = await this.dataService.getOneByOptions({
|
const transaction = await this.dataService.getOneByOptions({
|
||||||
where: {
|
where: {
|
||||||
id: data_id,
|
id: data_id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
old_data = _.cloneDeep(transaction);
|
||||||
|
|
||||||
if (['capture', 'settlement'].includes(data.transaction_status)) {
|
if (['capture', 'settlement'].includes(data.transaction_status)) {
|
||||||
Object.assign(transaction, {
|
Object.assign(transaction, {
|
||||||
|
@ -40,5 +53,17 @@ export class MidtransCallbackHandler
|
||||||
.manager.connection.createQueryRunner();
|
.manager.connection.createQueryRunner();
|
||||||
|
|
||||||
await this.dataService.create(queryRunner, TransactionModel, transaction);
|
await this.dataService.create(queryRunner, TransactionModel, transaction);
|
||||||
|
|
||||||
|
this.eventBus.publish(
|
||||||
|
new TransactionChangeStatusEvent({
|
||||||
|
id: data_id,
|
||||||
|
old: old_data,
|
||||||
|
data: data,
|
||||||
|
user: BLANK_USER,
|
||||||
|
description: 'Midtrans Callback',
|
||||||
|
module: TABLE_NAME.TRANSACTION,
|
||||||
|
op: OPERATION.UPDATE,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||||
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
import { TransactionDataService } from '../../../data/services/transaction-data.service';
|
||||||
import { TransactionModel } from '../../../data/models/transaction.model';
|
import { TransactionModel } from '../../../data/models/transaction.model';
|
||||||
import { calculateSalesFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper';
|
import { calculateSalesFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper';
|
||||||
|
import { CreateEventCalendarHelper } from 'src/modules/configuration/google-calendar/domain/usecases/managers/helpers/create-event-calanedar.helper';
|
||||||
|
import { TransactionUpdatedEvent } from '../../entities/event/transaction-updated.event';
|
||||||
|
|
||||||
@EventsHandler(TransactionChangeStatusEvent)
|
@EventsHandler(TransactionChangeStatusEvent, TransactionUpdatedEvent)
|
||||||
export class SettledTransactionHandler
|
export class SettledTransactionHandler
|
||||||
implements IEventHandler<TransactionChangeStatusEvent>
|
implements IEventHandler<TransactionChangeStatusEvent>
|
||||||
{
|
{
|
||||||
|
@ -21,20 +23,27 @@ export class SettledTransactionHandler
|
||||||
async handle(event: TransactionChangeStatusEvent) {
|
async handle(event: TransactionChangeStatusEvent) {
|
||||||
const old_data = event.data.old;
|
const old_data = event.data.old;
|
||||||
const current_data = event.data.data;
|
const current_data = event.data.data;
|
||||||
|
const settled = [STATUS.ACTIVE, STATUS.SETTLED].includes(
|
||||||
if (
|
current_data.status,
|
||||||
old_data.status == current_data.status ||
|
);
|
||||||
![STATUS.ACTIVE, STATUS.SETTLED].includes(current_data.status)
|
const oldSettled = [STATUS.ACTIVE, STATUS.SETTLED].includes(
|
||||||
)
|
old_data.status,
|
||||||
return;
|
);
|
||||||
|
|
||||||
const data = await this.dataService.getOneByOptions({
|
const data = await this.dataService.getOneByOptions({
|
||||||
where: {
|
where: {
|
||||||
id: current_data.id,
|
id: event.data.id,
|
||||||
},
|
},
|
||||||
relations: ['items'],
|
relations: ['items'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!settled || !oldSettled) return;
|
||||||
|
|
||||||
|
const queryRunner = this.dataService
|
||||||
|
.getRepository()
|
||||||
|
.manager.connection.createQueryRunner();
|
||||||
|
|
||||||
|
if (settled) {
|
||||||
const profit_formula = await this.formulaService.getOneByOptions({
|
const profit_formula = await this.formulaService.getOneByOptions({
|
||||||
where: {
|
where: {
|
||||||
type: FormulaType.PROFIT_SHARE,
|
type: FormulaType.PROFIT_SHARE,
|
||||||
|
@ -53,10 +62,6 @@ export class SettledTransactionHandler
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryRunner = this.dataService
|
|
||||||
.getRepository()
|
|
||||||
.manager.connection.createQueryRunner();
|
|
||||||
|
|
||||||
// const profit_share_value = this.calculateFormula(profit_formula.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(
|
const { dpp_value, tax_datas } = calculateSalesFormula(
|
||||||
sales_price.formula_string,
|
sales_price.formula_string,
|
||||||
|
@ -64,12 +69,24 @@ export class SettledTransactionHandler
|
||||||
data.payment_total_net_profit ?? 0,
|
data.payment_total_net_profit ?? 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const google_calendar = await CreateEventCalendarHelper(data);
|
||||||
|
|
||||||
Object.assign(data, {
|
Object.assign(data, {
|
||||||
payment_total_dpp: dpp_value,
|
payment_total_dpp: dpp_value,
|
||||||
profit_share_formula: profit_formula.formula_string,
|
profit_share_formula: profit_formula.formula_string,
|
||||||
sales_price_formula: sales_price.formula_string,
|
sales_price_formula: sales_price.formula_string,
|
||||||
taxes: tax_datas,
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await this.dataService.create(queryRunner, TransactionModel, data);
|
await this.dataService.create(queryRunner, TransactionModel, data);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue