[IMP] point_of_sale, *: improve customer display

*: hw_drivers

Improvements:
 - Makes the display responsive to practically never have a horizontal scrollbar.
 - Automatically reconnect to the customer display popup if it's still open from a previous session, allowing the user to keep it open between sessions.
 - Adds a view when no order is selected (in the restaurant POS UI, when the user is in the floors and tables view for example), which is also opened before leaving the POS UI (closing session or clicking on the Backend button).
 - Adds an empty order title as the one displayed in the backend when there is no product.
 - Improves the display of payment lines to take benefit of all the available free space.
 - Shows customer notes and discount in the customer display.
 - Adds order line unit next to or under the quantity (so as not to lose horizontal space).
 - Adds a footer dedicated to the Odoo logo, always visible.
 - Adds an optional user-customizable background image displayed either on the right side of the customer display if it is in landscape orientation, or in the top header of the portrait orientation.
 - Adds a title bar "Your Order".
 - Removes the "Customer Screen" label in the POS session UI and moves the status message of this screen to a notification and the title of the button.

Fixes the local display of customer display for restaurants when the "Customer Screen" button is clicked from the main view (floor with tables) and not from the view of a table order.
Removes .pos-adv and .pos-js_no_ADV css properties that no longer seem to be used.

Thanks to Xavier (xlu) for the design ideas and mockups.

task-id: 2906039
Closes #106907

