📊 ABC/XYZ
Updated
Global Core analytics in the Sales model: who brings turnover and how stable it is. Not localization and not a separate UI. Replenishment is a separate policy-cell matrix on top of the already calculated class, without a supplier order.
User instructions: how to recalculate. Mechanics: the service and the register.
Why#
Once Revenue, Stock and InventoryValue are already moving, the office needs a configurable classification rather than three letters in the code. The profile is the scheme; the bands are the class ladder; the information register is the history of the snapshot on a date.
Two seeded profiles:
- items by revenue over 12 months, Pareto 80/95, XYZ by CV;
- customers on the same scheme.
Beyond that you can add "stock in money", "stock in units", your own letters and more classes — as rows, without a release.
How it is built#
AbcProfile + AbcClassBand
↓ the Recalculate command / the RecalcAbcClassifications job
IAbcClassifier.RecalcAsync / RecalcAllEnabledAsync
↓
IR AbcClassification SliceLast(Profile, Subject)
Subject in the log is the Guid of an item or of a customer, whichever the profile names. Two profiles do not mix objects. A non-empty item group on an item profile narrows the selection: classes and shares are calculated inside the group, and outside items leave this date's slice. An empty group means the whole catalogue. On a customer profile the group is not used.
Measures:
| Measure | Item | Customer |
|---|---|---|
Revenue |
sum of Amount by the Item analytic |
same by Customer |
StockQty |
the Stock.Qty balance |
recalculation error |
InventoryValue |
the Value balance |
recalculation error |
ABC CumulativeShare: sorted by score descending, the class is set by the cumulative share before including the position. The first large item with 80% of revenue is A. Zero scores are excluded from Pareto.
XYZ: the window is cut into BucketCount buckets; Cv = σ/μ across buckets (μ = 0 → the last XYZ band). A stock snapshot does not calculate XYZ — the profile has XyzMethod = None.
Bands with a gap or overlap make the recalculation fail, and the log is left untouched.
Recalculation, the phone and replenishment#
Office recalculation, the AbcClassification log and the nightly RecalcAbcClassifications job (0 2 * * *, skips IsDisabled) are live.
The agent phone reads the CachedAbc projection (SliceLast of live Item and Customer profiles). One profile on a subject gives A/X; two add the profile name before the letters. A disabled profile and an empty class do not enter the projection. The phone does not calculate the class.
Replenishment is an AbcPolicyCell matrix: a pair of profile classes and a mode. Letters are not hardcoded: an A/X cell also works for Gold/Stable if the bands are named that way. An empty mode (Not set, the zero enum value) does not apply the cell.
| Mode | What the AbcSuggestion log writes |
|---|---|
| Keep stock | to order = coverage in days × (issue / window days) − balance, not below zero |
| Buy to order | to order = 0 |
What's not there yet#
- The classification does not move stock, reserve items or create procurement by itself; only Create purchase drafts writes draft orders from replenishment rows.
- Customer profiles do not produce replenishment proposals or purchase drafts.
- The agent phone only shows cached ABC/XYZ labels; it cannot recalculate classes or edit profile bands.
- There is no separate ABC/XYZ chart screen. The list and the card are ordinary platform forms.
Same topic for other readers: User · Developer