details:   https://code.tryton.org/tryton/commit/203ee7d98afd
branch:    default
user:      Maxime Richez <[email protected]>
date:      Wed Sep 23 09:46:34 2026 +0200
description:
        Allow sales configurations to create shipments in draft

        Closes #15088
diffstat:

 modules/sale/CHANGELOG                              |   1 +
 modules/sale/configuration.py                       |  16 ++++-
 modules/sale/sale.py                                |  12 +++-
 modules/sale/tests/scenario_sale_wait_shipment.json |   4 +
 modules/sale/tests/scenario_sale_wait_shipment.rst  |  73 +++++++++++++++++++++
 modules/sale/view/configuration_form.xml            |   6 +
 6 files changed, 110 insertions(+), 2 deletions(-)

diffs (204 lines):

diff -r fed8901dbb27 -r 203ee7d98afd modules/sale/CHANGELOG
--- a/modules/sale/CHANGELOG    Tue Sep 22 18:32:04 2026 +0200
+++ b/modules/sale/CHANGELOG    Wed Sep 23 09:46:34 2026 +0200
@@ -1,3 +1,4 @@
+* Allow sales configurations to create shipments in draft
 
 Version 8.0.0 - 2026-04-20
 --------------------------
diff -r fed8901dbb27 -r 203ee7d98afd modules/sale/configuration.py
--- a/modules/sale/configuration.py     Tue Sep 22 18:32:04 2026 +0200
+++ b/modules/sale/configuration.py     Wed Sep 23 09:46:34 2026 +0200
@@ -15,6 +15,9 @@
     'get_sale_invoice_methods', "Sale Invoice Method")
 sale_shipment_method = fields.Selection(
     'get_sale_shipment_methods', "Sale Shipment Method")
