add server to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 11:57:50 +02:00
parent 28e309981b
commit 80b97b5fdc
1303 changed files with 137049 additions and 0 deletions

View File

@@ -0,0 +1,433 @@
import * as R from 'ramda';
import { defaultTo, sumBy, get } from 'lodash';
import moment from 'moment';
import {
IInventoryDetailsQuery,
IItem,
IInventoryTransaction,
TInventoryTransactionDirection,
IInventoryDetailsNumber,
IInventoryDetailsDate,
IInventoryDetailsData,
IInventoryDetailsItem,
IInventoryDetailsClosing,
INumberFormatQuery,
IInventoryDetailsOpening,
IInventoryDetailsItemTransaction,
IFormatNumberSettings,
} from '@/interfaces';
import FinancialSheet from '../FinancialSheet';
import { transformToMapBy, transformToMapKeyValue } from 'utils';
import { filterDeep } from 'utils/deepdash';
const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
enum INodeTypes {
ITEM = 'item',
TRANSACTION = 'transaction',
OPENING_ENTRY = 'OPENING_ENTRY',
CLOSING_ENTRY = 'CLOSING_ENTRY',
}
export default class InventoryDetails extends FinancialSheet {
readonly inventoryTransactionsByItemId: Map<number, IInventoryTransaction[]>;
readonly openingBalanceTransactions: Map<number, IInventoryTransaction>;
readonly query: IInventoryDetailsQuery;
readonly numberFormat: INumberFormatQuery;
readonly baseCurrency: string;
readonly items: IItem[];
/**
* Constructor method.
* @param {IItem[]} items - Items.
* @param {IInventoryTransaction[]} inventoryTransactions - Inventory transactions.
* @param {IInventoryDetailsQuery} query - Report query.
* @param {string} baseCurrency - The base currency.
*/
constructor(
items: IItem[],
openingBalanceTransactions: IInventoryTransaction[],
inventoryTransactions: IInventoryTransaction[],
query: IInventoryDetailsQuery,
baseCurrency: string,
i18n: any
) {
super();
this.inventoryTransactionsByItemId = transformToMapBy(
inventoryTransactions,
'itemId'
);
this.openingBalanceTransactions = transformToMapKeyValue(
openingBalanceTransactions,
'itemId'
);
this.query = query;
this.numberFormat = this.query.numberFormat;
this.items = items;
this.baseCurrency = baseCurrency;
this.i18n = i18n;
}
/**
* Retrieve the number meta.
* @param {number} number
* @returns
*/
private getNumberMeta(
number: number,
settings?: IFormatNumberSettings
): IInventoryDetailsNumber {
return {
formattedNumber: this.formatNumber(number, {
excerptZero: true,
money: false,
...settings,
}),
number: number,
};
}
/**
* Retrieve the total number meta.
* @param {number} number -
* @param {IFormatNumberSettings} settings -
* @retrun {IInventoryDetailsNumber}
*/
private getTotalNumberMeta(
number: number,
settings?: IFormatNumberSettings
): IInventoryDetailsNumber {
return this.getNumberMeta(number, { excerptZero: false, ...settings });
}
/**
* Retrieve the date meta.
* @param {Date|string} date
* @returns {IInventoryDetailsDate}
*/
private getDateMeta(date: Date | string): IInventoryDetailsDate {
return {
formattedDate: moment(date).format('YYYY-MM-DD'),
date: moment(date).toDate(),
};
}
/**
* Adjusts the movement amount.
* @param {number} amount
* @param {TInventoryTransactionDirection} direction
* @returns {number}
*/
private adjustAmountMovement = R.curry(
(direction: TInventoryTransactionDirection, amount: number): number => {
return direction === 'OUT' ? amount * -1 : amount;
}
);
/**
* Accumlate and mapping running quantity on transactions.
* @param {IInventoryDetailsItemTransaction[]} transactions
* @returns {IInventoryDetailsItemTransaction[]}
*/
private mapAccumTransactionsRunningQuantity(
transactions: IInventoryDetailsItemTransaction[]
): IInventoryDetailsItemTransaction[] {
const initial = this.getNumberMeta(0);
const mapAccumAppender = (a, b) => {
const total = a.runningQuantity.number + b.quantityMovement.number;
const totalMeta = this.getNumberMeta(total, { excerptZero: false });
const accum = { ...b, runningQuantity: totalMeta };
return [accum, accum];
};
return R.mapAccum(
mapAccumAppender,
{ runningQuantity: initial },
transactions
)[1];
}
/**
* Accumlate and mapping running valuation on transactions.
* @param {IInventoryDetailsItemTransaction[]} transactions
* @returns {IInventoryDetailsItemTransaction}
*/
private mapAccumTransactionsRunningValuation(
transactions: IInventoryDetailsItemTransaction[]
): IInventoryDetailsItemTransaction[] {
const initial = this.getNumberMeta(0);
const mapAccumAppender = (a, b) => {
const adjusmtent = b.direction === 'OUT' ? -1 : 1;
const total = a.runningValuation.number + b.cost.number * adjusmtent;
const totalMeta = this.getNumberMeta(total, { excerptZero: false });
const accum = { ...b, runningValuation: totalMeta };
return [accum, accum];
};
return R.mapAccum(
mapAccumAppender,
{ runningValuation: initial },
transactions
)[1];
}
/**
* Retrieve the inventory transaction total.
* @param {IInventoryTransaction} transaction
* @returns {number}
*/
private getTransactionTotal = (transaction: IInventoryTransaction) => {
return transaction.quantity
? transaction.quantity * transaction.rate
: transaction.rate;
};
/**
* Mappes the item transaction to inventory item transaction node.
* @param {IItem} item
* @param {IInvetoryTransaction} transaction
* @returns {IInventoryDetailsItemTransaction}
*/
private itemTransactionMapper(
item: IItem,
transaction: IInventoryTransaction
): IInventoryDetailsItemTransaction {
const total = this.getTransactionTotal(transaction);
const amountMovement = this.adjustAmountMovement(transaction.direction);
// Quantity movement.
const quantityMovement = amountMovement(transaction.quantity);
const cost = get(transaction, 'costLotAggregated.cost', 0);
// Profit margin.
const profitMargin = total - cost;
// Value from computed cost in `OUT` or from total sell price in `IN` transaction.
const value = transaction.direction === 'OUT' ? cost : total;
// Value movement depends on transaction direction.
const valueMovement = amountMovement(value);
return {
nodeType: INodeTypes.TRANSACTION,
date: this.getDateMeta(transaction.date),
transactionType: this.i18n.__(transaction.transcationTypeFormatted),
transactionNumber: transaction?.meta?.transactionNumber,
direction: transaction.direction,
quantityMovement: this.getNumberMeta(quantityMovement),
valueMovement: this.getNumberMeta(valueMovement),
quantity: this.getNumberMeta(transaction.quantity),
total: this.getNumberMeta(total),
rate: this.getNumberMeta(transaction.rate),
cost: this.getNumberMeta(cost),
value: this.getNumberMeta(value),
profitMargin: this.getNumberMeta(profitMargin),
runningQuantity: this.getNumberMeta(0),
runningValuation: this.getNumberMeta(0),
};
}
/**
* Retrieve the inventory transcations by item id.
* @param {number} itemId
* @returns {IInventoryTransaction[]}
*/
private getInventoryTransactionsByItemId(
itemId: number
): IInventoryTransaction[] {
return defaultTo(this.inventoryTransactionsByItemId.get(itemId + ''), []);
}
/**
* Retrieve the item transaction node by the given item.
* @param {IItem} item
* @returns {IInventoryDetailsItemTransaction[]}
*/
private getItemTransactions(item: IItem): IInventoryDetailsItemTransaction[] {
const transactions = this.getInventoryTransactionsByItemId(item.id);
return R.compose(
this.mapAccumTransactionsRunningQuantity.bind(this),
this.mapAccumTransactionsRunningValuation.bind(this),
R.map(R.curry(this.itemTransactionMapper.bind(this))(item))
)(transactions);
}
/**
* Mappes the given item transactions.
* @param {IItem} item -
* @returns {(
* IInventoryDetailsItemTransaction
* | IInventoryDetailsOpening
* | IInventoryDetailsClosing
* )[]}
*/
private itemTransactionsMapper(
item: IItem
): (
| IInventoryDetailsItemTransaction
| IInventoryDetailsOpening
| IInventoryDetailsClosing
)[] {
const transactions = this.getItemTransactions(item);
const openingValuation = this.getItemOpeingValuation(item);
const closingValuation = this.getItemClosingValuation(
item,
transactions,
openingValuation
);
const hasTransactions = transactions.length > 0;
const isItemHasOpeningBalance = this.isItemHasOpeningBalance(item.id);
return R.pipe(
R.concat(transactions),
R.when(R.always(isItemHasOpeningBalance), R.prepend(openingValuation)),
R.when(R.always(hasTransactions), R.append(closingValuation))
)([]);
}
/**
* Detarmines the given item has opening balance transaction.
* @param {number} itemId - Item id.
* @return {boolean}
*/
private isItemHasOpeningBalance(itemId: number): boolean {
return !!this.openingBalanceTransactions.get(itemId);
}
/**
* Retrieve the given item opening valuation.
* @param {IItem} item -
* @returns {IInventoryDetailsOpening}
*/
private getItemOpeingValuation(item: IItem): IInventoryDetailsOpening {
const openingBalance = this.openingBalanceTransactions.get(item.id);
const quantity = defaultTo(get(openingBalance, 'quantity'), 0);
const value = defaultTo(get(openingBalance, 'value'), 0);
return {
nodeType: INodeTypes.OPENING_ENTRY,
date: this.getDateMeta(this.query.fromDate),
quantity: this.getTotalNumberMeta(quantity),
value: this.getTotalNumberMeta(value),
};
}
/**
* Retrieve the given item closing valuation.
* @param {IItem} item -
* @returns {IInventoryDetailsOpening}
*/
private getItemClosingValuation(
item: IItem,
transactions: IInventoryDetailsItemTransaction[],
openingValuation: IInventoryDetailsOpening
): IInventoryDetailsOpening {
const value = sumBy(transactions, 'valueMovement.number');
const quantity = sumBy(transactions, 'quantityMovement.number');
const profitMargin = sumBy(transactions, 'profitMargin.number');
const closingQuantity = quantity + openingValuation.quantity.number;
const closingValue = value + openingValuation.value.number;
return {
nodeType: INodeTypes.CLOSING_ENTRY,
date: this.getDateMeta(this.query.toDate),
quantity: this.getTotalNumberMeta(closingQuantity),
value: this.getTotalNumberMeta(closingValue),
profitMargin: this.getTotalNumberMeta(profitMargin),
};
}
/**
* Retrieve the item node of the report.
* @param {IItem} item
* @returns {IInventoryDetailsItem}
*/
private itemsNodeMapper(item: IItem): IInventoryDetailsItem {
return {
id: item.id,
name: item.name,
code: item.code,
nodeType: INodeTypes.ITEM,
children: this.itemTransactionsMapper(item),
};
}
/**
* Detarmines the given node equals the given type.
* @param {string} nodeType
* @param {IItem} node
* @returns {boolean}
*/
private isNodeTypeEquals(
nodeType: string,
node: IInventoryDetailsItem
): boolean {
return nodeType === node.nodeType;
}
/**
* Detarmines whether the given item node has transactions.
* @param {IInventoryDetailsItem} item
* @returns {boolean}
*/
private isItemNodeHasTransactions(item: IInventoryDetailsItem) {
return !!this.inventoryTransactionsByItemId.get(item.id);
}
/**
* Detarmines the filter
* @param {IInventoryDetailsItem} item
* @return {boolean}
*/
private isFilterNode(item: IInventoryDetailsItem): boolean {
return R.ifElse(
R.curry(this.isNodeTypeEquals)(INodeTypes.ITEM),
this.isItemNodeHasTransactions.bind(this),
R.always(true)
)(item);
}
/**
* Filters items nodes.
* @param {IInventoryDetailsItem[]} items -
* @returns {IInventoryDetailsItem[]}
*/
private filterItemsNodes(items: IInventoryDetailsItem[]) {
const filtered = filterDeep(
items,
this.isFilterNode.bind(this),
MAP_CONFIG
);
return defaultTo(filtered, []);
}
/**
* Retrieve the items nodes of the report.
* @param {IItem} items
* @returns {IInventoryDetailsItem[]}
*/
private itemsNodes(items: IItem[]): IInventoryDetailsItem[] {
return R.compose(
this.filterItemsNodes.bind(this),
R.map(this.itemsNodeMapper.bind(this))
)(items);
}
/**
* Retrieve the inventory item details report data.
* @returns {IInventoryDetailsData}
*/
public reportData(): IInventoryDetailsData {
return this.itemsNodes(this.items);
}
}

