-
-
Notifications
You must be signed in to change notification settings - Fork 602
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] pos_stock_available_online: Add new module to sync product avai…
…lability with POS [FIX] fixed pre-commit errors
- Loading branch information
1 parent
fdf2efe
commit f3be4c0
Showing
23 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
wait a bot :) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* Cetmix <https://cetmix.com/> | ||
* Dinar Gabbasov |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
39 changes: 39 additions & 0 deletions
39
pos_stock_available_online/static/src/js/Screens/ProductScreen/ProductItem.esm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
63 changes: 63 additions & 0 deletions
63
pos_stock_available_online/static/src/js/Screens/ProductScreen/ProductsWidget.esm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
Oops, something went wrong.