import { err, ok } from "@tailor-platform/erp-kit/core"; import { Decimal } from "decimal.js"; import type { Transaction } from "../../../generated/kysely-tailordb"; import { FifoCostNotFoundError, UnitCostRequiredError } from "../../../lib/errors.generated"; import { pushNonZero, type CostingFact, type CostingRole } from "../journalEntry"; import type { ConsumedSlice } from "./costLayer"; export async function priceFifoReceipt( db: Transaction, args: { itemId: string; layerId: string; quantity: Decimal; unitCost?: Decimal; counterpartRole: CostingRole; }, ) { const { itemId, layerId, quantity, unitCost, counterpartRole } = args; if (!unitCost) { return err(new UnitCostRequiredError(itemId)); } await db .insertInto("FifoCost") .values({ costLayerId: layerId, version: 1, unitCost: unitCost.toString(), }) .execute(); const actualValue = unitCost.mul(quantity); const facts: CostingFact[] = []; pushNonZero(facts, { role: "INVENTORY", dcIndicator: "DR", amount: actualValue.toString(), }); pushNonZero(facts, { role: counterpartRole, dcIndicator: "CR", amount: actualValue.toString(), }); return ok(facts); } export async function priceFifoIssue( db: Transaction, args: { slices: ConsumedSlice[]; counterpartRole: CostingRole }, ) { const { slices, counterpartRole } = args; let issueValue = new Decimal(0); for (const slice of slices) { const price = await db .selectFrom("FifoCost") .selectAll() .where("costLayerId", "=", slice.layerId) .orderBy("version", "desc") .limit(1) .executeTakeFirst(); if (!price) { return err(new FifoCostNotFoundError(slice.layerId)); } issueValue = issueValue.plus(slice.quantity.mul(price.unitCost)); } const facts: CostingFact[] = []; pushNonZero(facts, { role: counterpartRole, dcIndicator: "DR", amount: issueValue.toString(), }); pushNonZero(facts, { role: "INVENTORY", dcIndicator: "CR", amount: issueValue.toString(), }); return ok(facts); }