fix(InventoryValuation): inventory valuation report.

This commit is contained in:
a.bouhuolia
2021-03-29 15:19:35 +02:00
parent 5184365d2a
commit 5f573c095e
4 changed files with 58 additions and 99 deletions

View File

@@ -135,30 +135,6 @@ export default class ExchangeRatesService implements IExchangeRatesService {
return exchangeRates;
}
/**
* Deletes exchange rates in bulk.
* @param {number} tenantId
* @param {number[]} exchangeRatesIds
*/
public async deleteBulkExchangeRates(
tenantId: number,
exchangeRatesIds: number[]
): Promise<void> {
const { ExchangeRate } = this.tenancy.models(tenantId);
this.logger.info('[exchange_rates] trying delete in bulk.', {
tenantId,
exchangeRatesIds,
});
await this.validateExchangeRatesIdsExistance(tenantId, exchangeRatesIds);
await ExchangeRate.query().whereIn('id', exchangeRatesIds).delete();
this.logger.info('[exchange_rates] deleted successfully.', {
tenantId,
exchangeRatesIds,
});
}
/**
* Validates period of the exchange rate existance.
* @param {number} tenantId - Tenant id.
@@ -214,33 +190,4 @@ export default class ExchangeRatesService implements IExchangeRatesService {
throw new ServiceError(ERRORS.EXCHANGE_RATE_NOT_FOUND);
}
}
/**
* Validates exchange rates ids existance.
* @param {number} tenantId - Tenant id.
* @param {number[]} exchangeRatesIds - Exchange rates ids.
* @returns {Promise<void>}
*/
private async validateExchangeRatesIdsExistance(
tenantId: number,
exchangeRatesIds: number[]
): Promise<void> {
const { ExchangeRate } = this.tenancy.models(tenantId);
const storedExchangeRates = await ExchangeRate.query().whereIn(
'id',
exchangeRatesIds
);
const storedExchangeRatesIds = storedExchangeRates.map(
(category) => category.id
);
const notFoundExRates = difference(
exchangeRatesIds,
storedExchangeRatesIds
);
if (notFoundExRates.length > 0) {
throw new ServiceError(ERRORS.NOT_FOUND_EXCHANGE_RATES);
}
}
}

View File

