Invoice Cost Spreader is a lightweight landed-cost calculator for cannabis operators.
It spreads invoice-level costs like freight, fees, and discounts across received inventory lines using explicit allocation methods. The goal is to produce more defensible adjusted unit costs for inventory, margin analysis, COGS review, and reconciliation workflows.
Do not blindly spread invoice costs per line.
Cannabis invoices often contain wildly different quantities and values per line. A single invoice may include one bulk flower line, hundreds of pre-rolls, a few dozen eighths, and additional freight or fees. Spreading costs evenly across invoice lines can distort unit cost, margin, and COGS.
Invoice Cost Spreader supports allocation by unit count or invoice value so operators can calculate landed cost with clearer assumptions.
In short:
Better landed cost in.
Better COGS out.
Cannabis operators often receive inventory in systems that do not make landed cost easy to review or explain.
Common problems include:
- Freight or delivery fees listed at the invoice level
- Discounts applied across an entire invoice
- Multiple product types on one invoice
- Large quantity differences between invoice lines
- Manual spreadsheets used for cost adjustments
- Confusion between line-level cost and unit-level cost
- COGS reports that do not explain where the numbers came from
This tool helps turn invoice-level adjustments into structured, line-level landed cost data.
- Spread invoice-level additional costs across received lines
- Support allocation by unit count
- Support allocation by invoice value
- Apply invoice-level discounts
- Calculate adjusted line cost
- Calculate adjusted unit cost
- Return structured JSON output
- Write optional run-directory JSON artifacts
- Emit a MOBY-compatible run manifest sidecar in run-directory mode
- Warn when discounts exceed additional costs
- Includes automated tests with Vitest
- Runs from the command line
Unit allocation spreads costs based on each line’s share of total received units.
Example:
Line share = line quantity / total quantityThis is useful when the additional cost should be distributed evenly across sellable units.
Value allocation spreads costs based on each line’s share of the invoice’s base cost.
Example:
Line share = line base cost / total base costThis is useful when higher-value products should carry a larger share of the additional invoice costs.
{
"allocationMethod": "unit",
"additionalCosts": 180,
"discounts": 75,
"lines": [
{
"sku": "FLOWER-BULK-001",
"description": "Bulk Flower",
"quantity": 1,
"unitCost": 800
},
{
"sku": "PREROLL-240",
"description": "Pre-Rolls",
"quantity": 240,
"unitCost": 2.5
},
{
"sku": "EIGHTH-036",
"description": "Eighths",
"quantity": 36,
"unitCost": 12
}
]
}{
"allocationMethod": "unit",
"totalBaseCost": 1832,
"totalQuantity": 277,
"additionalCosts": 180,
"discounts": 75,
"netAdditionalCost": 105,
"lines": [
{
"sku": "FLOWER-BULK-001",
"description": "Bulk Flower",
"quantity": 1,
"unitCost": 800,
"lineBaseCost": 800,
"allocatedCost": 0.65,
"allocatedDiscount": 0.27,
"adjustedLineCost": 800.38,
"adjustedUnitCost": 800.38
},
{
"sku": "PREROLL-240",
"description": "Pre-Rolls",
"quantity": 240,
"unitCost": 2.5,
"lineBaseCost": 600,
"allocatedCost": 155.96,
"allocatedDiscount": 64.98,
"adjustedLineCost": 690.97,
"adjustedUnitCost": 2.88
},
{
"sku": "EIGHTH-036",
"description": "Eighths",
"quantity": 36,
"unitCost": 12,
"lineBaseCost": 432,
"allocatedCost": 23.39,
"allocatedDiscount": 9.75,
"adjustedLineCost": 445.65,
"adjustedUnitCost": 12.38
}
],
"warnings": []
}Clone the repo and install dependencies:
npm installRun the example invoice:
npm run spread -- examples/invoice-input.json --jsonThe CLI reads an invoice JSON file and outputs a structured landed-cost result.
By default, the CLI is stdout-only. It does not create files unless --run-dir is provided.
Write a saved run folder:
npm run spread -- examples/invoice-input.json --json --run-dir output/runs --run-id invoice-run-001Creates:
output/runs/invoice-run-001/
spread-result.json
moby-run-manifest.jsonIf --run-id is omitted, the CLI generates a timestamp-based run ID. The moby-run-manifest.json file follows the MobyRunManifest contract from moby-core and describes the invoice input, spread result artifact, warning metadata, and summary counts.
npm testRuns the test suite.
npm run spread -- examples/invoice-input.json --jsonRuns the invoice cost spreader CLI.
npm run spread -- examples/invoice-input.json --json --run-dir output/runs --run-id invoice-run-001Runs the CLI and writes a saved run folder with spread-result.json and moby-run-manifest.json.
npm run import -- --csv samples/korona-export-money-example.csv --map samples/korona-mapping.json --run-dir output/runs --run-id moby-sidecar-test-001 --moby-json output/runs/moby-sidecar-test-001/moby-import.jsonAdds:
output/runs/moby-sidecar-test-001/moby-import.jsonThe sidecar is the portable bridge artifact for MOBY-aware consumers such as trackingthc.com/import-review.
invoice-cost-spreader fits into the MOBY ecosystem as a costing adapter: it spreads invoice-level costs, discounts, and landed-cost adjustments into reviewable run artifacts that other TrackingTHC tools can inspect.
Use --run-dir when you want the normal CLI output saved as MOBY-compatible artifacts. Default stdout behavior stays unchanged; explicit run-directory mode writes the spread result and run manifest to disk.
npm run spread -- --invoice samples/vendor-invoice-example.csv --packages samples/pos-export-example.csv --run-dir output/runs --run-id sample-invoice-spread-001Example run output:
output/runs/sample-invoice-spread-001/
spread-result.json
moby-run-manifest.jsonspread-result.json is the module's normal result artifact. moby-run-manifest.json describes the run, sources, artifacts, warnings, and summary counts so committed sample manifests can be displayed in TrackingTHC MOBY Mission Control at /moby-runs.
This module does not replace accounting or POS systems. It creates reviewable costing artifacts that help teams compare, audit, and explain how invoice costs were allocated.
export type InvoiceCostInput = {
lines: InvoiceLine[];
additionalCosts: number;
discounts: number;
allocationMethod: "unit" | "value";
};export type InvoiceLine = {
sku: string;
description: string;
quantity: number;
unitCost: number;
};export type SpreadResult = {
allocationMethod: "unit" | "value";
totalBaseCost: number;
totalQuantity: number;
additionalCosts: number;
discounts: number;
netAdditionalCost: number;
lines: SpreadLineResult[];
warnings: string[];
};When --run-dir is used, spread-result.json preserves the same SpreadResult JSON shape printed to stdout.
moby-run-manifest.json is additive and includes:
schemaVersion
runId
runType
generatedBy
generatedAt
status
sources
artifacts
warnings
summary
metadataWarnings remain string[] in SpreadResult. The MOBY run manifest adapts those strings into MobyWarning objects with coarse stable codes and review metadata for downstream tooling.
- Cannabis invoice review
- Landed cost calculation
- COGS reconciliation
- Receiving audit support
- Margin analysis
- Inventory cost correction
- Finance handoff preparation
- POS or accounting import preparation
This is an early MVP and intentionally stays small.
Current limitations:
- Supports only
unitandvalueallocation methods - Does not yet support weight-based allocation
- Does not yet support manual per-line overrides
- Does not persist invoice history
- Does not connect directly to POS, accounting, or compliance systems
- Outputs JSON only
Possible future improvements:
- Markdown summary output
- CSV export
- Weight-based allocation
- Manual allocation overrides
- Per-line warning details
- Rounding mode configuration
- Invoice comparison examples
- POS import/export templates
- Integration into a larger cannabis operations workbench
Invoice Cost Spreader is part of a broader operator-first approach to cannabis tooling.
The goal is not to force operators into perfect enterprise workflows. The goal is to accept messy operational inputs, preserve the useful signal, and translate it into structured business data.
Or, less formally:
Landed cost with paws.
MIT