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

**URL:** <https://www.dolibarr.org/forum/t/module-assemble-to-order-ato-components-picked-per-product-category/31305>\
**Category:** PM modules\
**Created:** [September 4, 2026, 6:53am UTC](https://www.dolibarr.org/forum/t/module-assemble-to-order-ato-components-picked-per-product-category/31305 "2026-09-04T06:53:05Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![fbosman](https://www.dolibarr.org/forum/letter_avatar_proxy/v4/letter/f/ce7236/32.png) [@fbosman](https://www.dolibarr.org/forum/u/fbosman)\
**Post date:** [September 4, 2026, 6:53am UTC](https://www.dolibarr.org/forum/t/module-assemble-to-order-ato-components-picked-per-product-category/31305/1 "2026-09-04T06:53:05Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![zachmelo](https://www.dolibarr.org/forum/user_avatar/www.dolibarr.org/zachmelo/32/9195_2.png) [@zachmelo](https://www.dolibarr.org/forum/u/zachmelo)\
**Post date:** [September 13, 2026, 11:03pm UTC](https://www.dolibarr.org/forum/t/module-assemble-to-order-ato-components-picked-per-product-category/31305/2 "2026-09-13T23:03:45Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![fbosman](https://www.dolibarr.org/forum/letter_avatar_proxy/v4/letter/f/ce7236/32.png) [@fbosman](https://www.dolibarr.org/forum/u/fbosman)\
**Post date:** [September 14, 2026, 5:03am UTC](https://www.dolibarr.org/forum/t/module-assemble-to-order-ato-components-picked-per-product-category/31305/3 "2026-09-14T05:03:59Z")

</div>

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](https://github.com/fbosman/Dolibarr-ATO) you can find the new version.
