From 58bbfbd09846ab7ffb44ce13ce3da93412595e77 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Fri, 23 Nov 2018 11:18:33 -0800 Subject: [PATCH] Initial commit of `pos_product_catch_weight` for 11.0 --- pos_product_catch_weight/__init__.py | 1 + pos_product_catch_weight/__manifest__.py | 27 ++++ pos_product_catch_weight/models/__init__.py | 1 + pos_product_catch_weight/models/pos_order.py | 57 +++++++ .../static/src/css/pos.css | 30 ++++ .../static/src/js/chrome.js | 74 +++++++++ .../static/src/js/models.js | 140 ++++++++++++++++++ .../static/src/xml/pos.xml | 40 +++++ pos_product_catch_weight/templates/assets.xml | 16 ++ 9 files changed, 386 insertions(+) create mode 100755 pos_product_catch_weight/__init__.py create mode 100755 pos_product_catch_weight/__manifest__.py create mode 100644 pos_product_catch_weight/models/__init__.py create mode 100644 pos_product_catch_weight/models/pos_order.py create mode 100755 pos_product_catch_weight/static/src/css/pos.css create mode 100755 pos_product_catch_weight/static/src/js/chrome.js create mode 100755 pos_product_catch_weight/static/src/js/models.js create mode 100755 pos_product_catch_weight/static/src/xml/pos.xml create mode 100755 pos_product_catch_weight/templates/assets.xml diff --git a/pos_product_catch_weight/__init__.py b/pos_product_catch_weight/__init__.py new file mode 100755 index 00000000..0650744f --- /dev/null +++ b/pos_product_catch_weight/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_product_catch_weight/__manifest__.py b/pos_product_catch_weight/__manifest__.py new file mode 100755 index 00000000..eabc6362 --- /dev/null +++ b/pos_product_catch_weight/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2018 Tecnativa S.L. - David Vidal +# ^^^ For OCA `pos_lot_selection` +# Copyright 2018 Hibou Corp. - Jared Kipe +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'POS Catch Weight', + 'version': '11.0.1.0.0', + 'category': 'Point of Sale', + 'author': 'Hibou Corp., ' + 'Tecnativa,' + 'Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/pos', + 'license': 'AGPL-3', + 'depends': [ + 'point_of_sale', + 'product_catch_weight', + ], + 'data': [ + 'templates/assets.xml', + ], + 'qweb': [ + 'static/src/xml/pos.xml' + ], + 'application': False, + 'installable': True, +} diff --git a/pos_product_catch_weight/models/__init__.py b/pos_product_catch_weight/models/__init__.py new file mode 100644 index 00000000..e9ab911d --- /dev/null +++ b/pos_product_catch_weight/models/__init__.py @@ -0,0 +1 @@ +from . import pos_order diff --git a/pos_product_catch_weight/models/pos_order.py b/pos_product_catch_weight/models/pos_order.py new file mode 100644 index 00000000..a2dac987 --- /dev/null +++ b/pos_product_catch_weight/models/pos_order.py @@ -0,0 +1,57 @@ +from odoo import api, fields, models + + +class PosOrderLine(models.Model): + _inherit = 'pos.order.line' + + @api.model + def create(self, values): + quant_model = self.sudo().env['stock.quant'] + res = super(PosOrderLine, self).create(values) + if res.pack_lot_ids: + lot_names = res.pack_lot_ids.mapped('lot_name') + product_id = res.product_id.id + quants = quant_model.search([ + ('product_id', '=', product_id), + ('location_id', '=', res.order_id.location_id.id), + ('lot_id', '!=', False), + ('lot_id.name', 'in', lot_names), + ]) + for l in res.pack_lot_ids: + named_quants = quants.filtered(lambda q: q.lot_id.name == l.lot_name) + for q in named_quants: + l.lot_id = q.lot_id + return res + + @api.depends('price_unit', 'tax_ids', 'qty', 'discount', 'product_id', 'pack_lot_ids.lot_id') + def _compute_amount_line_all(self): + # This is a hard override due to the closed nature of this method. + for line in self: + fpos = line.order_id.fiscal_position_id + tax_ids_after_fiscal_position = fpos.map_tax(line.tax_ids, line.product_id, + line.order_id.partner_id) if fpos else line.tax_ids + price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) + + lot_ratio_sum = 0.0 + for l in line.pack_lot_ids: + if l.lot_id: + lot_ratio_sum += l.lot_catch_weight_ratio + else: + lot_ratio_sum += 1.0 + if lot_ratio_sum != 0.0: + lot_ratio = lot_ratio_sum / line.qty + price = (line.price_unit * lot_ratio) * (1 - (line.discount or 0.0) / 100.0) + + taxes = tax_ids_after_fiscal_position.compute_all(price, line.order_id.pricelist_id.currency_id, line.qty, + product=line.product_id, partner=line.order_id.partner_id) + line.update({ + 'price_subtotal_incl': taxes['total_included'], + 'price_subtotal': taxes['total_excluded'], + }) + + +class PosOrderLineLot(models.Model): + _inherit = 'pos.pack.operation.lot' + + lot_id = fields.Many2one('stock.production.lot', string='Lot') + lot_catch_weight_ratio = fields.Float(related='lot_id.catch_weight_ratio') diff --git a/pos_product_catch_weight/static/src/css/pos.css b/pos_product_catch_weight/static/src/css/pos.css new file mode 100755 index 00000000..3b40170f --- /dev/null +++ b/pos_product_catch_weight/static/src/css/pos.css @@ -0,0 +1,30 @@ +/* Copyright 2018 Tecnativa - David Vidal + Copyright 2018 Hibou Corp. - Jared Kipe + License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). +*/ + +.pos .popup .packlot-select { + border-bottom: solid 1px rgba(60,60,60,0.1); + margin-top: 3px; +} + +.pos .popup select { + text-align: left; + padding: 10px; + display: inline-block; + border-radius: 3px; + border: solid 1px #cecbcb; + margin-bottom: 4px; + background: white; + font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial; + color: #444; + width: 80%; + min-height: 44px; + font-size: 20px; + box-sizing: border-box; +} + +.pos .popup select:focus, .pos .popup select:active { + outline: none; + box-shadow: 0px 0px 0px 3px #6EC89B; +} diff --git a/pos_product_catch_weight/static/src/js/chrome.js b/pos_product_catch_weight/static/src/js/chrome.js new file mode 100755 index 00000000..e2da8d72 --- /dev/null +++ b/pos_product_catch_weight/static/src/js/chrome.js @@ -0,0 +1,74 @@ +/* Copyright 2018 Tecnativa - David Vidal + Copyright 2018 Hibou Corp. - Jared Kipe + License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ + +odoo.define("pos_product_catch_weight.chrome", function (require) { + "use strict"; + + var chrome = require("point_of_sale.chrome"); + + chrome.Chrome.include({ + build_widgets: function () { + var res = this._super.apply(this, arguments); + var packlotline = this.gui.popup_instances.packlotline; + // Add events over instanced popup + var events = { + "change .packlot-line-select": "lot_to_input", + }; + packlotline.events = Object.assign( + packlotline.events, events + ); + // Add methods over instanced popup + // Write the value in the corresponding input + packlotline.lot_to_input = function (event) { + var $select = $(event.target); + var $option = this.$("select.packlot-line-select option"); + var $input = this.$el.find("input"); + if ($input.length) { + for (var i = 0; i < $input.length; i++) { + var $i = $input[i]; + if (!$i.value || i + 1 == $input.length) { + $i.value = $select[0].value; + $i.blur(); + $i.focus(); + } + } + } + $option.prop('selected', function () { + return this.defaultSelected; + }); + }; + + packlotline.click_confirm = function(){ + var pack_lot_lines = this.options.pack_lot_lines; + this.$('.packlot-line-input').each(function(index, el){ + var cid = $(el).attr('cid'), + lot_name = $(el).val(); + var pack_line = pack_lot_lines.get({cid: cid}); + var quant = null; + for (var i = 0; i < pack_lot_lines.product_quants.length; i++) { + if (pack_lot_lines.product_quants[i].lot_id[1] == lot_name) { + quant = pack_lot_lines.product_quants[i]; + break; + } + } + if (quant) { + pack_line.set_quant(quant); + } else { + pack_line.set_lot_name(lot_name); + } + }); + pack_lot_lines.remove_empty_model(); + pack_lot_lines.set_quantity_by_lot(); + this.options.order.save_to_db(); + this.options.order_line.trigger('change', this.options.order_line); + this.gui.close_popup(); + }, + + this.gui.popup_instances.packlotline = packlotline; + + return res; + }, + }); + +}); diff --git a/pos_product_catch_weight/static/src/js/models.js b/pos_product_catch_weight/static/src/js/models.js new file mode 100755 index 00000000..b699273a --- /dev/null +++ b/pos_product_catch_weight/static/src/js/models.js @@ -0,0 +1,140 @@ +/* Copyright 2018 Tecnativa - David Vidal + Copyright 2018 Hibou Corp. - Jared Kipe + License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ + +odoo.define("pos_product_catch_weight.models", function (require) { + "use strict"; + + var models = require("point_of_sale.models"); + var session = require("web.session"); + var utils = require('web.utils'); + var round_pr = utils.round_precision; + + models.PosModel = models.PosModel.extend({ + get_lot: function (product, location_id) { + var done = new $.Deferred(); + session.rpc("/web/dataset/search_read", { + "model": "stock.quant", + "domain": [ + ["location_id", "=", location_id], + ["product_id", "=", product], + ["lot_id", "!=", false]], + "fields": [ + 'lot_id', + 'quantity', + 'lot_catch_weight', + 'lot_catch_weight_ratio', + 'lot_catch_weight_uom_id', + ] + }, {'async': false}).then(function (result) { + var product_quants = []; + if (result.length) { + product_quants = result.records; + } + done.resolve(product_quants); + }); + return done; + }, + }); + + var _orderline_super = models.Orderline.prototype; + models.Orderline = models.Orderline.extend({ + compute_lot_lines: function(){ + var done = new $.Deferred(); + var compute_lot_lines = _orderline_super.compute_lot_lines.apply(this, arguments); + this.pos.get_lot(this.product.id, this.pos.config.stock_location_id[0]) + .then(function (product_quants) { + compute_lot_lines.product_quants = product_quants; + done.resolve(compute_lot_lines); + }); + return compute_lot_lines; + }, + + get_base_price: function(){ + var rounding = this.pos.currency.rounding; + var valid_product_lot = this.pack_lot_lines.get_valid_lots(); + var lot_ratio_sum = 0.0; + + for (var i=0; valid_product_lot && i < valid_product_lot.length; i++) { + lot_ratio_sum += valid_product_lot[i].get('lot_catch_weight_ratio'); + } + var qty = this.get_quantity(); + if (lot_ratio_sum != 0.0) { + qty = lot_ratio_sum; + } + return round_pr(this.get_unit_price() * qty * (1 - this.get_discount()/100), rounding); + }, + + get_all_prices: function(){ + var valid_product_lot = this.pack_lot_lines.get_valid_lots(); + var lot_ratio_sum = 0.0; + for (var i=0; valid_product_lot && i < valid_product_lot.length; i++) { + lot_ratio_sum += valid_product_lot[i].get('lot_catch_weight_ratio'); + } + var qty = this.get_quantity(); + var qty_ratio = 1.0 + if (lot_ratio_sum != 0.0) { + qty_ratio = lot_ratio_sum / qty; + } + + var price_unit = (this.get_unit_price() * qty_ratio) * (1.0 - (this.get_discount() / 100.0)); + + var taxtotal = 0; + + var product = this.get_product(); + var taxes_ids = product.taxes_id; + var taxes = this.pos.taxes; + var taxdetail = {}; + var product_taxes = []; + + _(taxes_ids).each(function(el){ + product_taxes.push(_.detect(taxes, function(t){ + return t.id === el; + })); + }); + + var all_taxes = this.compute_all(product_taxes, price_unit, this.get_quantity(), this.pos.currency.rounding); + _(all_taxes.taxes).each(function(tax) { + taxtotal += tax.amount; + taxdetail[tax.id] = tax.amount; + }); + + return { + "priceWithTax": all_taxes.total_included, + "priceWithoutTax": all_taxes.total_excluded, + "tax": taxtotal, + "taxDetails": taxdetail, + }; + }, + + }); + + //var _packlotline_super = models.Packlotline.prototype; + models.Packlotline = models.Packlotline.extend({ + defaults: { + lot_name: null, + lot_catch_weight_ratio: 1.0, + lot_catch_weight: 1.0, + lot_catch_weight_uom_id: null, + }, + + set_quant: function(quant) { + this.set({ + lot_name: _.str.trim(quant.lot_id[1]) || null, + lot_catch_weight_ratio: quant.lot_catch_weight_ratio || 1.0, + lot_catch_weight: quant.lot_catch_weight || 1.0, + lot_catch_weight_uom_id: quant.lot_catch_weight_uom_id || null, + }); + }, + + set_lot_name: function(name){ + this.set({ + lot_name : _.str.trim(name) || null, + lot_catch_weight_ratio : 1.0, + lot_catch_weight : 1.0, + lot_catch_weight_uom_id : null, + }); + }, + }) + +}); diff --git a/pos_product_catch_weight/static/src/xml/pos.xml b/pos_product_catch_weight/static/src/xml/pos.xml new file mode 100755 index 00000000..86c76ea6 --- /dev/null +++ b/pos_product_catch_weight/static/src/xml/pos.xml @@ -0,0 +1,40 @@ + + + + + + + +
+ + + +
+
+
+ + + + + +
  • + -- + + @ + + +
  • +
    +
    +
    + +
    diff --git a/pos_product_catch_weight/templates/assets.xml b/pos_product_catch_weight/templates/assets.xml new file mode 100755 index 00000000..45c5a58b --- /dev/null +++ b/pos_product_catch_weight/templates/assets.xml @@ -0,0 +1,16 @@ + + + + + +