From f27882fa3cc11fd99982ca919b7fa0913b8fd644 Mon Sep 17 00:00:00 2001 From: riddhikansaraflectra Date: Wed, 20 Jun 2018 07:39:59 +0000 Subject: [PATCH] Master so/po riddhi --- addons/blanket_so_po/__init__.py | 4 + addons/blanket_so_po/__manifest__.py | 26 +++ .../demo/blanket_purchase_demo.xml | 41 ++++ .../blanket_so_po/demo/blanket_sale_demo.xml | 45 +++++ addons/blanket_so_po/models/__init__.py | 5 + addons/blanket_so_po/models/purchase.py | 66 +++++++ addons/blanket_so_po/models/sale.py | 114 +++++++++++ .../blanket_so_po/static/description/icon.png | Bin 0 -> 7052 bytes addons/blanket_so_po/tests/__init__.py | 4 + .../test_purchase_to_invoice_and_delivery.py | 175 +++++++++++++++++ .../test_sale_to_invoice_and_delivery.py | 180 ++++++++++++++++++ addons/blanket_so_po/views/purchase_view.xml | 51 +++++ addons/blanket_so_po/views/sale_view.xml | 47 +++++ addons/blanket_so_po/wizard/__init__.py | 6 + .../wizard/transfer_po_products.py | 56 ++++++ .../wizard/transfer_po_products_view.xml | 39 ++++ .../wizard/transfer_so_products.py | 52 +++++ .../wizard/transfer_so_products_view.xml | 38 ++++ addons/purchase/tests/test_stockvaluation.py | 2 +- 19 files changed, 950 insertions(+), 1 deletion(-) create mode 100755 addons/blanket_so_po/__init__.py create mode 100644 addons/blanket_so_po/__manifest__.py create mode 100644 addons/blanket_so_po/demo/blanket_purchase_demo.xml create mode 100644 addons/blanket_so_po/demo/blanket_sale_demo.xml create mode 100644 addons/blanket_so_po/models/__init__.py create mode 100644 addons/blanket_so_po/models/purchase.py create mode 100644 addons/blanket_so_po/models/sale.py create mode 100644 addons/blanket_so_po/static/description/icon.png create mode 100644 addons/blanket_so_po/tests/__init__.py create mode 100644 addons/blanket_so_po/tests/test_purchase_to_invoice_and_delivery.py create mode 100644 addons/blanket_so_po/tests/test_sale_to_invoice_and_delivery.py create mode 100755 addons/blanket_so_po/views/purchase_view.xml create mode 100755 addons/blanket_so_po/views/sale_view.xml create mode 100755 addons/blanket_so_po/wizard/__init__.py create mode 100644 addons/blanket_so_po/wizard/transfer_po_products.py create mode 100755 addons/blanket_so_po/wizard/transfer_po_products_view.xml create mode 100644 addons/blanket_so_po/wizard/transfer_so_products.py create mode 100755 addons/blanket_so_po/wizard/transfer_so_products_view.xml diff --git a/addons/blanket_so_po/__init__.py b/addons/blanket_so_po/__init__.py new file mode 100755 index 00000000..c73120bb --- /dev/null +++ b/addons/blanket_so_po/__init__.py @@ -0,0 +1,4 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from . import wizard +from . import models diff --git a/addons/blanket_so_po/__manifest__.py b/addons/blanket_so_po/__manifest__.py new file mode 100644 index 00000000..5fae39ea --- /dev/null +++ b/addons/blanket_so_po/__manifest__.py @@ -0,0 +1,26 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Blanket Sale Order/Purchase Order', + 'version': "1.0", + 'category': 'Sales and Purchase Management', + 'summary': 'A Blanket Sales/Purchase Order clearly lays out the terms ' + 'and conditions of a Sales/Purchase including quantities ' + 'required and when they are to be delivered.', + "author": "Flectra", + 'website': 'https://flectrahq.com', + 'depends': ['purchase', 'sale_stock'], + 'data': [ + 'wizard/transfer_so_products_view.xml', + 'wizard/transfer_po_products_view.xml', + 'views/sale_view.xml', + 'views/purchase_view.xml', + ], + 'demo': [ + 'demo/blanket_sale_demo.xml', + 'demo/blanket_purchase_demo.xml' + ], + 'installable': True, + 'application': False, + 'auto_install': False, +} diff --git a/addons/blanket_so_po/demo/blanket_purchase_demo.xml b/addons/blanket_so_po/demo/blanket_purchase_demo.xml new file mode 100644 index 00000000..7f605db9 --- /dev/null +++ b/addons/blanket_so_po/demo/blanket_purchase_demo.xml @@ -0,0 +1,41 @@ + + + + + + + + + + [RAM-SR5] RAM DDR SR5 + + + + 6000 + 10 + + + + + + [M-Wir] Mouse, Wireless] + + + + 200 + 5 + + + + + + [MBi9] Motherboard I9P57 + + + + 3000 + 8 + + + + diff --git a/addons/blanket_so_po/demo/blanket_sale_demo.xml b/addons/blanket_so_po/demo/blanket_sale_demo.xml new file mode 100644 index 00000000..7cb790fd --- /dev/null +++ b/addons/blanket_so_po/demo/blanket_sale_demo.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + Laptop E5023 + + 10 + + 2950.00 + + + + + + Headset USB + + 3 + + 2950.00 + + + + + + Webcamv + + 10 + + 45.00 + + + + diff --git a/addons/blanket_so_po/models/__init__.py b/addons/blanket_so_po/models/__init__.py new file mode 100644 index 00000000..76c0748f --- /dev/null +++ b/addons/blanket_so_po/models/__init__.py @@ -0,0 +1,5 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + +from . import sale +from . import purchase diff --git a/addons/blanket_so_po/models/purchase.py b/addons/blanket_so_po/models/purchase.py new file mode 100644 index 00000000..b2eacfc6 --- /dev/null +++ b/addons/blanket_so_po/models/purchase.py @@ -0,0 +1,66 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + +from flectra import api, fields, models, _ +from flectra.exceptions import Warning + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + @api.multi + def button_cancel(self): + res = super(PurchaseOrder, self).button_cancel() + if self.order_line.filtered( + lambda l: l.blanket_po_line): + raise Warning( + _('Sorry, You can not cancel blanket line based PO.')) + self.write({'state': 'cancel'}) + return res + + +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + @api.multi + def _prepare_stock_moves(self, picking): + res = super(PurchaseOrderLine, self)._prepare_stock_moves(picking) + self.ensure_one() + context = dict(self._context) + if self.product_id.type not in ['product', + 'consu'] or self.blanket_po_line \ + and not context.get('blanket'): + return [] + qty = 0.0 + for move in self.move_ids.filtered( + lambda x: x.state != 'cancel' and not + x.location_dest_id.usage == "supplier"): + qty += move.product_uom._compute_quantity( + move.product_uom_qty, self.product_uom, + rounding_method='HALF-UP') + for re in res: + if self.blanket_po_line and context.get('transfer_qty'): + re['product_uom_qty'] = context.get('transfer_qty') + else: + re['product_uom_qty'] = self.product_qty - qty + return res + + blanket_po_line = fields.Boolean(string="Blanket Order", copy=False) + remaining_to_po_transfer = fields.Float(string="Remaining to Transfer", + copy=False) + + @api.multi + def create(self, vals): + if vals.get('product_qty') and vals.get('blanket_po_line'): + vals.update( + {'remaining_to_po_transfer': vals.get('product_qty')}) + res = super(PurchaseOrderLine, self).create(vals) + return res + + @api.multi + def write(self, values): + result = super(PurchaseOrderLine, self).write(values) + for line in self: + if 'product_qty' and 'blanket_po_line' in values: + line.remaining_to_po_transfer = line.product_qty + return result diff --git a/addons/blanket_so_po/models/sale.py b/addons/blanket_so_po/models/sale.py new file mode 100644 index 00000000..5973cab1 --- /dev/null +++ b/addons/blanket_so_po/models/sale.py @@ -0,0 +1,114 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + +from flectra import api, models, fields +from flectra.exceptions import UserError +from flectra.tools import float_compare + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + _rec_name = 'product_id' + + blanket_so_line = fields.Boolean(string="Blanket Order", copy=False) + remaining_to_so_transfer = fields.Float(string="Remaining to Transfer", + copy=False) + + @api.multi + def _action_launch_procurement_rule(self): + """ + Launch procurement group run method with required/custom fields + genrated by a + sale order line. procurement group will launch '_run_move', + '_run_buy' or '_run_manufacture' + depending on the sale order line product rule. + """ + precision = self.env['decimal.precision'].precision_get( + 'Product Unit of Measure') + errors = [] + context = dict(self._context) + for line in self: + if line.state != 'sale' or not line.product_id.type in ( + 'consu', 'product') or line.blanket_so_line and \ + not context.get('blanket'): + continue + qty = 0.0 + for move in line.move_ids.filtered(lambda r: r.state != 'cancel'): + qty += move.product_uom._compute_quantity(move.product_uom_qty, + line.product_uom, + rounding_method='HALF-UP') + if float_compare(qty, line.product_uom_qty, + precision_digits=precision) >= 0: + continue + + group_id = line.order_id.procurement_group_id + if not group_id: + group_id = self.env['procurement.group'].create({ + 'name': line.order_id.name, + 'move_type': line.order_id.picking_policy, + 'sale_id': line.order_id.id, + 'partner_id': line.order_id.partner_shipping_id.id, + }) + line.order_id.procurement_group_id = group_id + else: + # In case the procurement group is already created and the + # order was + # cancelled, we need to update certain values of the group. + updated_vals = {} + if group_id.partner_id != line.order_id.partner_shipping_id: + updated_vals.update( + {'partner_id': line.order_id.partner_shipping_id.id}) + if group_id.move_type != line.order_id.picking_policy: + updated_vals.update( + {'move_type': line.order_id.picking_policy}) + if updated_vals: + group_id.write(updated_vals) + + values = line._prepare_procurement_values(group_id=group_id) + + if line.blanket_so_line and context.get('blanket'): + product_qty = context.get('transfer_qty') + else: + product_qty = line.product_uom_qty - qty + + procurement_uom = line.product_uom + quant_uom = line.product_id.uom_id + get_param = self.env['ir.config_parameter'].sudo().get_param + if procurement_uom.id != quant_uom.id and get_param( + 'stock.propagate_uom') != '1': + product_qty = line.product_uom._compute_quantity(product_qty, + quant_uom, + rounding_method='HALF-UP') + procurement_uom = quant_uom + + try: + self.env['procurement.group'].run(line.product_id, product_qty, + procurement_uom, + line.order_id.partner_shipping_id.property_stock_customer, + line.name, + line.order_id.name, values) + except UserError as error: + errors.append(error.name) + if errors: + raise UserError('\n'.join(errors)) + return True + + @api.multi + def create(self, vals): + if vals.get('product_uom_qty') and vals.get('blanket_so_line'): + vals.update( + {'remaining_to_so_transfer': vals.get('product_uom_qty')}) + res = super(SaleOrderLine, self).create(vals) + return res + + @api.multi + def write(self, values): + result = super(SaleOrderLine, self).write(values) + for line in self: + if 'product_uom_qty' and 'blanket_so_line' in values: + line.remaining_to_so_transfer = line.product_uom_qty + return result diff --git a/addons/blanket_so_po/static/description/icon.png b/addons/blanket_so_po/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3dc4657f8080345f508abab73d675073761f5437 GIT binary patch literal 7052 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 + + + + + inherit.purchase.form.view + purchase.order + + 1 + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ +
diff --git a/addons/blanket_so_po/views/sale_view.xml b/addons/blanket_so_po/views/sale_view.xml new file mode 100755 index 00000000..7f05658a --- /dev/null +++ b/addons/blanket_so_po/views/sale_view.xml @@ -0,0 +1,47 @@ + + + + + + inherit.sale.order.form.view + sale.order + + 1 + + + + + + + + +
+
+
+ + + + + + + + + +
+
+ +
diff --git a/addons/blanket_so_po/wizard/__init__.py b/addons/blanket_so_po/wizard/__init__.py new file mode 100755 index 00000000..c4e49532 --- /dev/null +++ b/addons/blanket_so_po/wizard/__init__.py @@ -0,0 +1,6 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + + +from . import transfer_po_products +from . import transfer_so_products diff --git a/addons/blanket_so_po/wizard/transfer_po_products.py b/addons/blanket_so_po/wizard/transfer_po_products.py new file mode 100644 index 00000000..7e5954c6 --- /dev/null +++ b/addons/blanket_so_po/wizard/transfer_po_products.py @@ -0,0 +1,56 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + +from flectra import api, fields, models, _ +from flectra.exceptions import ValidationError + + +class PurchaseTransferProducts(models.TransientModel): + _name = 'purchase.transfer.products' + _description = 'Transfer products from Purchase Lines' + + transfer_qty = fields.Float("Transfer Qty") + ref_id = fields.Many2one('purchase.order.line', + string="Product Reference", + readonly=True) + + @api.model + def default_get(self, fields): + context = dict(self._context) + result = super(PurchaseTransferProducts, self).default_get( + fields) + purchase_line = self.env['purchase.order.line'].browse( + context.get('active_id')) + result.update({ + 'ref_id': purchase_line.id or False, + 'transfer_qty': purchase_line.remaining_to_po_transfer}) + return result + + @api.multi + def split_qty_wt_newline_po(self): + self.ensure_one() + if self.ref_id.remaining_to_po_transfer < self.transfer_qty: + raise ValidationError(_( + 'Sorry, You can not transfer more than requested or ' + 'remains!')) + elif self.transfer_qty <= 0: + raise ValidationError(_( + 'Sorry, You can not transfer zero or negative ' + 'quantity!')) + self.ref_id._create_or_update_picking() + pickings = self.ref_id.order_id.picking_ids.filtered( + lambda p: p.state not in ('done', 'cancel')) + self.ref_id.remaining_to_po_transfer -= self.transfer_qty + for picking in pickings: + for line in picking.move_lines.filtered( + lambda l: l.product_id.id == self.ref_id.product_id.id and + l.purchase_line_id.id == self.ref_id.id): + total_product_qty = \ + self.ref_id.remaining_to_po_transfer + \ + self.ref_id.qty_received + line.product_uom_qty = \ + self.ref_id.product_qty - total_product_qty + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } diff --git a/addons/blanket_so_po/wizard/transfer_po_products_view.xml b/addons/blanket_so_po/wizard/transfer_po_products_view.xml new file mode 100755 index 00000000..f4ade64f --- /dev/null +++ b/addons/blanket_so_po/wizard/transfer_po_products_view.xml @@ -0,0 +1,39 @@ + + + + + + purchase.transfer.products.form.view + purchase.transfer.products + +
+ + + + + + +
+
+
+
+
+ + + Transfer Products + purchase.transfer.products + form + form + + new + + +
+ diff --git a/addons/blanket_so_po/wizard/transfer_so_products.py b/addons/blanket_so_po/wizard/transfer_so_products.py new file mode 100644 index 00000000..f76f211d --- /dev/null +++ b/addons/blanket_so_po/wizard/transfer_so_products.py @@ -0,0 +1,52 @@ +# Part of Flectra. See LICENSE file for full copyright and licensing +# details. + +from flectra import api, fields, models, _ +from flectra.exceptions import ValidationError + + +class SaleTransferProducts(models.TransientModel): + _name = 'sale.transfer.products' + _description = 'Transfer products from Sale Lines' + + transfer_qty = fields.Float("Transfer Qty") + ref_id = fields.Many2one('sale.order.line', string="Product Reference", + readonly=True) + + @api.model + def default_get(self, fields): + context = dict(self._context) + result = super(SaleTransferProducts, self).default_get(fields) + sale_line = self.env['sale.order.line'].browse( + context.get('active_id')) + result.update({ + 'ref_id': sale_line.id or False, + 'transfer_qty': sale_line.remaining_to_so_transfer}) + return result + + @api.multi + def split_qty_wt_newline(self): + if self.ref_id.remaining_to_so_transfer < self.transfer_qty: + raise ValidationError(_( + 'Sorry, You can not transfer more than requested or ' + 'remains!')) + elif self.transfer_qty <= 0: + raise ValidationError(_( + 'Sorry, You can not transfer zero or negative ' + 'quantity!')) + self.ref_id._action_launch_procurement_rule() + pickings = self.ref_id.order_id.picking_ids.filtered( + lambda p: p.state not in ('done', 'cancel')) + self.ref_id.remaining_to_so_transfer -= self.transfer_qty + for picking in pickings: + for line in picking.move_lines.filtered( + lambda l: l.product_id.id == self.ref_id.product_id.id and + l.sale_line_id.id == self.ref_id.id): + total_product_qty = self.ref_id.remaining_to_so_transfer \ + + self.ref_id.qty_delivered + line.product_uom_qty = self.ref_id.product_uom_qty - \ + total_product_qty + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } diff --git a/addons/blanket_so_po/wizard/transfer_so_products_view.xml b/addons/blanket_so_po/wizard/transfer_so_products_view.xml new file mode 100755 index 00000000..7fa2e212 --- /dev/null +++ b/addons/blanket_so_po/wizard/transfer_so_products_view.xml @@ -0,0 +1,38 @@ + + + + + + sale.transfer.products.form.view + sale.transfer.products + +
+ + + + + + +
+
+
+
+
+ + + Transfer Products + sale.transfer.products + form + form + + new + + +
diff --git a/addons/purchase/tests/test_stockvaluation.py b/addons/purchase/tests/test_stockvaluation.py index 2a39e208..93c8c83b 100644 --- a/addons/purchase/tests/test_stockvaluation.py +++ b/addons/purchase/tests/test_stockvaluation.py @@ -195,7 +195,7 @@ class TestStockValuation(TransactionCase): wizard.process() # the unit price of the stock move has been updated to the latest value - self.assertEquals(move1.price_unit, price_unit_usd_new_rate) + self.assertEquals(round(move1.price_unit), round(price_unit_usd_new_rate)) self.assertAlmostEqual(self.product1.stock_value, price_unit_usd_new_rate * 10, delta=0.1)