Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pos_second_uom/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions pos_second_uom/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "POS Second UoM",
"category": "Point of Sale",
"depends": ["product", "uom", "point_of_sale"],
"author": "habar",
"data": [
"views/product_template_view.xml",
],
"assets": {
"point_of_sale._assets_pos": [
"pos_second_uom/static/src/js/control_buttons.js",
"pos_second_uom/static/src/xml/control_button.xml",
],
},
"installable": True,
"application": False,
"license": "LGPL-3",
}
2 changes: 2 additions & 0 deletions pos_second_uom/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_template
from . import product_product
11 changes: 11 additions & 0 deletions pos_second_uom/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from odoo import api, models


class ProductProduct(models.Model):
_inherit = "product.product"

@api.model
def _load_pos_data_fields(self, config_id):
fields_list = super()._load_pos_data_fields(config_id)
fields_list.append("pos_second_uom_id")
return fields_list
44 changes: 44 additions & 0 deletions pos_second_uom/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError


class ProductTemplate(models.Model):
_inherit = 'product.template'

pos_second_uom_id = fields.Many2one(
'uom.uom',
string="POS Second Unit of Measure"
)
pos_second_uom_domain_ids = fields.Many2many('uom.uom', compute="_compute_pos_second_uom_domain_ids", string="All Pos Second Uom")

@api.depends("uom_id")
def _compute_pos_second_uom_domain_ids(self):
for rec in self:
if not rec.uom_id:
rec.pos_second_uom_domain_ids = self.env['uom.uom'].search([])
continue

root_uom = rec.uom_id
while root_uom.relative_uom_id:
root_uom = root_uom.relative_uom_id

compatible_uoms = self.env['uom.uom'].search([
'|', ('id', '=', root_uom.id), ('parent_path', 'like', f'%{root_uom.id}%')
])

rec.pos_second_uom_domain_ids = compatible_uoms

@api.constrains('pos_second_uom_id', 'uom_id')
def _check_uom_compatibility(self):
for record in self:
if record.pos_second_uom_id and record.uom_id:
root_main = record.uom_id
while root_main.relative_uom_id:
root_main = root_main.relative_uom_id

root_second = record.pos_second_uom_id
while root_second.relative_uom_id:
root_second = root_second.relative_uom_id

if root_main.id != root_second.id:
raise ValidationError(_("Selected Second UoM must be from the same unit hierarchy family!"))
45 changes: 45 additions & 0 deletions pos_second_uom/static/src/js/control_buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons";
import { NumberPopup } from "@point_of_sale/app/components/popups/number_popup/number_popup";
import { makeAwaitable } from "@point_of_sale/app/utils/make_awaitable_dialog";
import { patch } from "@web/core/utils/patch";

patch(ControlButtons.prototype, {
displaySecondUomButton() {
const line = this.currentOrder?.getSelectedOrderline();
return line?.product_id?.pos_second_uom_id;
},

async clickSecondUomButton() {
const line = this.currentOrder?.getSelectedOrderline();

if (!line) {
return;
}

const secondUom = line.product_id.pos_second_uom_id;
const mainUom = line.product_id.uom_id;

const qty = await makeAwaitable(
this.dialog,
NumberPopup,
{
title: `Enter ${secondUom.name} Quantity`,
startingValue: 0,
}
);

if (qty === null || qty === undefined) {
return;
}

const enteredQty = parseFloat(qty);

if (isNaN(enteredQty)) {
return;
}

const convertedQty = (enteredQty * secondUom.factor) / mainUom.factor;

line.setQuantity(convertedQty);
},
});
22 changes: 22 additions & 0 deletions pos_second_uom/static/src/xml/control_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-inherit="point_of_sale.ControlButtons" t-inherit-mode="extension">
<xpath expr="//button[hasclass('more-btn')]" position="before">
<button t-if="displaySecondUomButton()"
t-att-class="ui.isSmall
? 'btn bg-100 btn-md py-2 mt-2 text-start flex-shrink-0'
: 'btn btn-secondary btn-lg flex-shrink-0'"
t-on-click="clickSecondUomButton">
Add Quantity
</button>
</xpath>
</t>

<t t-inherit="point_of_sale.Orderline" t-inherit-mode="extension">
<xpath expr="//div//span[hasclass('qty')]" position="after">
<span t-if="props.line.product_id.uom_id" class="pos-uom-tag me-1 small fw-bold" style="font-size: 0.9em; vertical-align: middle;">
<t t-out="props.line.product_id.uom_id.name"/>
</span>
</xpath>
</t>
</templates>
14 changes: 14 additions & 0 deletions pos_second_uom/views/product_template_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="product_template_form_view_pos_second_uom" model="ir.ui.view">
<field name="name">product.template.form.pos.second.uom</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="point_of_sale.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='pos']" position="inside">
<field name="pos_second_uom_domain_ids" invisible="1"/>
<field name="pos_second_uom_id" domain="[('id', 'in', pos_second_uom_domain_ids)]"/>
</xpath>
</field>
</record>
</odoo>