Module] Assemble-to-Order (ATO) — components picked per product category

Hi all,

I’ve almost published a small module for a case that kits/BOMs don’t cover: products you
sell as one article but assemble per order.

A “server” consists of a monitor, a cpu and a switch — but which monitor depends
on stock and on what the customer wants. A virtual product (PRODUIT_SOUSPRODUITS)
needs a fixed component list, so that doesn’t fit.

What it does

On the composed product you define composition rules per product category
(“1 from Monitors, 1 from Keyboards”) instead of a fixed BOM. The concrete
articles are chosen in the draft order, and are added as real order lines below
the composite line via fk_parent_line. Price stays on the parent, stock runs
through the children.

The composed product is a service, so Dolibarr books no stock on it and it never
reaches the shipment. Only the components do.

Why at order entry, not at shipment

This was the main design decision, and it’s worth flagging for anyone attempting
something similar. Expedition::valid() calls manageStockMvtOnEvt() at line ~856,
before call_trigger(‘SHIPPING_VALIDATE’), and that query reads cd.fk_product from
commandedet — not ed.fk_product from expeditiondet. So you cannot redirect the
stock movement from a trigger there; the best you get is booking wrong and rolling
back. Resolving the composition one step earlier removes the problem instead of
working around it.

The consequence is everything after order validation is untouched core: shipment,
stock movements, batch/serial, delivery note, invoicing, returns. Barcode picking
on a handheld just sees ordinary product lines — no connector changes needed.

Other notes

  • ORDER_VALIDATE is blocked while a mandatory rule is unfulfilled. No stock has
    been booked at that point, so nothing needs rolling back.
  • One setting governs component-line visibility across order card, order PDF,
    invoice card and invoice PDF at once — deviating per place is deliberately not
    possible. Screen goes through printObjectSubLine, PDF through
    commonGenerateDocument (pdf_writelinedesc only replaces the description, not the
    line). Facture::createFromOrder() copies special_code and fk_parent_line, so the
    invoice side needs no extra code.
  • Components may be chosen a few at a time; completeness is only enforced at
    validation.

Dolibarr 20+, PHP 7.4+, GPLv3, EN/NL. Requires STOCK_SUPPORTS_SERVICES and
SHIPMENT_SUPPORTS_SERVICES to be off; the setup page checks both.

Feedback welcome, especially from anyone who has hit the same
sell-abstract/ship-concrete problem and solved it differently.

I had not considered this as a valid approach and we have an exhaustive list of products and variations. I’ll give this a try on a staging server and let you know how it works. Some screenshots or a demo video would be great!

Hi,

I’m waiting for approval of this module on dolistore.

On GitHub - fbosman/Dolibarr-ATO: Assemble-to-Order for Dolibarr: composition rules per product category, resolved into real order lines at order entry · GitHub you can find the new version.