closes odoo/odoo#118721

Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
Theo VINCENT (thvi)
2023-06-09 10:54:43 +02:00
parent 652acdeadc
commit ee792569f0
14 changed files with 644 additions and 362 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<title class="origin">{{ title or "Odoo's IoTBox" }}</title>
<script class="origin" type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<link class="origin" rel="stylesheet" href="/web/static/lib/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="/web/static/src/libs/fontawesome/css/font-awesome.css"/>
<link class="origin" rel="stylesheet" type="text/css" href="/web/static/src/libs/fontawesome/css/font-awesome.css"/>
<script type="text/javascript" class="origin">
var display_identifier = '{{ display_identifier }}';
{{ cust_js|safe }}
@@ -75,6 +75,7 @@ class PosConfig(models.Model):
iface_customer_facing_display = fields.Boolean(compute='_compute_customer_facing_display')
iface_customer_facing_display_via_proxy = fields.Boolean(string='Customer Facing Display', help="Show checkout to customers with a remotely-connected screen.")
iface_customer_facing_display_local = fields.Boolean(string='Local Customer Facing Display', help="Show checkout to customers.")
iface_customer_facing_display_background_image_1920 = fields.Image(string='Background Image', max_width=1920, max_height=1920, compute='_compute_iface_customer_facing_display_background_image_1920', store=True)
iface_print_via_proxy = fields.Boolean(string='Print via Proxy', help="Bypass browser printing and prints via the hardware proxy.")
iface_scan_via_proxy = fields.Boolean(string='Scan via Proxy', help="Enable barcode scanning with a remotely connected barcode scanner and card swiping with a Vantiv card reader.")
iface_big_scrollbars = fields.Boolean('Large Scrollbars', help='For imprecise industrial touchscreens.')
@@ -249,6 +250,12 @@ class PosConfig(models.Model):
if not pos_config.tip_product_id:
pos_config.tip_product_id = self.env['product.product'].search([('default_code', '=', 'TIPS')], limit=1)
@api.depends('iface_customer_facing_display')
def _compute_iface_customer_facing_display_background_image_1920(self):
for config in self:
if not config.iface_customer_facing_display:
config.iface_customer_facing_display_background_image_1920 = False
@api.constrains('rounding_method')
def _check_rounding_method_strategy(self):
for config in self:
@@ -63,6 +63,7 @@ class ResConfigSettings(models.TransientModel):
pos_iface_cashdrawer = fields.Boolean(string='Cashdrawer', compute='_compute_pos_iface_cashdrawer', readonly=False, store=True)
pos_iface_customer_facing_display_local = fields.Boolean(related='pos_config_id.iface_customer_facing_display_local', readonly=False)
pos_iface_customer_facing_display_via_proxy = fields.Boolean(string='Customer Facing Display', compute='_compute_pos_iface_customer_facing_display_via_proxy', readonly=False, store=True)
pos_iface_customer_facing_display_background_image_1920 = fields.Image(related='pos_config_id.iface_customer_facing_display_background_image_1920', readonly=False)
pos_iface_electronic_scale = fields.Boolean(string='Electronic Scale', compute='_compute_pos_iface_electronic_scale', readonly=False, store=True)
pos_iface_print_auto = fields.Boolean(related='pos_config_id.iface_print_auto', readonly=False)
pos_iface_print_skip_screen = fields.Boolean(related='pos_config_id.iface_print_skip_screen', readonly=False)
@@ -14,11 +14,42 @@ export class LocalDisplay extends Reactive {
this.globalState = globalState;
}
async connect() {
if (this.popupWindow && !this.popupWindow.closed) {
return;
}
// Because there is no way to know if the popup is already opened, PopupWindowLastStatus
// localStorage boolean is used to know if the popup was opened.
// This allows to get the already opened popup, and prevents to open the customer display
// automatically by default (most web browsers forbid to open popup windows without an user
// interaction, like a button click).
// window.open will get the already opened popup or otherwise open one
this.popupWindow = window.open("", "Customer Display", "height=600,width=900");
this.update({ refreshResources: true });
if (this.popupWindow && !this.popupWindow.closed) {
this.setPopupWindowLastStatus(true);
this.popupWindow.addEventListener("beforeunload", () => {
this.setPopupWindowLastStatus(false);
});
this.update({ refreshResources: true });
} else {
this.setPopupWindowLastStatus(false);
}
}
async update({ refreshResources = false } = {}) {
setPopupWindowLastStatus(open) {
if (open) {
window.localStorage.setItem("pos-customerdisplay-local-open", "true");
} else {
window.localStorage.removeItem("pos-customerdisplay-local-open");
}
}
isPopupWindowLastStatusOpen() {
return window.localStorage.getItem("pos-customerdisplay-local-open") === "true";
}
async update({ refreshResources = false, closeUI = false } = {}) {
if (!this.popupWindow || this.popupWindow.closed) {
if (this.isPopupWindowLastStatusOpen()) {
this.connect();
}
return;
}
// TODO: this could probably be improved by loading owl in the popup window,
@@ -27,18 +58,32 @@ export class LocalDisplay extends Reactive {
// animations.
const { body: displayBody, head: displayHead } = this.popupWindow.document;
const container = document.createElement("div");
container.innerHTML = await this.globalState.customerDisplayHTML();
container.innerHTML = await this.globalState.customerDisplayHTML(closeUI);
if (refreshResources) {
if (!container.innerHTML || container.innerHTML === "undefined") {
displayBody.textContent = "";
return;
}
if (displayHead.innerHTML.trim().length == 0 || refreshResources) {
displayHead.textContent = "";
displayHead.appendChild(container.querySelector(".resources"));
// The scripts must be evaluated because adding an element containing
// a script block doesn't make it evaluated.
const scriptContent = displayHead.querySelector(
"script#old_browser_fix_auto_scroll"
).innerHTML;
this.popupWindow.eval(scriptContent);
}
displayBody.textContent = "";
displayBody.appendChild(container.querySelector(".pos-customer_facing_display"));
const orderLines = displayBody.querySelector(".pos_orderlines_list");
orderLines.scrollTop = orderLines.scrollHeight;
// The fixScrollingIfNecessary method is called in setTimeout to be called after
// the old_browser_fix_auto_scroll script is evaluated and after the body is updated.
setTimeout(() => {
this.popupWindow.fixScrollingIfNecessary();
}, 0);
}
}
@@ -64,8 +109,8 @@ export class RemoteDisplay extends Reactive {
this.status = error === undefined ? "failure" : "not_found";
}
}
async update() {
const html = await this.globalState.customerDisplayHTML();
async update({ closeUI = false } = {}) {
const html = await this.globalState.customerDisplayHTML(closeUI);
if (this.isUpdatingStatus && this.hardwareProxy.connectionInfo.status === "connected") {
return this.hardwareProxy.message("customer_facing_display", { html });
}
@@ -3,47 +3,85 @@
<t t-name="point_of_sale.CustomerFacingDisplayHead" owl="1">
<div class="resources">
<base t-att-href="origin"/>
<base t-att-href="origin" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="pragma" content="no-cache" />
<link rel="stylesheet" type="text/css" href="/web/static/lib/bootstrap/dist/css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="/web/static/src/libs/fontawesome/css/font-awesome.css"/>
<link rel="stylesheet" type="text/css" href="/point_of_sale/static/src/css/customer_facing_display.css"/>
<link rel="stylesheet" type="text/css" href="/web/static/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="/web/static/src/libs/fontawesome/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="/point_of_sale/static/src/css/customer_facing_display.css" />
<!-- The scroll to the last selected order line (in the POS UI) is made using scroll-snap-* css properties, but the JS code below checks and does an alternative attempt with scrollIntoView if the css properties are not supported or not behaving correctly. (this JS script is in the xml template to be accessible for local and remote displays) -->
<script type="text/javascript" id="old_browser_fix_auto_scroll">
function isCentered(el) {
const rect = el.getBoundingClientRect();
const elemHeight = (rect.top + rect.bottom) / 2;
const windowMiddleHeight = window.innerHeight / 2;
return (windowMiddleHeight * 0.9 &lt;= elemHeight) &amp;&amp; (elemHeight &lt;= windowMiddleHeight * 1.1);
}
function fixScrollingIfNecessary() {
const selectedOrderlineShouldBeScrolledTo = document.querySelector(".pos-customer_facing_display .pos_orderlines_list.backend_product_screen .selected_orderline");
if (selectedOrderlineShouldBeScrolledTo &amp;&amp; !isCentered(selectedOrderlineShouldBeScrolledTo)) {
selectedOrderlineShouldBeScrolledTo.scrollIntoView({ behavior: "instant", block: "center" });
}
}
</script>
</div>
</t>
<t t-name="point_of_sale.CustomerFacingDisplayNoOrder" owl="1">
<t t-call="point_of_sale.CustomerFacingDisplayHead" />
<div class="pos-customer_facing_display pos-no-order pos-palette_01" t-attf-style="background-image: #{backgroundImageCSSValue};">
<!-- The remote display replaces pos-customer_facing_display contents, but not it -->
<!-- Therefore, pos-no-order is an inner div -->
<div class="pos-no-order" t-attf-style="background-image: #{backgroundImageCSSValue};">
<div class="pos-company_logo" t-attf-style="background-image:url(/logo?company=#{pos.company.id})" />
</div>
</div>
</t>
<t t-name="point_of_sale.CustomerFacingDisplayOrder" owl="1">
<!-- Header -->
<t t-call="point_of_sale.CustomerFacingDisplayHead"/>
<t t-call="point_of_sale.CustomerFacingDisplayHead" />
<div class="pos-customer_facing_display pos-palette_01">
<!-- Orderlines -->
<div class="pos-customer_products" name="Products list">
<t t-call="point_of_sale.CustomerFacingDisplayOrderLines"/>
<!-- Only visible in portrait orientation -->
<div class="pos-portrait-top">
<div class="pos-header" t-attf-style="background-image: #{backgroundImageCSSValue};">
<div class="pos-company_logo" t-attf-style="background-image:url(/logo?company=#{pos.company.id})" />
</div>
</div>
<div class="pos-payment_info">
<!-- Company Logo -->
<div class="pos-company_logo" t-attf-style="background-image:url(/logo?company=#{pos.company.id})"/>
<!-- Orderlines -->
<div class="pos-customer_products" name="Products list">
<t t-call="point_of_sale.CustomerFacingDisplayOrderLines" />
</div>
<div class="pos-payment_info" t-attf-style="background-image: #{backgroundImageCSSValue};">
<!-- Company Logo only visible in landscape orientation -->
<div class="pos-company_logo" t-attf-style="background-image:url(/logo?company=#{pos.company.id})" />
<div class="pos-payment_info_details">
<!-- Order TOtal -->
<!-- Order Total -->
<div class="pos-total">
<div>
<span class="total-amount-formatting">TOTAL</span>
</div>
<div>
<span class="pos_total-amount" t-esc="formatCurrency(order and order.get_total_with_tax() || 0)"/>
<div class="pos-amount-container pos-spaced-line-container">
<span class="name">Total:</span>
<div class="spacer" />
<div class="pos-spaced-line-container">
<div class="spacer" />
<span class="pos-total_amount amount" t-esc="pos.env.utils.formatCurrency(order and order.get_total_with_tax() || 0)" />
</div>
</div>
</div>
<!-- Paymentlines -->
<t t-call="point_of_sale.CustomerFacingDisplayPaymentLines"/>
<t t-call="point_of_sale.CustomerFacingDisplayPaymentLines" />
</div>
<!-- Odoo Logo -->
<div class="pos-odoo_logo_container">
<span>powered by </span>
</div>
<!-- Odoo Logo -->
<div class="pos-odoo_logo_container">
<span>Powered by </span>
<div class="logo" />
</div>
</div>
</div>
@@ -51,22 +89,76 @@
<t t-name="point_of_sale.CustomerFacingDisplayOrderLines" owl="1">
<div class="pos_orderlines">
<div class="pos_orderlines_item pos_orderlines_header">
<div/>
<div/>
<div>Quantity</div>
<div>Price</div>
</div>
<div class="pos_orderlines_list">
<t t-if="order">
<div t-foreach="order.get_orderlines()" t-as="orderline" t-key="orderline_index" class="pos_orderlines_item">
<div><div t-attf-style="background-image:url(#{productImages[orderline.product.id]})"/></div>
<div t-esc="orderline.get_full_product_name()"/>
<div t-esc="orderline.get_quantity_str()"/>
<div t-esc="formatCurrency(orderline.get_display_price())"/>
<t t-if="order">
<t t-if="order.get_current_screen_data().name != 'ReceiptScreen'">
<t t-if="order.get_orderlines().length > 0">
<div class="pos-order_top_bar">
<span>Your Order</span>
</div>
<div class="pos_orderlines_list" t-att-class="{ 'backend_product_screen': order.get_current_screen_data().name === 'ProductScreen' }">
<table>
<thead>
<tr>
<th colspan="2" class="pos-product-th">
<span>Product</span>
</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr t-foreach="order.get_orderlines()" t-key="orderline.id" t-as="orderline" class="pos_orderlines_item" t-att-class="{ 'selected_orderline': orderline.id === order.get_selected_orderline().id }">
<td class="product_img">
<img t-attf-src="#{productImages[orderline.product.id]}" />
</td>
<td class="product_text_info">
<ul>
<li t-esc="orderline.get_full_product_name()" />
<t t-if="orderline.get_discount_str() !== '0'">
<li class="product_details">
<i class="fa fa-tag" role="img" aria-label="Discount" title="Discount" />
<t t-esc="orderline.get_discount_str()" />% <span class="gray">discount</span>
</li>
</t>
<t t-if="orderline.get_customer_note()">
<li class="product_details">
<i class="fa fa-sticky-note" role="img" aria-label="Customer Note" title="Customer Note" />
<span class="gray" t-esc="orderline.get_customer_note()" />
</li>
</t>
</ul>
</td>
<td class="product_quantity gray">
<span t-esc="orderline.get_quantity_str()" />
<span t-esc="orderline.get_unit().name" />
</td>
<td>
<div t-esc="pos.env.utils.formatCurrency(orderline.get_display_price())" />
</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
fixScrollingIfNecessary();
});
</script>
</t>
<t t-else="">
<div class="order-empty">
<i class="fa fa-shopping-cart" role="img" aria-label="Shopping cart"
title="Shopping cart" />
<h1>This order is empty</h1>
</div>
</t>
</t>
<t t-else="">
<div class="pos-thank-you-message">
<span>Thank you for your purchase!</span>
</div>
</t>
</div>
</t>
</div>
</t>
@@ -74,20 +166,24 @@
<div class="pos-paymentlines">
<t t-if="order">
<t t-foreach="order.get_paymentlines()" t-as="paymentline" t-key="paymentline_index">
<div>
<span><t t-esc="paymentline.name"/>:</span>
</div>
<div>
<span t-esc="formatCurrency(paymentline.get_amount())"/>
<div class="pos-amount-container pos-spaced-line-container">
<span class="name"><t t-esc="paymentline.name" />:</span>
<div class="spacer" />
<div class="pos-spaced-line-container">
<div class="spacer" />
<span class="amount" t-esc="pos.env.utils.formatCurrency(paymentline.get_amount())" />
</div>
</div>
</t>
</t>
<div>
<span class="pos-change_title">Change</span>
</div>
<div>
<span class="pos-change_amount" t-esc="formatCurrency(order and order.get_change() || 0)"/>
<div class="pos-amount-container pos-spaced-line-container">
<span class="name">Change:</span>
<div class="spacer" />
<div class="pos-spaced-line-container">
<div class="spacer" />
<span class="amount" t-esc="pos.env.utils.formatCurrency(order and order.get_change() || 0)" />
</div>
</div>
</div>
</t>
+15 -1
View File
@@ -3,7 +3,7 @@
import { Chrome } from "@point_of_sale/app/pos_app";
import { Loader } from "@point_of_sale/app/loader/loader";
import { setLoadXmlDefaultApp, templates } from "@web/core/assets";
import { App, mount, reactive, whenReady } from "@odoo/owl";
import { App, mount, reactive, whenReady, Component } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { hasTouch } from "@web/core/browser/feature_detection";
import { localization } from "@web/core/l10n/localization";
@@ -25,6 +25,20 @@ whenReady(() => {
server_version_info: session.server_version_info,
isEnterprise: session.server_version_info.slice(-1)[0] === "e",
};
// Wait for all templates
await odoo.ready(/\.bundle\.xml/);
// Make a temporary app to be able to use renderToString method before the main app is available.
const renderToStringApp = new App(Component, {
name: "renderToString app",
templates,
dev: !!odoo.debug,
warnIfNoStaticProps: true,
translatableAttributes: ["data-tooltip"],
translateFn: _t,
});
renderToString.app = renderToStringApp;
// setup environment
const env = makeEnv();
await startServices(env);
@@ -25,6 +25,7 @@ export class ClosePosPopup extends AbstractAwaitablePopup {
this.orm = useService("orm");
this.report = useService("report");
this.hardwareProxy = useService("hardware_proxy");
this.customerDisplay = useService("customer_display");
this.manualInputCashCount = false;
this.cashControl = this.pos.globalState.config.cash_control;
this.closeSessionClicked = false;
@@ -133,6 +134,10 @@ export class ClosePosPopup extends AbstractAwaitablePopup {
if (!this.closeSessionClicked) {
this.closeSessionClicked = true;
if (this.customerDisplay) {
this.customerDisplay.update({ closeUI: true });
}
if (this.cashControl) {
const response = await this.orm.call(
"pos.session",
@@ -10,13 +10,32 @@ export class CustomerFacingDisplayButton extends Component {
setup() {
this.pos = usePos();
this.customerDisplay = useState(useService("customer_display"));
this.notification = useService("pos_notification");
}
get message() {
return {
const msg = {
success: "",
warning: _t("Connected, Not Owned"),
failure: _t("Disconnected"),
not_found: _t("Customer Screen Unsupported. Please upgrade the IoT Box"),
}[this.customerDisplay.status];
if (
this.previousDisplayedStatus &&
this.previousDisplayedStatus != this.customerDisplay.status
) {
this.displayMessage(msg);
this.previousDisplayedStatus = this.customerDisplay.status;
}
return msg;
}
displayMessage(message) {
if (this.notification) {
if (message.length == 0) {
message = "Connected";
}
this.notification.add("Customer Display : " + message, 3000);
}
}
}
@@ -2,19 +2,20 @@
<templates id="template" xml:space="preserve">
<t t-name="point_of_sale.CustomerFacingDisplayButton" owl="1">
<li class="menu-item navbar-button" t-on-click="() => customerDisplay.connect()">
<span class="message"><t t-esc="message" /></span>
<div class="menu-item navbar-button" t-on-click="() => {customerDisplay.connect(); this.displayMessage(message);}">
<div t-if="customerDisplay.status === 'warning'" class="js_warning oe_icon oe_orange">
<i class="fa fa-fw fa-desktop" role="img" aria-label="Customer Screen Warning" title="Customer Screen Warning"></i>
<i class="fa fa-fw fa-desktop" role="img" t-attf-aria-label="Customer Screen Warning : {{message}}" t-attf-title="Customer Screen Warning : {{message}}"></i>
</div>
<div t-if="customerDisplay.status === 'failure'" class="js_disconnected oe_icon oe_red">
<i class="fa fa-fw fa-desktop" role="img" aria-label="Customer Screen Disconnected" title="Customer Screen Disconnected"></i>
<div t-if="customerDisplay.status === 'failure'" class="js_disconnected oe_icon oe_red">
<i class="fa fa-fw fa-desktop" role="img" t-attf-aria-label="Customer Screen : {{message}}" t-attf-title="Customer Screen : {{message}}"></i>
</div>
<div t-if="customerDisplay.status === 'not_found'" class="js_disconnected oe_icon oe_red">
<i class="fa fa-fw fa-desktop" role="img" t-attf-aria-label="Customer Screen Not Found : {{message}}" t-attf-title="Customer Screen Not Found : {{message}}"></i>
</div>
<div t-if="customerDisplay.status === 'success'" class="js_connected oe_icon oe_green">
<i class="fa fa-fw fa-desktop" role="img" aria-label="Customer Screen Connected" title="Customer Screen Connected"></i>
</div>
<span>Customer Screen</span>
</li>
</div>
</div>
</t>
</templates>
@@ -945,11 +945,25 @@ export class PosGlobalState extends PosModel {
*
* @returns {string}
*/
async customerDisplayHTML() {
const order = this.get_order();
if (!order) {
return;
async customerDisplayHTML(closeUI = false) {
const backgroundImageBase64 =
this.config.iface_customer_facing_display_background_image_1920;
let backgroundImageCSSValue;
if (backgroundImageBase64) {
backgroundImageCSSValue = "url('data:image/png;base64," + backgroundImageBase64 + "')";
} else {
backgroundImageCSSValue = "none";
}
const order = this.get_order();
if (closeUI || !order) {
return renderToString("point_of_sale.CustomerFacingDisplayNoOrder", {
pos: this,
origin: window.location.origin,
backgroundImageCSSValue,
});
}
const orderLines = order.get_orderlines();
const productImages = Object.fromEntries(
await Promise.all(
@@ -964,6 +978,7 @@ export class PosGlobalState extends PosModel {
pos: this,
formatCurrency: this.env.utils.formatCurrency,
origin: window.location.origin,
backgroundImageCSSValue,
order,
productImages,
});
@@ -3970,6 +3985,9 @@ export class Order extends PosModel {
set_screen_data(value) {
this.screen_data["value"] = value;
}
get_current_screen_data() {
return this.screen_data["value"] ?? { name: "ProductScreen" };
}
//see set_screen_data
get_screen_data() {
const screen = this.screen_data["value"];
@@ -127,6 +127,11 @@ export class PosStore extends Reactive {
}
async closePos() {
const customerDisplayService = this.globalState.env.services.customer_display;
if (customerDisplayService) {
customerDisplayService.update({ closeUI: true });
}
// If pos is not properly loaded, we just go back to /web without
// doing anything in the order data.
if (!this.globalState || this.globalState.db.get_orders().length === 0) {
@@ -46,11 +46,14 @@ body .pos-customer_facing_display {
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
overflow: hidden;
}
body .pos-customer_facing_display .pos-customer_products {
overflow: auto;
padding: 1%;
}
body .pos-customer_facing_display .pos-customer_products,
body .pos-customer_facing_display .pos-payment_info {
height: 100%;
padding: 2%;
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
@@ -67,6 +70,119 @@ body .pos-customer_facing_display .pos-payment_info {
-ms-flex-positive: 1;
flex-grow: 1;
}
.pos-customer_facing_display .pos_orderlines_list {
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
-o-flex-direction: column;
flex-direction: column;
height: 100%;
}
.pos-customer_facing_display .pos-order_top_bar {
border-radius: 0.2rem;
padding: 0.5rem 1rem 0.3rem 1.3rem;
color: white;
font-weight: bold;
font-size: max(min(3.2vh, 3.2vw), 1rem);
background-color: #343A40;
}
.pos-customer_facing_display .pos_orderlines_list table {
text-align: center;
vertical-align: middle;
border-collapse: separate;
border-spacing: 0 10px;
width: 100%;
}
.pos-customer_facing_display .pos_orderlines_list table th {
position: sticky;
top: 0;
padding: 0.5rem;
color: #212529;
font-weight: 590;
font-size: max(min(2vh, 2vw), 1rem);
}
.pos-customer_facing_display .pos_orderlines_list table th.pos-product-th {
text-align: left;
}
.pos-customer_facing_display .pos_orderlines_list table th.pos-product-th span {
margin-left: 1rem;
}
.pos-customer_facing_display .pos_orderlines_list table td {
word-wrap: break-word;
max-width: min(13vw, 8rem);
padding: 0 0.3vw;
font-size: max(min(3vh, 3vw), 1rem);
font-weight: bold;
}
.pos-customer_facing_display .pos_orderlines_list table td.product_img {
padding: 1vh 1vh;
max-width: unset;
}
.pos-customer_facing_display .pos_orderlines_list table td.product_img img {
width: min(10vh, 10vw);
height: min(10vh, 10vw);
border-radius: 10%;
}
.pos-customer_facing_display .pos_orderlines_list table td.product_text_info {
min-width: 15vw;
max-width: 30vw;
}
.pos-customer_facing_display .pos_orderlines_list table .product_text_info ul {
text-align: left;
margin: 0;
list-style-type: none;
padding: 0;
}
.pos-customer_facing_display .pos_orderlines_list table td .product_details i.fa{
margin-right: 0.5rem;
color: gray;
}
.pos-customer_facing_display .pos_orderlines_list table td .product_details {
font-size: max(min(2.5vh, 2.5vw), 0.8rem);
}
.pos-customer_facing_display .pos_orderlines_list table td.product_quantity > span + span {
margin-left: .3rem;
word-wrap: unset;
white-space: nowrap;
word-break: break-word;
}
.gray {
color: gray;
}
.pos-customer_facing_display .order-empty {
text-align: center;
margin: auto;
}
.pos-customer_facing_display .order-empty .fa {
font-size: min(max(8vw, 2.3rem), 4.3rem);
}
.pos-customer_facing_display .order-empty h1 {
font-size: min(max(4vw, 1.3rem), 2.3rem);
}
body .pos-customer_facing_display .pos_orderlines {
width: 100%;
height: 100%;
@@ -83,94 +199,43 @@ body .pos-customer_facing_display .pos_orderlines {
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_list {
overflow-y: scroll;
scroll-snap-type: y mandatory;
padding-right: 1.5vw;
position: relative;
height: 100%;
}
.pos-customer_facing_display .pos_orderlines .pos_orderlines_item td:first-child {
border-left-style: solid;
border-top-left-radius: 0.9vw;
border-bottom-left-radius: 0.9vw;
}
.pos-customer_facing_display .pos_orderlines .pos_orderlines_item td:last-child {
border-left-style: solid;
border-top-right-radius: 0.9vw;
border-bottom-right-radius: 0.9vw;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item {
margin-bottom: 1vw;
padding: 1%;
border-radius: 0.3vw;
height: auto;
-webkit-box-flex: 0 1 auto;
-webkit-flex: 0 1 auto;
-moz-box-flex: 0 1 auto;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
-webkit-flex-direction: row;
-moz-flex-direction: row;
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-webkit-align-items: center;
-moz-box-align: center;
-ms-flex-align: center;
-ms-grid-row-align: center;
align-items: center;
border-radius: 0.9vw;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item:last-of-type {
animation: item_in 1s ease;
body .pos-customer_facing_display .pos_orderlines_list.backend_product_screen .selected_orderline {
scroll-snap-align: center;
animation: item_in 1s ease;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item.pos_orderlines_header {
background-color: transparent;
box-shadow: none;
animation: none;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item.pos_orderlines_header > div, body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item.pos_orderlines_header > div:last-child {
border-left-width: 0;
text-align: center;
font-size: 70%;
font-weight: normal;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item.pos_orderlines_header > div:last-child {
text-align: left;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div {
width: 5%;
text-align: left;
margin-right: 4%;
font-size: 80%;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-moz-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div:first-child {
margin-right: 2%;
-webkit-box-flex: 1 1 1%;
-webkit-flex: 1 1 1%;
-moz-box-flex: 1 1 1%;
-ms-flex: 1 1 1%;
flex: 1 1 1%;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div:nth-child(2) {
width: 40%;
border-left: 1px solid;
padding-left: 2%;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div:nth-child(3) {
text-align: center;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div:last-child {
margin-right: 0;
font-weight: bold;
}
body .pos-customer_facing_display .pos_orderlines .pos_orderlines_item > div div {
background-position: center;
background-size: cover;
padding-top: 75%;
display: block;
body .pos-customer_facing_display .pos-thank-you-message {
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: min(max(4vw, 1.3rem), 2.3rem);
text-align: center;
}
body .pos-customer_facing_display .pos-payment_info {
max-width: 30%;
padding: 2% 2% 1% 2%;
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
@@ -182,35 +247,14 @@ body .pos-customer_facing_display .pos-payment_info {
-ms-flex-pack: space-between;
justify-content: space-between;
}
body .pos-customer_facing_display .pos-payment_info .pos-adv,
body .pos-customer_facing_display .pos-payment_info .pos-company_logo {
background-position: center top;
background-size: contain;
background-repeat: no-repeat;
body .pos-customer_facing_display .pos-company_logo {
background-image: url(/logo);
background-size: contain;
background-repeat: no-repeat;
}
body .pos-customer_facing_display .pos-payment_info .pos-adv[style*="url(http://placehold.it"],
body .pos-customer_facing_display .pos-payment_info .pos-company_logo[style*="url(http://placehold.it"] {
body .pos-customer_facing_display .pos-company_logo[style*="url(http://placehold.it"] {
background-color: #ccc;
}
body .pos-customer_facing_display .pos-payment_info .pos-company_logo {
background-image: url(/logo);
margin-bottom: 10%;
-webkit-box-flex: 0 0 20%;
-webkit-flex: 0 0 20%;
-moz-box-flex: 0 0 20%;
-ms-flex: 0 0 20%;
flex: 0 0 20%;
}
body .pos-customer_facing_display .pos-payment_info .pos-adv {
margin-bottom: 5%;
border-bottom: 10px solid transparent;
box-shadow: 0 1px rgba(246, 246, 246, 0.2);
-webkit-box-flex: 1 1 60%;
-webkit-flex: 1 1 60%;
-moz-box-flex: 1 1 60%;
-ms-flex: 1 1 60%;
flex: 1 1 60%;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total,
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines {
-webkit-flex-direction: row;
@@ -238,43 +282,137 @@ body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .p
-ms-grid-row-align: baseline;
align-items: baseline;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total > div,
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines > div {
-webkit-box-flex: 1 0 48%;
-webkit-flex: 1 0 48%;
-moz-box-flex: 1 0 48%;
-ms-flex: 1 0 48%;
flex: 1 0 48%;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total > div:nth-child(even),
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines > div:nth-child(even) {
font-weight: bold;
font-size: 120%;
margin-right: 0;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total {
font-size: 2vw;
font-size: min(max(3.7vw, 1rem), 2rem);
font-weight: bold;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-amount-container {
width: 100%;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-spaced-line-container {
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
flex-grow: 1;
flex-direction: row;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-amount-container.pos-spaced-line-container .name {
min-width: unset;
max-width: unset;
width: fit-content;
min-height: unset;
max-height: unset;
height: fit-content;
flex: unset;
margin-right: .3rem;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-spaced-line-container .spacer {
flex-grow: 1;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-amount-container.pos-spaced-line-container .amount {
word-break: break-all;
white-space: break-spaces;
word-wrap: break-word;
text-align: left;
min-width: fit-content;
max-width: fit-content;
width: unset;
align-self: flex-end;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total .pos-total_amount {
font-size: min(max(4vw, 1.3rem), 2.3rem);
font-weight: bold;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines {
margin-top: 2%;
font-size: 1.5vw;
font-size: min(max(2vw, .9rem), 1.6rem);
font-weight: normal;
line-height: 1.3;
color: #DEE2E6;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-odoo_logo_container {
background-image: url(/web/static/img/logo_inverse_white_206px.png);
background-position: right top;
background-size: contain;
background-repeat: no-repeat;
height: 1.5vw;
margin-top: 10%;
display: flex;
justify-content: end;
align-items: flex-end;
body .pos-customer_facing_display .pos-payment_info .pos-odoo_logo_container {
background: #212529;
opacity: .9;
border-top: gray solid 1px;
height: max(min(3.1vh, 2.1rem), 1.1rem);
width: 100%;
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-odoo_logo_container span {
margin-right: 5vw;
font-size: 1vw;
body .pos-customer_facing_display .pos-payment_info .pos-odoo_logo_container .logo {
height: max(min(min(2vh, 2vw), 2rem), .8rem);
width: max(min(min(6vh, 6vw), 6rem), 2.6rem);
margin-left: .3rem;
background-image: url(/web/static/img/logo_inverse_white_206px.png);
background-position: right top;
background-size: contain;
background-repeat: no-repeat;
}
body .pos-customer_facing_display .pos-payment_info .pos-odoo_logo_container span {
font-size: max(min(2vw, 1rem), .8rem);
color: rgba(255, 255, 255, 0.4);
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines::after {
height: 2vw; /* this empty element gives space between the paymentlines and the Odoo logo footer only if there is enough space (depending on the amount of paymentlines) */
content: '';
display: block;
width: 100%;
}
/* properties for default orientation (landscape): */
body .pos-customer_facing_display .pos-portrait-top {
display: none;
}
body .pos-customer_facing_display .pos-no-order {
display: block;
width: 100%;
height: 100%;
background-size: cover;
background-color: #343A40;
}
body .pos-customer_facing_display .pos-no-order .pos-company_logo {
display: block;
background-position: center top;
margin-top: 5vh;
height: max(10vh, 3rem);
width: auto;
}
body .pos-customer_facing_display .pos-payment_info .pos-company_logo {
display: initial;
background-position: center top;
margin: 10%;
-webkit-box-flex: 1 0 20%;
-webkit-flex: 1 0 20%;
-moz-box-flex: 1 0 20%;
-ms-flex: 1 0 20%;
flex: 1 0 20%;
}
body .pos-customer_facing_display .pos-payment_info {
background-size: cover; /* background image displayed */
}
body .pos-customer_facing_display .pos-customer_products,
body .pos-customer_facing_display .pos-payment_info {
height: 100%;
}
/* end of properties for default orientation (landscape) */
@media all and (orientation: portrait) {
body .pos-customer_facing_display {
font-size: 2vh;
@@ -285,38 +423,40 @@ body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .p
-o-flex-direction: column;
flex-direction: column;
}
body .pos-customer_facing_display:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 17vh;
}
body .pos-customer_facing_display .pos-payment_info .pos-adv {
position: fixed;
top: 0;
left: 0;
height: 15vh;
width: 99vw;
margin: 0.5vh;
border-width: 0;
body .pos-customer_facing_display .pos-portrait-top {
-webkit-display: flex;
-moz-display: flex;
-ms-display: flex;
-o-display: flex;
display: flex;
height: 15vh;
padding: 1% 1% 0 1%;
}
body .pos-customer_facing_display.pos-js_no_ADV:before {
display: none;
body .pos-customer_facing_display .pos-portrait-top .pos-header {
background-image: var(--pos-bg-img);
background-size: cover;
border-radius: 0.2rem 0.2rem 0 0;
height: 100%;
width: 100%;
padding: 1% 30%;
background-color: #343A40;
}
body .pos-customer_facing_display.pos-js_no_ADV .pos-customer_products {
padding-top: 0;
body .pos-customer_facing_display .pos-portrait-top .pos-company_logo {
height: 100%;
background-position: center;
}
body .pos-customer_facing_display .pos-customer_products {
padding-top: 17vh;
height: 72vw;
overflow: hidden;
flex-grow: 1;
overflow: auto;
padding-top: 0;
height: unset;
}
body .pos-customer_facing_display .pos_orderlines_list table th {
font-size: min(5vw, 1rem);
}
body .pos-customer_facing_display .pos-order_top_bar {
border-radius: 0 0 0.2rem 0.2rem;
border-top: solid gray 1px;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines {
-webkit-box-flex: 1 0 auto;
@@ -325,12 +465,6 @@ body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .p
-ms-flex: 1 0 auto;
flex: 1 0 auto;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_item > div:nth-child(2) {
width: 30%;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_item.pos_orderlines_header div {
font-size: 90%;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_list {
padding-right: 1.5vh;
height: auto;
@@ -339,107 +473,32 @@ body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .p
box-shadow: 0 0.1vh 0.1vh #dddddd;
margin-bottom: 1vh;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_list .pos_orderlines_item > div {
font-size: 100%;
}
body .pos-customer_facing_display .pos-payment_info {
background-size: 0 0; /* background image hidden */
max-width: 100%;
overflow: hidden;
padding-top: 0;
min-height: 120px;
-webkit-box-flex: 0 1 23vw;
-webkit-flex: 0 1 23vw;
-moz-box-flex: 0 1 23vw;
-ms-flex: 0 1 23vw;
flex: 0 1 23vw;
-webkit-flex-direction: row;
-moz-flex-direction: row;
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-webkit-align-items: center;
-moz-box-align: center;
-ms-flex-align: center;
-ms-grid-row-align: center;
align-items: center;
-webkit-box-pack: space-between;
-webkit-justify-content: space-between;
-moz-box-pack: space-between;
-ms-flex-pack: space-between;
justify-content: space-between;
width: 100%;
max-height: 40vh;
height: unset;
flex-grow: 0;
}
body .pos-customer_facing_display .pos-payment_info .pos-company_logo {
margin: 0;
background-position: left center;
margin-right: 5%;
height: 100%;
padding: 0;
-webkit-box-flex: 1 1 20%;
-webkit-flex: 1 1 20%;
-moz-box-flex: 1 1 20%;
-ms-flex: 1 1 20%;
flex: 1 1 20%;
display: none;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details {
-webkit-box-flex: 0 1 50%;
-webkit-flex: 0 1 50%;
-moz-box-flex: 0 1 50%;
-ms-flex: 0 1 50%;
flex: 0 1 50%;
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
-o-flex-direction: column;
flex-direction: column;
min-width: 170px;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total {
font-size: 3vw;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total .pos_total-amount {
font-size: 3.5vw;
flex-grow: 1;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-paymentlines {
margin-top: 2%;
font-size: 80%;
line-height: 1.2;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-odoo_logo_container {
position: absolute;
right: 3%;
bottom: 1%;
font-size: max(2.5vw, .7rem);
}
}
@media all and (orientation: portrait) and (max-width: 340px) {
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_list {
padding-right: 0;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_list .pos_orderlines_item > div {
font-size: 70%;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_header > div {
font-size: 60%;
}
body .pos-customer_facing_display .pos-customer_products .pos_orderlines .pos_orderlines_header > div:last-child {
text-align: center;
}
body .pos-customer_facing_display .pos-payment_info .pos-company_logo {
display: none !important;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details {
-webkit-box-flex: 1 0 100%;
-webkit-flex: 1 0 100%;
-moz-box-flex: 1 0 100%;
-ms-flex: 1 0 100%;
flex: 1 0 100%;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total {
font-size: 6vw;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details .pos-total .pos_total-amount {
font-size: 6.5vw;
}
body .pos-customer_facing_display .pos-payment_info .pos-payment_info_details {
background: #212529;
opacity: .9;
padding: 1% 6%;
flex-grow: 0;
overflow: hidden;
}
body .pos-hidden {
@@ -447,21 +506,21 @@ body .pos-hidden {
}
.pos-palette_01 .pos-payment_info {
background: #3E3E3E;
background: #343A40;
color: #f6f6f6;
}
.pos-palette_01 .pos-customer_products {
background: #f6f6f6;
color: #585858;
}
.pos-palette_01.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #f6f6f6;
}
.pos-palette_01 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #aaaaaa;
}
.pos-palette_01 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_01:before {
background: #3E3E3E;
@@ -476,14 +535,14 @@ body .pos-hidden {
background: #ecf2f6;
color: #364152;
}
.pos-palette_02.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ecf2f6;
}
.pos-palette_02 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #364152;
}
.pos-palette_02 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_02:before {
background: #364152;
@@ -498,14 +557,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_03.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_03 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_03 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_03:before {
background: #1BA39C;
@@ -520,14 +579,14 @@ body .pos-hidden {
background: #efeeec;
color: #585858;
}
.pos-palette_04.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #efeeec;
}
.pos-palette_04 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a9a499;
}
.pos-palette_04 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_04:before {
background: #0b7b6c;
@@ -542,14 +601,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_05.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_05 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_05 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_05:before {
background: #E26868;
@@ -564,14 +623,14 @@ body .pos-hidden {
background: #f6f6f6;
color: #585858;
}
.pos-palette_06.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #f6f6f6;
}
.pos-palette_06 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #aaaaaa;
}
.pos-palette_06 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_06:before {
background: #9E373B;
@@ -586,14 +645,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_07.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_07 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_07 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_07:before {
background: #ce9934;
@@ -608,14 +667,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_08.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_08 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_08 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_08:before {
background: #a48c77;
@@ -630,14 +689,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_09.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_09 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_09 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_09:before {
background: linear-gradient(30deg, #014d43, #127e71);
@@ -652,14 +711,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_10.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_10 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_10 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_10:before {
background: linear-gradient(30deg, #e2316c, #ea4c89);
@@ -674,14 +733,14 @@ body .pos-hidden {
background: #ececec;
color: #585858;
}
.pos-palette_11.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #ececec;
}
.pos-palette_11 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: white;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #a0a0a0;
}
.pos-palette_11 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_11:before {
background: linear-gradient(30deg, #362b3d, #5b4a63);
@@ -696,14 +755,14 @@ body .pos-hidden {
background: #5b5b5b;
color: #bdb9b9;
}
.pos-palette_12.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #5b5b5b;
}
.pos-palette_12 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: #f5f5f5;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #0f0f0f;
}
.pos-palette_12 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_12:before {
background: #434343;
@@ -718,14 +777,14 @@ body .pos-hidden {
background: #a2a2ab;
color: #f6f6f6;
}
.pos-palette_13.pos-customer_facing_display .pos_orderlines_list table th {
background-color: #a2a2ab;
}
.pos-palette_13 .pos-customer_products .pos_orderlines_list .pos_orderlines_item {
background-color: #f6f6f6;
color: #3E3E3E;
box-shadow: 0 0.1vh 0.1vh #55555f;
}
.pos-palette_13 .pos-customer_products .pos_orderlines_list .pos_orderlines_item div:nth-child(2) {
border-color: rgba(62, 62, 62, 0.3);
}
@media all and (orientation: portrait) {
.pos-palette_13:before {
background: linear-gradient(30deg, #1a1b1f, #3d3f45);
@@ -79,6 +79,10 @@
<div class="row">
<label string="Customer Display" for="iface_customer_facing_display_via_proxy" class="col-lg-4 o_light_label"/>
<field name="iface_customer_facing_display_via_proxy"/>
<div attrs="{'invisible' : [('iface_customer_facing_display_via_proxy', '=', False)]}">
<label for="iface_customer_facing_display_background_image_1920" />
<field name="iface_customer_facing_display_background_image_1920" widget="image" readonly="0" style="width: max(min(min(30vw, 30vh), 100%), 10rem); display: block; margin-top: .3rem;" />
</div>
</div>
</div>
</setting>
@@ -303,6 +303,10 @@
</setting>
<setting id="customer_display" string="Customer Display" help="Show checkout to customers through a second display">
<field name="pos_iface_customer_facing_display_local"/>
<div attrs="{'invisible' : [('pos_iface_customer_facing_display_local', '=', False)]}">
<label for="pos_iface_customer_facing_display_background_image_1920" />
<field name="pos_iface_customer_facing_display_background_image_1920" widget="image" style="width: max(min(min(30vw, 30vh), 100%), 10rem); display: block; margin-top: .3rem;"/>
</div>
</setting>
<setting string="IoT Box" help="Connect devices using an IoT Box">
<field name="pos_is_posbox"/>
@@ -330,6 +334,10 @@
<div class="row">
<label string="Customer Display" for="pos_iface_customer_facing_display_via_proxy" class="col-lg-4 o_light_label"/>
<field name="pos_iface_customer_facing_display_via_proxy"/>
<div attrs="{'invisible' : [('pos_iface_customer_facing_display_via_proxy', '=', False)]}">
<label for="pos_iface_customer_facing_display_background_image_1920" />
<field name="pos_iface_customer_facing_display_background_image_1920" widget="image" style="width: max(min(min(30vw, 30vh), 100%), 10rem); display: block; margin-top: .3rem;" />
</div>
</div>
</div>
</setting>