diff --git a/CHANGELOG b/CHANGELOG index d93ced8a83..7ad9961279 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +* Add delivery time on product +* Use compute delivery date for stock moves +* Group stock moves on shipment using a key + Version 2.0.0 - 2011-04-27 * Bug fixes (see mercurial logs for details) diff --git a/sale.py b/sale.py index 493c43abb7..23133e2ed0 100644 --- a/sale.py +++ b/sale.py @@ -2,6 +2,10 @@ #this repository contains the full copyright notices and license terms. import copy from decimal import Decimal +import datetime +from itertools import groupby +from functools import partial +from operator import itemgetter from trytond.model import ModelWorkflow, ModelView, ModelSQL, fields from trytond.modules.company import CompanyReport from trytond.wizard import Wizard @@ -667,6 +671,14 @@ class Sale(ModelWorkflow, ModelSQL, ModelView): }) return True + def set_sale_date(self, sale_id): + date_obj = Pool().get('ir.date') + + self.write(sale_id, { + 'sale_date': date_obj.today(), + }) + return True + def _get_invoice_line_sale_line(self, sale): ''' Return invoice line values for each sale lines @@ -777,13 +789,25 @@ class Sale(ModelWorkflow, ModelSQL, ModelView): res[line.id] = val return res + def _group_shipment_key(self, moves, move): + ''' + The key to group moves by shipments + + :param moves: a list of moves values + :param move: a tuple of line id and a dictionary of the move values + + :return: a list of key-value as tuples of the shipment + ''' + planned_date = max(m['planned_date'] for m in moves) + return (('planned_date', planned_date),) + def create_shipment(self, sale_id): ''' Create a shipment for the sale :param sale_id: the sale id - :return: the created shipment id or None + :return: the list of created shipment id or None ''' pool = Pool() shipment_obj = pool.get('stock.shipment.out') @@ -795,25 +819,30 @@ class Sale(ModelWorkflow, ModelSQL, ModelView): moves = self._get_move_sale_line(sale) if not moves: return + keyfunc = partial(self._group_shipment_key, moves.values()) + moves = moves.items() + moves = sorted(moves, key=keyfunc) + shipments = [] with Transaction().set_user(0, set_context=True): - shipment_id = shipment_obj.create({ - 'planned_date': sale.sale_date, - 'customer': sale.party.id, - 'delivery_address': sale.shipment_address.id, - 'reference': sale.reference, - 'warehouse': sale.warehouse.id, - }) - - for line_id in moves: - vals = moves[line_id] - vals['shipment_out'] = shipment_id - move_id = move_obj.create(vals) - sale_line_obj.write(line_id, { - 'moves': [('add', move_id)], - }) + for key, grouped_moves in groupby(moves, key=keyfunc): + values = { + 'customer': sale.party.id, + 'delivery_address': sale.shipment_address.id, + 'reference': sale.reference, + 'warehouse': sale.warehouse.id, + } + values.update(dict(key)) + shipment_id = shipment_obj.create(values) + shipments.append(shipment_id) + for line_id, values in grouped_moves: + values['shipment_out'] = shipment_id + move_id = move_obj.create(values) + sale_line_obj.write(line_id, { + 'moves': [('add', move_id)], + }) shipment_obj.workflow_trigger_validate(shipment_id, 'waiting') - return shipment_id + return shipments def wkf_draft(self, sale): self.write(sale.id, {'state': 'draft'}) @@ -824,6 +853,7 @@ class Sale(ModelWorkflow, ModelSQL, ModelView): self.write(sale.id, {'state': 'quotation'}) def wkf_confirmed(self, sale): + self.set_sale_date(sale.id) self.write(sale.id, {'state': 'confirmed'}) def wkf_waiting_invoice_sale(self, sale): @@ -1380,6 +1410,7 @@ class SaleLine(ModelSQL, ModelView): :return: a dictionary of values of move ''' uom_obj = Pool().get('product.uom') + product_obj = Pool().get('product.product') res = {} if line.type != 'line': @@ -1407,7 +1438,8 @@ class SaleLine(ModelSQL, ModelView): res['company'] = line.sale.company.id res['unit_price'] = line.unit_price res['currency'] = line.sale.currency.id - res['planned_date'] = line.sale.sale_date + res['planned_date'] = product_obj.compute_delivery_date( + line.product) return res SaleLine() @@ -1488,6 +1520,12 @@ class Template(ModelSQL, ModelView): context={'category': (Eval('default_uom'), 'uom.category')}, on_change_with=['default_uom', 'sale_uom', 'salable'], depends=['active', 'salable', 'default_uom']) + delivery_time = fields.Integer('Delivery Time', states={ + 'readonly': ~Eval('active', True), + 'invisible': ~Eval('salable', False), + }, + depends=['active', 'salable'], + help='In number of days') def __init__(self): super(Template, self).__init__() @@ -1580,6 +1618,16 @@ class Product(ModelSQL, ModelView): currency.id) return res + def compute_delivery_date(self, product, date=None): + ''' + Compute the delivery date for the Product at a the given date + ''' + date_obj = Pool().get('ir.date') + + if not date: + date = date_obj.today() + return date + datetime.timedelta(product.delivery_time) + Product() diff --git a/sale.xml b/sale.xml index 7c947bb753..fa6ded7c0c 100644 --- a/sale.xml +++ b/sale.xml @@ -879,6 +879,8 @@ this repository contains the full copyright notices and license terms. -->