Skip to content

Commit

Permalink
Merge PR #922 into 16.0
Browse files Browse the repository at this point in the history
Signed-off-by ivantodorovich
  • Loading branch information
OCA-git-bot committed Mar 27, 2023
2 parents 4689132 + f3be4c0 commit a1b315d
Show file tree
Hide file tree
Showing 23 changed files with 482 additions and 0 deletions.
1 change: 1 addition & 0 deletions pos_stock_available_online/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
wait a bot :)
1 change: 1 addition & 0 deletions pos_stock_available_online/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions pos_stock_available_online/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Point of Sale Stock Available Online",
"version": "16.0.1.0.0",
"category": "Sales/Point of Sale",
"summary": "Show the available quantity of products in the Point of Sale ",
"depends": ["point_of_sale", "stock_available", "base_automation"],
"website": "https://github.com/OCA/pos",
"author": "Cetmix, Odoo Community Association (OCA)",
"maintainers": ["GabbasovDinar", "CetmixGitDrone"],
"installable": True,
"data": ["views/res_config_settings_view.xml"],
"assets": {
"point_of_sale.assets": [
"pos_stock_available_online/static/src/css/**/*.css",
"pos_stock_available_online/static/src/js/**/*.js",
"pos_stock_available_online/static/src/xml/**/*.xml",
],
},
"license": "AGPL-3",
}
5 changes: 5 additions & 0 deletions pos_stock_available_online/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import pos_config
from . import pos_session
from . import res_config_settings
from . import stock_quant
from . import stock_warehouse
53 changes: 53 additions & 0 deletions pos_stock_available_online/models/pos_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import logging

from odoo import fields, models

_logger = logging.getLogger(__name__)


class PosConfig(models.Model):
_inherit = "pos.config"

display_product_quantity = fields.Boolean(
default=True,
)
main_warehouse_id = fields.Many2one(
"stock.warehouse",
related="picking_type_id.warehouse_id",
store=True,
)
additional_warehouse_ids = fields.Many2many(
"stock.warehouse",
"pos_config_stock_warehouse_rel",
"pos_config_id",
"warehouse_id",
string="Additional Warehouses",
domain="[('company_id', '=', company_id)]",
help="For the selected warehouses will be displayed "
"quantity of available products in the POS",
)
minimum_product_quantity_alert = fields.Float(
default=0.0,
)

def _get_channel_name(self):
"""
Return full channel name as combination, POS Config ID and const CHANNEL
"""
self.ensure_one()
return '["{}","{}"]'.format("pos_stock_available_online", self.id)

def _notify_available_quantity(self, message):
"""
Notify POSes about product updates
"""
if not isinstance(message, list):
message = [message]
notifications = []
for config in self:
notifications.append(
[config._get_channel_name(), "pos.config/product_update", message]
)
if notifications:
self.env["bus.bus"]._sendmany(notifications)
_logger.debug("POS notifications for %s: %s", self.ids, notifications)
22 changes: 22 additions & 0 deletions pos_stock_available_online/models/pos_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from odoo import models


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

def _process_pos_ui_product_product(self, products):
config = self.config_id
if config.display_product_quantity:
product_obj = self.env["product.product"]
for product_info in products:
product = product_obj.browse(product_info["id"])
# prepared first main warehouse info
warehouse_info = [
config.main_warehouse_id._prepare_vals_for_pos(product)
]
# prepared additional warehouses info
for warehouse in config.additional_warehouse_ids:
warehouse_info.append(warehouse._prepare_vals_for_pos(product))
product_info["warehouse_info"] = warehouse_info

return super()._process_pos_ui_product_product(products)
23 changes: 23 additions & 0 deletions pos_stock_available_online/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

pos_display_product_quantity = fields.Boolean(
related="pos_config_id.display_product_quantity",
readonly=False,
)
pos_main_warehouse_id = fields.Many2one(
"stock.warehouse",
related="pos_config_id.main_warehouse_id",
)
pos_additional_warehouse_ids = fields.Many2many(
"stock.warehouse",
related="pos_config_id.additional_warehouse_ids",
readonly=False,
)
pos_minimum_product_quantity_alert = fields.Float(
related="pos_config_id.minimum_product_quantity_alert",
readonly=False,
)
47 changes: 47 additions & 0 deletions pos_stock_available_online/models/stock_quant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import logging

from odoo import models

_logger = logging.getLogger(__name__)


class StockQuant(models.Model):
_inherit = "stock.quant"

def _prepare_pos_message(self):
"""
Return prepared message to send to POS
"""
self.ensure_one()
return self.warehouse_id._prepare_vals_for_pos(self.product_id)

def _notify_pos(self):
"""
Send notification to POS
"""
pos_session_obj = self.env["pos.session"]
for quant in self:
warehouse_id = quant.warehouse_id.id
configs = pos_session_obj.search(
[
("state", "=", "opened"),
("config_id.display_product_quantity", "=", True),
"|",
("config_id.additional_warehouse_ids", "in", [warehouse_id]),
("config_id.main_warehouse_id", "=", warehouse_id),
"|",
("config_id.iface_available_categ_ids", "=", False),
(
"config_id.iface_available_categ_ids",
"in",
[quant.product_id.pos_categ_id.id],
),
],
).mapped("config_id")
if configs:
configs._notify_available_quantity(quant._prepare_pos_message())

