Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/backend/fixtures/lambda/report.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"program": "SBC",
"locations": [10],
"locations": [],
"period": {
"from": "2023-01-10",
"to": "2023-01-31"
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './database/database.module';
import { DepositModule } from './deposits/deposit.module';
import { ExcelexportModule } from './excelexport/excelexport.module';
import { ExcelExportModule } from './excelexport/excelexport.module';
import { ExceptionModule } from './exception/exception.module';
import { LocationModule } from './location/location.module';
import { LoggerModule } from './logger/logger.module';
Expand All @@ -27,7 +27,7 @@ import { TransactionModule } from './transaction/transaction.module';
ParseModule,
LocationModule,
ExceptionModule,
ExcelexportModule,
ExcelExportModule,
ReportingModule,
ConfigModule.forRoot({
ignoreEnvFile:
Expand Down
8 changes: 4 additions & 4 deletions apps/backend/src/excelexport/excelexport.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Logger, Module } from '@nestjs/common';
import { ExcelexportService } from './excelexport.service';
import { ExcelExportService } from './excelexport.service';
import { S3ManagerService } from '../s3-manager/s3-manager.service';

@Module({
providers: [ExcelexportService, S3ManagerService, Logger],
exports: [ExcelexportService]
providers: [ExcelExportService, S3ManagerService, Logger],
exports: [ExcelExportService]
})
export class ExcelexportModule {}
export class ExcelExportModule {}
53 changes: 47 additions & 6 deletions apps/backend/src/excelexport/excelexport.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { format } from 'date-fns';
import * as Excel from 'exceljs';
import * as path from 'path';
import { Stream } from 'stream';
import { AppLogger } from '../logger/logger.service';
import { S3ManagerService } from '../s3-manager/s3-manager.service';
@Injectable()
export class ExcelexportService {
export class ExcelExportService {
private workbook: Excel.Workbook;

constructor(
Expand Down Expand Up @@ -53,20 +54,60 @@ export class ExcelexportService {
}
}

public generateWorkbook(title: string): void {
this.workbook.title = title;
this.workbook.created = new Date(format(new Date(), 'yyyy, MM, dd'));
}

public addSheet(name: string): void {
this.workbook.addWorksheet(name);
}

/* eslint-disable */
public addHeader(sheetName: string, style: any): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addHeaderToRow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header is added to the sheet here ie:
Screenshot 2023-03-16 at 11 10 29 AM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved?

const sheet = this.workbook.getWorksheet(sheetName);
sheet.insertRow(1, []);
const row = sheet.getRow(1);
row.addPageBreak();
row.getCell('E').value = sheetName;
row.getCell('E').style = style;
row.height = 20;
sheet.getRow(2).addPageBreak();
}

/*eslint-disable @typescript-eslint/no-unused-vars*/
public addCellStyle(
sheetName: string,
rowNumber: number,
style: Partial<Excel.Style>
): void {
const sheet = this.workbook.getWorksheet(sheetName);

const row = sheet.getRow(rowNumber);
row.eachCell((cell, _colNumber) => {
sheet.getCell(cell.address).style = style;
});
}

/*eslint-disable @typescript-eslint/no-explicit-any*/
public addRow(sheetName: string, rowData: any[]): void {
public addRows(sheetName: string, rowData: any[], startIndex: number): void {
const sheet = this.workbook.getWorksheet(sheetName);
sheet.addRow(rowData);

rowData.forEach((row, index) => {
sheet.insertRow(index + startIndex, row.values);
sheet.getRow(index + startIndex).commit();
if (row.style) {
this.addCellStyle(sheetName, index + startIndex, row.style);
}
});

sheet.spliceRows(1, 0, new Array(3));
}

/*eslint-disable @typescript-eslint/no-explicit-any*/
public addColumn(sheetName: string, columnData: any[]): void {
public addColumns(sheetName: string, columnData: any[], style?: any): void {
const sheet = this.workbook.getWorksheet(sheetName);
sheet.columns.push({ header: 'New Column', key: 'newColumn', width: 20 });
sheet.getColumn('newColumn').values = columnData;
sheet.columns = columnData;
sheet.columns.forEach((column) => (column.width = 20));
}
}
9 changes: 4 additions & 5 deletions apps/backend/src/lambdas/reconcile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ export const handler = async (
appLogger.log({ event });
appLogger.log({ context });

// TODO [CCFPCM-410] verify criteria for handling $0.00 amounts
// appLogger.log(`Soft Removing Zero Dollar Payments`);
// await paymentService.softRemoveZeroDollarPayments();

const locations =
event.location_ids.length === 0
? await locationService.getLocationsBySource(event.program)
: await locationService.getLocationsByID(event);
: await locationService.getLocationsByID(
event.program,
event.location_ids
);

appLogger.log(`=========================================================`);
appLogger.log(`Found ${locations.length} Locations`);
Expand Down
2 changes: 2 additions & 0 deletions apps/backend/src/lambdas/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { ReportingService } from '../reporting/reporting.service';
export const handler = async (event: ReportConfig, context?: Context) => {
const app = await NestFactory.createApplicationContext(AppModule);
const reportingService = app.get(ReportingService);

const appLogger = app.get(AppLogger);
appLogger.log({ context });
await reportingService.generateReport(event);
await reportingService.generateDailySummary(event);
};
9 changes: 5 additions & 4 deletions apps/backend/src/location/location.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { In, Repository, Not } from 'typeorm';
import { LocationEnum } from './const';
import { LocationEntity } from './entities/master-location-data.entity';
import { Ministries } from '../constants';
import { ReconciliationEventInput } from '../reconciliation/types';

@Injectable()
export class LocationService {
Expand Down Expand Up @@ -32,17 +31,19 @@ export class LocationService {
}

public async getLocationsByID(
event: ReconciliationEventInput
program: Ministries,
location_ids: number[]
): Promise<LocationEntity[]> {
return await this.locationRepo.find({
select: {
location_id: true,
pt_location_id: true,
description: true
},
where: {
source_id: event.program,
source_id: program,
method: `${LocationEnum.Bank}`,
location_id: In(event.location_ids)
location_id: In(location_ids)
},
order: {
location_id: 'ASC'
Expand Down
10 changes: 10 additions & 0 deletions apps/backend/src/reporting/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const dailySummaryColumns = [
{ header: 'Program', key: 'program' },
{ header: 'Date', key: 'date' },
{ header: 'Location ID', key: 'location_id' },
{ header: 'Location', key: 'location_name' },
{ header: 'Total Payments', key: 'total_payments' },
{ header: 'Total Unmatched', key: 'total_unmatched_payments' },
{ header: '% Unmatched', key: 'percent_unmatched' },
{ header: 'Sum Of Payments', key: 'total_sum' }
];
15 changes: 15 additions & 0 deletions apps/backend/src/reporting/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as Excel from 'exceljs';
import { Ministries } from '../constants';

export interface ReportConfig {
Expand All @@ -13,3 +14,17 @@ export interface ReportConfig {
};
reports: boolean;
}

export interface DailySummary {
values: {
program: string;
date: string;
location_id: number;
location_name: string;
total_payments: number;
total_unmatched_payments: number;
percent_unmatched: number;
total_sum: number;
};
style: Partial<Excel.Style>;
}
9 changes: 7 additions & 2 deletions apps/backend/src/reporting/reporting.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Logger, Module } from '@nestjs/common';
import { ReportingService } from './reporting.service';
import { DepositModule } from '../deposits/deposit.module';
import { ExcelexportModule } from '../excelexport/excelexport.module';
import { ExcelExportModule } from '../excelexport/excelexport.module';
import { LocationModule } from '../location/location.module';
import { TransactionModule } from '../transaction/transaction.module';

@Module({
imports: [DepositModule, TransactionModule, LocationModule, ExcelexportModule],
imports: [
DepositModule,
TransactionModule,
LocationModule,
ExcelExportModule
],
providers: [ReportingService, Logger],
exports: [ReportingService]
})
Expand Down
102 changes: 97 additions & 5 deletions apps/backend/src/reporting/reporting.service.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,124 @@
import { Inject, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import format from 'date-fns/format';
import { Repository } from 'typeorm';
import { ReportConfig } from './interfaces';
import { dailySummaryColumns } from './const';
import { DailySummary, ReportConfig } from './interfaces';
import { columnStyle, rowStyle, headerStyle } from './styles';
import { Ministries } from '../constants';
import { CashDepositEntity } from '../deposits/entities/cash-deposit.entity';
import { POSDepositEntity } from '../deposits/entities/pos-deposit.entity';
import { ExcelexportService } from '../excelexport/excelexport.service';
import { ExcelExportService } from '../excelexport/excelexport.service';
import { LocationEntity } from '../location/entities';
import { LocationService } from '../location/location.service';
import { AppLogger } from '../logger/logger.service';
import { PaymentEntity } from '../transaction/entities';
import { PaymentService } from '../transaction/payment.service';

export class ReportingService {
constructor(
@Inject(Logger) private readonly appLogger: AppLogger,
@InjectRepository(POSDepositEntity)
private posDepositRepo: Repository<POSDepositEntity>,
@Inject(LocationService)
private locationService: LocationService,
@InjectRepository(CashDepositEntity)
private cashDepositRepo: Repository<CashDepositEntity>,
@Inject(PaymentService)
private paymentService: PaymentService,
@InjectRepository(PaymentEntity)
private paymentRepo: Repository<PaymentEntity>,
@Inject(ExcelexportService)
private excelWorkbook: ExcelexportService
@Inject(ExcelExportService)
private excelWorkbook: ExcelExportService
) {}

async generateReport(config: ReportConfig) {
this.appLogger.log(config);
this.appLogger.log('Generating report');
this.excelWorkbook.addSheet('Summary');
await this.excelWorkbook.saveS3('test');
}

async generateDailySummary(config: ReportConfig) {
this.appLogger.log(config);
this.appLogger.log('Generating Daily Summary Report');

const locations = await this.locationService.getLocationsBySource(
config.program
);

const dailySummaryReport = await Promise.all(
locations.map(
async (location: LocationEntity) =>
await this.dailyReportPaymentInfo(
format(new Date(config.period.from), 'yyyy-MM-dd'),
location,
config.program
)
)
);

const rowStartIndex = 4;
const colStartIndex = 3;

this.excelWorkbook.generateWorkbook('Reconciliation Report');
this.excelWorkbook.addSheet('Daily Summary');
this.excelWorkbook.addColumns('Daily Summary', dailySummaryColumns);
this.excelWorkbook.addRows(
'Daily Summary',
dailySummaryReport,
rowStartIndex
);
this.excelWorkbook.addHeader('Daily Summary', headerStyle);
/* set column-headers style */
this.excelWorkbook.addCellStyle(
'Daily Summary',
colStartIndex,
columnStyle
);

await this.excelWorkbook.saveLocal();
await this.excelWorkbook.saveS3('Reconciliation Report');
}

async dailyReportPaymentInfo(
date: string,
location: LocationEntity,
program: Ministries
): Promise<DailySummary> {
const payments = await this.paymentService.findPaymentsWithPartialSelect(
location,
date
);
const exceptions = payments.filter(
(itm: PaymentEntity) => itm.status === 'EXCEPTION'
).length;

const total = payments.length;

const unmatchedPercentage =
total != 0 ? parseFloat(((exceptions / total) * 100).toFixed(2)) : 0;

/*eslint-disable */
const totalSum = payments.reduce(
(acc: number, itm: PaymentEntity) => (acc += itm.amount),
0
);

return {
values: {
program,
date,
location_id: location.location_id,
location_name: location.description,
total_payments: total,
total_unmatched_payments: exceptions,
percent_unmatched: unmatchedPercentage,
total_sum: parseFloat(totalSum.toFixed(2))
},
style: rowStyle(exceptions !== 0)
};
}

async reportPosMatchSummaryByDate(): Promise<unknown> {
const results = await this.posDepositRepo.manager.query(`
SELECT
Expand Down
Loading