+sale_wait_shipment = fields.Boolean(
+    "Sale Wait Shipment",
+    help="Create customer shipments in a waiting state")
 sale_quotation_validity = fields.TimeDelta(
     "Sale Quotation Validity",
     domain=['OR',
@@ -55,6 +58,7 @@
     sale_invoice_method = fields.MultiValue(sale_invoice_method)
     get_sale_invoice_methods = get_sale_methods('invoice_method')
     sale_shipment_method = fields.MultiValue(sale_shipment_method)
+    sale_wait_shipment = fields.MultiValue(sale_wait_shipment)
     get_sale_shipment_methods = get_sale_methods('shipment_method')
     sale_process_after = fields.TimeDelta(
         "Process Sale after",
@@ -69,7 +73,11 @@
     @classmethod
     def multivalue_model(cls, field):
         pool = Pool()
-        if field in {'sale_invoice_method', 'sale_shipment_method'}:
+        if field in {
+                'sale_invoice_method',
+                'sale_shipment_method',
+                'sale_wait_shipment',
+                }:
             return pool.get('sale.configuration.sale_method')
         if field == 'sale_sequence':
             return pool.get('sale.configuration.sequence')
@@ -80,6 +88,7 @@
     default_sale_sequence = default_func('sale_sequence')
     default_sale_invoice_method = default_func('sale_invoice_method')
     default_sale_shipment_method = default_func('sale_shipment_method')
+    default_sale_wait_shipment = default_func('sale_wait_shipment')
 
 
 class ConfigurationSequence(ModelSQL, CompanyValueMixin):
@@ -107,6 +116,7 @@
     get_sale_invoice_methods = get_sale_methods('invoice_method')
     sale_shipment_method = sale_shipment_method
     get_sale_shipment_methods = get_sale_methods('shipment_method')
+    sale_wait_shipment = sale_wait_shipment
 
     @classmethod
     def __register__(cls, module_name):
@@ -128,6 +138,10 @@
     def default_sale_shipment_method(cls):
         return 'order'
 
+    @classmethod
+    def default_sale_wait_shipment(cls):
+        return True
+
 
 class ConfigurationQuotation(ModelSQL, ValueMixin):
     __name__ = 'sale.configuration.quotation'
diff -r fed8901dbb27 -r 203ee7d98afd modules/sale/sale.py
--- a/modules/sale/sale.py      Tue Sep 22 18:32:04 2026 +0200
+++ b/modules/sale/sale.py      Wed Sep 23 09:46:34 2026 +0200
@@ -1242,6 +1242,8 @@
         pool = Pool()
         ShipmentOut = pool.get('stock.shipment.out')
         ShipmentOutReturn = pool.get('stock.shipment.out.return')
+        Config = pool.get('sale.configuration')
+        config = Config(1)
 
         shipments_out, shipments_return = {}, {}
         for sale in sales:
@@ -1254,7 +1256,15 @@
 
         shipments = sum((v for v in shipments_out.values()), [])
         ShipmentOut.save(shipments)
-        ShipmentOut.wait(shipments)
+
+        to_wait = []
+        for company, c_shipments in groupby(
+                shipments, key=lambda s: s.company):
+            if config.get_multivalue('sale_wait_shipment', company=company.id):
+                to_wait.extend(c_shipments)
+        if to_wait:
+            ShipmentOut.wait(to_wait)
+
         for sale, shipments in shipments_out.items():
             for shipment in shipments:
                 sale.copy_resources_to(shipment)
diff -r fed8901dbb27 -r 203ee7d98afd 
modules/sale/tests/scenario_sale_wait_shipment.json
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/sale/tests/scenario_sale_wait_shipment.json       Wed Sep 23 
09:46:34 2026 +0200
@@ -0,0 +1,4 @@
+[
+    {"sale_wait_shipment": true}
+    ,{"sale_wait_shipment": false}
+]
diff -r fed8901dbb27 -r 203ee7d98afd 
modules/sale/tests/scenario_sale_wait_shipment.rst
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/sale/tests/scenario_sale_wait_shipment.rst        Wed Sep 23 
09:46:34 2026 +0200
@@ -0,0 +1,73 @@
+===========================
+Sale Wait Shipment Scenario
+===========================
+
+Imports::
+
+    >>> from decimal import Decimal
+
+    >>> from proteus import Model
+    >>> from trytond.modules.account.tests.tools import create_chart, 
get_accounts
+    >>> from trytond.modules.company.tests.tools import create_company
+    >>> from trytond.tests.tools import activate_modules, assertEqual
+
+    >>> sale_wait_shipment = globals().get('sale_wait_shipment', True)
+
+Activate modules::
+
+    >>> config = activate_modules('sale', create_company, create_chart)
+
+    >>> Party = Model.get('party.party')
+    >>> ProductCategory = Model.get('product.category')
+    >>> ProductTemplate = Model.get('product.template')
+    >>> ProductUom = Model.get('product.uom')
+    >>> Sale = Model.get('sale.sale')
+    >>> SaleConfiguration = Model.get('sale.configuration')
+
+Create party::
+
+    >>> customer = Party(name='Customer')
+    >>> customer.save()
+
+Create account categories::
+
+    >>> accounts = get_accounts()
+
+    >>> account_category = ProductCategory(name="Account Category")
+    >>> account_category.accounting = True
+    >>> account_category.account_revenue = accounts['revenue']
+    >>> account_category.save()
+
+Create product::
+
+    >>> unit, = ProductUom.find([('name', '=', "Unit")])
+
+    >>> template = ProductTemplate()
+    >>> template.name = 'product'
+    >>> template.default_uom = unit
+    >>> template.type = 'goods'
+    >>> template.salable = True
+    >>> template.list_price = Decimal('10.0000')
+    >>> template.account_category = account_category
+    >>> template.save()
+    >>> product, = template.products
+
+Set wait shipment::
+
+    >>> sale_config = SaleConfiguration(1)
+    >>> sale_config.sale_wait_shipment = sale_wait_shipment
+    >>> sale_config.save()
+
+Create a sale::
+
+    >>> sale = Sale()
+    >>> sale.party = customer
+    >>> line = sale.lines.new()
+    >>> line.product = product
+    >>> line.quantity = 10
+    >>> sale.click('quote')
+    >>> sale.click('confirm')
+    >>> sale.state
+    'processing'
+    >>> shipment, = sale.shipments
+    >>> assertEqual(shipment.state, 'waiting' if sale_wait_shipment else 
'draft')
diff -r fed8901dbb27 -r 203ee7d98afd modules/sale/view/configuration_form.xml
--- a/modules/sale/view/configuration_form.xml  Tue Sep 22 18:32:04 2026 +0200
+++ b/modules/sale/view/configuration_form.xml  Wed Sep 23 09:46:34 2026 +0200
@@ -5,11 +5,17 @@
     <label name="sale_sequence"/>
     <field name="sale_sequence"/>
     <newline />
+
     <label name="sale_invoice_method" />
     <field name="sale_invoice_method" />
+    <newline/>
+
     <label name="sale_shipment_method" />
     <field name="sale_shipment_method" />
+    <label name="sale_wait_shipment"/>
+    <field name="sale_wait_shipment"/>
     <newline/>
+
     <label name="sale_quotation_validity"/>
     <field name="sale_quotation_validity"/>
     <label name="sale_process_after"/>

Reply via email to