Allow sales configurations to create shipments in draft

Closes #15088
This commit is contained in:
Maxime Richez
2026-09-23 09:46:34 +02:00
parent bada63ef4b
commit 621fded36b
6 changed files with 110 additions and 2 deletions
+1
View File
@@ -1,3 +1,4 @@
* Allow sales configurations to create shipments in draft
Version 8.0.0 - 2026-04-20
--------------------------
+15 -1
View File
@@ -15,6 +15,9 @@ sale_invoice_method = fields.Selection(
'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 @@ class Configuration(
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 @@ class Configuration(
@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 @@ class Configuration(
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 @@ class ConfigurationSaleMethod(ModelSQL, ValueMixin):
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 @@ class ConfigurationSaleMethod(ModelSQL, ValueMixin):
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'
+11 -1
View File
@@ -1242,6 +1242,8 @@ class Sale(
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 @@ class Sale(
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)
@@ -0,0 +1,4 @@
[
{"sale_wait_shipment": true}
,{"sale_wait_shipment": false}
]
@@ -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')
+6
View File
@@ -5,11 +5,17 @@ this repository contains the full copyright notices and license terms. -->
<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"/>