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"/>