mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 05:40:31 +00:00
feat: export purchases by items to csv/xlsx (#327)
This commit is contained in:
@@ -3,8 +3,10 @@ import {
|
||||
IAccount,
|
||||
IAccountCreateDTO,
|
||||
IAccountEditDTO,
|
||||
IAccountResponse,
|
||||
IAccountsFilter,
|
||||
IAccountsTransactionsFilter,
|
||||
IFilterMeta,
|
||||
IGetAccountTransactionPOJO,
|
||||
} from '@/interfaces';
|
||||
import { CreateAccount } from './CreateAccount';
|
||||
@@ -14,6 +16,7 @@ import { ActivateAccount } from './ActivateAccount';
|
||||
import { GetAccounts } from './GetAccounts';
|
||||
import { GetAccount } from './GetAccount';
|
||||
import { GetAccountTransactions } from './GetAccountTransactions';
|
||||
|
||||
@Service()
|
||||
export class AccountsApplication {
|
||||
@Inject()
|
||||
@@ -113,19 +116,22 @@ export class AccountsApplication {
|
||||
|
||||
/**
|
||||
* Retrieves the accounts list.
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsFilter} filterDTO
|
||||
* @returns
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsFilter} filterDTO
|
||||
* @returns {Promise<{ accounts: IAccountResponse[]; filterMeta: IFilterMeta }>}
|
||||
*/
|
||||
public getAccounts = (tenantId: number, filterDTO: IAccountsFilter) => {
|
||||
public getAccounts = (
|
||||
tenantId: number,
|
||||
filterDTO: IAccountsFilter
|
||||
): Promise<{ accounts: IAccountResponse[]; filterMeta: IFilterMeta }> => {
|
||||
return this.getAccountsService.getAccountsList(tenantId, filterDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the given account transactions.
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsTransactionsFilter} filter
|
||||
* @returns {Promise<IGetAccountTransactionPOJO[]>}
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsTransactionsFilter} filter
|
||||
* @returns {Promise<IGetAccountTransactionPOJO[]>}
|
||||
*/
|
||||
public getAccountsTransactions = (
|
||||
tenantId: number,
|
||||
|
||||
@@ -2,36 +2,34 @@ import { get, isEmpty, sumBy } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import FinancialSheet from '../FinancialSheet';
|
||||
import { allPassedConditionsPass, transformToMap } from 'utils';
|
||||
import { IAccountTransaction, IItem } from '@/interfaces';
|
||||
import {
|
||||
IAccountTransaction,
|
||||
IInventoryValuationTotal,
|
||||
IInventoryValuationItem,
|
||||
IInventoryValuationReportQuery,
|
||||
IInventoryValuationStatement,
|
||||
IItem,
|
||||
} from '@/interfaces';
|
||||
IPurchasesByItemsItem,
|
||||
IPurchasesByItemsReportQuery,
|
||||
IPurchasesByItemsSheetData,
|
||||
IPurchasesByItemsTotal,
|
||||
} from '@/interfaces/PurchasesByItemsSheet';
|
||||
|
||||
export default class InventoryValuationReport extends FinancialSheet {
|
||||
export class PurchasesByItems extends FinancialSheet {
|
||||
readonly baseCurrency: string;
|
||||
readonly items: IItem[];
|
||||
readonly itemsTransactions: Map<number, IAccountTransaction>;
|
||||
readonly query: IInventoryValuationReportQuery;
|
||||
readonly query: IPurchasesByItemsReportQuery;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {IInventoryValuationReportQuery} query
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @param {IItem[]} items
|
||||
* @param {IAccountTransaction[]} itemsTransactions
|
||||
* @param {string} baseCurrency
|
||||
*/
|
||||
constructor(
|
||||
query: IInventoryValuationReportQuery,
|
||||
query: IPurchasesByItemsReportQuery,
|
||||
items: IItem[],
|
||||
itemsTransactions: IAccountTransaction[],
|
||||
baseCurrency: string
|
||||
) {
|
||||
super();
|
||||
|
||||
this.baseCurrency = baseCurrency;
|
||||
this.items = items;
|
||||
this.itemsTransactions = transformToMap(itemsTransactions, 'itemId');
|
||||
@@ -98,7 +96,7 @@ export default class InventoryValuationReport extends FinancialSheet {
|
||||
* @param {IInventoryValuationItem} item
|
||||
* @returns
|
||||
*/
|
||||
private itemSectionMapper = (item: IItem): IInventoryValuationItem => {
|
||||
private itemSectionMapper = (item: IItem): IPurchasesByItemsItem => {
|
||||
const meta = this.getItemTransaction(item.id);
|
||||
|
||||
return {
|
||||
@@ -145,9 +143,9 @@ export default class InventoryValuationReport extends FinancialSheet {
|
||||
|
||||
/**
|
||||
* Retrieve the items sections.
|
||||
* @returns {IInventoryValuationItem[]}
|
||||
* @returns {IPurchasesByItemsItem[]}
|
||||
*/
|
||||
private itemsSection = (): IInventoryValuationItem[] => {
|
||||
private itemsSection = (): IPurchasesByItemsItem[] => {
|
||||
return R.compose(
|
||||
R.when(this.isItemsPostFilter, this.itemsFilter),
|
||||
this.itemsMapper
|
||||
@@ -156,10 +154,10 @@ export default class InventoryValuationReport extends FinancialSheet {
|
||||
|
||||
/**
|
||||
* Retrieve the total section of the sheet.
|
||||
* @param {IInventoryValuationItem[]} items
|
||||
* @returns {IInventoryValuationTotal}
|
||||
* @param {IPurchasesByItemsItem[]} items
|
||||
* @returns {IPurchasesByItemsTotal}
|
||||
*/
|
||||
totalSection(items: IInventoryValuationItem[]): IInventoryValuationTotal {
|
||||
private totalSection(items: IPurchasesByItemsItem[]): IPurchasesByItemsTotal {
|
||||
const quantityPurchased = sumBy(items, (item) => item.quantityPurchased);
|
||||
const purchaseCost = sumBy(items, (item) => item.purchaseCost);
|
||||
|
||||
@@ -176,12 +174,12 @@ export default class InventoryValuationReport extends FinancialSheet {
|
||||
|
||||
/**
|
||||
* Retrieve the sheet data.
|
||||
* @returns
|
||||
* @returns {IInventoryValuationStatement}
|
||||
*/
|
||||
reportData(): IInventoryValuationStatement {
|
||||
public reportData(): IPurchasesByItemsSheetData {
|
||||
const items = this.itemsSection();
|
||||
const total = this.totalSection(items);
|
||||
|
||||
return items.length > 0 ? { items, total } : {};
|
||||
return { items, total };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { PurchasesByItemsExport } from './PurchasesByItemsExport';
|
||||
import {
|
||||
IPurchasesByItemsReportQuery,
|
||||
IPurchasesByItemsSheet,
|
||||
IPurchasesByItemsTable,
|
||||
} from '@/interfaces/PurchasesByItemsSheet';
|
||||
import { PurchasesByItemsTableInjectable } from './PurchasesByItemsTableInjectable';
|
||||
import { PurchasesByItemsService } from './PurchasesByItemsService';
|
||||
|
||||
@Service()
|
||||
export class PurcahsesByItemsApplication {
|
||||
@Inject()
|
||||
private purchasesByItemsSheet: PurchasesByItemsService;
|
||||
|
||||
@Inject()
|
||||
private purchasesByItemsTable: PurchasesByItemsTableInjectable;
|
||||
|
||||
@Inject()
|
||||
private purchasesByItemsExport: PurchasesByItemsExport;
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items in json format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns
|
||||
*/
|
||||
public sheet(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<IPurchasesByItemsSheet> {
|
||||
return this.purchasesByItemsSheet.purchasesByItems(tenantId, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items in table format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns {Promise<IPurchasesByItemsTable>}
|
||||
*/
|
||||
public table(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<IPurchasesByItemsTable> {
|
||||
return this.purchasesByItemsTable.table(tenantId, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items in csv format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
public csv(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<string> {
|
||||
return this.purchasesByItemsExport.csv(tenantId, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items in xlsx format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public xlsx(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<Buffer> {
|
||||
return this.purchasesByItemsExport.xlsx(tenantId, query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { TableSheet } from '@/lib/Xlsx/TableSheet';
|
||||
import { PurchasesByItemsTableInjectable } from './PurchasesByItemsTableInjectable';
|
||||
import { IPurchasesByItemsReportQuery } from '@/interfaces/PurchasesByItemsSheet';
|
||||
|
||||
@Service()
|
||||
export class PurchasesByItemsExport {
|
||||
@Inject()
|
||||
private purchasesByItemsTable: PurchasesByItemsTableInjectable;
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items sheet in XLSX format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public async xlsx(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<Buffer> {
|
||||
const table = await this.purchasesByItemsTable.table(tenantId, query);
|
||||
|
||||
const tableSheet = new TableSheet(table.table);
|
||||
const tableCsv = tableSheet.convertToXLSX();
|
||||
|
||||
return tableSheet.convertToBuffer(tableCsv, 'xlsx');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items sheet in CSV format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public async csv(
|
||||
tenantId: number,
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<string> {
|
||||
const table = await this.purchasesByItemsTable.table(tenantId, query);
|
||||
|
||||
const tableSheet = new TableSheet(table.table);
|
||||
const tableCsv = tableSheet.convertToCSV();
|
||||
|
||||
return tableCsv;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
IInventoryValuationReportQuery,
|
||||
IInventoryValuationStatement,
|
||||
IInventoryValuationSheetMeta,
|
||||
} from '@/interfaces';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import PurchasesByItems from './PurchasesByItems';
|
||||
import { PurchasesByItems } from './PurchasesByItems';
|
||||
import { Tenant } from '@/system/models';
|
||||
import {
|
||||
IPurchasesByItemsReportQuery,
|
||||
IPurchasesByItemsSheet,
|
||||
IPurchasesByItemsSheetMeta,
|
||||
} from '@/interfaces/PurchasesByItemsSheet';
|
||||
|
||||
@Service()
|
||||
export default class InventoryValuationReportService {
|
||||
export class PurchasesByItemsService {
|
||||
@Inject()
|
||||
private tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Defaults balance sheet filter query.
|
||||
* @return {IBalanceSheetQuery}
|
||||
* Defaults purchases by items filter query.
|
||||
* @return {IPurchasesByItemsReportQuery}
|
||||
*/
|
||||
get defaultQuery(): IInventoryValuationReportQuery {
|
||||
get defaultQuery(): IPurchasesByItemsReportQuery {
|
||||
return {
|
||||
fromDate: moment().startOf('month').format('YYYY-MM-DD'),
|
||||
toDate: moment().format('YYYY-MM-DD'),
|
||||
@@ -40,7 +40,7 @@ export default class InventoryValuationReportService {
|
||||
* @param {number} tenantId -
|
||||
* @returns {IBalanceSheetMeta}
|
||||
*/
|
||||
reportMetadata(tenantId: number): IInventoryValuationSheetMeta {
|
||||
reportMetadata(tenantId: number): IPurchasesByItemsSheetMeta {
|
||||
const settings = this.tenancy.settings(tenantId);
|
||||
|
||||
const organizationName = settings.get({
|
||||
@@ -62,18 +62,13 @@ export default class InventoryValuationReportService {
|
||||
* Retrieve balance sheet statement.
|
||||
* -------------
|
||||
* @param {number} tenantId
|
||||
* @param {IBalanceSheetQuery} query
|
||||
*
|
||||
* @return {IBalanceSheetStatement}
|
||||
* @param {IPurchasesByItemsReportQuery} query
|
||||
* @return {Promise<IPurchasesByItemsSheet>}
|
||||
*/
|
||||
public async purchasesByItems(
|
||||
tenantId: number,
|
||||
query: IInventoryValuationReportQuery
|
||||
): Promise<{
|
||||
data: IInventoryValuationStatement;
|
||||
query: IInventoryValuationReportQuery;
|
||||
meta: IInventoryValuationSheetMeta;
|
||||
}> {
|
||||
query: IPurchasesByItemsReportQuery
|
||||
): Promise<IPurchasesByItemsSheet> {
|
||||
const { Item, InventoryTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
const tenant = await Tenant.query()
|
||||
@@ -106,7 +101,6 @@ export default class InventoryValuationReportService {
|
||||
builder.modify('filterDateRange', filter.fromDate, filter.toDate);
|
||||
}
|
||||
);
|
||||
|
||||
const purchasesByItemsInstance = new PurchasesByItems(
|
||||
filter,
|
||||
inventoryItems,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import * as R from 'ramda';
|
||||
import { ITableColumn, ITableColumnAccessor, ITableRow } from '@/interfaces';
|
||||
import { ROW_TYPE } from './_types';
|
||||
import { tableRowMapper } from '@/utils';
|
||||
import { FinancialTable } from '../FinancialTable';
|
||||
import { FinancialSheetStructure } from '../FinancialSheetStructure';
|
||||
import FinancialSheet from '../FinancialSheet';
|
||||
import {
|
||||
IPurchasesByItemsItem,
|
||||
IPurchasesByItemsSheetData,
|
||||
IPurchasesByItemsTotal,
|
||||
} from '@/interfaces/PurchasesByItemsSheet';
|
||||
|
||||
export class PurchasesByItemsTable extends R.compose(
|
||||
FinancialTable,
|
||||
FinancialSheetStructure
|
||||
)(FinancialSheet) {
|
||||
private data: IPurchasesByItemsSheetData;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param data
|
||||
*/
|
||||
constructor(data) {
|
||||
super();
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves thge common table accessors.
|
||||
* @returns {ITableColumnAccessor[]}
|
||||
*/
|
||||
private commonTableAccessors(): ITableColumnAccessor[] {
|
||||
return [
|
||||
{ key: 'item_name', accessor: 'name' },
|
||||
{ key: 'quantity_purchases', accessor: 'quantityPurchasedFormatted' },
|
||||
{ key: 'purchase_amount', accessor: 'purchaseCostFormatted' },
|
||||
{ key: 'average_cost', accessor: 'averageCostPriceFormatted' },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the common table columns.
|
||||
* @returns {ITableColumn[]}
|
||||
*/
|
||||
private commonTableColumns(): ITableColumn[] {
|
||||
return [
|
||||
{ label: 'Item name', key: 'item_name' },
|
||||
{ label: 'Quantity Purchased', key: 'quantity_purchases' },
|
||||
{ label: 'Purchase Amount', key: 'purchase_amount' },
|
||||
{ label: 'Average Price', key: 'average_cost' },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given item node to table row.
|
||||
* @param {IPurchasesByItemsItem} item
|
||||
* @returns {ITableRow}
|
||||
*/
|
||||
private itemMap = (item: IPurchasesByItemsItem): ITableRow => {
|
||||
const columns = this.commonTableAccessors();
|
||||
const meta = {
|
||||
rowTypes: [ROW_TYPE.ITEM],
|
||||
};
|
||||
return tableRowMapper(item, columns, meta);
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps the given items nodes to table rows.
|
||||
* @param {IPurchasesByItemsItem[]} items - Items nodes.
|
||||
* @returns {ITableRow[]}
|
||||
*/
|
||||
private itemsMap = (items: IPurchasesByItemsItem[]): ITableRow[] => {
|
||||
return R.map(this.itemMap)(items);
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps the given total node to table rows.
|
||||
* @param {IPurchasesByItemsTotal} total
|
||||
* @returns {ITableRow}
|
||||
*/
|
||||
private totalNodeMap = (total: IPurchasesByItemsTotal): ITableRow => {
|
||||
const columns = this.commonTableAccessors();
|
||||
const meta = {
|
||||
rowTypes: [ROW_TYPE.TOTAL],
|
||||
};
|
||||
return tableRowMapper(total, columns, meta);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the table columns.
|
||||
* @returns {ITableColumn[]}
|
||||
*/
|
||||
public tableColumns(): ITableColumn[] {
|
||||
const columns = this.commonTableColumns();
|
||||
return R.compose(this.tableColumnsCellIndexing)(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the table rows.
|
||||
* @returns {ITableRow[]}
|
||||
*/
|
||||
public tableData(): ITableRow[] {
|
||||
const itemsRows = this.itemsMap(this.data.items);
|
||||
const totalRow = this.totalNodeMap(this.data.total);
|
||||
|
||||
return R.compose(
|
||||
R.when(R.always(R.not(R.isEmpty(itemsRows))), R.append(totalRow))
|
||||
)(itemsRows) as ITableRow[];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
IPurchasesByItemsReportQuery,
|
||||
IPurchasesByItemsTable,
|
||||
} from '@/interfaces/PurchasesByItemsSheet';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { PurchasesByItemsService } from './PurchasesByItemsService';
|
||||
import { PurchasesByItemsTable } from './PurchasesByItemsTable';
|
||||
|
||||
@Service()
|
||||
export class PurchasesByItemsTableInjectable {
|
||||
@Inject()
|
||||
private purchasesByItemsSheet: PurchasesByItemsService;
|
||||
|
||||
/**
|
||||
* Retrieves the purchases by items table format.
|
||||
* @param {number} tenantId
|
||||
* @param {IPurchasesByItemsReportQuery} filter
|
||||
* @returns {Promise<IPurchasesByItemsTable>}
|
||||
*/
|
||||
public async table(
|
||||
tenantId: number,
|
||||
filter: IPurchasesByItemsReportQuery
|
||||
): Promise<IPurchasesByItemsTable> {
|
||||
const { data, query, meta } =
|
||||
await this.purchasesByItemsSheet.purchasesByItems(tenantId, filter);
|
||||
|
||||
const table = new PurchasesByItemsTable(data);
|
||||
|
||||
return {
|
||||
table: {
|
||||
columns: table.tableColumns(),
|
||||
rows: table.tableData(),
|
||||
},
|
||||
meta,
|
||||
query,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
export enum ROW_TYPE {
|
||||
TOTAL = 'TOTAL',
|
||||
ITEM = 'ITEM'
|
||||
}
|
||||
Reference in New Issue
Block a user