feat: integrate CouchDB module across various services and add transaction summary endpoint
parent
d6717c9c60
commit
47d45cb65c
|
@ -10,7 +10,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||||
import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model';
|
import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model';
|
||||||
import { TransactionTaxModel } from 'src/modules/transaction/transaction/data/models/transaction-tax.model';
|
import { TransactionTaxModel } from 'src/modules/transaction/transaction/data/models/transaction-tax.model';
|
||||||
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
|
@ -19,6 +19,7 @@ import { TransactionTaxModel } from 'src/modules/transaction/transaction/data/mo
|
||||||
CONNECTION_NAME.DEFAULT,
|
CONNECTION_NAME.DEFAULT,
|
||||||
),
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
|
CouchModule,
|
||||||
],
|
],
|
||||||
controllers: [GoogleCalendarController],
|
controllers: [GoogleCalendarController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { TransactionDataService } from 'src/modules/transaction/transaction/data
|
||||||
import { PaymentTransactionHandler } from './domain/handlers/payment-transaction.handler';
|
import { PaymentTransactionHandler } from './domain/handlers/payment-transaction.handler';
|
||||||
import { MailTemplateController } from './infrastructure/mail.controller';
|
import { MailTemplateController } from './infrastructure/mail.controller';
|
||||||
import { PdfMakeManager } from '../export/domain/managers/pdf-make.manager';
|
import { PdfMakeManager } from '../export/domain/managers/pdf-make.manager';
|
||||||
|
import { CouchModule } from '../couch/couch.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
|
@ -19,6 +19,7 @@ import { PdfMakeManager } from '../export/domain/managers/pdf-make.manager';
|
||||||
CONNECTION_NAME.DEFAULT,
|
CONNECTION_NAME.DEFAULT,
|
||||||
),
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
|
CouchModule,
|
||||||
],
|
],
|
||||||
controllers: [MailTemplateController],
|
controllers: [MailTemplateController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { ItemQueueModel } from '../item-related/item-queue/data/models/item-queu
|
||||||
import { QueueTimeFormula } from './domain/usecases/formula/queue-time.formula';
|
import { QueueTimeFormula } from './domain/usecases/formula/queue-time.formula';
|
||||||
import { QueueJobController } from './infrastructure/controllers/queue-job.controller';
|
import { QueueJobController } from './infrastructure/controllers/queue-job.controller';
|
||||||
import { GenerateQueueManager } from './domain/usecases/generate-queue.manager';
|
import { GenerateQueueManager } from './domain/usecases/generate-queue.manager';
|
||||||
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
|
@ -57,6 +57,7 @@ import { GenerateQueueManager } from './domain/usecases/generate-queue.manager';
|
||||||
CONNECTION_NAME.DEFAULT,
|
CONNECTION_NAME.DEFAULT,
|
||||||
),
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
|
CouchModule,
|
||||||
],
|
],
|
||||||
controllers: [QueueController, QueueAdminController, QueueJobController],
|
controllers: [QueueController, QueueAdminController, QueueJobController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -19,13 +19,13 @@ import { BatchCancelReconciliationManager } from './domain/usecases/managers/bat
|
||||||
import { BatchConfirmReconciliationManager } from './domain/usecases/managers/batch-confirm-reconciliation.manager';
|
import { BatchConfirmReconciliationManager } from './domain/usecases/managers/batch-confirm-reconciliation.manager';
|
||||||
import { RecapReconciliationManager } from './domain/usecases/managers/recap-reconciliation.manager';
|
import { RecapReconciliationManager } from './domain/usecases/managers/recap-reconciliation.manager';
|
||||||
import { RecapPosTransactionHandler } from './domain/usecases/handlers/recap-pos-transaction.handler';
|
import { RecapPosTransactionHandler } from './domain/usecases/handlers/recap-pos-transaction.handler';
|
||||||
import { SalesPriceFormulaDataService } from '../sales-price-formula/data/services/sales-price-formula-data.service';
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
TypeOrmModule.forFeature([TransactionModel], CONNECTION_NAME.DEFAULT),
|
TypeOrmModule.forFeature([TransactionModel], CONNECTION_NAME.DEFAULT),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
|
CouchModule,
|
||||||
],
|
],
|
||||||
controllers: [ReconciliationDataController, ReconciliationReadController],
|
controllers: [ReconciliationDataController, ReconciliationReadController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { CancelRefundManager } from './domain/usecases/managers/cancel-refund.ma
|
||||||
import { RefundItemModel } from './data/models/refund-item.model';
|
import { RefundItemModel } from './data/models/refund-item.model';
|
||||||
import { TransactionDataService } from '../transaction/data/services/transaction-data.service';
|
import { TransactionDataService } from '../transaction/data/services/transaction-data.service';
|
||||||
import { TransactionModel } from '../transaction/data/models/transaction.model';
|
import { TransactionModel } from '../transaction/data/models/transaction.model';
|
||||||
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
|
@ -32,6 +32,7 @@ import { TransactionModel } from '../transaction/data/models/transaction.model';
|
||||||
CONNECTION_NAME.DEFAULT,
|
CONNECTION_NAME.DEFAULT,
|
||||||
),
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
|
CouchModule,
|
||||||
],
|
],
|
||||||
controllers: [RefundDataController, RefundReadController],
|
controllers: [RefundDataController, RefundReadController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -4,12 +4,14 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { TransactionModel } from '../models/transaction.model';
|
import { TransactionModel } from '../models/transaction.model';
|
||||||
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import { CouchService } from 'src/modules/configuration/couch/data/services/couch.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TransactionDataService extends BaseDataService<TransactionModel> {
|
export class TransactionDataService extends BaseDataService<TransactionModel> {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(TransactionModel, CONNECTION_NAME.DEFAULT)
|
@InjectRepository(TransactionModel, CONNECTION_NAME.DEFAULT)
|
||||||
private repo: Repository<TransactionModel>,
|
private repo: Repository<TransactionModel>,
|
||||||
|
private couchService: CouchService,
|
||||||
) {
|
) {
|
||||||
super(repo);
|
super(repo);
|
||||||
}
|
}
|
||||||
|
@ -20,4 +22,14 @@ export class TransactionDataService extends BaseDataService<TransactionModel> {
|
||||||
where: { id: booking_id },
|
where: { id: booking_id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveTransactionToCouch(transaction) {
|
||||||
|
const id = transaction.id ?? transaction._id;
|
||||||
|
const couchData = await this.couchService.getDoc(id, 'transaction');
|
||||||
|
if (!couchData) {
|
||||||
|
await this.couchService.createDoc(transaction, 'transaction');
|
||||||
|
} else {
|
||||||
|
await this.couchService.updateDoc(transaction, 'transaction');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,52 @@ export class TransactionReadService extends BaseReadService<TransactionEntity> {
|
||||||
|
|
||||||
return transactions;
|
return transactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSummary(posId: string, startDate: string) {
|
||||||
|
const query = `select payment_type_counter, payment_type_method_name, sum(payment_total) payment_total, sum(payment_total_pay) payment_total_pay
|
||||||
|
from transactions t
|
||||||
|
where 1=1
|
||||||
|
and t.creator_counter_no IN (${posId})
|
||||||
|
and invoice_date = '${startDate}'
|
||||||
|
and status = 'settled'
|
||||||
|
group by payment_type_counter, payment_type_method_name;`;
|
||||||
|
const transactions = await this.repo.query(query);
|
||||||
|
|
||||||
|
const qtyQuery = `select ti.item_name, sum(ti.qty) total_qty, count(ti.item_name), sum(ti.qty), string_agg(distinct ti.item_price::text, '') price,
|
||||||
|
sum(payment_total) payment_total, sum(payment_total_pay) payment_total_pay
|
||||||
|
from transactions t
|
||||||
|
inner join transaction_items ti on t.id = ti.transaction_id
|
||||||
|
where t.creator_counter_no IN (${posId})
|
||||||
|
and invoice_date = '${startDate}'
|
||||||
|
and t.status = 'settled'
|
||||||
|
group by ti.item_name`;
|
||||||
|
const qtyTransactions = await this.repo.query(qtyQuery);
|
||||||
|
|
||||||
|
return { payment: transactions, qty: qtyTransactions };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLastTransactionByPos(
|
||||||
|
posId: string,
|
||||||
|
): Promise<TransactionEntity | null> {
|
||||||
|
const transaction = await this.repo.findOne({
|
||||||
|
select: [
|
||||||
|
'id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'status',
|
||||||
|
'invoice_code',
|
||||||
|
'creator_counter_no',
|
||||||
|
'invoice_date',
|
||||||
|
'payment_total',
|
||||||
|
],
|
||||||
|
where: {
|
||||||
|
creator_counter_no: parseInt(posId),
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
created_at: 'DESC',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,4 +141,10 @@ export class TransactionDataOrchestrator {
|
||||||
await this.batchConfirmDataManager.execute();
|
await this.batchConfirmDataManager.execute();
|
||||||
return this.batchConfirmDataManager.getResult();
|
return this.batchConfirmDataManager.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveTransactionToCouch(transaction: any[]) {
|
||||||
|
for (const t of transaction) {
|
||||||
|
await this.serviceData.saveTransactionToCouch(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrat
|
||||||
import { DetailTransactionManager } from './managers/detail-transaction.manager';
|
import { DetailTransactionManager } from './managers/detail-transaction.manager';
|
||||||
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
||||||
import { PriceCalculator } from './calculator/price.calculator';
|
import { PriceCalculator } from './calculator/price.calculator';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TransactionReadOrchestrator extends BaseReadOrchestrator<TransactionEntity> {
|
export class TransactionReadOrchestrator extends BaseReadOrchestrator<TransactionEntity> {
|
||||||
|
@ -26,6 +28,16 @@ export class TransactionReadOrchestrator extends BaseReadOrchestrator<Transactio
|
||||||
return this.indexManager.getResult();
|
return this.indexManager.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async summary(posId: string) {
|
||||||
|
const today = moment().format('YYYY-MM-DD');
|
||||||
|
const summary = await this.serviceData.getSummary(posId, today);
|
||||||
|
const lastTransaction = await this.serviceData.getLastTransactionByPos(
|
||||||
|
posId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return { summary, lastTransaction };
|
||||||
|
}
|
||||||
|
|
||||||
async detail(dataId: string): Promise<TransactionEntity> {
|
async detail(dataId: string): Promise<TransactionEntity> {
|
||||||
this.detailManager.setData(dataId);
|
this.detailManager.setData(dataId);
|
||||||
this.detailManager.setService(this.serviceData, TABLE_NAME.TRANSACTION);
|
this.detailManager.setService(this.serviceData, TABLE_NAME.TRANSACTION);
|
||||||
|
@ -50,17 +62,24 @@ export class TransactionReadOrchestrator extends BaseReadOrchestrator<Transactio
|
||||||
transaction.payment_total_dpp = price.dpp_value;
|
transaction.payment_total_dpp = price.dpp_value;
|
||||||
transaction.payment_total_share = price.other.total_profit_share;
|
transaction.payment_total_share = price.other.total_profit_share;
|
||||||
transaction.payment_total_tax = price.other.payment_total_tax;
|
transaction.payment_total_tax = price.other.payment_total_tax;
|
||||||
console.log({ price }, transaction.payment_total);
|
console.log(transaction.id);
|
||||||
|
await this.serviceData.getRepository().save(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ids = [];
|
||||||
|
|
||||||
async calculatePrice(): Promise<void> {
|
async calculatePrice(): Promise<void> {
|
||||||
const transactions = await this.serviceData.getManyByOptions({
|
const transactions = await this.serviceData.getManyByOptions({
|
||||||
where: {
|
where: {
|
||||||
is_recap_transaction: false,
|
// is_recap_transaction: false,
|
||||||
|
id: In(this.ids),
|
||||||
},
|
},
|
||||||
relations: ['items', 'items.bundling_items'],
|
relations: ['items', 'items.bundling_items'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(transactions.length);
|
||||||
|
// return;
|
||||||
|
|
||||||
for (const transaction of transactions) {
|
for (const transaction of transactions) {
|
||||||
try {
|
try {
|
||||||
const price = await this.calculator.calculate(transaction);
|
const price = await this.calculator.calculate(transaction);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
BadRequestException,
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
|
@ -7,17 +8,19 @@ import {
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Res,
|
Res,
|
||||||
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { TransactionDataOrchestrator } from '../domain/usecases/transaction-data.orchestrator';
|
import { TransactionDataOrchestrator } from '../domain/usecases/transaction-data.orchestrator';
|
||||||
import { TransactionDto } from './dto/transaction.dto';
|
import { TransactionDto } from './dto/transaction.dto';
|
||||||
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
|
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiBody, ApiTags } from '@nestjs/swagger';
|
||||||
import { TransactionEntity } from '../domain/entities/transaction.entity';
|
import { TransactionEntity } from '../domain/entities/transaction.entity';
|
||||||
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
|
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
|
||||||
import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto';
|
import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto';
|
||||||
import { Public } from 'src/core/guards';
|
import { Public } from 'src/core/guards';
|
||||||
import { DownloadPdfDto } from './dto/donwload-pdf.dto';
|
import { DownloadPdfDto } from './dto/donwload-pdf.dto';
|
||||||
|
import { OtpAuthGuard } from 'src/modules/configuration/otp-verification/infrastructure/guards/otp-auth-guard';
|
||||||
|
|
||||||
@ApiTags(`${MODULE_NAME.TRANSACTION.split('-').join(' ')} - data`)
|
@ApiTags(`${MODULE_NAME.TRANSACTION.split('-').join(' ')} - data`)
|
||||||
@Controller(`v1/${MODULE_NAME.TRANSACTION}`)
|
@Controller(`v1/${MODULE_NAME.TRANSACTION}`)
|
||||||
|
@ -91,4 +94,29 @@ export class TransactionDataController {
|
||||||
async delete(@Param('id') dataId: string): Promise<string> {
|
async delete(@Param('id') dataId: string): Promise<string> {
|
||||||
return await this.orchestrator.delete(dataId);
|
return await this.orchestrator.delete(dataId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('save-to-couch')
|
||||||
|
@ApiBody({
|
||||||
|
schema: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@Public(true)
|
||||||
|
@UseGuards(OtpAuthGuard)
|
||||||
|
async saveToCouch(@Body() body: any[]) {
|
||||||
|
try {
|
||||||
|
await this.orchestrator.saveTransactionToCouch(body);
|
||||||
|
return {
|
||||||
|
message: 'Success',
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
throw new BadRequestException({
|
||||||
|
message: error.message,
|
||||||
|
error: error.stack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,12 @@ export class TransactionReadController {
|
||||||
return await this.orchestrator.detail(id);
|
return await this.orchestrator.detail(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Public(true)
|
||||||
|
@Get('summary/:posId')
|
||||||
|
async summary(@Param('posId') posId: string) {
|
||||||
|
return await this.orchestrator.summary(posId);
|
||||||
|
}
|
||||||
|
|
||||||
@Public(true)
|
@Public(true)
|
||||||
@Get('dummy/:id')
|
@Get('dummy/:id')
|
||||||
async calculate(@Param('id') id: string): Promise<string> {
|
async calculate(@Param('id') id: string): Promise<string> {
|
||||||
|
|
|
@ -47,6 +47,9 @@ import { TransactionDemographyModel } from './data/models/transaction-demography
|
||||||
import { PriceCalculator } from './domain/usecases/calculator/price.calculator';
|
import { PriceCalculator } from './domain/usecases/calculator/price.calculator';
|
||||||
import { ItemModel } from 'src/modules/item-related/item/data/models/item.model';
|
import { ItemModel } from 'src/modules/item-related/item/data/models/item.model';
|
||||||
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
|
import { JWT_EXPIRED } from 'src/core/sessions/constants';
|
||||||
|
import { JWT_SECRET } from 'src/core/sessions/constants';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -56,6 +59,10 @@ import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
|
JwtModule.register({
|
||||||
|
secret: JWT_SECRET,
|
||||||
|
signOptions: { expiresIn: JWT_EXPIRED },
|
||||||
|
}),
|
||||||
TypeOrmModule.forFeature(
|
TypeOrmModule.forFeature(
|
||||||
[
|
[
|
||||||
TransactionModel,
|
TransactionModel,
|
||||||
|
|
Loading…
Reference in New Issue