View File

@@ -0,0 +1,120 @@
import { Inject } from 'typedi';
import { raw } from 'objection';
import { isEmpty } from 'lodash';
import moment from 'moment';
import {
IItem,
IInventoryDetailsQuery,
IInventoryTransaction,
} from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
export default class InventoryDetailsRepository {
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve inventory items.
* @param {number} tenantId -
* @returns {Promise<IItem>}
*/
public getInventoryItems(
tenantId: number,
itemsIds?: number[]
): Promise<IItem[]> {
const { Item } = this.tenancy.models(tenantId);
return Item.query().onBuild((q) => {
q.where('type', 'inventory');
if (!isEmpty(itemsIds)) {
q.whereIn('id', itemsIds);
}
});
}
/**
* Retrieve the items opening balance transactions.
* @param {number} tenantId -
* @param {IInventoryDetailsQuery}
* @return {Promise<IInventoryTransaction>}
*/
public async openingBalanceTransactions(
tenantId: number,
filter: IInventoryDetailsQuery
): Promise<IInventoryTransaction[]> {
const { InventoryTransaction } = this.tenancy.models(tenantId);
const openingBalanceDate = moment(filter.fromDate)
.subtract(1, 'days')
.toDate();
// Opening inventory transactions.
const openingTransactions = InventoryTransaction.query()
.select('*')
.select(raw("IF(`DIRECTION` = 'IN', `QUANTITY`, 0) as 'QUANTITY_IN'"))
.select(raw("IF(`DIRECTION` = 'OUT', `QUANTITY`, 0) as 'QUANTITY_OUT'"))
.select(
raw(
"IF(`DIRECTION` = 'IN', IF(`QUANTITY` IS NULL, `RATE`, `QUANTITY` * `RATE`), 0) as 'VALUE_IN'"
)
)
.select(
raw(
"IF(`DIRECTION` = 'OUT', IF(`QUANTITY` IS NULL, `RATE`, `QUANTITY` * `RATE`), 0) as 'VALUE_OUT'"
)
)
.modify('filterDateRange', null, openingBalanceDate)
.orderBy('date', 'ASC')
.as('inventory_transactions');
if (!isEmpty(filter.warehousesIds)) {
openingTransactions.modify('filterByWarehouses', filter.warehousesIds);
}
if (!isEmpty(filter.branchesIds)) {
openingTransactions.modify('filterByBranches', filter.branchesIds);
}
const openingBalanceTransactions = await InventoryTransaction.query()
.from(openingTransactions)
.select('itemId')
.select(raw('SUM(`QUANTITY_IN` - `QUANTITY_OUT`) AS `QUANTITY`'))
.select(raw('SUM(`VALUE_IN` - `VALUE_OUT`) AS `VALUE`'))
.groupBy('itemId')
.sum('rate as rate')
.sum('quantityIn as quantityIn')
.sum('quantityOut as quantityOut')
.sum('valueIn as valueIn')
.sum('valueOut as valueOut')
.withGraphFetched('itemCostAggregated');
return openingBalanceTransactions;
}
/**
* Retrieve the items inventory tranasactions.
* @param {number} tenantId -
* @param {IInventoryDetailsQuery}
* @return {Promise<IInventoryTransaction>}
*/
public async itemInventoryTransactions(
tenantId: number,
filter: IInventoryDetailsQuery
): Promise<IInventoryTransaction[]> {
const { InventoryTransaction } = this.tenancy.models(tenantId);
const inventoryTransactions = InventoryTransaction.query()
.modify('filterDateRange', filter.fromDate, filter.toDate)
.orderBy('date', 'ASC')
.withGraphFetched('meta')
.withGraphFetched('costLotAggregated');
if (!isEmpty(filter.branchesIds)) {
inventoryTransactions.modify('filterByBranches', filter.branchesIds);
}
if (!isEmpty(filter.warehousesIds)) {
inventoryTransactions.modify('filterByWarehouses', filter.warehousesIds);
}
return inventoryTransactions;
}
}

