> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alforse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shelf life

> How Alforse stamps expiration dates on tracked stock, and blocks consuming it once expired.

**Shelf life** determines when serial- or batch-tracked stock expires and whether it can be used afterward. The expiration date belongs to the physical **tracked entity**, so shelf life applies only to **Serial-** and **Batch-tracked** items.

Three values control shelf life: an item-level **policy**, a tracked entity's **expiration date**, and a **company-wide rule** for expired stock.

For example, receiving a batch under a **120-day** policy sets its expiration date 120 days later. After that date, Alforse blocks issue to a job unless an authorized user overrides the block.

## How a date gets set: the three modes

An item's shelf-life policy has one **mode**. `NotManaged` is the default — no expiry is tracked, and choosing it removes any existing policy. The other three modes each decide how the expiration date is computed:

| Mode | The date is… | Applies to |
| - | - | - |
| Fixed Duration | a start event **+ a number of days** | Make or Buy items |
| Calculated | the **earliest expiry of the components** consumed to make it | Make items |
| Set on Receipt | **typed in by the operator** at receipt. Nothing is computed | Buy items |

HEADS UP

Shelf life is **not** a single "days" field on the item. Only **Fixed Duration** is a day count.
*Calculated* inherits the soonest expiry of its inputs, and *Set on Receipt* captures the supplier's
printed date by hand. A "received date + N days" mental model is wrong for two of the three modes.

## When the clock starts

For **Fixed Duration**, the start event depends on how the item is sourced:

* **Made** items start at a **job operation** finishing (or starting) — optionally gated to a specific
  **trigger process** (say, *Pasteurise* or *Packaging*), with **Before** or **After** timing. Sub-assemblies
  stamp their own batches from their own operations.
* **Bought** items start from the **receipt's posting date**, not "today", plus the configured days.

**Calculated** items take the minimum expiration date across the tracked components they consume, so a build
can never outlive its shortest-dated ingredient. Whether that minimum spans **every** dated input or only
inputs that themselves carry a shelf-life policy is the company's *calculated input scope*: `AllInputs`
(the default) or `ManagedInputsOnly`.

## Policy fields

The policy lives on the item's pick method:

FieldType

<details>
  <summary>**Mode**</summary>

  *Fixed Duration*, *Calculated*, or *Set on Receipt*. *(applies to: all)*
</details>

<details>
  <summary>**Days**</summary>

  The shelf-life length added to the start event. *(applies to: Fixed Duration)*
</details>

<details>
  <summary>**Trigger process**</summary>

  The operation that starts the clock; blank means any operation. *(applies to: Fixed Duration (made))*
</details>

<details>
  <summary>**Timing**</summary>

  Whether the clock starts **Before** or **After** that process. *(applies to: Fixed Duration (made))*
</details>

<details>
  <summary>**Calculate from BOM**</summary>

  Also cap the date at the earliest expiry of the consumed components. *(applies to: Fixed Duration)*
</details>

NOTE

The expiration date is only ever written once, where it was blank. Alforse never silently overwrites a date a
batch already carries. A manual override is available, but it requires a **reason**, which is kept on the
entity's history.

## What happens to expired stock

A company-wide **expired-entity policy** governs every material issue and stock transfer:

| Policy | Effect when stock is past its date |
| - | - |
| Warn | Allowed, with a warning. |
| Block | Rejected. *(default)* |
| BlockWithOverride | Rejected unless the user supplies an override reason. |

HEADS UP

Expiry is **enforced, not cosmetic.** The default policy is **Block**. Consuming or transferring an expired
batch is rejected outright, with the error *"Cannot consume expired tracked entit(y/ies)"*. The check runs
wherever stock is consumed or moved (material issues, stock transfers, and maintenance work), so it holds
whether the action comes from the office or the floor.

Picking is **FEFO-aware**: available tracked entities are offered earliest-expiry-first, so the oldest stock
leaves first by default. A **near-expiry warning** highlights batches approaching their date in the tracked-entity
lists; set its lead time (in days) in company settings. Leaving it blank turns the warning badges off.

## Company settings

Set company-wide in **Settings → Inventory**:

FieldType

<details>
  <summary>**Expired-entity policy**</summary>

  *Warn*, *Block*, or *BlockWithOverride* for issues and transfers.
</details>

<details>
  <summary>**Near-expiry warning (days)**</summary>

  Lead time for the amber "expiring soon" badges; blank disables them.
</details>

<details>
  <summary>**Default shelf-life days**</summary>

  The starting value of the days input when an item is first set to Fixed Duration. Defaults to 7.
</details>

<details>
  <summary>**Calculated input scope**</summary>

  `AllInputs` or `ManagedInputsOnly` for *Calculated* mode.
</details>

## Where you set it

| Setting | Where |
| - | - |
| The per-item policy (mode, days, trigger process, timing) | On the item's **pick method** (item ↔ location), under its shelf-life fields. |
| The expired-entity policy, near-expiry days, default days | **Settings → Inventory**, in the shelf-life section. |
| A one-off date correction | The expiry-edit action on a tracked entity (reason required). |

NOTE

Setting a shelf-life policy is only allowed on **Serial** or **Batch** items. Fungible *Inventory* and
*Non-Inventory* items have no tracked entity to carry a date, so the option doesn't apply.

## Related

**Traceability**

Expiration lives on the tracked entity — the same lot/serial record traceability follows.

[Open](/docs/reference/traceability.md)

**Inventory**

Locations, the movement ledger, and tracked stock.

[Open](/docs/reference/inventory.md)

**Items**

Only Serial- and Batch-tracked items can carry a shelf-life policy.

[Open](/docs/reference/items.md)

**Storage rules**

The other inventory guard: validate transactions instead of dating stock.

[Open](/docs/reference/storage-rules.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.