diff --git a/CHANGELOG b/CHANGELOG index 34f88f269a..8a851ddfdc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,2 +1,4 @@ +* Group requests of same product and unit into one purchase line + Version 4.0.0 - 2016-05-02 -* Initial release \ No newline at end of file +* Initial release diff --git a/doc/index.rst b/doc/index.rst index 9453dfc821..3069a3262b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -34,6 +34,6 @@ can be in one of these states: which is cancelled. A wizard allows to create purchases based on a selection of draft purchase -requests. The new purchases contains one purchase line by purchase request and +requests. The new purchases contains one purchase line by product and unit and group them by warehouses and by suppliers. Once the purchases are created, the corresponding purchase requests are set to the state Purchased. diff --git a/purchase_request.py b/purchase_request.py index f07cc25309..8b40eb354b 100644 --- a/purchase_request.py +++ b/purchase_request.py @@ -325,6 +325,16 @@ class CreatePurchase(Wizard): ('invoice_address', request.party.address_get(type='invoice')), ) + def _group_purchase_line_key(self, request): + ''' + The key to group requests by lines + A list of key-value as tuples of the purchase line + ''' + return ( + ('product', request.product), + ('unit', request.uom), + ) + def transition_start(self): pool = Pool() Request = pool.get('purchase.request') @@ -378,54 +388,55 @@ class CreatePurchase(Wizard): for f, v in key: setattr(purchase, f, v) purchase.save() - for request in grouped_requests: - line = self.compute_purchase_line(request, purchase) + for line_key, line_requests in groupby( + grouped_requests, key=self._group_purchase_line_key): + line_requests = list(line_requests) + line = self.compute_purchase_line( + line_key, line_requests, purchase) line.purchase = purchase line.save() - Request.write([request], { + Request.write(line_requests, { 'purchase_line': line.id, }) return 'end' @staticmethod - def _get_tax_rule_pattern(request): + def _get_tax_rule_pattern(line, purchase): ''' Get tax rule pattern ''' return {} @classmethod - def compute_purchase_line(cls, request, purchase): + def compute_purchase_line(cls, key, requests, purchase): pool = Pool() Product = pool.get('product.product') Line = pool.get('purchase.line') - line = Line( - product=request.product, - unit=request.uom, - quantity=request.quantity, - description=request.product.name, - ) + line = Line() + for f, v in key: + setattr(line, f, v) + line.description = line.product.name + line.quantity = sum(r.quantity for r in requests) - # XXX purchase with several lines of the same product - with Transaction().set_context(uom=request.uom.id, - supplier=request.party.id, - currency=request.currency.id): + with Transaction().set_context(uom=line.unit.id, + supplier=purchase.party.id, + currency=purchase.currency.id): product_price = Product.get_purchase_price( - [request.product], request.quantity)[request.product.id] + [line.product], line.quantity)[line.product.id] product_price = product_price.quantize( Decimal(1) / 10 ** Line.unit_price.digits[1]) if product_price is None: - cls.raise_user_error('missing_price', (request.product.rec_name,), + cls.raise_user_error('missing_price', (line.product.rec_name,), 'please_update') line.unit_price = product_price taxes = [] - for tax in request.product.supplier_taxes_used: - if request.party and request.party.supplier_tax_rule: - pattern = cls._get_tax_rule_pattern(request) - tax_ids = request.party.supplier_tax_rule.apply(tax, pattern) + for tax in line.product.supplier_taxes_used: + if purchase.party and purchase.party.supplier_tax_rule: + pattern = cls._get_tax_rule_pattern(line, purchase) + tax_ids = purchase.party.supplier_tax_rule.apply(tax, pattern) if tax_ids: taxes.extend(tax_ids) continue diff --git a/tests/scenario_purchase_request.rst b/tests/scenario_purchase_request.rst index 4837d0b766..e47974cfb4 100644 --- a/tests/scenario_purchase_request.rst +++ b/tests/scenario_purchase_request.rst @@ -210,3 +210,46 @@ Handle again the exception:: >>> handle_exception.execute('cancel_request') >>> pr.state 'cancel' + +Re-create the purchase request:: + + >>> create_pr = Wizard('purchase.request.create') + >>> create_pr.execute('create_') + +Create a second purchase request manually:: + + >>> config.user = 1 # admin + >>> pr = PurchaseRequest() + >>> pr.product = product + >>> pr.quantity = 1 + >>> pr.uom = unit + >>> pr.warehouse = warehouse_loc + >>> pr.origin = Model.get('stock.order_point')() + >>> pr.save() + +There is now 2 draft purchase requests:: + + >>> config.user = purchase_user.id + >>> prs = PurchaseRequest.find([('state', '=', 'draft')]) + >>> len(prs) + 2 + +Create the purchase with a unique line:: + + >>> create_purchase = Wizard('purchase.request.create_purchase', prs) + >>> create_purchase.form.party = supplier + >>> create_purchase.execute('start') + >>> pr.state + 'purchased' + + >>> Purchase = Model.get('purchase.purchase') + >>> purchase, = Purchase.find([('state', '=', 'draft')]) + >>> len(purchase.lines) + 1 + >>> line, = purchase.lines + >>> line.product == product + True + >>> line.quantity + 2.0 + >>> line.unit == unit + True