diff --git a/oca_dependencies.txt b/oca_dependencies.txt index 9650cd3f..358e9650 100644 --- a/oca_dependencies.txt +++ b/oca_dependencies.txt @@ -2,3 +2,4 @@ account-payment queue partner-contact stock-logistics-barcode +product-attribute diff --git a/pos_product_multi_price/__init__.py b/pos_product_multi_price/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/pos_product_multi_price/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_product_multi_price/__manifest__.py b/pos_product_multi_price/__manifest__.py new file mode 100644 index 00000000..3ff352bd --- /dev/null +++ b/pos_product_multi_price/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2020 Lorenzo Battistini @ TAKOBI +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Point of sale - Product Multi Price", + "summary": "Use pricelists based on multiple prices in point of sale", + "version": "12.0.1.0.0", + "development_status": "Beta", + "category": "Point Of Sale", + "website": "https://github.com/OCA/pos", + "author": "TAKOBI, Odoo Community Association (OCA)", + "maintainers": ["eLBati"], + "license": "AGPL-3", + "application": False, + "installable": True, + "auto_install": True, + "depends": [ + "point_of_sale", + "product_multi_price" + ], + "data": [ + "views/assets.xml", + ], +} diff --git a/pos_product_multi_price/models/__init__.py b/pos_product_multi_price/models/__init__.py new file mode 100644 index 00000000..9649db77 --- /dev/null +++ b/pos_product_multi_price/models/__init__.py @@ -0,0 +1 @@ +from . import product diff --git a/pos_product_multi_price/models/product.py b/pos_product_multi_price/models/product.py new file mode 100644 index 00000000..0492410b --- /dev/null +++ b/pos_product_multi_price/models/product.py @@ -0,0 +1,24 @@ +import json +from odoo import models, fields, api + + +class Product(models.Model): + _inherit = 'product.product' + + # technical field used in POS frontend + price_ids_json = fields.Char( + "Multi price data dict", readonly=True, + compute="_compute_price_ids_json") + + @api.multi + def _compute_price_ids_json(self): + for p in self: + res = [] + for price in p.price_ids: + res.append({ + 'id': price.id, + 'price_name': price.name.name or '', + 'price_id': price.name.id or '', + 'price': price.price, + }) + p.price_ids_json = json.dumps(res) diff --git a/pos_product_multi_price/readme/CONTRIBUTORS.rst b/pos_product_multi_price/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..2b476d75 --- /dev/null +++ b/pos_product_multi_price/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `TAKOBI `_: + + * Lorenzo Battistini diff --git a/pos_product_multi_price/readme/DESCRIPTION.rst b/pos_product_multi_price/readme/DESCRIPTION.rst new file mode 100644 index 00000000..719284fb --- /dev/null +++ b/pos_product_multi_price/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Make pricelists based on ``product_multi_price`` work in point of sale. + +See ``product_multi_price``'s documentation about how to configure and use it. diff --git a/pos_product_multi_price/static/src/js/models.js b/pos_product_multi_price/static/src/js/models.js new file mode 100644 index 00000000..353fbc7c --- /dev/null +++ b/pos_product_multi_price/static/src/js/models.js @@ -0,0 +1,64 @@ +odoo.define('pos_product_multi_price.models', function (require) { +"use strict"; + +var models = require('point_of_sale.models'); + +models.load_fields("product.product", ["price_ids_json"]); + +var _product_super = models.Product.prototype; +models.Product = models.Product.extend({ + get_price: function(pricelist, quantity) { + // partially copied from "point_of_sale.models" + + var self = this; + var price_ids_json = JSON.parse(this.price_ids_json); + var price = _product_super.get_price.apply(this, arguments); + + var date = moment().startOf('day'); + + var category_ids = []; + var category = this.categ; + while (category) { + category_ids.push(category.id); + category = category.parent; + } + var pricelist_items = _.filter(pricelist.items, function (item) { + return (! item.product_tmpl_id || item.product_tmpl_id[0] === self.product_tmpl_id) && + (! item.product_id || item.product_id[0] === self.id) && + (! item.categ_id || _.contains(category_ids, item.categ_id[0])) && + (! item.date_start || moment(item.date_start).isSameOrBefore(date)) && + (! item.date_end || moment(item.date_end).isSameOrAfter(date)); + }); + _.find(pricelist_items, function (rule) { + if (rule.min_quantity && quantity < rule.min_quantity) { + return false; + } + if (rule.base === 'multi_price' && rule.compute_price == 'formula') { + _.forEach(price_ids_json, function (multi_price) { + if (multi_price.price_id == rule.multi_price_name[0]) { + price = multi_price.price; + var price_limit = price; + price = price - (price * (rule.price_discount / 100)); + if (rule.price_round) { + price = round_pr(price, rule.price_round); + } + if (rule.price_surcharge) { + price += rule.price_surcharge; + } + if (rule.price_min_margin) { + price = Math.max(price, price_limit + rule.price_min_margin); + } + if (rule.price_max_margin) { + price = Math.min(price, price_limit + rule.price_max_margin); + } + return true; + } + }); + } + return false + }); + return price; + }, +}); + +}); diff --git a/pos_product_multi_price/views/assets.xml b/pos_product_multi_price/views/assets.xml new file mode 100644 index 00000000..553c62a6 --- /dev/null +++ b/pos_product_multi_price/views/assets.xml @@ -0,0 +1,10 @@ + + + +