[MERGE] sale_order_dates: several improvements to usability and planned date computing, courtesy of Lionel Sausin (Numerigraphe)
bzr revid: odo@openerp.com-20140306202430-aw45sqw6og8ezcni
This commit is contained in:
commit
499e0e323d
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Dates on Sales Order',
|
'name': 'Dates on Sales Order',
|
||||||
'version': '1.0',
|
'version': '1.1',
|
||||||
'category': 'Sales Management',
|
'category': 'Sales Management',
|
||||||
'description': """
|
'description': """
|
||||||
Add additional date information to the sales order.
|
Add additional date information to the sales order.
|
||||||
|
@ -30,7 +30,7 @@ Add additional date information to the sales order.
|
||||||
|
|
||||||
You can add the following additional dates to a sales order:
|
You can add the following additional dates to a sales order:
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
* Requested Date
|
* Requested Date (will be used as the expected date on pickings)
|
||||||
* Commitment Date
|
* Commitment Date
|
||||||
* Effective Date
|
* Effective Date
|
||||||
""",
|
""",
|
||||||
|
@ -40,7 +40,7 @@ You can add the following additional dates to a sales order:
|
||||||
'depends': ['sale_stock'],
|
'depends': ['sale_stock'],
|
||||||
'data': ['sale_order_dates_view.xml'],
|
'data': ['sale_order_dates_view.xml'],
|
||||||
'demo': [],
|
'demo': [],
|
||||||
'test': [],
|
'test': ['test/requested_date.yml'],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
'auto_install': False,
|
'auto_install': False,
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,14 @@ msgstr ""
|
||||||
|
|
||||||
#. module: sale_order_dates
|
#. module: sale_order_dates
|
||||||
#: help:sale.order,effective_date:0
|
#: help:sale.order,effective_date:0
|
||||||
msgid "Date on which picking is created."
|
msgid "Date on which the first Delivery Order was created."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: sale_order_dates
|
#. module: sale_order_dates
|
||||||
#: help:sale.order,requested_date:0
|
#: help:sale.order,requested_date:0
|
||||||
msgid "Date requested by the customer for the sale."
|
msgid "Date by which the customer has requested the items to be delivered.\n"
|
||||||
|
"When this Order gets confirmed, the Delivery Order's expected date will be computed based on this date and the Company's Security Delay.\n"
|
||||||
|
"Leave this field empty if you want the Delivery Order to be processed as soon as possible. In that case the expected date will be computed using the default method: based on the Product Lead Times and the Company's Security Delay."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: sale_order_dates
|
#. module: sale_order_dates
|
||||||
|
@ -52,6 +54,18 @@ msgstr ""
|
||||||
|
|
||||||
#. module: sale_order_dates
|
#. module: sale_order_dates
|
||||||
#: help:sale.order,commitment_date:0
|
#: help:sale.order,commitment_date:0
|
||||||
msgid "Committed date for delivery."
|
msgid "Date by which the products is sure to be delivered. This is a date that you can promise to the customer, based on the Product Lead Times."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sale_order_dates
|
||||||
|
#: code:addons/sale_order_dates/sale_order_dates.py:90
|
||||||
|
#, python-format
|
||||||
|
msgid "Requested date is too soon!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sale_order_dates
|
||||||
|
#: code:addons/sale_order_dates/sale_order_dates.py:91
|
||||||
|
#, python-format
|
||||||
|
msgid "The date requested by the customer is sooner than the commitment date. You may be unable to honor the customer's request."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,40 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
from openerp.tools.translate import _
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
|
||||||
class sale_order_dates(osv.osv):
|
class sale_order_dates(osv.osv):
|
||||||
|
"""Add several date fields to Sale Orders, computed or user-entered"""
|
||||||
_inherit = 'sale.order'
|
_inherit = 'sale.order'
|
||||||
|
|
||||||
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
|
"""Don't copy the requested date along with the Sale Order"""
|
||||||
|
if default is None:
|
||||||
|
default = {}
|
||||||
|
else:
|
||||||
|
default = default.copy()
|
||||||
|
default['requested_date'] = False
|
||||||
|
return super(sale_order_dates, self).copy(cr, uid, id, default=default,
|
||||||
|
context=context)
|
||||||
|
|
||||||
|
def _order_line_move_date(self, cr, uid, line, context=None):
|
||||||
|
"""Compute the expected date from the requested date, not the order date"""
|
||||||
|
order=line.order_id
|
||||||
|
if order and order.requested_date:
|
||||||
|
date_planned = datetime.strptime(order.requested_date,
|
||||||
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
date_planned -= timedelta(days=order.company_id.security_lead)
|
||||||
|
return date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
else:
|
||||||
|
return super(sale_order_dates, self)._order_line_move_date(cr, uid, line)
|
||||||
|
|
||||||
def _get_effective_date(self, cr, uid, ids, name, arg, context=None):
|
def _get_effective_date(self, cr, uid, ids, name, arg, context=None):
|
||||||
|
"""Read the shipping date from the related packings"""
|
||||||
|
# XXX would be better if it returned the date the picking was processed
|
||||||
res = {}
|
res = {}
|
||||||
dates_list = []
|
dates_list = []
|
||||||
for order in self.browse(cr, uid, ids, context=context):
|
for order in self.browse(cr, uid, ids, context=context):
|
||||||
|
@ -41,22 +66,56 @@ class sale_order_dates(osv.osv):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_commitment_date(self, cr, uid, ids, name, arg, context=None):
|
def _get_commitment_date(self, cr, uid, ids, name, arg, context=None):
|
||||||
|
"""Compute the commitment date"""
|
||||||
res = {}
|
res = {}
|
||||||
dates_list = []
|
dates_list = []
|
||||||
for order in self.browse(cr, uid, ids, context=context):
|
for order in self.browse(cr, uid, ids, context=context):
|
||||||
dates_list = []
|
dates_list = []
|
||||||
for line in order.order_line:
|
for line in order.order_line:
|
||||||
dt = datetime.strptime(order.date_order, '%Y-%m-%d') + relativedelta(days=line.delay or 0.0)
|
dt = (datetime.strptime(order.date_order,
|
||||||
dt_s = dt.strftime('%Y-%m-%d')
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
+ timedelta(days=line.delay or 0.0) )
|
||||||
|
dt_s = dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
dates_list.append(dt_s)
|
dates_list.append(dt_s)
|
||||||
if dates_list:
|
if dates_list:
|
||||||
res[order.id] = min(dates_list)
|
res[order.id] = min(dates_list)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def onchange_requested_date(self, cr, uid, ids, requested_date,
|
||||||
|
commitment_date, context=None):
|
||||||
|
"""Warn if the requested dates is sooner than the commitment date"""
|
||||||
|
if (requested_date and commitment_date
|
||||||
|
and requested_date < commitment_date):
|
||||||
|
return {'warning': {
|
||||||
|
'title': _('Requested date is too soon!'),
|
||||||
|
'message': _("The date requested by the customer is "
|
||||||
|
"sooner than the commitment date. You may be "
|
||||||
|
"unable to honor the customer's request.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'commitment_date': fields.function(_get_commitment_date, store=True, type='date', string='Commitment Date', help="Committed date for delivery."),
|
'commitment_date': fields.function(_get_commitment_date, store=True,
|
||||||
'requested_date': fields.date('Requested Date', help="Date requested by the customer for the sale."),
|
type='date', string='Commitment Date',
|
||||||
'effective_date': fields.function(_get_effective_date, type='date', store=True, string='Effective Date',help="Date on which picking is created."),
|
help="Date by which the products is sure to be delivered. This is "
|
||||||
|
"a date that you can promise to the customer, based on the "
|
||||||
|
"Product Lead Times."),
|
||||||
|
'requested_date': fields.date('Requested Date',
|
||||||
|
readonly=True, states={'draft': [('readonly', False)]},
|
||||||
|
help="Date by which the customer has requested the items to be "
|
||||||
|
"delivered.\n"
|
||||||
|
"When this Order gets confirmed, the Delivery Order's "
|
||||||
|
"expected date will be computed based on this date and the "
|
||||||
|
"Company's Security Delay.\n"
|
||||||
|
"Leave this field empty if you want the Delivery Order to be "
|
||||||
|
"processed as soon as possible. In that case the expected "
|
||||||
|
"date will be computed using the default method: based on "
|
||||||
|
"the Product Lead Times and the Company's Security Delay."),
|
||||||
|
'effective_date': fields.function(_get_effective_date, type='date',
|
||||||
|
store=True, string='Effective Date',
|
||||||
|
help="Date on which the first Delivery Order was created."),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,25 @@
|
||||||
<group name="sale_pay" position="after">
|
<group name="sale_pay" position="after">
|
||||||
<group colspan="2" col="2" >
|
<group colspan="2" col="2" >
|
||||||
<separator string="Dates" colspan="2"/>
|
<separator string="Dates" colspan="2"/>
|
||||||
<field name="requested_date"/>
|
<field name="requested_date" on_change="onchange_requested_date(requested_date, commitment_date)"/>
|
||||||
<field name="commitment_date"/>
|
<field name="commitment_date"/>
|
||||||
<field name="effective_date"/>
|
<field name="effective_date"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record id="view_order_tree_date" model="ir.ui.view">
|
||||||
|
<field name="name">sale.order.tree.inherit5</field>
|
||||||
|
<field name="model">sale.order</field>
|
||||||
|
<field name="type">tree</field>
|
||||||
|
<field name="inherit_id" ref="sale.view_order_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="date_order" position="after">
|
||||||
|
<field name="requested_date"/>
|
||||||
|
<field name="commitment_date"/>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
-
|
||||||
|
In order to test the Requested Date feature in Sale Orders in OpenERP,
|
||||||
|
I update a demo Sale Order with Requested Date on 2010-12-17
|
||||||
|
-
|
||||||
|
!python {model: sale.order}: |
|
||||||
|
so = self.write(cr, uid, ref("sale.order"), {'requested_date': '2010-07-12'})
|
||||||
|
-
|
||||||
|
I confirm the Sale Order.
|
||||||
|
-
|
||||||
|
!workflow {
|
||||||
|
model: sale.order, action: order_confirm,
|
||||||
|
ref: sale.order
|
||||||
|
}
|
||||||
|
-
|
||||||
|
I verify that the Procurements and Stock Moves have been generated with the
|
||||||
|
correct date
|
||||||
|
-
|
||||||
|
!python {model: sale.order}: |
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
|
||||||
|
so = self.browse(cr, uid, ref("sale.order"))
|
||||||
|
security_delay = timedelta(days=so.shop_id.company_id.security_lead)
|
||||||
|
requested_date = datetime.strptime(so.requested_date,
|
||||||
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
right_date = (requested_date - security_delay).strftime(
|
||||||
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
for line in so.order_line:
|
||||||
|
assert line.procurement_id, "No Procurement was created"
|
||||||
|
assert line.procurement_id.date_planned == right_date, "The planned date for the Procurement Order is wrong"
|
||||||
|
assert line.procurement_id.move_id.date_expected == right_date, "The expected date for the Stock Move is wrong"
|
|
@ -313,6 +313,15 @@ class sale_order(osv.osv):
|
||||||
'company_id': order.company_id.id,
|
'company_id': order.company_id.id,
|
||||||
'note': line.name,
|
'note': line.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _order_line_move_date(self, cr, uid, line, context=None):
|
||||||
|
"""Compute the Stock Move date for the Sale Order Line"""
|
||||||
|
date_planned = datetime.strptime(line.order_id.date_order,
|
||||||
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
date_planned += timedelta(days=line.delay or 0.0)
|
||||||
|
date_planned -= timedelta(days=line.order_id.company_id.security_lead)
|
||||||
|
return date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
|
||||||
|
|
||||||
def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, context=None):
|
def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, context=None):
|
||||||
location_id = order.warehouse_id.lot_stock_id.id
|
location_id = order.warehouse_id.lot_stock_id.id
|
||||||
|
@ -412,7 +421,7 @@ class sale_order(osv.osv):
|
||||||
if line.state == 'done':
|
if line.state == 'done':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
|
date_planned = self._order_line_move_date(cr, uid, line, context=context)
|
||||||
|
|
||||||
if line.product_id:
|
if line.product_id:
|
||||||
if line.product_id.type in ('product', 'consu'):
|
if line.product_id.type in ('product', 'consu'):
|
||||||
|
|
Loading…
Reference in New Issue