diff --git a/models/inventory/InventorySettings.ts b/models/inventory/InventorySettings.ts index 34dcb6f3..69b27da3 100644 --- a/models/inventory/InventorySettings.ts +++ b/models/inventory/InventorySettings.ts @@ -1,12 +1,10 @@ import { Doc } from 'fyo/model/doc'; import { FiltersMap, ReadOnlyMap } from 'fyo/model/types'; import { AccountTypeEnum } from 'models/baseModels/Account/types'; -import { ValuationMethod } from './types'; export class InventorySettings extends Doc { defaultLocation?: string; stockInHand?: string; - valuationMethod?: ValuationMethod; stockReceivedButNotBilled?: string; costOfGoodsSold?: string; enableBarcodes?: boolean; diff --git a/models/inventory/StockTransfer.ts b/models/inventory/StockTransfer.ts index bcc97fad..49c6509c 100644 --- a/models/inventory/StockTransfer.ts +++ b/models/inventory/StockTransfer.ts @@ -27,6 +27,7 @@ import { validateSerialNumber, } from './helpers'; import { ReturnDocItem } from './types'; +import { getShipmentCOGSAmountFromSLEs } from 'reports/inventory/helpers'; export abstract class StockTransfer extends Transfer { name?: string; @@ -128,7 +129,7 @@ export abstract class StockTransfer extends Transfer { 'stockInHand' )) as string; - const amount = this.grandTotal ?? this.fyo.pesa(0); + const amount = await this.getPostingAmount(); const posting = new LedgerPosting(this, this.fyo); if (this.isSales) { @@ -163,6 +164,14 @@ export abstract class StockTransfer extends Transfer { return posting; } + async getPostingAmount(): Promise { + if (!this.isSales) { + return this.grandTotal ?? this.fyo.pesa(0); + } + + return await getShipmentCOGSAmountFromSLEs(this); + } + async validateAccounts() { const settings: string[] = ['stockInHand']; if (this.isSales) { diff --git a/reports/inventory/StockLedger.ts b/reports/inventory/StockLedger.ts index 7d80e3ce..a86201a1 100644 --- a/reports/inventory/StockLedger.ts +++ b/reports/inventory/StockLedger.ts @@ -90,9 +90,7 @@ export class StockLedger extends Report { } async _setRawData() { - const valuationMethod = - this.fyo.singles.InventorySettings?.valuationMethod ?? - ValuationMethod.FIFO; + const valuationMethod = ValuationMethod.FIFO; const rawSLEs = await getRawStockLedgerEntries(this.fyo); this._rawData = getStockLedgerEntries(rawSLEs, valuationMethod); diff --git a/reports/inventory/helpers.ts b/reports/inventory/helpers.ts index a18b0c16..28196d56 100644 --- a/reports/inventory/helpers.ts +++ b/reports/inventory/helpers.ts @@ -3,17 +3,22 @@ import { StockQueue } from 'models/inventory/stockQueue'; import { ValuationMethod } from 'models/inventory/types'; import { ModelNameEnum } from 'models/types'; import { safeParseFloat, safeParseInt } from 'utils/index'; -import { +import type { ComputedStockLedgerEntry, RawStockLedgerEntry, StockBalanceEntry, } from './types'; +import type { QueryFilter } from 'utils/db/types'; +import type { StockTransfer } from 'models/inventory/StockTransfer'; type Item = string; type Location = string; type Batch = string; -export async function getRawStockLedgerEntries(fyo: Fyo) { +export async function getRawStockLedgerEntries( + fyo: Fyo, + filters: QueryFilter = {} +) { const fieldnames = [ 'name', 'date', @@ -29,11 +34,73 @@ export async function getRawStockLedgerEntries(fyo: Fyo) { return (await fyo.db.getAllRaw(ModelNameEnum.StockLedgerEntry, { fields: fieldnames, + filters, orderBy: ['date', 'created', 'name'], order: 'asc', })) as RawStockLedgerEntry[]; } +export async function getShipmentCOGSAmountFromSLEs( + stockTransfer: StockTransfer +) { + const fyo = stockTransfer.fyo; + const date = stockTransfer.date ?? new Date(); + const items = (stockTransfer.items ?? []).filter((i) => i.item); + const itemNames = Array.from(new Set(items.map((i) => i.item))) as string[]; + + type Item = string; + type Batch = string; + type Location = string; + type Queues = Record>>; + + const rawSles = await getRawStockLedgerEntries(fyo, { + item: ['in', itemNames], + date: ['<=', date.toISOString()], + }); + + const q: Queues = {}; + for (const sle of rawSles) { + const i = sle.item; + const l = sle.location; + const b = sle.batch ?? '-'; + + q[i] ??= {}; + q[i][l] ??= {}; + q[i][l][b] ??= new StockQueue(); + + const sq = q[i][l][b]; + if (sle.quantity > 0) { + const rate = fyo.pesa(sle.rate); + sq.inward(rate.float, sle.quantity); + } else { + sq.outward(-sle.quantity); + } + } + + let total = fyo.pesa(0); + for (const item of items) { + const i = item.item ?? '-'; + const l = item.location ?? '-'; + const b = item.batch ?? '-'; + + const sq = q[i][l][b]; + const stAmount = item.amount ?? 0; + if (!sq) { + total = total.add(stAmount); + } + + const stRate = item.rate?.float ?? 0; + const stQuantity = item.quantity ?? 0; + + const rate = sq.outward(stQuantity) ?? stRate; + const amount = rate * stQuantity; + + total = total.add(amount); + } + + return total; +} + export function getStockLedgerEntries( rawSLEs: RawStockLedgerEntry[], valuationMethod: ValuationMethod diff --git a/schemas/app/inventory/InventorySettings.json b/schemas/app/inventory/InventorySettings.json index d0c6461c..fd1c6ceb 100644 --- a/schemas/app/inventory/InventorySettings.json +++ b/schemas/app/inventory/InventorySettings.json @@ -4,24 +4,6 @@ "isSingle": true, "isChild": false, "fields": [ - { - "fieldname": "valuationMethod", - "label": "Valuation Method", - "fieldtype": "Select", - "options": [ - { - "value": "FIFO", - "label": "FIFO" - }, - { - "value": "MovingAverage", - "label": "Moving Average" - } - ], - "default": "FIFO", - "required": true, - "section": "Default" - }, { "fieldname": "defaultLocation", "label": "Default Location",