Product Costing Categories
This process describes the implemented catalogue classification and its
operator-run backfill. Products.Costing_Category is separate from the commercial
Product_Category. Classification does not change billing prices or identify
which Product belongs on an invoice line.
Classification
| Category | Cost basis identified by the classification |
|---|---|
Labour/service |
Internal delivery labour; no Product purchase price is required |
Purchased product/licence |
Purchased goods, licences or externally supplied services |
Mixed/bundle |
Both internal labour and identified purchased components |
Unclassified |
Costing type requires review |
A blank or zero cost price does not establish a category. Explicit supplier-cost or delivery-budget links remain relevant in every category. The classification alone does not establish complete costs or a historical margin.
Seat L1/L2/L3/SB, their annual/prorated variants and Extra Device are classified
as Labour/service because their licences are billed separately. Those licence
Products have their own purchased-cost basis. An externally purchased service
is a purchased item even though its name contains “service”.
Prepare and apply the backfill
Preparation captures all existing Products, including inactive records, and
produces one classification per Product. Clear hardware/goods/software/licence
categories map to purchased items. Other classifications require an explicit
Product-ID decision and reason; otherwise the migration writes Unclassified.
It does not infer labour from a missing price or broad “Managed Services” or
“service” categories.
Applying the saved migration creates the Costing Category picklist when absent
and updates only Costing_Category. Established classifications are preserved.
The writer checks captured source values before batches of up to 100, uses a
server-time cutoff to reject concurrent edits, disables optional record triggers
and verifies every saved record.
The private journal supports restarting a partially completed run. Changed records, conflicting metadata or failed readback stop the batch. The writer does not modify Product prices, invoice Product links, invoices or billing inputs. New Products with blank categories remain unclassified until populated.
Implementation: commercial_services/product_costing_migration.py.
Classification logic: app/service_planning/product_costing.py.
Validation: tests/commercial_services/test_product_costing_migration.py.