DEV Community

Isaac Mwendwa Muthui
Isaac Mwendwa Muthui

Posted on Edited on Originally published at factoraerp.com

Aflatoxin Results Belong to Lots, Not PDFs: Modelling Grain Intake Tests, Silo Moves and Holds in a Food ERP

By Isaac Muthui, CEO, Tamalaki Business Network Ltd. Originally published at factoraerp.com.

Most factory systems store an aflatoxin result as a PDF attached to a purchase order or a supplier record. That answers "did we get a certificate?". It does not answer the question a regulator or a QA lead asks after a market sample fails: which flour batches used grain from the lots that tested high, and where did that flour go?

An aflatoxin result is only useful if it belongs to something you can trace: a lot of grain that arrived on a specific truck, sat in a specific silo, and was consumed by specific production batches. This post walks through how we think about modelling that in an ERP for food and agro manufacturers. The operational checklist behind it is in the original article.

What the domain rules say

The requirements come from food safety standards, not from software people:

  • EAS 44:2011 (milled maize products) sets a maximum of 10 ppb total aflatoxin and 5 ppb aflatoxin B1 (ISO 16050), 13% maximum moisture, and sampling according to ISO 13690. Source
  • Codex CXC 51-2003 (mycotoxins in cereals) says the intermittent presence of mycotoxins "is to be expected", asks for validated methods and sampling plans, and for procedures to handle suspect grain "through segregation, reconditioning, recall or diversion". It warns that small quantities of highly contaminated grain "can greatly increase mycotoxin levels" in otherwise good grain, and that grain should be tested at loading or unloading before storage at the processing plant. Source

Read as a spec: results attach to lots, lots have a status that gates their use, mixing is an event you must record, and you need to walk the graph from a finished batch back to suppliers and forward to customers.

The data model

A simplified version of the entities:

GrainLot        id, supplier_id, vehicle_reg, received_at, net_kg, status
                status: received | on_hold | accepted | accepted_for_reconditioning | rejected
LotTest         id, lot_id, type (moisture | aflatoxin_total | aflatoxin_b1 | visual),
                value, unit, method, kit_lot, tested_by, tested_at, lab (internal | external)
StorageMove     id, lot_id, from_location, to_location (silo/store), kg, moved_at
StorageReading  id, location_id, temperature_c, moisture_pct, read_at, read_by
Batch           id, product_id, produced_at, line_id
BatchInput      batch_id, location_id or lot_id, kg
BatchTest       id, batch_id, type, value, unit, method, tested_at
Dispatch        id, batch_id, customer_id, kg, dispatched_at
Enter fullscreen mode Exit fullscreen mode

Three design choices matter more than the field list.

1. Status is derived from tests and decisions, not typed in. A lot arrives as received. It cannot move to accepted until the required tests for that supplier and season exist and pass, and a named person records the decision. A failed or missing result puts it on_hold, and stock on hold cannot be issued to production. That turns the intake specification into an enforced rule instead of a sticky note at the weighbridge.

2. Silos are where traceability gets hard. Once three trucks go into one silo, the grain is mixed. You do not need a perfect physical model of grain flow. You need a conservative one: record every StorageMove into a silo, and treat every batch milled from that silo during a window as potentially containing any lot that was in it. When a market sample fails, over-including a few batches is fine. Missing one is not.

3. Blending is a recorded event, not a fix. The tempting shortcut with a high lot is to mix it into clean grain until the average passes. The rules say no. In the model, a lot on_hold simply has no valid path into a silo that feeds food production. Reconditioning or diversion is a separate, approved status with its own destination.

The query that matters

When a market sample of a flour batch fails, the questions are:

-- 1. Which grain lots could have gone into this batch?
SELECT DISTINCT sm.lot_id
FROM batch_inputs bi
JOIN storage_moves sm ON sm.to_location = bi.location_id
WHERE bi.batch_id = :failed_batch
  AND sm.moved_at <= (SELECT produced_at FROM batches WHERE id = :failed_batch);

-- 2. Which other batches drew from the same silos in the same window?
-- 3. Which customers received those batches, and how much is still in our stores?
Enter fullscreen mode Exit fullscreen mode

With the graph in place, these run in seconds. Without it, they take a team a weekend with gate books, lab sheets and dispatch notes, which is exactly when you are least able to afford it.

Storage monitoring as a time series

Codex says a 2-3°C rise in stored grain temperature may indicate mould or insects. That is a classic time-series alert: store StorageReading rows per location, compute the change against the last few readings, and raise a non-conformance with an owner when the rise crosses your threshold. The alert is only as good as the reading schedule, so missing readings should be an alert too.

What to keep simple

  • The intake test form should be a phone form at the weighbridge, with a server timestamp and the lot number pre-filled. If it takes five minutes, it will be filled in at the end of the shift from memory.
  • Keep limits, test frequencies and supplier risk levels as configuration, because they come from your HACCP plan, your customers and KEBS, not from code.
  • Store the method and kit lot with each rapid test result. When you compare rapid results with an external laboratory, you will want to know which kit produced which number.

The general lesson: in food manufacturing, the useful record is not "a test exists" but "this lot, with this result, went here, and became that". Once tests, holds and silo moves are facts tied to lots, "where did the bad grain go?" becomes a query.

The full 8-step aflatoxin control checklist, with the EAS 44 and Codex references, is on the FactoraERP blog.

Isaac Muthui, CEO, Tamalaki Business Network Ltd

Top comments (0)