Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REF] pos_lot_selection: Make it work properly on offline mode #4

Merged
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
18 changes: 16 additions & 2 deletions pos_lot_selection/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,23 @@ Authors
Contributors
------------

- Tecnativa
- Camptocamp
- Nguyen Minh Chien <chien@trobz.com>

- Iryna Vyshnevska
- Ivan Todorovich
- Maksym Yankin

- Dixmit

- Enric Tobella

- Tecnativa

- David Vidal

- Trobz Consulting

- Nguyen Minh Chien chien@trobz.com

Maintainers
-----------
Expand Down
3 changes: 3 additions & 0 deletions pos_lot_selection/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from . import product_product
from . import stock_lot

from . import pos_session
18 changes: 18 additions & 0 deletions pos_lot_selection/models/pos_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2024 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import models


class PosSession(models.Model):
_inherit = "pos.session"

def _loader_params_product_product(self):
result = super()._loader_params_product_product()
result["search_params"]["fields"].append("available_lot_for_pos_ids")
return result

def get_pos_ui_product_product_by_params(self, custom_search_params):
return super(
PosSession, self.with_company(self.company_id.id)
).get_pos_ui_product_product_by_params(custom_search_params)
48 changes: 48 additions & 0 deletions pos_lot_selection/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2022 Camptocamp SA
# Copyright 2024 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo import api, fields, models
from odoo.tools import float_compare


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

available_lot_for_pos_ids = fields.Json(
compute="_compute_available_lot_for_pos", prefetch=False
)

@api.depends()
@api.depends_context("company")
def _compute_available_lot_for_pos(self):
for record in self:
record.available_lot_for_pos_ids = record.get_available_lots_for_pos(
self.env.company.id
)

def get_available_lots_for_pos(self, company_id):
self.ensure_one()
if self.type != "product" or self.tracking == "none":
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the original code we had:
if self.type != "product" or self.tracking != "none":

Obviously it should be self.tracking == "none"

return []
lots = (
self.env["stock.lot"]
.sudo()
.search(
[
"&",
["product_id", "=", self.id],
"|",
["company_id", "=", company_id],
["company_id", "=", False],
]
)
)

lots = lots.filtered(
lambda lot: float_compare(
lot.product_qty, 0, precision_digits=lot.product_uom_id.rounding
)
> 0
)
return [lot._get_pos_info() for lot in lots]
32 changes: 9 additions & 23 deletions pos_lot_selection/models/stock_lot.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
# Copyright 2022 Camptocamp SA
# Copyright 2024 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo import api, models
from odoo.tools import float_compare
from odoo import models


class ProductionLot(models.Model):
class StockLot(models.Model):
_inherit = "stock.lot"

@api.model
def get_available_lots_for_pos(self, product_id, company_id):
lots = self.sudo().search(
[
"&",
["product_id", "=", product_id],
"|",
["company_id", "=", company_id],
["company_id", "=", False],
]
)

lots = lots.filtered(
lambda rec: float_compare(
rec.product_qty, 0, precision_digits=rec.product_uom_id.rounding
)
> 0
)

return lots.mapped("name")
def _get_pos_info(self):
# We will add this as a hook to add more fields if necessary
return {
"id": self.id,
"name": self.name,
}
11 changes: 9 additions & 2 deletions pos_lot_selection/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
- Tecnativa
- Camptocamp
- Nguyen Minh Chien \<<chien@trobz.com>\>
- Iryna Vyshnevska
- Ivan Todorovich
- Maksym Yankin
- Dixmit
- Enric Tobella
- Tecnativa
- David Vidal
- Trobz Consulting
- Nguyen Minh Chien <chien@trobz.com>
21 changes: 18 additions & 3 deletions pos_lot_selection/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,24 @@ <h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
<li>Camptocamp</li>
<li>Nguyen Minh Chien &lt;<a class="reference external" href="mailto:chien&#64;trobz.com">chien&#64;trobz.com</a>&gt;</li>
<li>Camptocamp<ul>
<li>Iryna Vyshnevska</li>
<li>Ivan Todorovich</li>
<li>Maksym Yankin</li>
</ul>
</li>
<li>Dixmit<ul>
<li>Enric Tobella</li>
</ul>
</li>
<li>Tecnativa<ul>
<li>David Vidal</li>
</ul>
</li>
<li>Trobz Consulting<ul>
<li>Nguyen Minh Chien <a class="reference external" href="mailto:chien&#64;trobz.com">chien&#64;trobz.com</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
43 changes: 38 additions & 5 deletions pos_lot_selection/static/src/js/EditListPopup.esm.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
/** @odoo-module */

