Compare commits

...
Sign in to create a new pull request.

4 commits

10 changed files with 187 additions and 8 deletions

View file

View file

@ -0,0 +1,19 @@
{
"name": "Mail Quoted Reply Icon",
"summary": "Changes the icon for quoted reply from fa-reply to fa-envelope",
"version": "16.0.1.0.0",
"category": "Discuss",
"license": "AGPL-3",
"author": "Criptoamrt",
"website": "https://criptomart.net",
"depends": ["mail_quoted_reply"],
"data": [],
"demo": [],
"installable": True,
"application": False,
"assets": {
"web.assets_backend": [
"/mail_quoted_reply_icon/static/src/models/*.js",
],
},
}

View file

@ -0,0 +1,33 @@
/** @odoo-module **/
import {registerPatch} from "@mail/model/model_core";
registerPatch({
name: "MessageActionView",
fields: {
classNames: {
compute() {
let classNames = this._super() || "";
if (
this.messageAction.messageActionListOwner ===
this.messageAction.replyMessageAction
) {
// Replace the fa-reply icon added by mail_quoted_reply with fa-envelope
classNames = classNames.replace("fa-reply", "fa-envelope");
}
return classNames;
},
},
title: {
compute() {
if (
this.messageAction.messageActionListOwner ===
this.messageAction.replyMessageAction
) {
return this.env._t("Reply by Email");
}
return this._super();
},
},
},
});

View file

@ -0,0 +1,43 @@
POS Product Available Link
=========================
Automatically disables available_in_pos when sale_ok is unchecked on products.
Features
========
* When you uncheck "Can be Sold" (sale_ok), the product is also removed from POS (available_in_pos).
* Prevents products with sale_ok=False from appearing in POS.
Installation
============
Install this module as usual via Apps or with odoo-bin.
Configuration
=============
No configuration required.
Usage
=====
1. Go to Products.
2. Uncheck "Can be Sold".
3. The product will no longer be available in POS.
Known issues / Roadmap
======================
* Only disables available_in_pos when sale_ok is unchecked. Does not re-enable.
Credits
=======
Authors
-------
* Your Name
Contributors
------------
* Odoo Community Association (OCA)

View file

@ -0,0 +1 @@
from . import models

View file

@ -0,0 +1,13 @@
{
"name": "POS Product Available Link",
"summary": "Automatically enable/disable available_in_pos when sale_ok is checked/unchecked.",
"version": "16.0.1.0.0",
"category": "Point of Sale",
"license": "AGPL-3",
"author": "Criptomart",
"website": "https://criptomart.net",
"depends": ["point_of_sale", "product"],
"data": [],
"installable": True,
"application": False,
}

View file

@ -0,0 +1 @@
from . import product

View file

@ -0,0 +1,32 @@
# Copyright 2026 Your Name
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
class ProductTemplate(models.Model):
_inherit = "product.template"
@api.onchange("sale_ok")
def _onchange_sale_ok_link_available_in_pos(self):
for product in self:
product.available_in_pos = product.sale_ok
def write(self, vals):
if "sale_ok" in vals:
vals["available_in_pos"] = vals["sale_ok"]
return super().write(vals)
class ProductProduct(models.Model):
_inherit = "product.product"
@api.onchange("sale_ok")
def _onchange_sale_ok_link_available_in_pos(self):
for product in self:
product.available_in_pos = product.sale_ok
def write(self, vals):
if "sale_ok" in vals:
vals["available_in_pos"] = vals["sale_ok"]
return super().write(vals)

View file

@ -0,0 +1,21 @@
from odoo.tests.common import TransactionCase
class TestProductAvailableLink(TransactionCase):
def setUp(self):
super().setUp()
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"sale_ok": True,
"available_in_pos": True,
}
)
def test_uncheck_sale_ok_disables_available_in_pos(self):
self.product.sale_ok = False
self.assertFalse(self.product.available_in_pos)
def test_write_sale_ok_false_disables_available_in_pos(self):
self.product.write({"sale_ok": False})
self.assertFalse(self.product.available_in_pos)

View file

@ -174,13 +174,21 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
if days_with_stock != 0 if days_with_stock != 0
else 1 else 1
) )
uom_categ_unit = self.env.ref(
"uom.product_uom_categ_unit", raise_if_not_found=False
)
if self.order_days != 0: if self.order_days != 0:
qty_to_order = max( qty_calc = (self.order_days * res["units_avg_delivered"]) - res[
0, "units_virtual_available"
(self.order_days * res["units_avg_delivered"]) ]
- res["units_virtual_available"], qty_to_order = max(0, qty_calc)
) # Round only if the UoM category is 'uom.product_uom_categ_unit'
if (
product_id.uom_po_id
and uom_categ_unit
and product_id.uom_po_id.category_id.id == uom_categ_unit.id
):
qty_to_order = math.ceil(qty_to_order)
# Force a minimum suggested quantity when forecast <= 0 and product configured # Force a minimum suggested quantity when forecast <= 0 and product configured
# We apply this BEFORE packaging adjustment so packages logic can upscale it. # We apply this BEFORE packaging adjustment so packages logic can upscale it.
@ -198,7 +206,15 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
packaging_qty = product_id.packaging_ids[:1].qty packaging_qty = product_id.packaging_ids[:1].qty
if packaging_qty: if packaging_qty:
qty_to_order = math.ceil(qty_to_order / packaging_qty) * packaging_qty qty_to_order = math.ceil(qty_to_order / packaging_qty) * packaging_qty
res["units_included"] = qty_to_order # Round only if the UoM category is 'uom.product_uom_categ_unit'
if (
product_id.uom_po_id
and uom_categ_unit
and product_id.uom_po_id.category_id.id == uom_categ_unit.id
):
res["units_included"] = math.ceil(qty_to_order)
else:
res["units_included"] = qty_to_order
# Get quantities scrapped # Get quantities scrapped
domain = self._get_move_line_domain(product_id, src="internal", dst="inventory") domain = self._get_move_line_domain(product_id, src="internal", dst="inventory")
@ -417,7 +433,7 @@ class PurchaseOrderRecommendationLine(models.TransientModel):
def _compute_packaging_qty(self): def _compute_packaging_qty(self):
for rec in self: for rec in self:
if rec.packaging_id and rec.packaging_id.qty: if rec.packaging_id and rec.packaging_id.qty:
rec.packaging_qty = int(rec.units_included // rec.packaging_id.qty) rec.packaging_qty = math.ceil(rec.units_included / rec.packaging_id.qty)
else: else:
rec.packaging_qty = 0 rec.packaging_qty = 0