mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
feat(server): sales by items table
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { query, ValidationChain } from 'express-validator';
|
||||
import moment from 'moment';
|
||||
import { query, ValidationChain, ValidationSchema } from 'express-validator';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||
import BaseFinancialReportController from './BaseFinancialReportController';
|
||||
import SalesByItemsReportService from '@/services/FinancialStatements/SalesByItems/SalesByItemsService';
|
||||
import { AbilitySubject, ReportsAction } from '@/interfaces';
|
||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
||||
import { SalesByItemsApplication } from '@/services/FinancialStatements/SalesByItems/SalesByItemsApplication';
|
||||
|
||||
@Service()
|
||||
export default class SalesByItemsReportController extends BaseFinancialReportController {
|
||||
@Inject()
|
||||
salesByItemsService: SalesByItemsReportService;
|
||||
salesByItemsApp: SalesByItemsApplication;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
@@ -32,6 +31,7 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon
|
||||
|
||||
/**
|
||||
* Validation schema.
|
||||
* @returns {ValidationChain[]}
|
||||
*/
|
||||
private get validationSchema(): ValidationChain[] {
|
||||
return [
|
||||
@@ -68,7 +68,6 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon
|
||||
) {
|
||||
const { tenantId } = req;
|
||||
const filter = this.matchedQueryData(req);
|
||||
|
||||
const accept = this.accepts(req);
|
||||
|
||||
const acceptType = accept.types([
|
||||
@@ -77,13 +76,33 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon
|
||||
ACCEPT_TYPE.APPLICATION_CSV,
|
||||
ACCEPT_TYPE.APPLICATION_XLSX,
|
||||
]);
|
||||
|
||||
// Retrieves the csv format.
|
||||
if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) {
|
||||
const buffer = await this.salesByItemsApp.csv(tenantId, filter);
|
||||
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=output.csv');
|
||||
res.setHeader('Content-Type', 'text/csv');
|
||||
|
||||
return res.send(buffer);
|
||||
// Retrieves the json table format.
|
||||
} else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) {
|
||||
const table = await this.salesByItemsApp.table(tenantId, filter);
|
||||
|
||||
return res.status(200).send(table);
|
||||
// Retrieves the xlsx format.
|
||||
} else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) {
|
||||
} else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) {
|
||||
const buffer = this.salesByItemsApp.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 {
|
||||
await this.salesByItemsService.salesByItems(tenantId, filter);
|
||||
return res.status(200).send({ meta, data, query });
|
||||
const sheet = await this.salesByItemsApp.sheet(tenantId, filter);
|
||||
return res.status(200).send(sheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export class SalesByItemsApplication {
|
||||
public sheet(tenantId: number, filter: ISalesByItemsReportQuery) {
|
||||
return this.salesByItemsSheet.salesByItems(tenantId, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the sales by items report in table format.
|
||||
* @param {number} tenantId
|
||||
@@ -33,6 +34,7 @@ export class SalesByItemsApplication {
|
||||
public table(tenantId: number, filter: ISalesByItemsReportQuery) {
|
||||
return this.salesByItemsTable.table(tenantId, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the sales by items report in csv format.
|
||||
* @param {number} tenantId
|
||||
@@ -42,6 +44,7 @@ export class SalesByItemsApplication {
|
||||
public csv(tenantId: number, filter: ISalesByItemsReportQuery) {
|
||||
return this.salesByItemsExport.csv(tenantId, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the sales by items report in xlsx format.
|
||||
* @param {number} tenantId
|
||||
|
||||
@@ -1,47 +1,72 @@
|
||||
import * as R from 'ramda';
|
||||
import { ISalesByItemsSheetStatement, ITableColumn, ITableData, ITableRow } from '@/interfaces';
|
||||
import {
|
||||
ISalesByItemsItem,
|
||||
ISalesByItemsSheetStatement,
|
||||
ISalesByItemsTotal,
|
||||
ITableColumn,
|
||||
ITableRow,
|
||||
} from '@/interfaces';
|
||||
import { tableRowMapper } from '@/utils';
|
||||
|
||||
export class SalesByItemsTable {
|
||||
private readonly data: ISalesByItemsSheetStatement;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {ISalesByItemsSheetStatement} data
|
||||
*/
|
||||
constructor(data: ISalesByItemsSheetStatement) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the common table accessors.
|
||||
* @returns {ITableColumn[]}
|
||||
*/
|
||||
private commonTableAccessors() {
|
||||
return [
|
||||
{ key: 'item_name', accessor: 'name' },
|
||||
{ key: 'quantity', accessor: 'quantitySoldFormatted' },
|
||||
{ key: 'sold', accessor: 'soldCostFormatted' },
|
||||
{ key: 'sold_quantity', accessor: 'quantitySoldFormatted' },
|
||||
{ key: 'sold_amount', accessor: 'soldCostFormatted' },
|
||||
{ key: 'average_price', accessor: 'averageSellPriceFormatted' },
|
||||
];
|
||||
}
|
||||
|
||||
private itemMap(item: any) {
|
||||
/**
|
||||
* Maps the given item node to table row.
|
||||
* @param {ISalesByItemsItem} item
|
||||
* @returns {ITableRow}
|
||||
*/
|
||||
private itemMap = (item: ISalesByItemsItem): ITableRow => {
|
||||
const columns = this.commonTableAccessors();
|
||||
const meta = {};
|
||||
|
||||
return tableRowMapper(item, columns, meta);
|
||||
}
|
||||
|
||||
private itemsMap(items: any[]) {
|
||||
return R.map(this.itemMap, items);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param total
|
||||
* @returns
|
||||
* Maps the given items nodes to table rows.
|
||||
* @param {ISalesByItemsItem[]} items
|
||||
* @returns {ITableRow[]}
|
||||
*/
|
||||
private totalMap(total: any) {
|
||||
private itemsMap = (items: ISalesByItemsItem[]): ITableRow[] => {
|
||||
return R.map(this.itemMap, items);
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps the given total node to table row.
|
||||
* @param {ISalesByItemsTotal} total
|
||||
* @returns {ITableRow[]}
|
||||
*/
|
||||
private totalMap = (total: ISalesByItemsTotal) => {
|
||||
const columns = this.commonTableAccessors();
|
||||
const meta = {};
|
||||
|
||||
return tableRowMapper(total, columns, meta);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves the table rows.
|
||||
* @returns {ITableRow[]}
|
||||
*/
|
||||
public tableData(): ITableRow[] {
|
||||
@@ -57,9 +82,10 @@ export class SalesByItemsTable {
|
||||
*/
|
||||
public tableColumns(): ITableColumn[] {
|
||||
return [
|
||||
{ key: 'item_name', label: 'Item Name' },
|
||||
{ key: 'quantity', label: 'Quantity' },
|
||||
{ key: 'sold_cost', label: 'Sold Cost' },
|
||||
{ key: 'item_name', label: 'Item name' },
|
||||
{ key: 'sold_quantity', label: 'Sold quantity' },
|
||||
{ key: 'sold_amount', label: 'Sold amount' },
|
||||
{ key: 'average_price', label: 'Average price' },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user