/*
Copyright 2022 Camptocamp SA
Copyright 2023 Dixmit
Copyright 2022 Camptocamp
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
*/

import {onWillStart, useState} from "@odoo/owl";
import {ConnectionLostError} from "@web/core/network/rpc_service";
import {EditListInput} from "@point_of_sale/app/store/select_lot_popup/edit_list_input/edit_list_input";
import {EditListPopup} from "@point_of_sale/app/store/select_lot_popup/select_lot_popup";

import {_t} from "@web/core/l10n/translation";
import {patch} from "@web/core/utils/patch";
import {session} from "@web/session";

patch(EditListInput.prototype, {
get_lot_name(lot) {
return lot.name;
},
});
patch(EditListPopup.prototype, {
setup() {
super.setup(...arguments);
super.setup();
this.data = useState({
lots: this.env.services.pos.selectedProduct.available_lot_for_pos_ids,
});
onWillStart(this.onWillStart);
},
async onWillStart() {
if (this.props.title === _t("Lot/Serial Number(s) Required")) {
this.props.lots = session.lots;
// We keep this in order to ensure that this call is only done
// when we add a serial
try {
const lots = await this.env.services.orm.call(
"product.product",
"get_available_lots_for_pos",
[
[this.env.services.pos.selectedProduct.id],
this.env.services.pos.company.id,
]
);
this.data.lots = lots;
this.env.services.pos.selectedProduct.available_lot_for_pos_ids = lots;
} catch (error) {
if (error instanceof ConnectionLostError) {
return;
}
throw error;
}
}
},
});
18 changes: 0 additions & 18 deletions pos_lot_selection/static/src/js/OrderWidget.esm.js

This file was deleted.

20 changes: 0 additions & 20 deletions pos_lot_selection/static/src/js/Product.esm.js

This file was deleted.

30 changes: 13 additions & 17 deletions pos_lot_selection/static/src/js/models.esm.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
/** @odoo-module */

/*
Copyright 2022 Camptocamp SA
Copyright 2023 Dixmit
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
*/

import {PosStore} from "@point_of_sale/app/store/pos_store";
import {patch} from "@web/core/utils/patch";
import {session} from "@web/session";
import {Orderline, Product} from "@point_of_sale/app/store/models";

patch(PosStore.prototype, {
async getProductLots(product) {
try {
return await this.orm.silent.call(
"stock.lot",
"get_available_lots_for_pos",
[product.id, session.user_companies.current_company]
);
} catch (error) {
console.error(error);
return [];
}
import {patch} from "@web/core/utils/patch";
patch(Product.prototype, {
getAddProductOptions() {
this.pos.selectedProduct = this;
return super.getAddProductOptions(...arguments);
},
});
patch(Orderline.prototype, {
editPackLotLines() {
this.pos.selectedProduct = this.product;
return super.editPackLotLines(...arguments);
},
});
6 changes: 3 additions & 3 deletions pos_lot_selection/static/src/xml/LotSelectorPopup.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<t t-inherit="point_of_sale.EditListPopup" t-inherit-mode="extension">
<EditListInput position="attributes">
<attribute name="lots">props.lots</attribute>
<attribute name="lots">data.lots</attribute>
</EditListInput>
</t>

Expand All @@ -20,9 +20,9 @@
t-foreach="props.lots"
t-as="lot"
t-key="lot_index"
t-att-value="lot"
t-att-value="get_lot_name(lot)"
>
<t t-esc="lot" />
<t t-esc="get_lot_name(lot)" />
</option>
</t>
</datalist>
Expand Down
4 changes: 4 additions & 0 deletions pos_lot_selection/static/tests/tours/LotSelection.tour.esm.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/** @odoo-module */
/*
Copyright 2023 Trobz Consulting
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
*/

import * as Chrome from "@point_of_sale/../tests/tours/helpers/ChromeTourMethods";
import * as ReceiptScreen from "@point_of_sale/../tests/tours/helpers/ReceiptScreenTourMethods";
Expand Down
3 changes: 2 additions & 1 deletion pos_lot_selection/tests/test_frontend.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Copyright 2023 Trobz Consulting
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import odoo.tests

Expand Down