@@ -4,7 +4,8 @@ import {
IItem,
IInventoryValuationReportQuery,
IInventoryValuationItem,
IAccountTransaction,
InventoryCostLotTracker,
IInventoryValuationStatement,
IInventoryValuationTotal
} from 'interfaces';
import { transformToMap } from 'utils'
@@ -12,8 +13,8 @@ import { transformToMap } from 'utils'
export default class InventoryValuationSheet extends FinancialSheet {
readonly query: IInventoryValuationReportQuery;
readonly items: IItem[];
readonly INInventoryCostLots: Map<number, IAccountTransaction>;
readonly OUTInventoryCostLots: Map<number, IAccountTransaction>;
readonly INInventoryCostLots: Map<number, InventoryCostLotTracker>;
readonly OUTInventoryCostLots: Map<number, InventoryCostLotTracker>;
readonly baseCurrency: string;
/**
@@ -27,8 +28,8 @@ export default class InventoryValuationSheet extends FinancialSheet {
constructor(
query: IInventoryValuationReportQuery,
items: IItem[],
INInventoryCostLots: IAccountTransaction[],
OUTInventoryCostLots: IAccountTransaction[],
INInventoryCostLots: Map<number, InventoryCostLotTracker[]>,
OUTInventoryCostLots: Map<number, InventoryCostLotTracker[]>,
baseCurrency: string
) {
super();
@@ -41,37 +42,59 @@ export default class InventoryValuationSheet extends FinancialSheet {
this.numberFormat = this.query.numberFormat;
}
/**
* Retrieve the item cost and quantity from the given transaction map.
* @param {Map<number, InventoryCostLotTracker[]>} transactionsMap
* @param {number} itemId
* @returns
*/
getItemTransaction(
transactionsMap,
transactionsMap: Map<number, InventoryCostLotTracker[]>,
itemId: number,
): { cost: number, quantity: number } {
const meta = transactionsMap.get(itemId);
const cost = get(meta, 'cost', 0);
const quantity = get(meta, 'cost', 0);
const quantity = get(meta, 'quantity', 0);
return { cost, quantity };
}
/**
* Retrieve the cost and quantity of the givne item from `IN` transactions.
* @param {number} itemId -
*/
getItemINTransaction(
itemId: number,
): { cost: number, quantity: number } {
return this.getItemTransaction(this.INInventoryCostLots, itemId);
}
/**
* Retrieve the cost and quantity of the given item from `OUT` transactions.
* @param {number} itemId -
*/
getItemOUTTransaction(
itemId: number,
): { cost: number, quantity: number } {
return this.getItemTransaction(this.OUTInventoryCostLots, itemId);
}
/**
* Retrieve the item closing valuation.
* @param {number} itemId - Item id.
*/
getItemValuation(itemId: number): number {
const { cost: INValuation } = this.getItemINTransaction(itemId);
const { cost: OUTValuation } = this.getItemOUTTransaction(itemId);
return INValuation - OUTValuation;
return Math.max(INValuation - OUTValuation, 0);
}
/**
* Retrieve the item closing quantity.
* @param {number} itemId - Item id.
*/
getItemQuantity(itemId: number): number {
const { quantity: INQuantity } = this.getItemINTransaction(itemId);
const { quantity: OUTQuantity } = this.getItemOUTTransaction(itemId);
@@ -79,10 +102,21 @@ export default class InventoryValuationSheet extends FinancialSheet {
return INQuantity - OUTQuantity;
}
/**
* Calculates the item weighted average cost from the given valuation and quantity.
* @param {number} valuation
* @param {number} quantity
* @returns {number}
*/
calcAverage(valuation: number, quantity: number): number {
return quantity ? valuation / quantity : 0;
}
/**
* Mapping the item model object to inventory valuation item
* @param {IItem} item
* @returns {IInventoryValuationItem}
*/
itemMapper(item: IItem): IInventoryValuationItem {
const valuation = this.getItemValuation(item.id);
const quantity = this.getItemQuantity(item.id);
@@ -103,13 +137,18 @@ export default class InventoryValuationSheet extends FinancialSheet {
}
/**
*
* @returns
* Retrieve the inventory valuation items.
* @returns {IInventoryValuationItem[]}
*/
itemsSection() {
itemsSection(): IInventoryValuationItem[] {
return this.items.map(this.itemMapper.bind(this));
}
/**
* Retrieve the inventory valuation total.
* @param {IInventoryValuationItem[]} items
* @returns {IInventoryValuationTotal}
*/
totalSection(items: IInventoryValuationItem[]): IInventoryValuationTotal {
const valuation = sumBy(items, item => item.valuation);
const quantity = sumBy(items, item => item.quantity);
@@ -122,7 +161,11 @@ export default class InventoryValuationSheet extends FinancialSheet {
};
}
reportData() {
/**
* Retrieve the inventory valuation report data.
* @returns {IInventoryValuationStatement}
*/
reportData(): IInventoryValuationStatement {
const items = this.itemsSection();
const total = this.totalSection(items);

View File

@@ -89,11 +89,12 @@ export default class InventoryValuationSheetService {
builder.select('itemId');
builder.groupBy('itemId');
};
// Retrieve the inventory cost `IN` transactions.
const INTransactions = await InventoryCostLotTracker.query()
.onBuild(commonQuery)
.where('direction', 'IN');
// Retrieve the inventory cost `OUT` transactions.
const OUTTransactions = await InventoryCostLotTracker.query()
.onBuild(commonQuery)
.where('direction', 'OUT');
@@ -105,7 +106,7 @@ export default class InventoryValuationSheetService {
OUTTransactions,
baseCurrency,
);
// Retrieve the inventory valuation report data.
const inventoryValuationData = inventoryValuationInstance.reportData();
return {