View File

@@ -0,0 +1,125 @@
import moment from 'moment';
import { Service, Inject } from 'typedi';
import {
IInventoryDetailsQuery,
IInvetoryItemDetailDOO,
IInventoryItemDetailMeta,
} from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService';
import InventoryDetails from './InventoryDetails';
import FinancialSheet from '../FinancialSheet';
import InventoryDetailsRepository from './InventoryDetailsRepository';
import InventoryService from '@/services/Inventory/Inventory';
import { parseBoolean } from 'utils';
import { Tenant } from '@/system/models';
@Service()
export default class InventoryDetailsService extends FinancialSheet {
@Inject()
tenancy: TenancyService;
@Inject()
reportRepo: InventoryDetailsRepository;
@Inject()
inventoryService: InventoryService;
/**
* Defaults balance sheet filter query.
* @return {IBalanceSheetQuery}
*/
private get defaultQuery(): IInventoryDetailsQuery {
return {
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
toDate: moment().endOf('year').format('YYYY-MM-DD'),
itemsIds: [],
numberFormat: {
precision: 2,
divideOn1000: false,
showZero: false,
formatMoney: 'total',
negativeFormat: 'mines',
},
noneTransactions: false,
branchesIds: [],
warehousesIds: [],
};
}
/**
* Retrieve the balance sheet meta.
* @param {number} tenantId -
* @returns {IInventoryItemDetailMeta}
*/
private reportMetadata(tenantId: number): IInventoryItemDetailMeta {
const settings = this.tenancy.settings(tenantId);
const isCostComputeRunning =
this.inventoryService.isItemsCostComputeRunning(tenantId);
const organizationName = settings.get({
group: 'organization',
key: 'name',
});
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
return {
isCostComputeRunning: parseBoolean(isCostComputeRunning, false),
organizationName,
baseCurrency,
};
}
/**
* Retrieve the inventory details report data.
* @param {number} tenantId -
* @param {IInventoryDetailsQuery} query -
* @return {Promise<IInvetoryItemDetailDOO>}
*/
public async inventoryDetails(
tenantId: number,
query: IInventoryDetailsQuery
): Promise<IInvetoryItemDetailDOO> {
const i18n = this.tenancy.i18n(tenantId);
const tenant = await Tenant.query()
.findById(tenantId)
.withGraphFetched('metadata');
const filter = {
...this.defaultQuery,
...query,
};
// Retrieves the items.
const items = await this.reportRepo.getInventoryItems(
tenantId,
filter.itemsIds
);
// Opening balance transactions.
const openingBalanceTransactions =
await this.reportRepo.openingBalanceTransactions(tenantId, filter);
// Retrieves the inventory transaction.
const inventoryTransactions =
await this.reportRepo.itemInventoryTransactions(tenantId, filter);
// Inventory details report mapper.
const inventoryDetailsInstance = new InventoryDetails(
items,
openingBalanceTransactions,
inventoryTransactions,
filter,
tenant.metadata.baseCurrency,
i18n
);
return {
data: inventoryDetailsInstance.reportData(),
query: filter,
meta: this.reportMetadata(tenantId),
};
}
}

