Harvest & Supply Inventory
Agro-input staging, growing-crop biological asset tracking (IAS 41), silo & storage management, and material consumption analytics — the four ledgers that turn field spend into capitalized harvest value.
What this group does
Four screens, one service file (src/services/harvestSupplyInventoryService.ts), covering the full input-to-output supply chain: chemicals/fertilizers/seeds are staged and deducted as they're used; growing crops are tracked as biological assets that accumulate capitalized costs (IAS 41-style) until harvest; harvested volume lands in silo/storage as intake lots; and every dollar spent along the way is reconciled through one shared material consumption ledger.
Under the hood — where the silo registry actually lives
The silo registry (SiloRecord) originally lived as a minimal stand-in inside agroTechExecutionService.ts, used by Season & Harvest Scheduling for storage reservation before this screen existed. When Silo & Storage Management shipped, ownership of that store moved into harvestSupplyInventoryService.ts — and agroTechExecutionService.ts now re-exports fetchSiloRegistry, saveSilo, reserveStorageCapacity, and the SiloRecord type from here, so existing callers (Season & Harvest Scheduling, Farm-to-Fork Traceability) needed no changes. If you're tracing where a silo write actually lands, always look in this file, even when the calling code imports from agroTechExecutionService.ts.
1. Agro-Input Staging
Purpose: Track on-hand stock of fertilizers, pesticides, seeds/seedlings, and soil conditioners staged for field use — expiration, hazard level, reorder threshold.
Key features
- Codes —
STG-2026-XXXXstaging lot id (generateStagingLotId) andSKU-2026-XXXXSKU id (generateSkuId), tracked separately since one SKU can have multiple staging lots (different expiration dates). - Categories —
fertilizers,pesticides,seeds_seedlings,soil_conditioners(AgroInputCategory). - Expiration countdown meter —
computeDaysToExpiration()returns days remaining (negative once expired). - Derived status —
computeDerivedStatus()always overrides stored status:expired_quarantinedif days-to-expire ≤ 0, elselow_stock_alertif quantity ≤ reorder threshold, elsestaged_ready(AgroInputStagingStatus). - MSDS hazard levels —
none,irritant,toxic,highly_toxic_corrosive(MsdsHazardLevel).
Integration triggers
| Action / Hook | What it does |
|---|---|
deductStagingStock | Deducts quantityOnHand across the SKU's staging lots (earliest-expiring first), recomputing each lot's derived status. Called from Field & Greenhouse Orders on order completion and from Agro-Chemical Analytics on chemical application. |
reconcileWithChemicalAnalytics | Pushes the staging lot's active-ingredient profile onto a matching Agro-Chemical Analytics record (matched by sourceTestId/recordCode/id), and marks syncedToChemicalAnalytics: true. Real write against qualityCropHealthService.ts. |
triggerPurchaseOrderReorder | Flips reorderTriggered: true on a low-stock record. A local flag only — no Purchase/Procurement screen exists yet in Agriculture to route the actual PO to. |
2. Growing Crop Tracking (WIP)
Purpose: Track each active planting as a biological asset (IAS 41-style) — accumulating capitalized costs by category as the crop moves through growth stages toward harvest.
Key features
- Batch codes —
WIP-2026-XXXX(generateWipBatchId). - Cost capitalization —
CapitalizedCostEntry[]tagged by categorylabor,irrigation,fertilizer,land_usage, each entry timestamped with an optional note. - GDD maturity gauge —
computeMaturityPercent()expresses accumulated Growing Degree Days as a percentage of the crop's target GDD, capped at 100. - Growth stages —
germination → vegetative → flowering → fruiting → harvest_ready(GrowthStage). - Status —
active_wip,storm_damage_flag,harvest_in_progress(GrowingCropWIPStatus).
Integration triggers
| Action / Hook | What it does |
|---|---|
capitalizeWIPToHarvest | On harvest completion, calls logInboundStorageBatch() (re-exported from this same file via agroTechExecutionService.ts) to create an unverified intake lot in the silo registry, then sets capitalizedToHarvest: true and status harvest_in_progress on the WIP record. |
syncAccumulatedCosts | Reads unreconciled Agro-Material Consumption records for the WIP's location, sums their totalCost, adds it to accumulatedInputCosts, and marks each consumption record wipCostsReconciled: true with a linkedWipId back-reference. Real, local — this service owns both the WIP store and the consumption ledger. |
3. Silo & Storage Management
Purpose: Manage bulk silo/warehouse storage capacity — fill level, grain condition, aeration, quarantine status — and link stored lots back to traceability.
Key features
- Silo codes —
SILO-2026-XXXX(generateSiloCode). - Fill capacity gauge —
computeFillPercent()expresses reserved tonnage as a percentage of total capacity, capped at 100. - Grain condition readings — moisture %, internal temperature (°C).
- Aeration fan status —
active,idle,maintenance_required(AerationFanStatus). - Quarantine status —
clear,mold_risk_warning,sealed(SiloQuarantineStatus). - Storage condition —
ambient,cold_storage,controlled_atmosphere,dry_depot(SiloCondition).
Integration triggers
| Action / Hook | What it does |
|---|---|
reserveStorageCapacity | Increments a silo's reservedTons by the expected harvest volume. Called by Season & Harvest Scheduling during harvest planning, via the re-export in agroTechExecutionService.ts. |
linkSiloLotToTraceability | Pushes a batch storage record into Farm-to-Fork Traceability, setting storageSiloId/storageSiloCode/storageOriginVerified: true on the matched trace record, and siloLotTraceabilityLinked: true on the silo. Real write against qualityCropHealthService.ts. |
triggerAerationMaintenance | Dispatches an "Aeration Motor Fault / Overheating" work order via createMaintenanceWorkOrder() (re-exported from agroTechExecutionService.ts, wrapping the domain-agnostic maintenanceWorkOrderService.ts), then sets the silo's aerationMaintenanceTriggered: true and aerationFanStatus: maintenance_required. |
4. Agro-Material Consumption
Purpose: The shared consumption ledger every other screen in this add-on posts into — the single source of truth for "what did we actually spend, on what, and where."
Key features
- Consumption IDs —
AMC-2026-XXXX(generateConsumptionId). - Source categories —
chemicals,fertilizers,water_utilities,power_electricity,fuel(MaterialSourceCategory). - Seasonal budget burn gauge —
computeBudgetBurnPercent()compares actual cost total against (budgeted cost/ha × hectares), can exceed 100 if over budget. - Reconciliation modal — a record carries optional
linkedWorkOrderId,linkedResourceCounterId, andlinkedWipIdback-references, plus amanuallyAdjustedflag and free-textreconciliationNote. - Every record is written by another screen — this ledger has no independent "create" flow of its own in the documented pipeline; it is populated entirely by
syncOrderMaterialsToConsumption(Field & Greenhouse Orders) andpostResourceToMaterialConsumption(Resource Counters).
Integration triggers
| Action / Hook | What it does |
|---|---|
syncOrderMaterialsToConsumption (source: Field & Greenhouse Orders) | On order completion, deducts each material from Agro-Input Staging and writes a matching consumption record here. |
postResourceToMaterialConsumption (source: Resource Counters) | Posts a utility counter's net usage and cost as a consumption record (resource type mapped to source category). |
syncAccumulatedCosts (source: Growing Crop Tracking WIP, reads this ledger) | Reads unreconciled records for a WIP's location and folds their cost into the WIP's accumulatedInputCosts, marking them wipCostsReconciled: true. |
End-to-end data flow
| Source screen / hook | Writes | Target screen / store |
|---|---|---|
Field & Greenhouse Orders · syncOrderMaterialsToConsumption | Deducts stock; creates consumption record | Agro-Input Staging + Agro-Material Consumption |
Agro-Input Staging · deductStagingStock | Reduces quantityOnHand per lot, recomputes status | own store (called from multiple sources) |
Agro-Input Staging · reconcileWithChemicalAnalytics | Syncs active ingredient onto matched record | Agro-Chemical Analytics |
Agro-Input Staging · triggerPurchaseOrderReorder | Sets reorderTriggered = true | own record (local flag only) |
Season & Harvest Scheduling · syncScheduleToWIP | Creates GrowingCropWIPRecord | Growing Crop Tracking WIP |
Growing Crop Tracking WIP · capitalizeWIPToHarvest | Creates INTAKE-<batchCode> silo lot | Silo & Storage Management registry |
Growing Crop Tracking WIP · syncAccumulatedCosts | Sums unreconciled consumption cost into accumulatedInputCosts | Agro-Material Consumption (read + reconcile) |
Season & Harvest Scheduling · reserveStorageCapacity (re-exported) | Increments silo reservedTons | Silo & Storage Management registry |
Silo & Storage Management · linkSiloLotToTraceability | Links storage silo to a lot; sets storageOriginVerified | Farm-to-Fork Traceability |
Silo & Storage Management · triggerAerationMaintenance | Dispatches aeration fault work order | maintenanceWorkOrderService (domain-agnostic) |
Resource Counters · postResourceToMaterialConsumption | Creates consumption record | Agro-Material Consumption |
Frequently Asked Questions
agroTechExecutionService.ts still export SiloRecord and silo functions?harvestSupplyInventoryService.ts when Silo & Storage Management shipped, but agroTechExecutionService.ts re-exports fetchSiloRegistry, saveSilo, reserveStorageCapacity, and the SiloRecord/SiloCondition types so that Season & Harvest Scheduling and other pre-existing callers needed zero import changes when ownership moved.manuallyAdjusted flag for hand corrections), not as the primary entry point for new consumption.capitalizeWIPToHarvest creates an unverified intake lot in the silo registry and flips the WIP's status to harvest_in_progress with capitalizedToHarvest: true — the accumulated capitalized costs stay on the WIP record as the batch's final cost basis; they aren't separately transferred elsewhere by this hook.triggerPurchaseOrderReorder only sets a local reorderTriggered flag on the record today — there is no Purchase/Procurement screen wired up in this add-on yet to receive an actual purchase order, so the flag is currently just a visual badge in the staging ledger.computeDerivedStatus() only recomputes the display status to expired_quarantined when days-to-expire ≤ 0; it does not zero out or remove the quantity. Actual stock deduction only happens via deductStagingStock, triggered by real consumption events.triggerAerationMaintenance routes through the domain-agnostic maintenanceWorkOrderService.ts (also used by Manufacturing's Maintenance Operations group), which already exists independently of whether Agriculture ships its own dedicated maintenance screens. See Agro-Equipment Maintenance for that group's roadmap status.