def write(self, vals):
res = super().write(vals)
self._notify_pos()
return res
18 changes: 18 additions & 0 deletions pos_stock_available_online/models/stock_warehouse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from odoo import models


class StockWarehouse(models.Model):
_inherit = "stock.warehouse"

def _prepare_vals_for_pos(self, product):
"""
Prepare warehouse info data to send a POS
"""
self.ensure_one()
return {
"id": self.id,
"name": self.name,
"code": self.code,
"quantity": product.with_context(warehouse=self.id).immediately_usable_qty,
"product_id": product.id,
}
14 changes: 14 additions & 0 deletions pos_stock_available_online/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
In "Point of Sale" configuration "Product Quantity" section activate "Display Product Quantity" feature:
.. image:: ../static/img/pos_config.png

By default quantity is displayed for the warehouse that is used in the POS stock operation type.

You can add additional warehouses to show quantity in by adding them into "Additional Warehouses" field.

In this case the following information will be displayed on product tiles:

- Total quantity = quantity in the default warehouse + quantity in the additional warehouses

- Quantity in the default warehouse

- Quantity in the additional warehouses.
2 changes: 2 additions & 0 deletions pos_stock_available_online/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Cetmix <https://cetmix.com/>
* Dinar Gabbasov
6 changes: 6 additions & 0 deletions pos_stock_available_online/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This module allows to display product quantities in selected locations in real time. Quantities are displayed directly on product tiles:
.. image:: ../static/img/pos_quantity.png

Once a product quantity is changed it will be simultaneously updated in all active POS.

This module depends on stock_available module which is available in https://github.com/OCA/stock-logistics-availability repo.
3 changes: 3 additions & 0 deletions pos_stock_available_online/readme/ROADMAP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module requires connection to update quantities and doesn't support offline mode.
Warehouses must belong to the same company as POS.
Offline mode support (probably additional module).
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions pos_stock_available_online/static/src/css/pos.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.pos .product-list .warehouse-info {
padding: 0.5rem;
font-weight: bold;
display: flex;
border-top: 1px solid #efefef;
justify-content: space-between;
}
.pos .product-list .warehouse-info .warehouse {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.pos .product-list .warehouse-info .warehouse .quantity {
color: black;
padding: 1px 2px;
font-size: 11px;
}
.pos .product-list .warehouse-info .warehouse .warehouse-name {
display: block;
color: #696969;
font-size: 10px;
}
.pos .product-list .warehouse-info .warehouse.total .warehouse-name {
font-weight: bold;
}
.pos .product-list .warehouse-info .warehouse .quantity.available {
color: #32a868;
}
.pos .product-list .warehouse-info .warehouse .quantity.not-available {
color: #ef5350;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/** @odoo-module **/

import ProductItem from "point_of_sale.ProductItem";
import Registries from "point_of_sale.Registries";
import {format} from "web.field_utils";
import utils from "web.utils";

const StockProductItem = (ProductItem) =>
class StockProductItem extends ProductItem {
format_quantity(quantity) {
const unit = this.env.pos.units_by_id[this.props.product.uom_id[0]];
var formattedQuantity = `${quantity}`;
if (unit) {
if (unit.rounding) {
var decimals = this.env.pos.dp["Product Unit of Measure"];
formattedQuantity = format.float(quantity, {
digits: [69, decimals],
});
} else {
formattedQuantity = utils.round_precision(quantity, 1).toFixed(0);
}
}
return `${formattedQuantity}`;
}
get display_total_quantity() {
return this.format_quantity(this.total_quantity);
}
get total_quantity() {
return this.warehouses.reduce(
(partialSum, warehouse) => partialSum + warehouse.quantity,
0
);
}
get warehouses() {
return this.props.product.warehouse_info;
}
};

Registries.Component.extend(ProductItem, StockProductItem);
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/** @odoo-module **/

import ProductsWidget from "point_of_sale.ProductsWidget";
import Registries from "point_of_sale.Registries";

const StockProductsWidget = (ProductsWidget) =>
class StockProductsWidget extends ProductsWidget {
setup() {
super.setup();
this.env.services.bus_service.addChannel(this._getChannelName());
this.env.services.bus_service.addEventListener(
"notification",
this._onNotification.bind(this)
);
}
_getChannelName() {
return JSON.stringify([
"pos_stock_available_online",
String(this.env.pos.config.id),
]);
}
_onNotification({detail: notifications}) {
var payloads = [];
for (const {payload, type} of notifications) {
if (type === "pos.config/product_update") {
payloads.push(payload);
}
}
this._handleNotification(payloads);
}
async _handleNotification(payloads) {
if (this.env.isDebug()) {
console.log("Payloads:", payloads);
}
const db = this.env.pos.db;
const ProductIds = [];
for (const payload of payloads) {
for (const message of payload) {
var product = db.get_product_by_id(message.product_id);
if (product) {
// Update warehouse info of the product
var warehouse = product.warehouse_info.find(
(wh) => wh.id === message.id
);
if (warehouse) {
warehouse.quantity = message.quantity;
} else {
product.warehouse_info.push(message);
}
} else {
ProductIds.push(message.id);
}
}
}
if (ProductIds.length) {
await this.env.pos._addProducts([...new Set(ProductIds)], false);
}
// Re-render product list without category switching
this.render(true);
}
};

Registries.Component.extend(ProductsWidget, StockProductsWidget);
Loading

0 comments on commit a1b315d

Please sign in to comment.