[MIG] stock_calendar: new API

This commit is contained in:
Thibault Delavallée
2016-07-12 17:53:10 +02:00
parent 3f7a950ccb
commit 4cb0965365
4 changed files with 107 additions and 112 deletions
+42 -50
View File
@@ -1,77 +1,69 @@
from datetime import datetime # -*- coding: utf-8 -*-
from dateutil.relativedelta import relativedelta # Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import api
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
from openerp import SUPERUSER_ID
from psycopg2 import OperationalError
from openerp.tools import float_compare, float_round
import pytz
import openerp
class procurement_order(osv.osv): from datetime import datetime
from odoo import api, fields, models
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
class ProcurementOrder(models.Model):
_inherit = 'procurement.order' _inherit = 'procurement.order'
_columns = { next_delivery_date = fields.Datetime('Next Delivery Date', help="The date of the next delivery for this procurement group, when this group is on the purchase calendar of the orderpoint")
'next_delivery_date': fields.datetime('Next Delivery Date', next_purchase_date = fields.Datetime('Next Purchase Date', help="The date the next purchase order should be sent to the vendor")
help="The date of the next delivery for this procurement group, when this group is on the purchase calendar of the orderpoint"),
'next_purchase_date': fields.datetime('Next Purchase Date',
help="The date the next purchase order should be sent to the vendor"),
}
def assign_group_date(self, cr, uid, ids, context=None): @api.multi
orderpoint_obj = self.pool.get("stock.warehouse.orderpoint") def assign_group_date(self):
for procurement in self.browse(cr, uid, ids, context=context): Orderpoint = self.env["stock.warehouse.orderpoint"]
ops = orderpoint_obj.search(cr, uid, [('location_id', '=', procurement.location_id.id), for procurement in self:
('product_id', '=', procurement.product_id.id)], context=context) orderpoint = Orderpoint.search([
if ops and ops[0]: ('location_id', '=', procurement.location_id.id),
orderpoint = orderpoint_obj.browse(cr, uid, ops[0], context=context) ('product_id', '=', procurement.product_id.id)], limit=1)
date_planned = datetime.strptime(procurement.date_planned, DEFAULT_SERVER_DATETIME_FORMAT) if orderpoint:
purchase_date, delivery_date = self.pool['stock.orderpoint']._get_previous_dates(cr, uid, [orderpoint.id], date_planned, context=context) date_planned = fields.Datetime.from_string(procurement.date_planned)
purchase_date, delivery_date = orderpoint._get_previous_dates(date_planned)
if purchase_date and delivery_date: if purchase_date and delivery_date:
self.write(cr, uid, [procurement.id], {'next_delivery_date': delivery_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT), procurement.write({
'next_purchase_date': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),}, context=context) 'next_delivery_date': delivery_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'next_purchase_date': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
def _get_purchase_order_date(self, schedule_date): def _get_purchase_order_date(self, schedule_date):
if self.next_purchase_date: if self.next_purchase_date:
return datetime.strptime(self.next_purchase_date, DEFAULT_SERVER_DATETIME_FORMAT) return fields.Datetime.from_string(self.next_purchase_date)
return super(procurement_order, self)._get_purchase_order_date(schedule_date) return super(ProcurementOrder, self)._get_purchase_order_date(schedule_date)
def _get_purchase_schedule_date(self): def _get_purchase_schedule_date(self):
if self.next_delivery_date: if self.next_delivery_date:
return datetime.strptime(self.next_delivery_date, DEFAULT_SERVER_DATETIME_FORMAT) return datetime.strptime(self.next_delivery_date, DEFAULT_SERVER_DATETIME_FORMAT)
return super(procurement_order, self)._get_purchase_schedule_date() return super(ProcurementOrder, self)._get_purchase_schedule_date()
def _prepare_purchase_order_line(self, cr, uid, ids, po, supplier, context=None): def _prepare_purchase_order_line(self, po, supplier):
res = super(procurement_order, self)._prepare_purchase_order_line(cr, uid, ids, po, supplier, context=context) res = super(ProcurementOrder, self)._prepare_purchase_order_line(po, supplier)
procurement = self.browse(cr, uid, ids, context=context) if self.next_delivery_date:
if procurement.next_delivery_date: res.update({'date_planned': self.next_delivery_date})
res.update({'date_planned': procurement.next_delivery_date})
return res return res
def _procurement_from_orderpoint_get_order(self, cr, uid, context=None): def _procurement_from_orderpoint_get_order(self):
return 'location_id, purchase_calendar_id, calendar_id' return 'location_id, purchase_calendar_id, calendar_id'
def _procurement_from_orderpoint_get_grouping_key(self, cr, uid, orderpoint_ids, context=None): def _procurement_from_orderpoint_get_grouping_key(self, orderpoint_ids):
orderpoint = self.pool['stock.warehouse.orderpoint'].browse(cr, uid, orderpoint_ids[0], context=context) orderpoint = self.env['stock.warehouse.orderpoint'].browse(orderpoint_ids[0])
return (orderpoint.location_id.id, orderpoint.purchase_calendar_id.id, orderpoint.calendar_id.id) return (orderpoint.location_id.id, orderpoint.purchase_calendar_id.id, orderpoint.calendar_id.id)
def _procurement_from_orderpoint_get_groups(self, cr, uid, orderpoint_ids, context=None): def _procurement_from_orderpoint_get_groups(self, orderpoint_ids):
orderpoint = self.pool['stock.warehouse.orderpoint'].browse(cr, uid, orderpoint_ids[0], context=context) orderpoint = self.env['stock.warehouse.orderpoint'].browse(orderpoint_ids[0])
res_groups = [] res_groups = []
date_groups = self._get_group(cr, uid, [orderpoint.id], context=context) date_groups = orderpoint._get_group()
for date, group in date_groups: for date, group in date_groups:
if orderpoint.calendar_id and orderpoint.calendar_id.attendance_ids: if orderpoint.calendar_id and orderpoint.calendar_id.attendance_ids:
date1, date2 = self._get_next_dates(cr, uid, [orderpoint.id], date, group, context=context) date1, date2 = orderpoint._get_next_dates(date, group)
res_groups += [{'to_date': date2, 'procurement_values': {'group': group, 'date': date1, 'purchase_date': date}}] # date1/date2 as deliveries and date as purchase confirmation date res_groups += [{'to_date': date2, 'procurement_values': {'group': group, 'date': date1, 'purchase_date': date}}] # date1/date2 as deliveries and date as purchase confirmation date
else: else:
res_groups += [{'to_date': False, 'procurement_values': {'group': group, 'date': date, 'purchase_date': date}}] res_groups += [{'to_date': False, 'procurement_values': {'group': group, 'date': date, 'purchase_date': date}}]
return res_groups return res_groups
def _procurement_from_orderpoint_post_process(self, cr, uid, orderpoint_ids, context=None): def _procurement_from_orderpoint_post_process(self, orderpoint_ids):
self.pool['stock.warehouse.orderpoint'].write( self.env['stock.warehouse.orderpoint'].browse(orderpoint_ids).write({
cr, uid, orderpoint_ids, { 'last_execution_date': datetime.utcnow().strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
'last_execution_date': datetime.utcnow().strftime(DEFAULT_SERVER_DATETIME_FORMAT) return super(ProcurementOrder, self)._procurement_from_orderpoint_post_process(orderpoint_ids)
}, context=context)
return super(procurement_order, self)._procurement_from_orderpoint_post_process(cr, uid, orderpoint_ids, context=context)
+20 -15
View File
@@ -1,16 +1,25 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime import datetime
from openerp.osv import fields, osv from odoo import api, fields, models
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
class resource_calendar_leaves(osv.osv): class ResourceCalendarAttendance(models.Model):
_inherit = "resource.calendar.attendance"
group_id = fields.Many2one('procurement.group', 'Procurement Group')
class ResourceCalendarLeaves(models.Model):
_inherit = "resource.calendar.leaves" _inherit = "resource.calendar.leaves"
_columns = {
'group_id': fields.many2one('procurement.group', string="Procurement Group"),
}
class resource_calendar(osv.osv): group_id = fields.Many2one('procurement.group', 'Procurement Group')
class ResourceCalendar(models.Model):
_inherit = "resource.calendar" _inherit = "resource.calendar"
# Keep as it takes into account times # Keep as it takes into account times
@@ -32,6 +41,8 @@ class resource_calendar(osv.osv):
:return list leaves: list of tuples (start_datetime, end_datetime) of :return list leaves: list of tuples (start_datetime, end_datetime) of
leave intervals leave intervals
""" """
# TDE FIXME: waw, overriding completely a method + changing its result
# and its behavior, very nice. Please FIXME.
resource_calendar = self.browse(cr, uid, id, context=context) resource_calendar = self.browse(cr, uid, id, context=context)
leaves = [] leaves = []
for leave in resource_calendar.leave_ids: for leave in resource_calendar.leave_ids:
@@ -75,6 +86,8 @@ class resource_calendar(osv.osv):
that are intervals to remove from the base interval that are intervals to remove from the base interval
:return list intervals: a list of tuples (begin datetime, end datetime) :return list intervals: a list of tuples (begin datetime, end datetime)
that are the remaining valid intervals """ that are the remaining valid intervals """
# TDE FIXME: waw, overriding completely a method + changing its result
# and its behavior, very nice. Please FIXME.
if not interval: if not interval:
return interval return interval
if leave_intervals is None: if leave_intervals is None:
@@ -109,11 +122,3 @@ class resource_calendar(osv.osv):
else: else:
intervals.append((current_interval[0], current_interval[1],)) intervals.append((current_interval[0], current_interval[1],))
return intervals return intervals
class resource_calendar_attendance(osv.osv):
_inherit = "resource.calendar.attendance"
_columns = {
'group_id': fields.many2one('procurement.group', 'Procurement Group'),
}
+42 -44
View File
@@ -1,28 +1,31 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from openerp.osv import fields, osv from odoo import fields, models
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
class stock_warehouse_orderpoint(osv.osv): class StockWarehouseOrderpoint(models.Model):
_inherit = "stock.warehouse.orderpoint" _inherit = "stock.warehouse.orderpoint"
_columns = { calendar_id = fields.Many2one(
'calendar_id': fields.many2one('resource.calendar', 'Calendar', 'resource.calendar', 'Calendar',
help="In the calendar you can define the days that the goods will be delivered. That way the scheduler will only take into account the goods needed until the second delivery and put the procurement date as the first delivery. "), help="In the calendar you can define the days that the goods will be delivered. That way the scheduler will "
'purchase_calendar_id': fields.many2one('resource.calendar', 'Purchase Calendar'), "only take into account the goods needed until the second delivery and put the procurement date as the first delivery.")
'last_execution_date': fields.datetime('Last Execution Date', readonly=True), purchase_calendar_id = fields.Many2one('resource.calendar', 'Purchase Calendar')
} last_execution_date = fields.Datetime('Last Execution Date', readonly=True)
def _prepare_procurement_values(self, cr, uid, ids, product_qty, date=False, purchase_date=False, group=False, context=None): def _prepare_procurement_values(self, product_qty, date=False, purchase_date=False, group=False):
res = super(stock_warehouse_orderpoint, self)._prepare_procurement_values(cr, uid, ids, product_qty, date=date, group=group, context=context) res = super(StockWarehouseOrderpoint, self)._prepare_procurement_values(product_qty, date=date, group=group)
res.update({ res.update({
'next_delivery_date': date, 'next_delivery_date': date,
'next_purchase_date': purchase_date}) 'next_purchase_date': purchase_date})
return res return res
def _get_group(self, cr, uid, ids, context=None): def _get_group(self):
""" """
Will return the groups and the end dates of the intervals of the purchase calendar Will return the groups and the end dates of the intervals of the purchase calendar
that need to be executed now. that need to be executed now.
@@ -30,55 +33,52 @@ class stock_warehouse_orderpoint(osv.osv):
:return [(date, group)] :return [(date, group)]
""" """
# TDE FIXME: unused context key 'no_round_hours' removed # TDE FIXME: unused context key 'no_round_hours' removed
orderpoint = self.browse(cr, uid, ids, context=context)[0]
# Check if orderpoint has last execution date and calculate if we need to calculate again already # Check if orderpoint has last execution date and calculate if we need to calculate again already
calendar_obj = self.pool.get("resource.calendar") Calendar = self.env["resource.calendar"]
att_obj = self.pool.get("resource.calendar.attendance") Attendance = self.env["resource.calendar.attendance"]
group = False group = False
date = False date = False
now_date = datetime.utcnow() now_date = datetime.utcnow()
res_intervals = [] res_intervals = []
if orderpoint.purchase_calendar_id and orderpoint.purchase_calendar_id.attendance_ids: if self.purchase_calendar_id and self.purchase_calendar_id.attendance_ids:
if orderpoint.last_execution_date: if self.last_execution_date:
new_date = datetime.strptime(orderpoint.last_execution_date, DEFAULT_SERVER_DATETIME_FORMAT) new_date = datetime.strptime(self.last_execution_date, DEFAULT_SERVER_DATETIME_FORMAT)
else: else:
new_date = datetime.utcnow() new_date = datetime.utcnow()
# TDE note: I bet accessing interval[2] will crash, no ? this code seems very louche # TDE note: I bet accessing interval[2] will crash, no ? this code seems very louche
intervals = calendar_obj._schedule_days(cr, uid, orderpoint.purchase_calendar_id.id, 1, new_date, compute_leaves=True, context=context) intervals = Calendar._schedule_days(self.purchase_calendar_id.id, 1, new_date, compute_leaves=True)
for interval in intervals: for interval in intervals:
# If last execution date, interval should start after it in order not to execute the same orderpoint twice # If last execution date, interval should start after it in order not to execute the same orderpoint twice
# TODO: Make the interval a little bigger # TODO: Make the interval a little bigger
if (orderpoint.last_execution_date and (interval[0] > new_date and interval[0] < now_date)) or (not orderpoint.last_execution_date and interval[0] < now_date and interval[1] > now_date): if (self.last_execution_date and (interval[0] > new_date and interval[0] < now_date)) or (not self.last_execution_date and interval[0] < now_date and interval[1] > now_date):
group = att_obj.browse(cr, uid, interval[2], context=context).group_id.id group = Attendance.browse(interval[2]).group_id.id
date = interval[1] date = interval[1]
res_intervals += [(date, group), ] res_intervals += [(date, group), ]
else: else:
return [(now_date, None)] return [(now_date, None)]
return res_intervals return res_intervals
def _get_previous_dates(self, cr, uid, ids, start_date=False, context=None): def _get_previous_dates(self, start_date=False):
""" """
Date should be given in utc Date should be given in utc
""" """
# TDE FIXME: unused context key 'no_round_hours' removed # TDE FIXME: unused context key 'no_round_hours' removed
orderpoint = self.browse(cr, uid, ids, context=context)[0] Attendance = self.env["resource.calendar.attendance"]
calendar_obj = self.pool.get('resource.calendar')
att_obj = self.pool.get('resource.calendar.attendance')
# First check if the orderpoint has a Calendar as it should be delivered at this calendar date # First check if the orderpoint has a Calendar as it should be delivered at this calendar date
purchase_date = False purchase_date = False
delivery_date = start_date delivery_date = start_date
if orderpoint.calendar_id and orderpoint.calendar_id.attendance_ids: if self.calendar_id and self.calendar_id.attendance_ids:
res = calendar_obj._schedule_days(cr, uid, orderpoint.calendar_id.id, -1, start_date, compute_leaves=True, context=context) res = self.calendar_id._schedule_days(-1, start_date, compute_leaves=True)[0] # CLEANME
if res and res[0][0] < start_date: if res and res[0][0] < start_date:
group_to_find = res[0][2] and att_obj.browse(cr, uid, res[0][2], context=context).group_id.id or False group_to_find = res[0][2] and Attendance.browse(res[0][2]).group_id.id
delivery_date = res[0][0] delivery_date = res[0][0]
found_date = delivery_date found_date = delivery_date
if orderpoint.purchase_calendar_id and orderpoint.purchase_calendar_id.attendance_ids: if self.purchase_calendar_id and self.purchase_calendar_id.attendance_ids:
while not purchase_date: while not purchase_date:
found_date = found_date + relativedelta(days=-1) # won't allow to deliver within the day found_date = found_date + relativedelta(days=-1) # won't allow to deliver within the day
res = calendar_obj._schedule_days(cr, uid, orderpoint.purchase_calendar_id.id, -1, found_date, compute_leaves=True, context=context) res = self.purchase_calendar_id._schedule_days(-1, found_date, compute_leaves=True)[0] # CLEANME
for re in res: for re in res:
group = re[2] and att_obj.browse(cr, uid, re[2], context=context).group_id.id or False group = re[2] and Attendance.browse(re[2]).group_id.id
found_date = re[0] found_date = re[0]
if not purchase_date and (group_to_find and group_to_find == group or (not group_to_find)): if not purchase_date and (group_to_find and group_to_find == group or (not group_to_find)):
purchase_date = re[0] purchase_date = re[0]
@@ -86,26 +86,24 @@ class stock_warehouse_orderpoint(osv.osv):
delivery_date = start_date or datetime.utcnow() delivery_date = start_date or datetime.utcnow()
return purchase_date, delivery_date return purchase_date, delivery_date
def _get_next_dates(self, cr, uid, ids, new_date=False, group=False, context=None): def _get_next_dates(self, new_date=False, group=False):
# TDE FIXME: unused context key 'no_round_hours' removed # TDE FIXME: unused context key 'no_round_hours' removed
orderpoint = self.browse(cr, uid, ids, context=context)[0] Attendance = self.env["resource.calendar.attendance"]
calendar_obj = self.pool.get('resource.calendar')
att_obj = self.pool.get('resource.calendar.attendance')
if not new_date: if not new_date:
new_date = datetime.utcnow() new_date = datetime.utcnow()
now_date = datetime.utcnow() now_date = datetime.utcnow()
# Search first calendar day (without group) # Search first calendar day (without group)
res = calendar_obj._schedule_days(cr, uid, orderpoint.calendar_id.id, 1, new_date, compute_leaves=True, context=context) res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0] # CLEANME
att_group = res and res[0][2] and att_obj.browse(cr, uid, res[0][2], context=context).group_id.id or False att_group = res and res[0][2] and Attendance.browse(res[0][2]).group_id.id
#If hours are smaller than the current date, search a day further # If hours are smaller than the current date, search a day further
if res and res[0][0] < now_date: if res and res[0][0] < now_date:
new_date = res[0][1] + relativedelta(days=1) new_date = res[0][1] + relativedelta(days=1)
res = calendar_obj._schedule_days(cr, uid, orderpoint.calendar_id.id, 1, new_date, compute_leaves=True, context=context) res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)
for re in res: for re in res:
att_group = False att_group = False
if re[2]: if re[2]:
att_group = att_obj.browse(cr, uid, re[2], context=context).group_id.id att_group = Attendance.browse(re[2]).group_id.id
if att_group == group: if att_group == group:
break break
@@ -114,14 +112,14 @@ class stock_warehouse_orderpoint(osv.osv):
while res and group and att_group != group and number < 100: while res and group and att_group != group and number < 100:
number += 1 number += 1
new_date = res[0][1] + relativedelta(days=1) new_date = res[0][1] + relativedelta(days=1)
res = calendar_obj._schedule_days(cr, uid, orderpoint.calendar_id.id, 1, new_date, compute_leaves=True, context=context) res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0]
att_group = False att_group = False
for re in res: for re in res:
if re[2]: if re[2]:
att_group = att_obj.browse(cr, uid, re[2], context=context).group_id.id att_group = Attendance.browse(re[2]).group_id.id
if att_group == group: if att_group == group:
break break
#number as safety pall for endless loops # number as safety pall for endless loops
if number >= 100: if number >= 100:
res = False res = False
@@ -130,7 +128,7 @@ class stock_warehouse_orderpoint(osv.osv):
if res: if res:
date1 = res[0][1] date1 = res[0][1]
new_date = res[0][1] + relativedelta(days=1) new_date = res[0][1] + relativedelta(days=1)
res = calendar_obj._schedule_days(cr, uid, orderpoint.calendar_id.id, 1, new_date, compute_leaves=True, context=context) res = self.calendar_id._schedule_days(1, new_date, compute_leaves=True)[0]
if res: if res:
return (date1, res[0][1]) return (date1, res[0][1])
return (False, False) return (False, False)
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <odoo>
<data> <data>
<record id="view_warehouse_orderpoint_form_inherit" model="ir.ui.view"> <record id="view_warehouse_orderpoint_form_inherit" model="ir.ui.view">
<field name="name">stock.warehouse.orderpoint.form.inherit</field> <field name="name">stock.warehouse.orderpoint.form.inherit</field>
@@ -13,4 +13,4 @@
</field> </field>
</record> </record>
</data> </data>
</openerp> </odoo>