From 220685d407b88cd0063de8bbf5a801c3148d3e5a Mon Sep 17 00:00:00 2001 From: robinkeunen Date: Fri, 8 Jun 2018 11:34:20 +0200 Subject: [PATCH 01/16] compute purchase order, performance fix --- compute_purchase_order/__init__.py | 1 + compute_purchase_order/__openerp__.py | 21 ++ compute_purchase_order/models/__init__.py | 4 + .../models/computed_purchase_order.py | 194 +++++++++++++++++ .../models/computed_purchase_order_line.py | 196 ++++++++++++++++++ .../models/product_template.py | 26 +++ .../models/purchase_order.py | 12 ++ .../security/ir.model.access.csv | 12 ++ .../views/computed_purchase_order.xml | 115 ++++++++++ .../views/product_template.xml | 24 +++ .../views/purchase_order.xml | 13 ++ 11 files changed, 618 insertions(+) create mode 100644 compute_purchase_order/__init__.py create mode 100644 compute_purchase_order/__openerp__.py create mode 100644 compute_purchase_order/models/__init__.py create mode 100644 compute_purchase_order/models/computed_purchase_order.py create mode 100644 compute_purchase_order/models/computed_purchase_order_line.py create mode 100644 compute_purchase_order/models/product_template.py create mode 100644 compute_purchase_order/models/purchase_order.py create mode 100644 compute_purchase_order/security/ir.model.access.csv create mode 100644 compute_purchase_order/views/computed_purchase_order.xml create mode 100644 compute_purchase_order/views/product_template.xml create mode 100644 compute_purchase_order/views/purchase_order.xml diff --git a/compute_purchase_order/__init__.py b/compute_purchase_order/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/compute_purchase_order/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/compute_purchase_order/__openerp__.py b/compute_purchase_order/__openerp__.py new file mode 100644 index 0000000..1018692 --- /dev/null +++ b/compute_purchase_order/__openerp__.py @@ -0,0 +1,21 @@ +# -*- encoding: utf-8 -*- +{ + 'name': 'Computed Purchase Order', + 'version': '9.0.1', + 'category': 'Purchase Order', + 'description': """ todo """, + 'author': 'Coop IT Easy', + 'website': 'https://github.com/coopiteasy/procurement-addons', + 'license': 'AGPL-3', + 'depends': [ + 'product', + 'purchase', + 'stock', + 'stock_coverage', + ], + 'data': [ + 'security/ir.model.access.csv', + 'views/computed_purchase_order.xml', + 'views/purchase_order.xml', + ], +} diff --git a/compute_purchase_order/models/__init__.py b/compute_purchase_order/models/__init__.py new file mode 100644 index 0000000..6fdf87d --- /dev/null +++ b/compute_purchase_order/models/__init__.py @@ -0,0 +1,4 @@ +from . import purchase_order +from . import computed_purchase_order +from . import computed_purchase_order_line +from . import product_template diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py new file mode 100644 index 0000000..2c4bb62 --- /dev/null +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- +from openerp import models, fields, api +from openerp.exceptions import ValidationError + + +class ComputedPurchaseOrder(models.Model): + _description = 'Computed Purchase Order' + _name = 'computed.purchase.order' + _order = 'id desc' + + name = fields.Char( + string='CPO Reference', + size=64, + default='New') + + order_date = fields.Datetime( + string='Purchase Order Date', + default=fields.Datetime.now, + help="Depicts the date where the Quotation should be validated and converted into a purchase order.") # noqa + + date_planned = fields.Datetime( + string='Date Planned' + ) + + supplier_id = fields.Many2one( + 'res.partner', + string='Supplier', + readonly=True, + help="Supplier of the purchase order.") + + order_line_ids = fields.One2many( + 'computed.purchase.order.line', + 'computed_purchase_order_id', + string='Order Lines', + ) + + total_amount = fields.Float( + string='Total Amount (w/o VAT)', + compute='_compute_cpo_total' + ) + + generated_purchase_order_ids = fields.One2many( + 'purchase.order', + 'original_cpo_id', + string='Generated Purchase Orders', + ) + + generated_po_count = fields.Integer( + string='Generated Purchase Order count', + compute='_compute_generated_po_count', + ) + + @api.model + def default_get(self, fields_list): + record = super(ComputedPurchaseOrder, self).default_get(fields_list) + + record['date_planned'] = self._get_default_date_planned() + record['supplier_id'] = self._get_selected_supplier_id() + record['order_line_ids'] = self._create_order_lines() + record['name'] = self._compute_default_name() + + return record + + def _get_default_date_planned(self): + return fields.Datetime.now() + + def _get_selected_supplier_id(self): + """ + Calcule le vendeur associé qui a la date de début la plus récente et + plus petite qu’aujourd’hui pour chaque article sélectionné. + Will raise an error if more than two sellers are set + """ + if 'active_ids' not in self.env.context: + return False + + product_ids = self.env.context['active_ids'] + products = self.env['product.template'].browse(product_ids) + + suppliers = set() + for product in products: + main_supplier_id = product.main_supplier_id.id + suppliers.add(main_supplier_id) + + if len(suppliers) == 0: + raise ValidationError(u'No supplier is set for selected articles.') + elif len(suppliers) == 1: + return suppliers.pop() + else: + raise ValidationError( + u'You must select article from a single supplier.') + + def _create_order_lines(self): + product_tmpl_ids = self._get_selected_products() + cpol_ids = [] + OrderLine = self.env['computed.purchase.order.line'] + for product_id in product_tmpl_ids: + cpol = OrderLine.create( + {'computed_purchase_order_id': self.id, + 'product_template_id': product_id, + } + ) + # should ideally be set in cpol defaults + cpol.purchase_quantity = cpol.minimum_purchase_qty + cpol_ids.append(cpol.id) + return cpol_ids + + def _compute_default_name(self): + supplier_id = self._get_selected_supplier_id() + if supplier_id: + supplier_name = ( + self.env['res.partner'] + .browse(supplier_id) + .name) + + name = u'CPO {} {}'.format( + supplier_name, + fields.Date.today()) + else: + name = 'New' + return name + + def _get_selected_products(self): + if 'active_ids' in self.env.context: + return self.env.context['active_ids'] + else: + return [] + + @api.multi + def _compute_generated_po_count(self): + for cpo in self: + cpo.generated_po_count = len(cpo.generated_purchase_order_ids) + + @api.multi + def get_generated_po_action(self): + self.ensure_one() + action = { + 'type': 'ir.actions.act_window', + 'res_model': 'purchase.order', + 'view_mode': 'tree,form,kanban', + 'target': 'current', + 'domain': [('id', 'in', self.generated_purchase_order_ids.ids)], + } + return action + + # @api.onchange(order_line_ids) # fixme + @api.multi + def _compute_cpo_total(self): + for cpo in self: + total_amount = sum(cpol.subtotal for cpol in cpo.order_line_ids) + cpo.total_amount = total_amount + + @api.multi + def create_purchase_order(self): + self.ensure_one() + + if sum(self.order_line_ids.mapped('purchase_quantity')) == 0: + raise ValidationError(u'You need at least a product to generate ' + u'a Purchase Order') + + PurchaseOrder = self.env['purchase.order'] + PurchaseOrderLine = self.env['purchase.order.line'] + + po_values = { + 'name': 'New', + 'date_order': self.order_date, + 'partner_id': self.supplier_id.id, + 'date_planned': self.date_planned, + } + purchase_order = PurchaseOrder.create(po_values) + + for cpo_line in self.order_line_ids: + if cpo_line.purchase_quantity > 0: + pol_values = { + 'name': cpo_line.name, + 'product_id': cpo_line.get_default_product_product().id, + 'product_qty': cpo_line.purchase_quantity, + 'price_unit': cpo_line.product_price, + 'product_uom': cpo_line.uom_po_id.id, + 'order_id': purchase_order.id, + 'date_planned': self.date_planned, + } + PurchaseOrderLine.create(pol_values) + + self.generated_purchase_order_ids += purchase_order + + action = { + 'type': 'ir.actions.act_window', + 'res_model': 'purchase.order', + 'res_id': purchase_order.id, + 'view_type': 'form', + 'view_mode': 'form', + 'target': 'current', + } + return action diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py new file mode 100644 index 0000000..92ca505 --- /dev/null +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +import logging + +from openerp import models, fields, api +from openerp.exceptions import ValidationError + +_logger = logging.getLogger(__name__) + + +class ComputedPurchaseOrderLine(models.Model): + _description = 'Computed Purchase Order Line' + _name = 'computed.purchase.order.line' + + computed_purchase_order_id = fields.Many2one( + 'computed.purchase.order', + string='Computed Purchase Order', + ) + + product_template_id = fields.Many2one( + 'product.template', + string='Linked Product Template', + required=True, + help='Product') + + name = fields.Char( + string='Product Name', + related='product_template_id.name', + read_only=True) + + supplierinfo_id = fields.Many2one( + 'product.supplierinfo', + string='Supplier information', + compute='_compute_supplierinfo', + store=True, + readonly=True, + ) + + category_id = fields.Many2one( + 'product.category', + string='Internal Category', + related='product_template_id.categ_id', + read_only=True) + + uom_id = fields.Many2one( + 'product.uom', + string='Unit of Measure', + read_only=True, + related='product_template_id.uom_id', + help="Default Unit of Measure used for all stock operation.") + + qty_available = fields.Float( + string='Stock Quantity', + related='product_template_id.qty_available', + read_only=True, + help='Quantity currently in stock. Does not take ' + 'into account incoming orders.') + + virtual_available = fields.Float( + string='Stock Quantity', + related='product_template_id.virtual_available', + read_only=True, + help='Virtual quantity taking into account current stock, incoming ' + 'orders and outgoing sales.') + + average_consumption = fields.Float( + string='Average Consumption', + related='product_template_id.average_consumption', + read_only=True) + + stock_coverage = fields.Float( + string='Stock Coverage', + related='product_template_id.estimated_stock_coverage', + read_only=True, + ) + + minimum_purchase_qty = fields.Float( + string='Minimum Purchase Quantity', + compute='_depends_on_product_template', + ) + + purchase_quantity = fields.Float( + string='Purchase Quantity', + required=True, + default=0.) + + uom_po_id = fields.Many2one( + 'product.uom', + string='Purchase Unit of Measure', + read_only=True, + related='product_template_id.uom_po_id', + help="Default Unit of Measure used for all stock operation.") + + product_price = fields.Float( + string='Product Price (w/o VAT)', + compute='_depends_on_product_template', + read_only=True, + help='Supplier Product Price by buying unit. Price is without VAT') + + virtual_coverage = fields.Float( + string='Expected Stock Coverage', + compute='_depends_on_purchase_quantity', + help='Expected stock coverage (in days) based on current stocks and average daily consumption') # noqa + + subtotal = fields.Float( + string='Subtotal (w/o VAT)', + compute='_depends_on_purchase_quantity') + + @api.multi + @api.depends('product_template_id') + def _depends_on_product_template(self): + for cpol in self: + # get supplier info + cpol.minimum_purchase_qty = cpol.supplierinfo_id.min_qty + cpol.product_price = cpol.supplierinfo_id.price + + @api.multi + @api.onchange('product_template_id') + def _onchange_purchase_quantity(self): + for cpol in self: + cpol.purchase_quantity = cpol.supplierinfo_id.min_qty + + @api.depends('purchase_quantity') + @api.multi + def _depends_on_purchase_quantity(self): + for cpol in self: + cpol.subtotal = cpol.product_price * cpol.purchase_quantity + avg = cpol.average_consumption + if avg > 0: + qty = cpol.virtual_available + cpol.purchase_quantity + cpol.virtual_coverage = qty / avg + else: + # todo what would be a good default value? (not float(inf)) + cpol.virtual_coverage = 9999 + + return True + + @api.multi + @api.depends('product_template_id') + @api.onchange('product_template_id') + def _compute_supplierinfo(self): + for cpol in self: + if not cpol.product_template_id: + cpol.supplierinfo_id = False + else: + SupplierInfo = self.env['product.supplierinfo'] + si = SupplierInfo.search([ + ('product_tmpl_id', '=', cpol.product_template_id.id), + ('name', '=', cpol.product_template_id.main_supplier_id.id) # noqa + ]) + + if len(si) == 0: + raise ValidationError( + u'No supplier information set for {name}' + .format(name=cpol.product_template_id.name)) + elif len(si) == 1: + cpol.supplierinfo_id = si + else: + _logger.warning( + u'product {name} has several suppliers, chose last' + .format(name=cpol.product_template_id.name) + ) + si = si.sorted(key=lambda r: r.create_date, reverse=True) + cpol.supplierinfo_id = si[0] + + @api.constrains('purchase_quantity') + def _check_minimum_purchase_quantity(self): + for cpol in self: + if cpol.purchase_quantity < 0: + raise ValidationError(u'Purchase quantity for {product_name} must be greater than 0' # noqa + .format(product_name=cpol.product_template_id.name)) + elif 0 < cpol.purchase_quantity < cpol.minimum_purchase_qty: + raise ValidationError(u'Purchase quantity for {product_name} must be greater than {min_qty}' # noqa + .format(product_name=cpol.product_template_id.name, + min_qty=cpol.minimum_purchase_qty)) + + @api.multi + def get_default_product_product(self): + self.ensure_one() + ProductProduct = self.env['product.product'] + products = ProductProduct.search([ + ('product_tmpl_id', '=', self.product_template_id.id) + ]) + + products = products.sorted( + key=lambda product: product.create_date, + reverse=True + ) + + if products: + return products[0] + else: + raise ValidationError( + u'%s:%s template has no variant set' + % (self.product_template_id.id, self.product_template_id.name) + ) + diff --git a/compute_purchase_order/models/product_template.py b/compute_purchase_order/models/product_template.py new file mode 100644 index 0000000..030719b --- /dev/null +++ b/compute_purchase_order/models/product_template.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from openerp import models, fields, api + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + main_supplier_id = fields.Many2one( + 'res.partner', + compute='_compute_main_supplier_id', + store=True + ) + + def _get_sorted_supplierinfo(self): + return self.seller_ids.sorted( + key=lambda seller: seller.date_start, + reverse=True) + + @api.multi + @api.depends('seller_ids', 'seller_ids.date_start') + def _compute_main_supplier_id(self): + # Calcule le vendeur associé qui a la date de début la plus récente + # et plus petite qu’aujourd’hui + for pt in self: + sellers_ids = pt._get_sorted_supplierinfo() + pt.main_supplier_id = sellers_ids and sellers_ids[0].name or False diff --git a/compute_purchase_order/models/purchase_order.py b/compute_purchase_order/models/purchase_order.py new file mode 100644 index 0000000..24da3c6 --- /dev/null +++ b/compute_purchase_order/models/purchase_order.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from openerp import models, fields + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + original_cpo_id = fields.Many2one( + 'computed.purchase.order', + string='Original CPO', + help='CPO used to generate this Purchase Order' + ) diff --git a/compute_purchase_order/security/ir.model.access.csv b/compute_purchase_order/security/ir.model.access.csv new file mode 100644 index 0000000..faf22c8 --- /dev/null +++ b/compute_purchase_order/security/ir.model.access.csv @@ -0,0 +1,12 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink + +access_purchase_order,purchase.order,model_computed_purchase_order,purchase.group_purchase_user,1,1,1,1 +access_purchase_order_manager,purchase.order,model_computed_purchase_order,purchase.group_purchase_manager,1,1,1,1 +access_purchase_order_stock_worker,purchase.order,model_computed_purchase_order,stock.group_stock_user,1,0,0,0 +access_purchase_order_invoicing_payments,purchase.order,model_computed_purchase_order,account.group_account_invoice,1,1,0,0 + +access_purchase_order_line,purchase.order.line user,model_computed_purchase_order_line,purchase.group_purchase_user,1,1,1,1 +access_purchase_order_line_manager,purchase.order.line manager,model_computed_purchase_order_line,purchase.group_purchase_manager,1,0,0,0 +access_purchase_order_line_stock_worker,purchase.order.line,model_computed_purchase_order_line,stock.group_stock_user,1,0,0,0 +access_purchase_order_line_manager,purchase.order.line,model_computed_purchase_order_line,purchase.group_purchase_manager,1,1,1,1 +access_purchase_order_line_invoicing_payments,purchase.order.line,model_computed_purchase_order_line,account.group_account_invoice,1,1,0,0 diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml new file mode 100644 index 0000000..10038e1 --- /dev/null +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -0,0 +1,115 @@ + + + + + + + computed.purchase.order.tree + computed.purchase.order + + + + + + + + + + + + + + computed.purchase.order.form + computed.purchase.order + +
+
+
+ + + + + + + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+ + + + computed.purchase.order + + + + + + + + + + + Computed Purchase Orders + ir.actions.act_window + computed.purchase.order + tree,form + + + + + + + + + +
diff --git a/compute_purchase_order/views/product_template.xml b/compute_purchase_order/views/product_template.xml new file mode 100644 index 0000000..c5607c8 --- /dev/null +++ b/compute_purchase_order/views/product_template.xml @@ -0,0 +1,24 @@ + + + + + product.template.tree + product.template + + + + + + + + + + + + + + + + + + diff --git a/compute_purchase_order/views/purchase_order.xml b/compute_purchase_order/views/purchase_order.xml new file mode 100644 index 0000000..75dc354 --- /dev/null +++ b/compute_purchase_order/views/purchase_order.xml @@ -0,0 +1,13 @@ + + + + purchase.order.form.inherit + purchase.order + + + + + + + + From a65092f66b6d8a3bad72b979144eeb86905cd8e9 Mon Sep 17 00:00:00 2001 From: robinkeunen Date: Fri, 15 Jun 2018 18:45:40 +0200 Subject: [PATCH 02/16] [IMP] add product code in product name on PO creaption from CPO --- compute_purchase_order/models/computed_purchase_order.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 2c4bb62..112ead8 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -170,8 +170,12 @@ class ComputedPurchaseOrder(models.Model): for cpo_line in self.order_line_ids: if cpo_line.purchase_quantity > 0: + if cpo_line.supplierinfo_id.product_code: + pol_name = '[%s] %s' % (cpo_line.supplierinfo_id.product_code, cpo_line.name) + else: + pol_name = cpo_line.name pol_values = { - 'name': cpo_line.name, + 'name': pol_name, 'product_id': cpo_line.get_default_product_product().id, 'product_qty': cpo_line.purchase_quantity, 'price_unit': cpo_line.product_price, From 0d4f5637555940998865e599f001f32fbd796a73 Mon Sep 17 00:00:00 2001 From: robinkeunen Date: Fri, 15 Jun 2018 18:51:03 +0200 Subject: [PATCH 03/16] remove category colonne (useless here) --- compute_purchase_order/views/computed_purchase_order.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml index 10038e1..16c94f1 100644 --- a/compute_purchase_order/views/computed_purchase_order.xml +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -57,7 +57,6 @@ - From c1fb80db756041e6228dabecec5cd12a36ca50c9 Mon Sep 17 00:00:00 2001 From: robinkeunen Date: Thu, 2 Aug 2018 16:47:12 +0200 Subject: [PATCH 04/16] compute purchase order line taxes id --- .../models/computed_purchase_order.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 112ead8..00a2e56 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from openerp import models, fields, api +from openerp import models, fields, api, SUPERUSER_ID from openerp.exceptions import ValidationError @@ -183,7 +183,8 @@ class ComputedPurchaseOrder(models.Model): 'order_id': purchase_order.id, 'date_planned': self.date_planned, } - PurchaseOrderLine.create(pol_values) + pol = PurchaseOrderLine.create(pol_values) + pol.compute_taxes_id() self.generated_purchase_order_ids += purchase_order @@ -196,3 +197,17 @@ class ComputedPurchaseOrder(models.Model): 'target': 'current', } return action + + +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + @api.multi + def compute_taxes_id(self): + for pol in self: + fpos = pol.order_id.fiscal_position_id + if self.env.uid == SUPERUSER_ID: + company_id = self.env.user.company_id.id + pol.taxes_id = fpos.map_tax(pol.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == company_id)) + else: + pol.taxes_id = fpos.map_tax(pol.product_id.supplier_taxes_id) From 32ca599e10955b6979ab362aa12ae691ca9a3885 Mon Sep 17 00:00:00 2001 From: "robin.keunen" Date: Wed, 3 Apr 2019 16:26:06 +0200 Subject: [PATCH 05/16] [FIX] cpo: use uom_po_id.factor to compute expected coverage --- compute_purchase_order/models/computed_purchase_order_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index 92ca505..3e82b65 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -126,7 +126,8 @@ class ComputedPurchaseOrderLine(models.Model): cpol.subtotal = cpol.product_price * cpol.purchase_quantity avg = cpol.average_consumption if avg > 0: - qty = cpol.virtual_available + cpol.purchase_quantity + qty = ((cpol.virtual_available / cpol.uom_id.factor) + + (cpol.purchase_quantity / cpol.uom_po_id.factor)) cpol.virtual_coverage = qty / avg else: # todo what would be a good default value? (not float(inf)) @@ -193,4 +194,3 @@ class ComputedPurchaseOrderLine(models.Model): u'%s:%s template has no variant set' % (self.product_template_id.id, self.product_template_id.name) ) - From 24087efebf6b93d818aa75f6cca0ff8816e7ef79 Mon Sep 17 00:00:00 2001 From: "robin.keunen" Date: Wed, 3 Apr 2019 17:05:11 +0200 Subject: [PATCH 06/16] [FIX] cpo: compute fiscal position --- .../models/computed_purchase_order.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 00a2e56..87973b8 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -205,9 +205,24 @@ class PurchaseOrderLine(models.Model): @api.multi def compute_taxes_id(self): for pol in self: - fpos = pol.order_id.fiscal_position_id if self.env.uid == SUPERUSER_ID: company_id = self.env.user.company_id.id - pol.taxes_id = fpos.map_tax(pol.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == company_id)) else: - pol.taxes_id = fpos.map_tax(pol.product_id.supplier_taxes_id) + company_id = self.company_id.id + + fpos_id = ( + self.env['account.fiscal.position'] + .with_context(company_id=company_id) + .get_fiscal_position(pol.partner_id.id) + ) + fpos = self.env['account.fiscal.position'].browse(fpos_id) + pol.order_id.fiscal_position_id = fpos + + taxes = self.product_id.supplier_taxes_id + taxes_id = fpos.map_tax(taxes) if fpos else taxes + + if taxes_id: + taxes_id = taxes_id.filtered( + lambda t: t.company_id.id == company_id) + + pol.taxes_id = taxes_id From 6f1cbacb01b192a70f9e861a21d3629d2ec578a2 Mon Sep 17 00:00:00 2001 From: "robin.keunen" Date: Fri, 10 May 2019 14:00:46 +0200 Subject: [PATCH 07/16] [IMP] cpo: add forecast qty to cpo view --- compute_purchase_order/models/computed_purchase_order_line.py | 2 +- compute_purchase_order/views/computed_purchase_order.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index 3e82b65..1b9a4f8 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -56,7 +56,7 @@ class ComputedPurchaseOrderLine(models.Model): 'into account incoming orders.') virtual_available = fields.Float( - string='Stock Quantity', + string='Forecast Quantity', related='product_template_id.virtual_available', read_only=True, help='Virtual quantity taking into account current stock, incoming ' diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml index 16c94f1..c84432b 100644 --- a/compute_purchase_order/views/computed_purchase_order.xml +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -58,6 +58,7 @@ + From e136ba0764f7a8e83bfba0f1b1532d00159c57a9 Mon Sep 17 00:00:00 2001 From: "robin.keunen" Date: Fri, 10 May 2019 14:08:31 +0200 Subject: [PATCH 08/16] [IMP] cpo: store total_amount (performance) --- compute_purchase_order/models/computed_purchase_order.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 87973b8..6ce507d 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -36,7 +36,8 @@ class ComputedPurchaseOrder(models.Model): total_amount = fields.Float( string='Total Amount (w/o VAT)', - compute='_compute_cpo_total' + compute='_compute_cpo_total', + store=True, ) generated_purchase_order_ids = fields.One2many( @@ -142,7 +143,7 @@ class ComputedPurchaseOrder(models.Model): } return action - # @api.onchange(order_line_ids) # fixme + @api.depends('order_line_ids.subtotal') @api.multi def _compute_cpo_total(self): for cpo in self: From d10b3482c9c2b17c4a65edc856c1b1647c8836f8 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 14:47:49 +0200 Subject: [PATCH 09/16] [MIG] compute_purchase_order: migration to 10.0 - followed oca guidelines - not tested on odoo 10.0 --- compute_purchase_order/{__openerp__.py => __manifest__.py} | 2 +- compute_purchase_order/models/computed_purchase_order.py | 4 ++-- compute_purchase_order/models/computed_purchase_order_line.py | 4 ++-- compute_purchase_order/models/product_template.py | 2 +- compute_purchase_order/models/purchase_order.py | 2 +- compute_purchase_order/views/computed_purchase_order.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename compute_purchase_order/{__openerp__.py => __manifest__.py} (94%) diff --git a/compute_purchase_order/__openerp__.py b/compute_purchase_order/__manifest__.py similarity index 94% rename from compute_purchase_order/__openerp__.py rename to compute_purchase_order/__manifest__.py index 1018692..5b0d038 100644 --- a/compute_purchase_order/__openerp__.py +++ b/compute_purchase_order/__manifest__.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- { 'name': 'Computed Purchase Order', - 'version': '9.0.1', + 'version': '10.0.1.0.0', 'category': 'Purchase Order', 'description': """ todo """, 'author': 'Coop IT Easy', diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 6ce507d..5cf0769 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from openerp import models, fields, api, SUPERUSER_ID -from openerp.exceptions import ValidationError +from odoo import models, fields, api, SUPERUSER_ID +from odoo.exceptions import ValidationError class ComputedPurchaseOrder(models.Model): diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index 1b9a4f8..161d48e 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- import logging -from openerp import models, fields, api -from openerp.exceptions import ValidationError +from odoo import models, fields, api +from odoo.exceptions import ValidationError _logger = logging.getLogger(__name__) diff --git a/compute_purchase_order/models/product_template.py b/compute_purchase_order/models/product_template.py index 030719b..83947be 100644 --- a/compute_purchase_order/models/product_template.py +++ b/compute_purchase_order/models/product_template.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from openerp import models, fields, api +from odoo import models, fields, api class ProductTemplate(models.Model): diff --git a/compute_purchase_order/models/purchase_order.py b/compute_purchase_order/models/purchase_order.py index 24da3c6..e82032d 100644 --- a/compute_purchase_order/models/purchase_order.py +++ b/compute_purchase_order/models/purchase_order.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from openerp import models, fields +from odoo import models, fields class PurchaseOrder(models.Model): diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml index c84432b..fe9efdd 100644 --- a/compute_purchase_order/views/computed_purchase_order.xml +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -55,7 +55,7 @@ - + From 1889bcd506504810fe6d9853227df198beede391 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 14:50:10 +0200 Subject: [PATCH 10/16] [MIG] compute_purchase_order: migration to 11.0 - followed oca guidelines - not tested on odoo 11.0 --- compute_purchase_order/__manifest__.py | 3 +-- .../models/computed_purchase_order.py | 11 +++++------ .../models/computed_purchase_order_line.py | 11 +++++------ compute_purchase_order/models/product_template.py | 1 - compute_purchase_order/models/purchase_order.py | 1 - 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/compute_purchase_order/__manifest__.py b/compute_purchase_order/__manifest__.py index 5b0d038..69d8b12 100644 --- a/compute_purchase_order/__manifest__.py +++ b/compute_purchase_order/__manifest__.py @@ -1,7 +1,6 @@ -# -*- encoding: utf-8 -*- { 'name': 'Computed Purchase Order', - 'version': '10.0.1.0.0', + 'version': '11.0.1.0.0', 'category': 'Purchase Order', 'description': """ todo """, 'author': 'Coop IT Easy', diff --git a/compute_purchase_order/models/computed_purchase_order.py b/compute_purchase_order/models/computed_purchase_order.py index 5cf0769..9df5623 100644 --- a/compute_purchase_order/models/computed_purchase_order.py +++ b/compute_purchase_order/models/computed_purchase_order.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from odoo import models, fields, api, SUPERUSER_ID from odoo.exceptions import ValidationError @@ -83,12 +82,12 @@ class ComputedPurchaseOrder(models.Model): suppliers.add(main_supplier_id) if len(suppliers) == 0: - raise ValidationError(u'No supplier is set for selected articles.') + raise ValidationError('No supplier is set for selected articles.') elif len(suppliers) == 1: return suppliers.pop() else: raise ValidationError( - u'You must select article from a single supplier.') + 'You must select article from a single supplier.') def _create_order_lines(self): product_tmpl_ids = self._get_selected_products() @@ -113,7 +112,7 @@ class ComputedPurchaseOrder(models.Model): .browse(supplier_id) .name) - name = u'CPO {} {}'.format( + name = 'CPO {} {}'.format( supplier_name, fields.Date.today()) else: @@ -155,8 +154,8 @@ class ComputedPurchaseOrder(models.Model): self.ensure_one() if sum(self.order_line_ids.mapped('purchase_quantity')) == 0: - raise ValidationError(u'You need at least a product to generate ' - u'a Purchase Order') + raise ValidationError('You need at least a product to generate ' + 'a Purchase Order') PurchaseOrder = self.env['purchase.order'] PurchaseOrderLine = self.env['purchase.order.line'] diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index 161d48e..9963c2e 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import logging from odoo import models, fields, api @@ -151,13 +150,13 @@ class ComputedPurchaseOrderLine(models.Model): if len(si) == 0: raise ValidationError( - u'No supplier information set for {name}' + 'No supplier information set for {name}' .format(name=cpol.product_template_id.name)) elif len(si) == 1: cpol.supplierinfo_id = si else: _logger.warning( - u'product {name} has several suppliers, chose last' + 'product {name} has several suppliers, chose last' .format(name=cpol.product_template_id.name) ) si = si.sorted(key=lambda r: r.create_date, reverse=True) @@ -167,10 +166,10 @@ class ComputedPurchaseOrderLine(models.Model): def _check_minimum_purchase_quantity(self): for cpol in self: if cpol.purchase_quantity < 0: - raise ValidationError(u'Purchase quantity for {product_name} must be greater than 0' # noqa + raise ValidationError('Purchase quantity for {product_name} must be greater than 0' # noqa .format(product_name=cpol.product_template_id.name)) elif 0 < cpol.purchase_quantity < cpol.minimum_purchase_qty: - raise ValidationError(u'Purchase quantity for {product_name} must be greater than {min_qty}' # noqa + raise ValidationError('Purchase quantity for {product_name} must be greater than {min_qty}' # noqa .format(product_name=cpol.product_template_id.name, min_qty=cpol.minimum_purchase_qty)) @@ -191,6 +190,6 @@ class ComputedPurchaseOrderLine(models.Model): return products[0] else: raise ValidationError( - u'%s:%s template has no variant set' + '%s:%s template has no variant set' % (self.product_template_id.id, self.product_template_id.name) ) diff --git a/compute_purchase_order/models/product_template.py b/compute_purchase_order/models/product_template.py index 83947be..61bf5e9 100644 --- a/compute_purchase_order/models/product_template.py +++ b/compute_purchase_order/models/product_template.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from odoo import models, fields, api diff --git a/compute_purchase_order/models/purchase_order.py b/compute_purchase_order/models/purchase_order.py index e82032d..2c57db6 100644 --- a/compute_purchase_order/models/purchase_order.py +++ b/compute_purchase_order/models/purchase_order.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from odoo import models, fields From 12e2b76c67224ae65e17272430b923b5c526cb4b Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 14:54:45 +0200 Subject: [PATCH 11/16] [MIG] compute_purchase_order: migration to 12.0 - followed oca guidelines --- compute_purchase_order/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compute_purchase_order/__manifest__.py b/compute_purchase_order/__manifest__.py index 69d8b12..2c0f38a 100644 --- a/compute_purchase_order/__manifest__.py +++ b/compute_purchase_order/__manifest__.py @@ -1,6 +1,6 @@ { 'name': 'Computed Purchase Order', - 'version': '11.0.1.0.0', + 'version': '12.0.1.0.0', 'category': 'Purchase Order', 'description': """ todo """, 'author': 'Coop IT Easy', From 315f28284ee41fbb24940b08cbe598e6c266f948 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 15:16:55 +0200 Subject: [PATCH 12/16] [FIX] compute_purchase_order: stock_coverage has been renamed --- compute_purchase_order/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compute_purchase_order/__manifest__.py b/compute_purchase_order/__manifest__.py index 2c0f38a..d7f1427 100644 --- a/compute_purchase_order/__manifest__.py +++ b/compute_purchase_order/__manifest__.py @@ -10,7 +10,7 @@ 'product', 'purchase', 'stock', - 'stock_coverage', + 'beesdoo_stock_coverage', ], 'data': [ 'security/ir.model.access.csv', From 1545f362cf13d58c40f5dda40cc1c38699a79186 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 15:32:31 +0200 Subject: [PATCH 13/16] [FIX] compute_purchase_order: fields renamed in beesdoo_stock_coverage --- .../models/computed_purchase_order_line.py | 8 ++++---- compute_purchase_order/views/computed_purchase_order.xml | 2 +- compute_purchase_order/views/product_template.xml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index 9963c2e..a0f3882 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -61,14 +61,14 @@ class ComputedPurchaseOrderLine(models.Model): help='Virtual quantity taking into account current stock, incoming ' 'orders and outgoing sales.') - average_consumption = fields.Float( + daily_sales = fields.Float( string='Average Consumption', - related='product_template_id.average_consumption', + related='product_template_id.daily_sales', read_only=True) stock_coverage = fields.Float( string='Stock Coverage', - related='product_template_id.estimated_stock_coverage', + related='product_template_id.stock_coverage', read_only=True, ) @@ -123,7 +123,7 @@ class ComputedPurchaseOrderLine(models.Model): def _depends_on_purchase_quantity(self): for cpol in self: cpol.subtotal = cpol.product_price * cpol.purchase_quantity - avg = cpol.average_consumption + avg = cpol.daily_sales if avg > 0: qty = ((cpol.virtual_available / cpol.uom_id.factor) + (cpol.purchase_quantity / cpol.uom_po_id.factor)) diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml index fe9efdd..947a749 100644 --- a/compute_purchase_order/views/computed_purchase_order.xml +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -60,7 +60,7 @@ - + diff --git a/compute_purchase_order/views/product_template.xml b/compute_purchase_order/views/product_template.xml index c5607c8..a600743 100644 --- a/compute_purchase_order/views/product_template.xml +++ b/compute_purchase_order/views/product_template.xml @@ -12,10 +12,10 @@ - + - - + + From ed302da9c4ae13bde70c6010d6fd030a80b3f06d Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 15:36:01 +0200 Subject: [PATCH 14/16] [FIX] compute_purchase_order: product.uom -> uom.uom --- compute_purchase_order/models/computed_purchase_order_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compute_purchase_order/models/computed_purchase_order_line.py b/compute_purchase_order/models/computed_purchase_order_line.py index a0f3882..4bdead9 100644 --- a/compute_purchase_order/models/computed_purchase_order_line.py +++ b/compute_purchase_order/models/computed_purchase_order_line.py @@ -41,7 +41,7 @@ class ComputedPurchaseOrderLine(models.Model): read_only=True) uom_id = fields.Many2one( - 'product.uom', + 'uom.uom', string='Unit of Measure', read_only=True, related='product_template_id.uom_id', @@ -83,7 +83,7 @@ class ComputedPurchaseOrderLine(models.Model): default=0.) uom_po_id = fields.Many2one( - 'product.uom', + 'uom.uom', string='Purchase Unit of Measure', read_only=True, related='product_template_id.uom_po_id', From ef5de3a290f7457513f247cd299421477bca0036 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 17:10:58 +0200 Subject: [PATCH 15/16] [FIX] computed_purchase_order: bad sql query - duplicated id --- compute_purchase_order/security/ir.model.access.csv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compute_purchase_order/security/ir.model.access.csv b/compute_purchase_order/security/ir.model.access.csv index faf22c8..982809e 100644 --- a/compute_purchase_order/security/ir.model.access.csv +++ b/compute_purchase_order/security/ir.model.access.csv @@ -6,7 +6,6 @@ access_purchase_order_stock_worker,purchase.order,model_computed_purchase_order, access_purchase_order_invoicing_payments,purchase.order,model_computed_purchase_order,account.group_account_invoice,1,1,0,0 access_purchase_order_line,purchase.order.line user,model_computed_purchase_order_line,purchase.group_purchase_user,1,1,1,1 -access_purchase_order_line_manager,purchase.order.line manager,model_computed_purchase_order_line,purchase.group_purchase_manager,1,0,0,0 +access_purchase_order_line_manager,purchase.order.line manager,model_computed_purchase_order_line,purchase.group_purchase_manager,1,1,1,1 access_purchase_order_line_stock_worker,purchase.order.line,model_computed_purchase_order_line,stock.group_stock_user,1,0,0,0 -access_purchase_order_line_manager,purchase.order.line,model_computed_purchase_order_line,purchase.group_purchase_manager,1,1,1,1 access_purchase_order_line_invoicing_payments,purchase.order.line,model_computed_purchase_order_line,account.group_account_invoice,1,1,0,0 From d20fa63cdf0d71968534b7869370320120b76d01 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Thu, 16 Apr 2020 17:13:11 +0200 Subject: [PATCH 16/16] [TOFIX] computed_purchase_order: cpo_seller_id is missing --- compute_purchase_order/views/computed_purchase_order.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compute_purchase_order/views/computed_purchase_order.xml b/compute_purchase_order/views/computed_purchase_order.xml index 947a749..bd888a9 100644 --- a/compute_purchase_order/views/computed_purchase_order.xml +++ b/compute_purchase_order/views/computed_purchase_order.xml @@ -32,7 +32,7 @@ - + @@ -54,9 +54,9 @@ - + - +