[IMP] point_of_sale: allow hiding images
In this commit we add the ability to toggle between showing and not showing product and category images in the pos ui. Because this change is done in stable, we store the user's selection in `ir.config.parameter`. In the forward port, this will be removed and the settings will be stored in `pos.config` Task 3704416 closes odoo/odoo#151823 Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
@@ -814,6 +814,10 @@ class PosConfig(models.Model):
|
||||
except (TypeError, ValueError, OverflowError):
|
||||
return default_limit
|
||||
|
||||
def toggle_images(self, for_products, for_categories):
|
||||
self.env['ir.config_parameter'].sudo().set_param('point_of_sale.show_product_images', for_products)
|
||||
self.env['ir.config_parameter'].sudo().set_param('point_of_sale.show_category_images', for_categories)
|
||||
|
||||
def get_limited_partners_loading(self):
|
||||
self.env.cr.execute("""
|
||||
WITH pm AS
|
||||
|
||||
@@ -1687,6 +1687,8 @@ class PosSession(models.Model):
|
||||
loaded_data['pos_special_products_ids'] = self.env['pos.config']._get_special_products().ids
|
||||
loaded_data['open_orders'] = self.env['pos.order'].search([('session_id', '=', self.id), ('state', '=', 'draft')]).export_for_ui()
|
||||
loaded_data['partner_commercial_fields'] = self.env['res.partner']._commercial_fields()
|
||||
loaded_data['show_product_images'] = self.env['ir.config_parameter'].sudo().get_param('point_of_sale.show_product_images', 'yes')
|
||||
loaded_data['show_category_images'] = self.env['ir.config_parameter'].sudo().get_param('point_of_sale.show_category_images', 'yes')
|
||||
|
||||
@api.model
|
||||
def _pos_ui_models_to_load(self):
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ export class CategorySelector extends Component {
|
||||
icon: { type: String, optional: true },
|
||||
separator: { type: String, optional: true },
|
||||
showSeparator: { type: Boolean, optional: true },
|
||||
imageUrl: { type: String, optional: true },
|
||||
imageUrl: { type: [String, Boolean], optional: true },
|
||||
},
|
||||
},
|
||||
class: { type: String, optional: true },
|
||||
|
||||
@@ -9,7 +9,7 @@ export class ProductCard extends Component {
|
||||
name: String,
|
||||
productId: Number,
|
||||
price: String,
|
||||
imageUrl: String,
|
||||
imageUrl: [String, Boolean],
|
||||
productInfo: { Boolean, optional: true },
|
||||
onClick: { type: Function, optional: true },
|
||||
onProductInfoClick: { type: Function, optional: true },
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<ul>
|
||||
<li class="menu-item position-relative d-flex">
|
||||
<i class="fa fa-bars" aria-hidden="true"></i>
|
||||
<ul class="dropdown-menu sub-menu position-absolute d-flex flex-column align-items-stretch w-100 bg-white shadow-lg z-index-1">
|
||||
<ul class="dropdown-menu sub-menu position-absolute d-flex flex-column align-items-stretch bg-white shadow-lg z-index-1">
|
||||
<li class="ticket-button" t-on-click="onTicketButtonClick">
|
||||
<a class="dropdown-item with-badge py-2">
|
||||
Orders
|
||||
@@ -51,6 +51,18 @@
|
||||
Switch Product View
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item navbar-button close-button" t-on-click="() => pos.toggleImages('product')">
|
||||
<a class="dropdown-item py-2">
|
||||
<t t-if="pos.show_product_images">Hide Product Images</t>
|
||||
<t t-else="">Show Product Images</t>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item navbar-button close-button" t-on-click="() => pos.toggleImages('category')">
|
||||
<a class="dropdown-item py-2">
|
||||
<t t-if="pos.show_category_images">Hide Category Images</t>
|
||||
<t t-else="">Show Category Images</t>
|
||||
</a>
|
||||
</li>
|
||||
<li t-if="this.env.debug" class="menu-item navbar-button" t-on-click="() => debug.toggleWidget()">
|
||||
<a class="dropdown-item py-2">
|
||||
Debug Window
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ export class ProductsWidget extends Component {
|
||||
|
||||
getShowCategoryImages() {
|
||||
return (
|
||||
this.pos.show_category_images &&
|
||||
Object.values(this.pos.db.category_by_id).some((category) => category.has_image) &&
|
||||
!this.ui.isSmall &&
|
||||
this.state.height >= 720
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
name="product.display_name"
|
||||
productId="product.id"
|
||||
price="product.getFormattedUnitPrice()"
|
||||
imageUrl="product.getImageUrl()"
|
||||
imageUrl="pos.show_product_images and product.getImageUrl()"
|
||||
onClick="() =>this.pos.addProductToCurrentOrder(product)"
|
||||
productInfo="true"
|
||||
onProductInfoClick="() => this.onProductInfoClick(product)"
|
||||
|
||||
@@ -180,6 +180,19 @@ export class PosStore extends Reactive {
|
||||
this.preloadImages();
|
||||
this.showScreen("ProductScreen");
|
||||
}
|
||||
toggleImages(imageType = "product") {
|
||||
if (imageType === "product") {
|
||||
this.show_product_images = !this.show_product_images;
|
||||
}
|
||||
if (imageType === "category") {
|
||||
this.show_category_images = !this.show_category_images;
|
||||
}
|
||||
this.orm.silent.call("pos.config", "toggle_images", [
|
||||
[this.config.id],
|
||||
this.show_product_images ? "yes" : "no",
|
||||
this.show_category_images ? "yes" : "no",
|
||||
]);
|
||||
}
|
||||
get productListViewMode() {
|
||||
const viewMode = this.productListView && this.ui.isSmall ? this.productListView : "grid";
|
||||
if (viewMode === "grid") {
|
||||
@@ -280,6 +293,8 @@ export class PosStore extends Reactive {
|
||||
this.pos_has_valid_product = loadedData["pos_has_valid_product"];
|
||||
this.db.addProductIdsToNotDisplay(loadedData["pos_special_products_ids"]);
|
||||
this.partner_commercial_fields = loadedData["partner_commercial_fields"];
|
||||
this.show_product_images = loadedData["show_product_images"] === "yes";
|
||||
this.show_category_images = loadedData["show_category_images"] === "yes";
|
||||
await this._loadPosPrinters(loadedData["pos.printer"]);
|
||||
this.open_orders_json = loadedData["open_orders"];
|
||||
}
|
||||
@@ -1237,12 +1252,14 @@ export class PosStore extends Reactive {
|
||||
try {
|
||||
// FIXME POSREF timeout
|
||||
// const timeout = typeof options.timeout === "number" ? options.timeout : 30000 * orders.length;
|
||||
const serverIds = await orm.call("pos.order", "create_from_ui", [
|
||||
orders,
|
||||
options.draft || false,
|
||||
], {
|
||||
context: this._getCreateOrderContext(orders, options),
|
||||
});
|
||||
const serverIds = await orm.call(
|
||||
"pos.order",
|
||||
"create_from_ui",
|
||||
[orders, options.draft || false],
|
||||
{
|
||||
context: this._getCreateOrderContext(orders, options),
|
||||
}
|
||||
);
|
||||
|
||||
for (const serverId of serverIds) {
|
||||
const order = this.env.services.pos.orders.find(
|
||||
@@ -1475,7 +1492,7 @@ export class PosStore extends Reactive {
|
||||
// 2) Deal with the rounding methods
|
||||
|
||||
const company = this.company;
|
||||
var round_tax = company.tax_calculation_rounding_method != 'round_globally';
|
||||
var round_tax = company.tax_calculation_rounding_method != "round_globally";
|
||||
|
||||
var initial_currency_rounding = currency_rounding;
|
||||
if (!round_tax) {
|
||||
@@ -1483,20 +1500,23 @@ export class PosStore extends Reactive {
|
||||
}
|
||||
|
||||
// 3) Iterate the taxes in the reversed sequence order to retrieve the initial base of the computation.
|
||||
var recompute_base = function(base_amount, incl_tax_amounts){
|
||||
var recompute_base = function (base_amount, incl_tax_amounts) {
|
||||
let fixed_amount = incl_tax_amounts.fixed_amount;
|
||||
let division_amount = 0.0;
|
||||
for(const [, tax_factor] of incl_tax_amounts.division_taxes){
|
||||
for (const [, tax_factor] of incl_tax_amounts.division_taxes) {
|
||||
division_amount += tax_factor;
|
||||
}
|
||||
let percent_amount = 0.0;
|
||||
for(const [, tax_factor] of incl_tax_amounts.percent_taxes){
|
||||
for (const [, tax_factor] of incl_tax_amounts.percent_taxes) {
|
||||
percent_amount += tax_factor;
|
||||
}
|
||||
|
||||
if(company.country && company.country.code === "IN"){
|
||||
for(const [i, tax_factor] of incl_tax_amounts.percent_taxes){
|
||||
const tax_amount = round_pr(base_amount * tax_factor / (100 + percent_amount), currency_rounding);
|
||||
if (company.country && company.country.code === "IN") {
|
||||
for (const [i, tax_factor] of incl_tax_amounts.percent_taxes) {
|
||||
const tax_amount = round_pr(
|
||||
(base_amount * tax_factor) / (100 + percent_amount),
|
||||
currency_rounding
|
||||
);
|
||||
cached_tax_amounts[i] = tax_amount;
|
||||
fixed_amount += tax_amount;
|
||||
}
|
||||
@@ -1509,8 +1529,12 @@ export class PosStore extends Reactive {
|
||||
fixed_amount: 0.0,
|
||||
});
|
||||
|
||||
return (base_amount - fixed_amount) / (1.0 + percent_amount / 100.0) * (100 - division_amount) / 100;
|
||||
}
|
||||
return (
|
||||
(((base_amount - fixed_amount) / (1.0 + percent_amount / 100.0)) *
|
||||
(100 - division_amount)) /
|
||||
100
|
||||
);
|
||||
};
|
||||
|
||||
var base = round_pr(price_unit * quantity, initial_currency_rounding);
|
||||
|
||||
@@ -1528,7 +1552,7 @@ export class PosStore extends Reactive {
|
||||
percent_taxes: [],
|
||||
division_taxes: [],
|
||||
fixed_amount: 0.0,
|
||||
}
|
||||
};
|
||||
|
||||
var cached_tax_amounts = {};
|
||||
if (handle_price_include) {
|
||||
@@ -1539,11 +1563,18 @@ export class PosStore extends Reactive {
|
||||
}
|
||||
if (tax.price_include) {
|
||||
if (tax.amount_type === "percent") {
|
||||
incl_tax_amounts.percent_taxes.push([i, tax.amount * tax.sum_repartition_factor]);
|
||||
incl_tax_amounts.percent_taxes.push([
|
||||
i,
|
||||
tax.amount * tax.sum_repartition_factor,
|
||||
]);
|
||||
} else if (tax.amount_type === "division") {
|
||||
incl_tax_amounts.division_taxes.push([i, tax.amount * tax.sum_repartition_factor]);
|
||||
incl_tax_amounts.division_taxes.push([
|
||||
i,
|
||||
tax.amount * tax.sum_repartition_factor,
|
||||
]);
|
||||
} else if (tax.amount_type === "fixed") {
|
||||
incl_tax_amounts.fixed_amount += Math.abs(quantity) * tax.amount * tax.sum_repartition_factor;
|
||||
incl_tax_amounts.fixed_amount +=
|
||||
Math.abs(quantity) * tax.amount * tax.sum_repartition_factor;
|
||||
} else {
|
||||
var tax_amount = self._compute_all(tax, base, quantity);
|
||||
incl_tax_amounts.fixed_amount += tax_amount;
|
||||
@@ -1558,7 +1589,10 @@ export class PosStore extends Reactive {
|
||||
});
|
||||
}
|
||||
|
||||
var total_excluded = round_pr(recompute_base(base, incl_tax_amounts), initial_currency_rounding);
|
||||
var total_excluded = round_pr(
|
||||
recompute_base(base, incl_tax_amounts),
|
||||
initial_currency_rounding
|
||||
);
|
||||
var total_included = total_excluded;
|
||||
|
||||
// 4) Iterate the taxes in the sequence order to fill missing base/amount values.
|
||||
@@ -1583,11 +1617,12 @@ export class PosStore extends Reactive {
|
||||
total_included_checkpoints[i] !== undefined &&
|
||||
tax.sum_repartition_factor != 0
|
||||
) {
|
||||
var tax_amount = total_included_checkpoints[i] - (base + cumulated_tax_included_amount);
|
||||
var tax_amount =
|
||||
total_included_checkpoints[i] - (base + cumulated_tax_included_amount);
|
||||
cumulated_tax_included_amount = 0;
|
||||
}else if(tax.price_include && cached_tax_amounts.hasOwnProperty(i)){
|
||||
} else if (tax.price_include && cached_tax_amounts.hasOwnProperty(i)) {
|
||||
var tax_amount = cached_tax_amounts[i];
|
||||
}else{
|
||||
} else {
|
||||
var tax_amount = self._compute_all(tax, tax_base_amount, quantity, true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user