[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:
Olivier Dony 2014-03-06 21:24:30 +01:00
commit 499e0e323d
6 changed files with 140 additions and 15 deletions

View File

@ -22,7 +22,7 @@
{
'name': 'Dates on Sales Order',
'version': '1.0',
'version': '1.1',
'category': 'Sales Management',
'description': """
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:
------------------------------------------------------------
* Requested Date
* Requested Date (will be used as the expected date on pickings)
* Commitment Date
* Effective Date
""",
@ -40,7 +40,7 @@ You can add the following additional dates to a sales order:
'depends': ['sale_stock'],
'data': ['sale_order_dates_view.xml'],
'demo': [],
'test': [],
'test': ['test/requested_date.yml'],
'installable': True,
'auto_install': False,
}

View File

@ -32,12 +32,14 @@ msgstr ""
#. module: sale_order_dates
#: help:sale.order,effective_date:0
msgid "Date on which picking is created."
msgid "Date on which the first Delivery Order was created."
msgstr ""
#. module: sale_order_dates
#: 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 ""
#. module: sale_order_dates
@ -52,6 +54,18 @@ msgstr ""
#. module: sale_order_dates
#: 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 ""

View File

@ -19,15 +19,40 @@
#
##############################################################################
from datetime import datetime
from dateutil.relativedelta import relativedelta
from datetime import datetime, timedelta
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):
"""Add several date fields to Sale Orders, computed or user-entered"""
_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):
"""Read the shipping date from the related packings"""
# XXX would be better if it returned the date the picking was processed
res = {}
dates_list = []
for order in self.browse(cr, uid, ids, context=context):
@ -41,22 +66,56 @@ class sale_order_dates(osv.osv):
return res
def _get_commitment_date(self, cr, uid, ids, name, arg, context=None):
"""Compute the commitment date"""
res = {}
dates_list = []
for order in self.browse(cr, uid, ids, context=context):
dates_list = []
for line in order.order_line:
dt = datetime.strptime(order.date_order, '%Y-%m-%d') + relativedelta(days=line.delay or 0.0)
dt_s = dt.strftime('%Y-%m-%d')
dt = (datetime.strptime(order.date_order,
DEFAULT_SERVER_DATE_FORMAT)
+ timedelta(days=line.delay or 0.0) )
dt_s = dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
dates_list.append(dt_s)
if dates_list:
res[order.id] = min(dates_list)
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 = {
'commitment_date': fields.function(_get_commitment_date, store=True, type='date', string='Commitment Date', help="Committed date for delivery."),
'requested_date': fields.date('Requested Date', help="Date requested by the customer for the sale."),
'effective_date': fields.function(_get_effective_date, type='date', store=True, string='Effective Date',help="Date on which picking is created."),
'commitment_date': fields.function(_get_commitment_date, store=True,
type='date', string='Commitment Date',
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."),
}

View File

@ -10,13 +10,25 @@
<group name="sale_pay" position="after">
<group colspan="2" col="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="effective_date"/>
</group>
</group>
</field>
</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>
</openerp>

View File

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

View File

@ -313,6 +313,15 @@ class sale_order(osv.osv):
'company_id': order.company_id.id,
'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):
location_id = order.warehouse_id.lot_stock_id.id
@ -412,7 +421,7 @@ class sale_order(osv.osv):
if line.state == 'done':
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.type in ('product', 'consu'):