Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export general ledger & Journal to CSV and XLSX #303

Merged
merged 9 commits into from
Jan 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { Router, Request, Response, NextFunction } from 'express';
import { query, ValidationChain } from 'express-validator';
import { Inject, Service } from 'typedi';
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
import GeneralLedgerService from '@/services/FinancialStatements/GeneralLedger/GeneralLedgerService';
import BaseFinancialReportController from './BaseFinancialReportController';
import { AbilitySubject, ReportsAction } from '@/interfaces';
import CheckPolicies from '@/api/middleware/CheckPolicies';
import { ACCEPT_TYPE } from '@/interfaces/Http';
import { GeneralLedgerApplication } from '@/services/FinancialStatements/GeneralLedger/GeneralLedgerApplication';

@Service()
export default class GeneralLedgerReportController extends BaseFinancialReportController {
@Inject()
generalLedgetService: GeneralLedgerService;
private generalLedgerApplication: GeneralLedgerApplication;

/**
* Router constructor.
Expand Down Expand Up @@ -61,20 +62,43 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo
* @param {Response} res -
*/
async generalLedger(req: Request, res: Response, next: NextFunction) {
const { tenantId, settings } = req;
const { tenantId } = req;
const filter = this.matchedQueryData(req);
const accept = this.accepts(req);

try {
const { data, query, meta } =
await this.generalLedgetService.generalLedger(tenantId, filter);

return res.status(200).send({
meta: this.transfromToResponse(meta),
data: this.transfromToResponse(data),
query: this.transfromToResponse(query),
});
} catch (error) {
next(error);
const acceptType = accept.types([
ACCEPT_TYPE.APPLICATION_JSON,
ACCEPT_TYPE.APPLICATION_JSON_TABLE,
ACCEPT_TYPE.APPLICATION_XLSX,
ACCEPT_TYPE.APPLICATION_CSV,
]);
// Retrieves the table format.
if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) {
const table = await this.generalLedgerApplication.table(tenantId, filter);

return res.status(200).send(table);
// Retrieves the csv format.
} else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) {
const buffer = await this.generalLedgerApplication.csv(tenantId, filter);

res.setHeader('Content-Disposition', 'attachment; filename=output.csv');
res.setHeader('Content-Type', 'text/csv');

return res.send(buffer);
// Retrieves the xlsx format.
} else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) {
const buffer = await this.generalLedgerApplication.xlsx(tenantId, filter);

res.setHeader('Content-Disposition', 'attachment; filename=output.xlsx');
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
);
return res.send(buffer);
// Retrieves the json format.
} else {
const sheet = await this.generalLedgerApplication.sheet(tenantId, filter);
return res.status(200).send(sheet);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { Request, Response, Router, NextFunction } from 'express';
import { castArray } from 'lodash';
import { query, oneOf } from 'express-validator';
import BaseFinancialReportController from './BaseFinancialReportController';
import JournalSheetService from '@/services/FinancialStatements/JournalSheet/JournalSheetService';
import { AbilitySubject, ReportsAction } from '@/interfaces';
import CheckPolicies from '@/api/middleware/CheckPolicies';
import { ACCEPT_TYPE } from '@/interfaces/Http';
import { JournalSheetApplication } from '@/services/FinancialStatements/JournalSheet/JournalSheetApplication';

@Service()
export default class JournalSheetController extends BaseFinancialReportController {
@Inject()
journalService: JournalSheetService;
private journalSheetApp: JournalSheetApplication;

/**
* Router constructor.
Expand Down Expand Up @@ -57,28 +58,49 @@ export default class JournalSheetController extends BaseFinancialReportControlle
* @param {Request} req -
* @param {Response} res -
*/
async journal(req: Request, res: Response, next: NextFunction) {
const { tenantId, settings } = req;
private async journal(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
let filter = this.matchedQueryData(req);

filter = {
...filter,
accountsIds: castArray(filter.accountsIds),
};
const accept = this.accepts(req);
const acceptType = accept.types([
ACCEPT_TYPE.APPLICATION_JSON,
ACCEPT_TYPE.APPLICATION_JSON_TABLE,
ACCEPT_TYPE.APPLICATION_XLSX,
ACCEPT_TYPE.APPLICATION_CSV,
]);

try {
const { data, query, meta } = await this.journalService.journalSheet(
tenantId,
filter
// Retrieves the json table format.
if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) {
const table = await this.journalSheetApp.table(tenantId, filter);
return res.status(200).send(table);
// Retrieves the csv format.
} else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) {
const buffer = await this.journalSheetApp.csv(tenantId, filter);

res.setHeader('Content-Disposition', 'attachment; filename=output.csv');
res.setHeader('Content-Type', 'text/csv');

return res.send(buffer);
// Retrieves the xlsx format.
} else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) {
const buffer = await this.journalSheetApp.xlsx(tenantId, filter);

res.setHeader('Content-Disposition', 'attachment; filename=output.xlsx');
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
);
return res.send(buffer);
// Retrieves the json format.
} else {
const sheet = await this.journalSheetApp.sheet(tenantId, filter);

return res.status(200).send({
data: this.transfromToResponse(data),
query: this.transfromToResponse(query),
meta: this.transfromToResponse(meta),
});
} catch (error) {
next(error);
return res.status(200).send(sheet);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,6 @@ export default class PaymentReceivesController extends BaseController {
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns
*/
public sendPaymentReceiveByMail = async (
req: Request,
Expand All @@ -546,6 +545,7 @@ export default class PaymentReceivesController extends BaseController {
includeOptionals: false,
}
);

try {
await this.paymentReceiveApplication.notifyPaymentByMail(
tenantId,
Expand Down
13 changes: 12 additions & 1 deletion packages/server/src/interfaces/GeneralLedgerSheet.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IFinancialTable } from "./Table";


export interface IGeneralLedgerSheetQuery {
Expand Down Expand Up @@ -36,6 +37,7 @@ export interface IGeneralLedgerSheetAccountTransaction {
referenceType?: string,

date: Date|string,
dateFormatted: string;
};

export interface IGeneralLedgerSheetAccountBalance {
Expand All @@ -56,6 +58,8 @@ export interface IGeneralLedgerSheetAccount {
closingBalance: IGeneralLedgerSheetAccountBalance,
}

export type IGeneralLedgerSheetData = IGeneralLedgerSheetAccount[];

export interface IAccountTransaction {
id: number,
index: number,
Expand All @@ -78,4 +82,11 @@ export interface IGeneralLedgerMeta {
isCostComputeRunning: boolean,
organizationName: string,
baseCurrency: string,
};
fromDate: string;
toDate: string;
};

export interface IGeneralLedgerTableData extends IFinancialTable {
meta: IGeneralLedgerMeta;
query: IGeneralLedgerSheetQuery;
}
62 changes: 39 additions & 23 deletions packages/server/src/interfaces/JournalReport.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,52 @@
import { IJournalEntry } from './Journal';
import { IFinancialTable } from './Table';

export interface IJournalReportQuery {
fromDate: Date | string,
toDate: Date | string,
fromDate: Date | string;
toDate: Date | string;
numberFormat: {
noCents: boolean,
divideOn1000: boolean,
},
transactionType: string,
transactionId: string,

accountsIds: number | number[],
fromRange: number,
toRange: number,
noCents: boolean;
divideOn1000: boolean;
};
transactionType: string;
transactionId: string;

accountsIds: number | number[];
fromRange: number;
toRange: number;
}

export interface IJournalReportEntriesGroup {
id: string,
entries: IJournalEntry[],
currencyCode: string,
credit: number,
debit: number,
formattedCredit: string,
formattedDebit: string,
id: string;
date: Date;
dateFormatted: string;
entries: IJournalEntry[];
currencyCode: string;
credit: number;
debit: number;
formattedCredit: string;
formattedDebit: string;
}

export interface IJournalReport {
entries: IJournalReportEntriesGroup[],
entries: IJournalReportEntriesGroup[];
}

export interface IJournalSheetMeta {
isCostComputeRunning: boolean,
organizationName: string,
baseCurrency: string,
}
isCostComputeRunning: boolean;
organizationName: string;
baseCurrency: string;
}

export interface IJournalTable extends IFinancialTable {
query: IJournalReportQuery;
meta: IJournalSheetMeta;
}

export type IJournalTableData = IJournalReportEntriesGroup[];

export interface IJournalSheet {
data: IJournalTableData;
query: IJournalReportQuery;
meta: IJournalSheetMeta;
}
3 changes: 3 additions & 0 deletions packages/server/src/models/Contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Model } from 'objection';
import TenantModel from 'models/TenantModel';

export default class Contact extends TenantModel {
email: string;
displayName: string;

/**
* Table name
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
IContact,
} from '@/interfaces';
import FinancialSheet from '../FinancialSheet';
import moment from 'moment';

/**
* General ledger sheet.
Expand Down Expand Up @@ -88,8 +89,10 @@ export default class GeneralLedgerSheet extends FinancialSheet {

const newEntry = {
date: entry.date,
dateFormatted: moment(entry.date).format('YYYY MMM DD'),
entryId: entry.id,

transactionNumber: entry.transactionNumber,
referenceType: entry.referenceType,
referenceId: entry.referenceId,
referenceTypeFormatted: this.i18n.__(entry.referenceTypeFormatted),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Inject } from 'typedi';
import {
IGeneralLedgerSheetQuery,
IGeneralLedgerTableData,
} from '@/interfaces';
import { GeneralLedgerTableInjectable } from './GeneralLedgerTableInjectable';
import { GeneralLedgerExportInjectable } from './GeneralLedgerExport';
import { GeneralLedgerService } from './GeneralLedgerService';

export class GeneralLedgerApplication {
@Inject()
private GLTable: GeneralLedgerTableInjectable;

@Inject()
private GLExport: GeneralLedgerExportInjectable;

@Inject()
private GLSheet: GeneralLedgerService;

/**
* Retrieves the G/L sheet in json format.
* @param {number} tenantId
* @param {IGeneralLedgerSheetQuery} query
*/
public sheet(tenantId: number, query: IGeneralLedgerSheetQuery) {
return this.GLSheet.generalLedger(tenantId, query);
}

/**
* Retrieves the G/L sheet in table format.
* @param {number} tenantId
* @param {IGeneralLedgerSheetQuery} query
* @returns {Promise<IGeneralLedgerTableData>}
*/
public table(
tenantId: number,
query: IGeneralLedgerSheetQuery
): Promise<IGeneralLedgerTableData> {
return this.GLTable.table(tenantId, query);
}

/**
* Retrieves the G/L sheet in xlsx format.
* @param {number} tenantId
* @param {IGeneralLedgerSheetQuery} query
* @returns {}
*/
public xlsx(
tenantId: number,
query: IGeneralLedgerSheetQuery
): Promise<Buffer> {
return this.GLExport.xlsx(tenantId, query);
}

/**
* Retrieves the G/L sheet in csv format.
* @param {number} tenantId -
* @param {IGeneralLedgerSheetQuery} query -
*/
public csv(
tenantId: number,
query: IGeneralLedgerSheetQuery
): Promise<string> {
return this.GLExport.csv(tenantId, query);
}
}
Loading
Loading