fix: value property in inventory item details.

This commit is contained in:
a.bouhuolia
2021-06-01 20:33:39 +02:00
parent d47633b8ea
commit 7428a7315a
7 changed files with 105 additions and 41 deletions

View File

@@ -1,5 +1,6 @@
import * as R from 'ramda';
import { defaultTo, sumBy, get } from 'lodash';
import moment from 'moment';
import {
IInventoryDetailsQuery,
IItem,
@@ -18,7 +19,6 @@ import {
import FinancialSheet from '../FinancialSheet';
import { transformToMapBy, transformToMapKeyValue } from 'utils';
import { filterDeep } from 'utils/deepdash';
import moment from 'moment';
const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
@@ -159,7 +159,8 @@ export default class InventoryDetails extends FinancialSheet {
const initial = this.getNumberMeta(0);
const mapAccumAppender = (a, b) => {
const total = a.runningValuation.number + b.valueMovement.number;
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 };
@@ -182,19 +183,22 @@ export default class InventoryDetails extends FinancialSheet {
item: IItem,
transaction: IInventoryTransaction
): IInventoryDetailsItemTransaction {
const value = transaction.quantity * transaction.rate;
const total = transaction.quantity * transaction.rate;
const amountMovement = R.curry(this.adjustAmountMovement)(
transaction.direction
);
// Quantity movement.
const quantityMovement = amountMovement(transaction.quantity);
const valueMovement = amountMovement(value);
const cost = defaultTo(transaction?.costLotAggregated.cost, 0);
// Profit margin.
const profitMargin = Math.max(
value - 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,
@@ -207,10 +211,11 @@ export default class InventoryDetails extends FinancialSheet {
valueMovement: this.getNumberMeta(valueMovement),
quantity: this.getNumberMeta(transaction.quantity),
value: this.getNumberMeta(value),
total: this.getNumberMeta(total),
rate: this.getNumberMeta(transaction.rate),
cost: this.getNumberMeta(transaction.costLotAggregated.cost),
value: this.getNumberMeta(value),
profitMargin: this.getNumberMeta(profitMargin),
@@ -314,14 +319,12 @@ export default class InventoryDetails extends FinancialSheet {
const value = sumBy(transactions, 'valueMovement.number');
const quantity = sumBy(transactions, 'quantityMovement.number');
const profitMargin = sumBy(transactions, 'profitMargin.number');
const cost = sumBy(transactions, 'cost.number');
return {
nodeType: INodeTypes.CLOSING_ENTRY,
date: this.getDateMeta(this.query.toDate),
quantity: this.getTotalNumberMeta(quantity),
value: this.getTotalNumberMeta(value),
cost: this.getTotalNumberMeta(cost),
profitMargin: this.getTotalNumberMeta(profitMargin),
};
}

View File

@@ -1,7 +1,11 @@
import { Inject } from 'typedi';
import { raw } from 'objection';
import moment from 'moment';
import { IItem, IInventoryDetailsQuery, IInventoryTransaction } from 'interfaces';
import {
IItem,
IInventoryDetailsQuery,
IInventoryTransaction,
} from 'interfaces';
import HasTenancyService from 'services/Tenancy/TenancyService';
export default class InventoryDetailsRepository {
@@ -10,7 +14,7 @@ export default class InventoryDetailsRepository {
/**
* Retrieve inventory items.
* @param {number} tenantId -
* @param {number} tenantId -
* @returns {Promise<IItem>}
*/
public getInventoryItems(tenantId: number): Promise<IItem[]> {
@@ -47,6 +51,7 @@ export default class InventoryDetailsRepository {
raw("IF(`DIRECTION` = 'OUT', `QUANTITY` * `RATE`, 0) as 'VALUE_OUT'")
)
.modify('filterDateRange', null, openingBalanceDate)
.orderBy('date', 'ASC')
.as('inventory_transactions');
const openingBalanceTransactions = await InventoryTransaction.query()
@@ -79,6 +84,7 @@ export default class InventoryDetailsRepository {
const inventoryTransactions = InventoryTransaction.query()
.modify('filterDateRange', filter.fromDate, filter.toDate)
.orderBy('date', 'ASC')
.withGraphFetched('meta')
.withGraphFetched('costLotAggregated');

View File

@@ -1,11 +1,16 @@
import moment from 'moment';
import { Service, Inject } from 'typedi';
import { raw } from 'objection';
import { IInventoryDetailsQuery, IInventoryTransaction } from 'interfaces';
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';
@Service()
export default class InventoryDetailsService extends FinancialSheet {
@@ -15,11 +20,14 @@ export default class InventoryDetailsService extends FinancialSheet {
@Inject()
reportRepo: InventoryDetailsRepository;
@Inject()
inventoryService: InventoryService;
/**
* Defaults balance sheet filter query.
* @return {IBalanceSheetQuery}
*/
get defaultQuery(): IInventoryDetailsQuery {
private get defaultQuery(): IInventoryDetailsQuery {
return {
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
toDate: moment().endOf('year').format('YYYY-MM-DD'),
@@ -34,15 +42,43 @@ export default class InventoryDetailsService extends FinancialSheet {
};
}
/**
* 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<any> {
): Promise<IInvetoryItemDetailDOO> {
// Settings tenant service.
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({
@@ -76,6 +112,8 @@ export default class InventoryDetailsService extends FinancialSheet {
return {
data: inventoryDetailsInstance.reportData(),
query: filter,
meta: this.reportMetadata(tenantId),
};
}
}

View File

@@ -22,8 +22,8 @@ const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
export default class InventoryDetailsTable {
/**
* Constructor methiod.
* @param {ICashFlowStatement} reportStatement
* Constructor method.
* @param {ICashFlowStatement} reportStatement - Report statement.
*/
constructor(reportStatement) {
this.report = reportStatement;
@@ -59,8 +59,8 @@ export default class InventoryDetailsTable {
accessor: 'quantityMovement.formattedNumber',
},
{ key: 'rate', accessor: 'rate.formattedNumber' },
{ key: 'value_movement', accessor: 'valueMovement.formattedNumber' },
{ key: 'cost', accessor: 'cost.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' },
@@ -82,9 +82,9 @@ export default class InventoryDetailsTable {
{ 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],
});
@@ -102,8 +102,8 @@ export default class InventoryDetailsTable {
{ key: 'empty' },
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
{ key: 'empty' },
{ key: 'empty' },
{ key: 'value', accessor: 'value.formattedNumber' },
{ key: 'cost', accessor: 'cost.formattedNumber' },
{ key: 'profitMargin', accessor: 'profitMargin.formattedNumber' },
];
@@ -171,13 +171,13 @@ export default class InventoryDetailsTable {
{ key: 'date', label: 'Date' },
{ key: 'transaction_type', label: 'Transaction type' },
{ key: 'transaction_id', label: 'Transaction #' },
{ key: 'quantity_movement', label: 'Quantity' },
{ key: 'quantity', label: 'Quantity' },
{ key: 'rate', label: 'Rate' },
{ key: 'value_movement', label: 'Value' },
{ key: 'cost', label: 'Cost' },
{ key: 'total', label: 'Total' },
{ key: 'value', label: 'Value' },
{ key: 'profit_margin', label: 'Profit Margin' },
{ key: 'quantity_on_hand', label: 'Running quantity' },
{ key: 'value', label: 'Running Value' },
{ key: 'running_quantity', label: 'Running quantity' },
{ key: 'running_value', label: 'Running Value' },
];
}
}

View File

@@ -5,6 +5,7 @@ import {
ITransactionsByContactsFilter,
IContact,
ILedger,
ILedgerEntry,
} from 'interfaces';
import FinancialSheet from '../FinancialSheet';
@@ -20,20 +21,20 @@ export default class TransactionsByContact extends FinancialSheet {
* @return {Omit<ITransactionsByContactsTransaction, 'runningBalance'>}
*/
protected contactTransactionMapper(
transaction
entry: ILedgerEntry,
): Omit<ITransactionsByContactsTransaction, 'runningBalance'> {
const account = this.accountsGraph.getNodeData(transaction.accountId);
const account = this.accountsGraph.getNodeData(entry.accountId);
const currencyCode = 'USD';
return {
credit: this.getContactAmount(transaction.credit, currencyCode),
debit: this.getContactAmount(transaction.debit, currencyCode),
credit: this.getContactAmount(entry.credit, currencyCode),
debit: this.getContactAmount(entry.debit, currencyCode),
accountName: account.name,
currencyCode: 'USD',
transactionNumber: transaction.transactionNumber,
transactionType: transaction.transactionType,
date: transaction.date,
createdAt: transaction.createdAt,
transactionNumber: entry.transactionNumber,
transactionType: entry.referenceTypeFormatted,
date: entry.date,
createdAt: entry.createdAt,
};
}