Skip to content

Commit

Permalink
Merge pull request #2722 from CAFECA-IO/feature/report
Browse files Browse the repository at this point in the history
Feature/ Mock report
  • Loading branch information
Luphia authored Oct 8, 2024
2 parents 877561e + 81b9a7a commit 92b4bf6
Show file tree
Hide file tree
Showing 13 changed files with 521 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "iSunFA",
"version": "0.8.2+34",
"version": "0.8.2+35",
"private": false,
"scripts": {
"dev": "next dev",
Expand Down
12 changes: 12 additions & 0 deletions src/constants/api_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export enum APIName {
JOURNAL_DELETE = 'JOURNAL_DELETE',
REPORT_LIST = 'REPORT_LIST',
REPORT_GET_BY_ID = 'REPORT_GET_BY_ID',
REPORT_GET_V2 = 'REPORT_GET_V2',
REPORT_GENERATE = 'REPORT_GENERATE',
STATUS_INFO_GET = 'STATUS_INFO_GET',
ACCOUNT_LIST = 'ACCOUNT_LIST',
Expand Down Expand Up @@ -156,6 +157,7 @@ export enum APIPath {
JOURNAL_DELETE = `${apiPrefix}/company/:companyId/journal/:journalId`,
REPORT_LIST = `${apiPrefix}/company/:companyId/report`,
REPORT_GET_BY_ID = `${apiPrefix}/company/:companyId/report/:reportId`,
REPORT_GET_V2 = `${apiPrefixV2}/company/:companyId/report`,
REPORT_GENERATE = `${apiPrefix}/company/:companyId/report`,
STATUS_INFO_GET = `${apiPrefix}/status_info`,
ACCOUNT_LIST = `${apiPrefix}/company/:companyId/account`,
Expand Down Expand Up @@ -522,4 +524,14 @@ export const APIConfig: Record<IAPIName, IAPIConfig> = {
method: HttpMethod.GET,
path: APIPath.CERTIFICATE_LIST,
}),

/**
* Info: (20241007 - Murky)
* Below is v2 API
*/
[APIName.REPORT_GET_V2]: createConfig({
name: APIName.REPORT_GET_V2,
method: HttpMethod.GET,
path: APIPath.REPORT_GET_V2,
}),
};
3 changes: 3 additions & 0 deletions src/constants/financial_report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ export const EMPTY_I_ACCOUNT_READY_FRONTEND: IAccountReadyForFrontend = {
curPeriodAmount: 0,
curPeriodAmountString: '0',
curPeriodPercentage: 0,
curPeriodPercentageString: '0',
prePeriodAmount: 0,
prePeriodAmountString: '0',
prePeriodPercentage: 0,
prePeriodPercentageString: '0',
indent: 0,
children: [],
};
3 changes: 3 additions & 0 deletions src/constants/zod_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ocrResultGetByIdValidator,
ocrUploadValidator,
} from '@/lib/utils/zod_schema/ocr';
import { reportGetValidatorV2 } from '@/lib/utils/zod_schema/report';
import {
voucherCreateValidator,
voucherDeleteValidatorV2,
Expand Down Expand Up @@ -77,4 +78,6 @@ export const API_ZOD_SCHEMA = {

[APIName.AI_ASK_V2]: askAIPostValidatorV2,
[APIName.AI_ASK_RESULT_V2]: askAIGetResultValidatorV2,

[APIName.REPORT_GET_V2]: reportGetValidatorV2,
};
3 changes: 3 additions & 0 deletions src/interfaces/accounting_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ export interface IAccountReadyForFrontend {
curPeriodAmount: number;
curPeriodAmountString: string;
curPeriodPercentage: number;
curPeriodPercentageString: string;
prePeriodAmount: number;
prePeriodAmountString: string;
prePeriodPercentage: number;
prePeriodPercentageString: string;
indent: number;
children: IAccountReadyForFrontend[];
}

export type IAccountQueryArgs = {
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/api_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type IAPIName =
| 'JOURNAL_DELETE'
| 'REPORT_LIST'
| 'REPORT_GET_BY_ID'
| 'REPORT_GET_V2'
| 'REPORT_GENERATE'
| 'STATUS_INFO_GET'
| 'ACCOUNT_LIST'
Expand Down
23 changes: 23 additions & 0 deletions src/lib/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,26 @@ export function generateUUID(): string {
const randomUUID = Math.random().toString(36).substring(2, 12);
return randomUUID;
}

/**
* Info: (20241007 - Murky)
* Return String version of number, comma will be added, add bracket if num is negative
* Return '-' if num is undefined, null or too small (-0.1~0.1)
* @param num - {number | null | undefined | string}
* number that be transform into string,
* if already string, than it will only be add comma than return
* @returns - {string} return number with comma and bracket
*/
export function numberBeDashIfFalsy(num: number | null | undefined | string) {
if (typeof num === 'string') {
return numberWithCommas(num);
}

if (num === null || num === undefined || (num < 0.1 && num > -0.1)) {
return '-';
}

const formattedNumber = numberWithCommas(Math.abs(num));

return num < 0 ? `(${formattedNumber})` : formattedNumber;
}
12 changes: 11 additions & 1 deletion src/lib/utils/report/financial_report_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import {
IFinancialReportInDB,
IncomeStatementOtherInfo,
} from '@/interfaces/report';
import { formatNumberSeparateByComma, getTimestampOfSameDateOfLastYear } from '@/lib/utils/common';
import {
formatNumberSeparateByComma,
getTimestampOfSameDateOfLastYear,
numberBeDashIfFalsy,
} from '@/lib/utils/common';

export default abstract class FinancialReportGenerator extends ReportGenerator {
protected lastPeriodStartDateInSecond: number;
Expand Down Expand Up @@ -166,16 +170,22 @@ export default abstract class FinancialReportGenerator extends ReportGenerator {
const prePeriodPercentage = lastPeriodAccount?.percentage
? Math.round(lastPeriodAccount.percentage * 100)
: 0;

const curPeriodPercentageString = numberBeDashIfFalsy(curPeriodPercentage);
const prePeriodPercentageString = numberBeDashIfFalsy(prePeriodPercentage);
const accountReadyForFrontend: IAccountReadyForFrontend = {
code: curPeriodAccount.code,
name: curPeriodAccount.name,
curPeriodAmount,
curPeriodPercentage,
curPeriodAmountString,
curPeriodPercentageString,
prePeriodAmount,
prePeriodPercentage,
prePeriodAmountString,
prePeriodPercentageString,
indent: curPeriodAccount.indent,
children: [],
};
curPeriodAccountReadyForFrontendArray.push(accountReadyForFrontend);
});
Expand Down
8 changes: 8 additions & 0 deletions src/lib/utils/zod_schema/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ export function zodTimestampInSeconds(canBeUndefined: boolean = false, defaultVa
.regex(/^\d+$/)
.transform((val) => timestampInSeconds(Number(val)));
}

export function zodTimestampInSecondsNoDefault() {
const setting = z
.string()
.regex(/^\d+$/)
.transform((val) => timestampInSeconds(Number(val)));
return setting;
}
21 changes: 21 additions & 0 deletions src/lib/utils/zod_schema/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { z } from 'zod';
import { IZodValidator } from '@/interfaces/zod_validator';
import { zodTimestampInSecondsNoDefault } from '@/lib/utils/zod_schema/common';
import { FinancialReportTypesKey } from '@/interfaces/report_type';

const reportGetQueryValidatorV2 = z.object({
startDate: zodTimestampInSecondsNoDefault(),
endDate: zodTimestampInSecondsNoDefault(),
language: z.string(),
reportType: z.nativeEnum(FinancialReportTypesKey),
});

const reportGetBodyValidatorV2 = z.object({});

export const reportGetValidatorV2: IZodValidator<
(typeof reportGetQueryValidatorV2)['shape'],
(typeof reportGetBodyValidatorV2)['shape']
> = {
query: reportGetQueryValidatorV2,
body: reportGetBodyValidatorV2,
};
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,13 @@ function transformDetailsIntoGeneral(
curPeriodAmount: 0,
curPeriodAmountString: '0',
curPeriodPercentage: 0,
curPeriodPercentageString: '0',
prePeriodAmount: 0,
prePeriodAmountString: '0',
prePeriodPercentage: 0,
prePeriodPercentageString: '0',
indent: account.indent,
children: [],
};
});
return general;
Expand Down
65 changes: 65 additions & 0 deletions src/pages/api/v2/company/[companyId]/report/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { handleGetRequest } from '@/pages/api/v2/company/[companyId]/report/index';
import { STATUS_MESSAGE } from '@/constants/status_code';

