[IMP] pos_self_order: improve qr code PDF

In order to improve the self order user experience, QR code generation
has been improved. Now, the user can reset the access_token linked to
the QR code and then regenerate them, he can also redownload the QR code
whenever he wishes.

The content of the QR code PDF has also been changed. Now, for each
table a QR code is generated and inserted in the PDF with the name of
the table and its unique identifier (access_token).

closes odoo/odoo#129100

Taskid: 3377335
Related: odoo/upgrade#4958
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
David Monnom (moda)
2023-08-21 14:14:47 +02:00
parent 734d58e22c
commit 808a73742c
7 changed files with 102 additions and 156 deletions
+26 -57
View File
@@ -188,65 +188,34 @@ class PosConfig(models.Model):
"has_active_session": self.has_active_session,
}
def _generate_data_for_qr_codes_page(self, cols: int = 4) -> Dict[str, List[Dict]]:
"""
:cols: the number of qr codes per row
"""
def _get_qr_code_data(self):
self.ensure_one()
return {
"floors": self._split_qr_codes_list(
self._get_qr_codes_info(cols * cols),
cols,
)
}
def _get_qr_codes_info(self, total_number: int) -> List[Dict]:
"""
total_number: the number of qr codes to generate (in the case where we don't have
floor management)
return: a list of dictionaries with the following keys:
- name: the name of the floor
- tables: a list of dictionaries with the following keys:
- id: the id of the table
- url: the url of the table
- name?: the name of the table
"""
self.ensure_one()
table_qr_code = []
if self.self_order_table_mode:
return self.floor_ids._get_data_for_qr_codes_page(self._get_self_order_url)
else:
return self._get_default_qr_codes(total_number, self._get_self_order_url)
table_qr_code.extend([{
'name': floor.name,
'type': 'table',
'tables': [
{
'identifier': table.identifier,
'id': table.id,
'name': table.name,
'url': self._get_self_order_url(table.id),
}
for table in floor.table_ids.filtered("active")
]
}
for floor in self.floor_ids]
)
def _split_qr_codes_list(self, floors: List[Dict], cols: int) -> List[Dict]:
"""
:floors: the list of floors
:cols: the number of qr codes per row
"""
self.ensure_one()
return [
{
"name": floor.get("name"),
"rows_of_tables": list(split_every(cols, floor["tables"], list)),
}
for floor in floors
]
table_qr_code.extend([{
'name': 'Generic',
'type': 'default',
'tables': [{
'id': i,
'url': self._get_self_order_url(),
} for i in range(0, 11)]
}])
def _get_default_qr_codes(
self, number: int, url: Callable[[Optional[int]], str]
) -> List[Dict]:
"""
:number: the number of qr codes to generate
:url: a function that takes a table id and returns the url of the table
"""
self.ensure_one()
return [
{
"tables": [
{
"id": 0,
"url": url(),
}
]
* number,
}
]
return table_qr_code
@@ -7,19 +7,6 @@ from typing import Dict, Callable, List, Optional
from odoo import api, fields, models
class RestaurantFloor(models.Model):
_inherit = "restaurant.floor"
def _get_data_for_qr_codes_page(self, url: Callable):
return [
{
"name": floor.name,
"tables": floor.table_ids.filtered("active")._get_data_for_qr_codes_page(url),
}
for floor in self
]
class RestaurantTable(models.Model):
_inherit = "restaurant.table"
@@ -35,17 +22,6 @@ class RestaurantTable(models.Model):
self.ensure_one()
return self.read(["name", "identifier"])[0]
def _get_data_for_qr_codes_page(self, url: Callable[[Optional[int]], str]) -> List[Dict]:
return [
{
'identifier': table.identifier,
'id': table.id,
'name': table.name,
'url': url(table.id),
}
for table in self
]
@staticmethod
def _get_identifier():
return uuid.uuid4().hex[:8]
@@ -2,6 +2,7 @@
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.tools.misc import split_every
class ResConfigSettings(models.TransientModel):
@@ -71,13 +72,21 @@ class ResConfigSettings(models.TransientModel):
"""
Generate the data needed to print the QR codes page
"""
if len(self.pos_config_id.floor_ids.table_ids) == 0:
raise UserError(_("Before you can create QR codes, you need to create tables for the restaurant."))
return self.env.ref("pos_self_order.report_self_order_qr_codes_page").report_action(
[], data=self.pos_config_id._generate_data_for_qr_codes_page(cols=3)
[], data={'floors': [
{
"name": floor.get("name"),
"type": floor.get("type"),
"table_rows": list(split_every(3, floor["tables"], list)),
}
for floor in self.pos_config_id._get_qr_code_data()
]}
)
def preview_self_order_app(self):
self.ensure_one()
return self.pos_config_id.preview_self_order_app()
def update_access_tokens(self):
self.ensure_one()
self.pos_config_id._update_access_token()
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -282,7 +282,9 @@ export class SelfOrder {
const order = this.orders.filter((o) => o.access_token === access_token);
let message = _t("Your order status has been changed");
if (order.length !== 1) {
if (order.length === 0) {
throw new Error("Warning, no order with this access_token");
} else if (order.length !== 1) {
throw new Error("Warning, two orders with the same access_token");
} else {
order[0].state = state;
+57 -68
View File
@@ -19,77 +19,66 @@
</data>
<template id="qr_codes_page">
<t t-call="web.basic_layout">
<div class="page">
<h1 class="text-center">
QR Code Menu
</h1>
<!-- There is a very annoying problem here:
wkhtmltopdf does not handle flex-wrap. ( at least not in this version )
This makes it so the bootstrap grid system does not work.
We have to do a workaround -->
<t t-foreach="floors" t-as="floor">
<!-- MDN states that "page-break-after" has been replaced by "break-after",
but "break-after" is not supported in this version of wkhtmltopdf so we
have to keep using "page-break-after" -->
<div style="page-break-after: always;">
<h3 t-if="floor.get('name')" t-out="floor['name']" class="mb-5"/>
<div
t-foreach="floor['rows_of_tables']"
t-as="row_of_tables"
class="d-flex"
>
<t t-foreach="row_of_tables"
t-as="table"
t-call="pos_self_order.qr_code"
/>
</div>
</div>
</t>
</div>
</t>
</template>
<template id="qr_code">
<t t-set="qr_code_size" t-value="180"/>
<div style="padding: 0px 40px; margin-bottom:40px; page-break-inside: avoid;">
<!-- This page-break-inside does not seem to work;
<!-- This page-break-inside does not seem to work;
It would be nice to have the qr codes so the title is never on
a different page then the qr code itself -->
<h4 class="fw-bold text-center"
style="margin-top: 20px"
t-if="table['id']"
>
Table: <t t-esc="table['name']"/>
</h4>
<div class="p-3">
<div class="mt-1 mb-4 position-relative top-0 start-0">
<img t-att-src="'/report/barcode/QR/%s?width=%s&amp;height=%s&amp;barLevel=H' %(table['url'], qr_code_size, qr_code_size)"
class="position-relative top-0 start-0"
/>
<t t-call="pos_self_order.first_letter_of_odoo_logo_svg"/>
</div>
<t t-set="qr_code_size" t-value="190"/>
<t t-call="web.basic_layout">
<div style="display: flex; align-items: center; padding: 0 20px; margin-bottom: 35px; padding-left: 0; margin-left: 0;">
<img src="/pos_self_order/static/img/default_qrcode_odoo.png" style="width: 100px; height: 100px; margin-right: 25px;"/>
<h2 stlye="color: #714C67;">Place the QR codes on your tables,<br/>
so your customer scan it to order</h2>
</div>
</div>
</template>
<template id="first_letter_of_odoo_logo_svg">
<svg
class="position-absolute top-50 start-50"
style="-webkit-transform: translate(-50%, -50%);"
t-att-width="qr_code_size/4"
t-att-height="qr_code_size/4"
viewBox="0 0 120 120" fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect width="120" height="120" rx="33" fill="white"/>
<g>
<path d="M60 110C87.6142 110 110 87.6142 110 60C110 32.3858 87.6142 10 60 10C32.3858 10 10 32.3858 10 60C10 87.6142 32.3858 110 60 110Z" fill="#9C5789"/>
<path d="M59.5166 89.6961C75.8029 89.6961 89.0055 76.4935 89.0055 60.2072C89.0055 43.9209 75.8029 30.7182 59.5166 30.7182C43.2303 30.7182 30.0276 43.9209 30.0276 60.2072C30.0276 76.4935 43.2303 89.6961 59.5166 89.6961Z" fill="white"/>
</g>
</g>
</svg>
<div>
<h3 style="color: #0C7285">How to use</h3>
<p>The below QR codes are predefined with a table number. One per table configured in your floor plan.</p>
<p>Want to customise table stand ? Either use any of the below QR codes as-is in your composition
or generate new ones with the online tool of your choice. Retrieve a URL by scanning the related QR code.</p>
</div>
<!-- Table with access token -->
<t t-if="floors" t-foreach="floors" t-as="floor">
<div t-att-style="'page-break-before: always;' if floor.get('type') == 'default' else ''">
<div t-if="floor.get('type') == 'default'" class="margin-bottom: 50px; page-break-before: always;">
<h3 style="color: #0C7285">Generic QR codes</h3>
<p>When one QR code is enough everywhere. If used in self-ordering, customer will be asked to enter the
table number before he can place an order.</p>
<p>Want to customise table stand ? Either use any of the below QR codes as-is in your composition
or generate new ones with the online tool of your choice. Retrieve a URL by scanning the related QR code.</p>
</div>
<h4 t-if="floor.get('name')" t-out="floor['name']" class="mb-3 mt-5"/>
<table style="border: none; border-collapse: collapse; width: 100%;">
<tbody style="border: none;">
<tr t-foreach="floor.get('table_rows')" t-as="row" style="border: none;">
<td t-foreach="row" t-as="table" style="width: 33%; text-align:center; border: none;">
<div class="mb-3" style="page-break-inside: avoid">
<h4 class="fw-bold text-center" t-if="table.get('name')">
Table: <t t-esc="table['name']"/>
</h4>
<div class="mt-1 mb-1 position-relative top-0 start-0">
<img t-att-src="'/report/barcode/QR/%s?width=%s&amp;height=%s&amp;barLevel=H' %(table['url'], qr_code_size, qr_code_size)" class="position-relative top-0 start-0" />
<svg class="position-absolute top-50 start-50" style="-webkit-transform: translate(-50%, -50%);" t-att-width="qr_code_size/4" t-att-height="qr_code_size/4" viewBox="0 0 120 120" fill="none"
xmlns="http://www.w3.org/2000/svg">
<g>
<rect width="120" height="120" rx="33" fill="white"/>
<g>
<path d="M60 110C87.6142 110 110 87.6142 110 60C110 32.3858 87.6142 10 60 10C32.3858 10 10 32.3858 10 60C10 87.6142 32.3858 110 60 110Z" fill="#9C5789"/>
<path d="M59.5166 89.6961C75.8029 89.6961 89.0055 76.4935 89.0055 60.2072C89.0055 43.9209 75.8029 30.7182 59.5166 30.7182C43.2303 30.7182 30.0276 43.9209 30.0276 60.2072C30.0276 76.4935 43.2303 89.6961 59.5166 89.6961Z" fill="white"/>
</g>
</g>
</svg>
</div>
<h6 class="fw-bold text-center mb-3" t-if="table.get('identifier')">
(<t t-esc="table['identifier']"/>)
</h6>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</odoo>
@@ -8,11 +8,12 @@
<setting id="iface_orderline_notes" position="after">
<setting string="QR Code Menu" help="Allow customers to see the menu from their phone">
<field name="pos_self_order_view_mode"/>
<div class="content-group d-flex" invisible="not pos_self_order_view_mode">
<div class="content-group d-flex gap-5" invisible="not pos_self_order_view_mode">
<div class="d-flex flex-column align-items-start w-50">
<button class="btn-link p-0" icon="oi-arrow-right" name="pos_self_order.custom_link_action" type="action" string="Configure Buttons"/>
<button class="btn-link p-0" icon="oi-arrow-right" name="generate_qr_codes_page" type="object" string="Generate QR Codes"/>
<button class="btn-link p-0" icon="oi-arrow-right" name="preview_self_order_app" type="object" string="Preview"/>
<button class="btn-link p-0" icon="oi-arrow-right" name="generate_qr_codes_page" type="object" string="Print QR Codes"/>
<button groups="base.group_no_one" class="btn-link p-0" icon="oi-arrow-right" name="update_access_tokens" type="object" string="Reset QR Codes"/>
</div>
<div class="d-flex flex-column align-items-start w-50">
<div class="d-flex flex-column align-items-start">