View File

@@ -0,0 +1,197 @@
import * as R from 'ramda';
import {
IInventoryDetailsItem,
IInventoryDetailsItemTransaction,
IInventoryDetailsClosing,
ITableColumn,
ITableRow,
IInventoryDetailsNode,
IInventoryDetailsOpening,
} from '@/interfaces';
import { mapValuesDeep } from 'utils/deepdash';
import { tableRowMapper } from 'utils';
enum IROW_TYPE {
ITEM = 'ITEM',
TRANSACTION = 'TRANSACTION',
CLOSING_ENTRY = 'CLOSING_ENTRY',
OPENING_ENTRY = 'OPENING_ENTRY',
}
const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
export default class InventoryDetailsTable {
i18n: any;
report: any;
/**
* Constructor method.
* @param {ICashFlowStatement} reportStatement - Report statement.
*/
constructor(reportStatement, i18n) {
this.report = reportStatement;
this.i18n = i18n;
}
/**
* Mappes the item node to table rows.
* @param {IInventoryDetailsItem} item
* @returns {ITableRow}
*/
private itemNodeMapper = (item: IInventoryDetailsItem) => {
const columns = [{ key: 'item_name', accessor: 'name' }];
return tableRowMapper(item, columns, {
rowTypes: [IROW_TYPE.ITEM],
});
};
/**
* Mappes the item inventory transaction to table row.
* @param {IInventoryDetailsItemTransaction} transaction
* @returns {ITableRow}
*/
private itemTransactionNodeMapper = (
transaction: IInventoryDetailsItemTransaction
) => {
const columns = [
{ key: 'date', accessor: 'date.formattedDate' },
{ key: 'transaction_type', accessor: 'transactionType' },
{ key: 'transaction_id', accessor: 'transactionNumber' },
{
key: 'quantity_movement',
accessor: 'quantityMovement.formattedNumber',
},
{ key: 'rate', accessor: 'rate.formattedNumber' },
{ key: 'total', accessor: 'total.formattedNumber' },
{ key: 'value', accessor: 'valueMovement.formattedNumber' },
{ key: 'profit_margin', accessor: 'profitMargin.formattedNumber' },
{ key: 'running_quantity', accessor: 'runningQuantity.formattedNumber' },
{
key: 'running_valuation',
accessor: 'runningValuation.formattedNumber',
},
];
return tableRowMapper(transaction, columns, {
rowTypes: [IROW_TYPE.TRANSACTION],
});
};
/**
* Opening balance transaction mapper to table row.
* @param {IInventoryDetailsOpening} transaction
* @returns {ITableRow}
*/
private openingNodeMapper = (
transaction: IInventoryDetailsOpening
): ITableRow => {
const columns = [
{ key: 'date', accessor: 'date.formattedDate' },
{ key: 'closing', value: this.i18n.__('Opening balance') },
{ key: 'empty' },
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
{ key: 'empty' },
{ key: 'empty' },
{ key: 'value', accessor: 'value.formattedNumber' },
];
return tableRowMapper(transaction, columns, {
rowTypes: [IROW_TYPE.OPENING_ENTRY],
});
};
/**
* Closing balance transaction mapper to table raw.
* @param {IInventoryDetailsClosing} transaction
* @returns {ITableRow}
*/
private closingNodeMapper = (
transaction: IInventoryDetailsClosing
): ITableRow => {
const columns = [
{ key: 'date', accessor: 'date.formattedDate' },
{ key: 'closing', value: this.i18n.__('Closing balance') },
{ key: 'empty' },
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
{ key: 'empty' },
{ key: 'empty' },
{ key: 'value', accessor: 'value.formattedNumber' },
{ key: 'profitMargin', accessor: 'profitMargin.formattedNumber' },
];
return tableRowMapper(transaction, columns, {
rowTypes: [IROW_TYPE.CLOSING_ENTRY],
});
};
/**
* Detarmines the ginve inventory details node type.
* @param {string} type
* @param {IInventoryDetailsNode} node
* @returns {boolean}
*/
private isNodeTypeEquals = (
type: string,
node: IInventoryDetailsNode
): boolean => {
return node.nodeType === type;
};
/**
* Mappes the given item or transactions node to table rows.
* @param {IInventoryDetailsNode} node -
* @return {ITableRow}
*/
private itemMapper = (node: IInventoryDetailsNode): ITableRow => {
return R.compose(
R.when(
R.curry(this.isNodeTypeEquals)('OPENING_ENTRY'),
this.openingNodeMapper
),
R.when(
R.curry(this.isNodeTypeEquals)('CLOSING_ENTRY'),
this.closingNodeMapper
),
R.when(R.curry(this.isNodeTypeEquals)('item'), this.itemNodeMapper),
R.when(
R.curry(this.isNodeTypeEquals)('transaction'),
this.itemTransactionNodeMapper
)
)(node);
};
/**
* Mappes the items nodes to table rows.
* @param {IInventoryDetailsItem[]} items
* @returns {ITableRow[]}
*/
private itemsMapper = (items: IInventoryDetailsItem[]): ITableRow[] => {
return mapValuesDeep(items, this.itemMapper, MAP_CONFIG);
};
/**
* Retrieve the table rows of the inventory item details.
* @returns {ITableRow[]}
*/
public tableData = (): ITableRow[] => {
return this.itemsMapper(this.report.data);
};
/**
* Retrieve the table columns of inventory details report.
* @returns {ITableColumn[]}
*/
public tableColumns = (): ITableColumn[] => {
return [
{ key: 'date', label: this.i18n.__('Date') },
{ key: 'transaction_type', label: this.i18n.__('Transaction type') },
{ key: 'transaction_id', label: this.i18n.__('Transaction #') },
{ key: 'quantity', label: this.i18n.__('Quantity') },
{ key: 'rate', label: this.i18n.__('Rate') },
{ key: 'total', label: this.i18n.__('Total') },
{ key: 'value', label: this.i18n.__('Value') },
{ key: 'profit_margin', label: this.i18n.__('Profit Margin') },
{ key: 'running_quantity', label: this.i18n.__('Running quantity') },
{ key: 'running_value', label: this.i18n.__('Running Value') },
];
};
}