import { FinancialReportTypesKey } from '@/interfaces/report_type';

let req: jest.Mocked<NextApiRequest>;
let res: jest.Mocked<NextApiResponse>;

jest.mock('../../../../../../lib/utils/session.ts', () => ({
getSession: jest.fn().mockResolvedValue({
userId: 1001,
companyId: 1001,
}),
}));

jest.mock('../../../../../../lib/utils/auth_check', () => ({
checkAuthorization: jest.fn().mockResolvedValue(true),
}));

// Info: (20241007 - Murky) Uncomment this to check zod return
// jest.mock('../../../../../../lib/utils/logger_back', () => ({
// loggerRequest: jest.fn().mockReturnValue({
// info: jest.fn(),
// error: jest.fn(),
// }),
// }));

beforeEach(() => {
req = {
headers: {},
query: {},
method: '',
socket: {},
json: jest.fn(),
} as unknown as jest.Mocked<NextApiRequest>;

res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
} as unknown as jest.Mocked<NextApiResponse>;
});

afterEach(() => {
jest.clearAllMocks();
});

describe('company/[companyId]/certificate', () => {
describe('GET Certificate List', () => {
it('should match patter', async () => {
req.query = {
startDate: '10000000',
endDate: '16000000',
language: 'zh',
reportType: FinancialReportTypesKey.balance_sheet,
};
req.body = {};

const { payload, statusMessage } = await handleGetRequest(req, res);

expect(statusMessage).toBe(STATUS_MESSAGE.SUCCESS_GET);
expect(payload).toBeDefined();
});
});
});
Loading

0 comments on commit 92b4bf6

Please sign in to comment.