[IMP] pos_self_order, website_sale: add info popup to product card in self

This commit introduce the information button on the product card in the
self order mode. This button open a popup with the newly created field
"description_self_order" which is an HTML field allowing the user to
have a very customizable description for the product.

It also removes the description_ecommerce field from the product view
form as it is a field used in the website and not adapted for
the backend (css/js not compatible).

closes odoo/odoo#138216

Task-id: 3512835
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
Adrien Guilliams (adgu)
2023-10-11 17:02:15 +00:00
parent 84e2d6ea55
commit 08a561d588
14 changed files with 114 additions and 14 deletions
+2
View File
@@ -63,6 +63,8 @@
'web/static/lib/bootstrap/js/dist/scrollspy.js',
"pos_self_order/static/src/app/**/*",
"point_of_sale/static/src/app/store/models/product_custom_attribute.js",
'web_editor/static/src/js/editor/odoo-editor/src/base_style.scss',
'web_editor/static/src/scss/web_editor.common.scss',
],
# Assets tests
"pos_self_order.assets_tests": [
@@ -15,6 +15,9 @@ class ProductTemplate(models.Model):
help="If this product is available in the Self Order screens",
default=True,
)
description_self_order = fields.Html(
string="Product Description for Self Order",
)
@api.onchange('available_in_pos')
def _on_change_available_in_pos(self):
@@ -141,7 +144,7 @@ class ProductProduct(models.Model):
"attributes": self._get_attributes(pos_config),
"name": self._get_name(),
"id": self.id,
"description_sale": self.description_sale,
"description_self_order": self.description_self_order,
"pos_categ_ids": self.pos_categ_ids.mapped("name") or ["Other"],
"pos_combo_ids": self.combo_ids.mapped("id") or False,
"is_pos_groupable": self.uom_id.is_pos_groupable,
@@ -4,6 +4,7 @@ import { Component, useRef } from "@odoo/owl";
import { useSelfOrder } from "@pos_self_order/app/self_order_service";
import { useService, useForwardRefToParent } from "@web/core/utils/hooks";
import { Line } from "@pos_self_order/app/models/line";
import { ProductInfoPopup } from "@pos_self_order/app/components/product_info_popup/product_info_popup";
export class ProductCard extends Component {
static template = "pos_self_order.ProductCard";
@@ -15,6 +16,7 @@ export class ProductCard extends Component {
setup() {
this.selfOrder = useSelfOrder();
this.router = useService("router");
this.dialog = useService("dialog");
useForwardRefToParent("currentProductCard");
}
@@ -112,4 +114,14 @@ export class ProductCard extends Component {
await this.selfOrder.getPricesFromServer();
}
}
showProductInfo() {
this.dialog.add(ProductInfoPopup, {
product: this.props.product,
title: this.props.product.name,
addToCart: () => {
this.selectProduct();
},
});
}
}
@@ -1,4 +1,28 @@
.self_order_product_card {
position: relative
}
.scale-up {
transform: scale(1.2);
transition: transform .75s ease-in-out;
}
.product-information-tag {
width: 0;
height: 0;
border-style: solid;
border-width: 0 34px 34px 0;
border-color: transparent #9a9ea180 transparent transparent;
position: absolute;
top: 0;
right: 17px;
color: white;
text-align: center;
z-index: 1;
}
.product-information-tag-logo {
position: absolute;
left: 22px;
top: 4px;
}
@@ -6,6 +6,9 @@
t-att-title="props.product.name"
t-on-click="selectProduct"
t-ref="selfProductCard">
<div t-if="props.product.description_self_order" class="product-information-tag" t-on-click.prevent.stop="showProductInfo">
<i class="product-information-tag-logo fa fa-info fs-4" role="img" aria-label="Product Information" title="Product Information" />
</div>
<div
class="ratio ratio-1x1 w-25 w-sm-50 w-md-100"
t-att-class="{
@@ -0,0 +1,17 @@
/** @odoo-module */
import { Component, useExternalListener } from "@odoo/owl";
export class ProductInfoPopup extends Component {
static template = "pos_self_order.ProductInfoPopup";
static props = ["product", "addToCart"];
setup() {
useExternalListener(window, "click", this.props.close);
}
addToCartAndClose() {
this.props.addToCart();
this.props.close();
}
}
@@ -0,0 +1,6 @@
.self_order_product_info_popup {
.modal-dialog {
height: auto !important;
top: 20%;
}
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_self_order.ProductInfoPopup" owl="1">
<div class="self_order_product_info_popup o_dialog" t-att-id="id">
<div role="dialog" class="modal d-block" tabindex="-1">
<div class="modal-dialog" role="document" t-on-click.stop="">
<div class="modal-content rounded">
<div class="modal-header">
<h1 class="modal-title fw-bolder" t-esc="props.product.name"/>
<button type="button" class="btn-close" t-on-click.stop="() => this.props.close()"></button>
</div>
<span class="modal-body o_self_order_main_desc fs-3 p-4 ps-5 overflow-auto" t-out="props.product.description_self_order" />
<div class="modal-footer">
<button type="button" class="btn btn-primary" t-on-click.stop="() => this.addToCartAndClose()">Add to Cart</button>
</div>
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -9,7 +9,7 @@ export class Product extends Reactive {
attributes,
name,
id,
description_sale,
description_self_order,
pos_categ_ids,
pos_combo_ids,
is_pos_groupable,
@@ -29,7 +29,7 @@ export class Product extends Reactive {
this.has_image = product.has_image;
this.attributes = product.attributes;
this.name = product.name;
this.description_sale = product.description_sale;
this.description_self_order = product.description_self_order;
this.pos_categ_ids = product.pos_categ_ids;
this.pos_combo_ids = product.pos_combo_ids;
this.is_pos_groupable = product.is_pos_groupable;
@@ -59,9 +59,9 @@
</div>
<div class="o-so-product-details-description">
<h2 t-esc="state.selectedProduct.name"/>
<small t-if="state.selectedProduct.description_sale"
<small t-if="state.selectedProduct.description_self_order"
class="o_self_order_main_desc d-block mb-3 text-muted"
t-out="state.selectedProduct.description_sale"
t-out="state.selectedProduct.description_self_order"
/>
<span class="fs-3" t-esc="selfOrder.formatMonetary(selfOrder.getProductDisplayPrice(state.selectedProduct))"/>
</div>
@@ -25,9 +25,9 @@
</div>
<div class="o-so-product-details-description">
<h2 t-esc="product.name"/>
<small t-if="product.description_sale"
<small t-if="product.description_self_order"
class="o_self_order_main_desc d-block mb-3 text-muted"
t-out="product.description_sale"
t-out="product.description_self_order"
/>
<span class="fs-3" t-esc="selfOrder.formatMonetary(selfOrder.getProductDisplayPrice(product))"/>
</div>
@@ -10,7 +10,7 @@ import { getColor } from "@web/core/colors/colors";
import { categorySorter } from "@pos_self_order/app/utils";
import { Order } from "@pos_self_order/app/models/order";
import { batched } from "@web/core/utils/timing";
import { useState } from "@odoo/owl";
import { useState, markup } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { cookie } from "@web/core/browser/cookie";
@@ -33,6 +33,8 @@ export class SelfOrder extends Reactive {
...session.pos_self_order_data,
});
this.markupDescriptions();
this.productsGroupedByCategory = {};
this.lastEditedProductId = null;
this.attributeValueById = {};
@@ -78,6 +80,14 @@ export class SelfOrder extends Reactive {
return this.editedOrder;
}
markupDescriptions() {
for (const product of this.products) {
product.description_self_order = product.description_self_order
? markup(product.description_self_order)
: "";
}
}
initData() {
this.currentLanguage = this.config.self_ordering_available_language_ids.find(
(l) => l.code === cookie.get("frontend_lang")
@@ -22,6 +22,14 @@
<xpath expr="//group[@name='pos']" position="inside">
<field name="self_order_available" invisible="not available_in_pos"/>
</xpath>
<group name="upsell" position="after">
<group string="Product Description for Self Order" name="description_self_order">
<field name="description_self_order"
placeholder="Information about your product for Self Order and Kiosk"
nolabel="1"
colspan="2"/>
</group>
</group>
</field>
</record>
@@ -168,12 +168,6 @@
<group name="product_template_images" string="Extra Product Media" invisible="not sale_ok">
<field name="product_template_image_ids" class="o_website_sale_image_list" context="{'default_name': name}" mode="kanban" add-label="Add a Media" nolabel="1"/>
</group>
<group string="eCommerce Description">
<field name="description_ecommerce"
placeholder="This note is added to the product page on your eCommerce shop"
nolabel="1"
colspan="2"/>
</group>
</xpath>
</field>
</record>