[FIX] pos_{online_payment_}self_order: price based on company taxes
**Steps to reproduce:** - Install pos_self_order. - Create a product with a price of any price, say 100. - Assign a tax of 10% to the product. - Create a new company and switch to it. - With the same product, add a new tax, say 20%. - Go back to the original company. - Open a bar (restaurant pos.config) that allows self order which also loads the product. - Open self order page and add the product. - [BUG] The product's price is not only 10%-taxed, but also 20%-taxed. **Explanation and fix** The issue is caused by use of sudo almost everywhere in the context of pos_self_order. This commit removes/reduces this use of sudo in many places and contextualize the records involved in the calculation such as pos.config, product.product, etc. to be the ones of the company and the user who opened the current pos.session. After this changes, only the taxes that belong to the company of the pos.config record are used in the price and tax calculations. closes odoo/odoo#131140 X-original-commit: 7ce7f3e21ad8f457742e27f88b7146c7d8fff5f3 Signed-off-by: David Monnom (moda) <moda@odoo.com> Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
@@ -28,7 +28,7 @@ class TestSelfOrderFrontendMobile(SelfOrderCommonTest):
|
||||
'self_order_pay_after': 'each',
|
||||
'self_order_online_payment_method_id': self.self_order_online_payment_method_id,
|
||||
})
|
||||
self.pos_config.open_ui()
|
||||
self.pos_config.with_user(self.pos_user).open_ui()
|
||||
|
||||
self.start_tour(
|
||||
self.pos_config._get_self_order_route(),
|
||||
|
||||
@@ -8,7 +8,7 @@ from odoo.http import request
|
||||
|
||||
from odoo.addons.pos_self_order.controllers.utils import (
|
||||
get_any_pos_config_sudo,
|
||||
get_table_sudo,
|
||||
reduce_privilege,
|
||||
)
|
||||
|
||||
|
||||
@@ -31,10 +31,8 @@ class PosQRMenuController(http.Controller):
|
||||
auth="public", website=True, sitemap=True,
|
||||
)
|
||||
def pos_self_order_start(self, config_id=None, access_token=None, table_identifier=None):
|
||||
self_order_mode = 'qr_code'
|
||||
table_infos = False
|
||||
pos_config_sudo = False
|
||||
pos_config_access_token = False
|
||||
table_sudo = False
|
||||
|
||||
if config_id and config_id.isnumeric() and access_token:
|
||||
pos_config_sudo = request.env["pos.config"].sudo().search([
|
||||
@@ -42,17 +40,23 @@ class PosQRMenuController(http.Controller):
|
||||
('access_token', '=', access_token)], limit=1)
|
||||
|
||||
if pos_config_sudo and pos_config_sudo.has_active_session and pos_config_sudo.self_order_table_mode:
|
||||
self_order_mode = pos_config_sudo.self_order_pay_after
|
||||
pos_config_access_token = pos_config_sudo.access_token
|
||||
table_sudo = get_table_sudo(identifier=table_identifier)
|
||||
table_infos = table_sudo._get_self_order_data() if table_sudo else False
|
||||
table_sudo = table_identifier and (
|
||||
request.env["restaurant.table"]
|
||||
.sudo()
|
||||
.search([("identifier", "=", table_identifier), ("active", "=", True)], limit=1)
|
||||
)
|
||||
elif config_id and config_id.isnumeric():
|
||||
pos_config_sudo = request.env["pos.config"].sudo().search([
|
||||
("id", "=", config_id), ("self_order_view_mode", "=", True)], limit=1)
|
||||
else:
|
||||
pos_config_sudo = get_any_pos_config_sudo()
|
||||
|
||||
if not pos_config_sudo:
|
||||
company = pos_config_sudo.company_id
|
||||
user = pos_config_sudo.current_session_id.user_id
|
||||
pos_config = reduce_privilege(pos_config_sudo, company, user)
|
||||
table = reduce_privilege(table_sudo, company, user)
|
||||
|
||||
if not pos_config:
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
return request.render(
|
||||
@@ -62,10 +66,10 @@ class PosQRMenuController(http.Controller):
|
||||
**request.env["ir.http"].get_frontend_session_info(),
|
||||
'currencies': request.env["ir.http"].get_currencies(),
|
||||
'pos_self_order_data': {
|
||||
'self_order_mode': self_order_mode,
|
||||
'table': table_infos,
|
||||
'access_token': pos_config_access_token,
|
||||
**pos_config_sudo._get_self_order_data(),
|
||||
'self_order_mode': pos_config.self_order_pay_after,
|
||||
'table': table._get_self_order_data() if table else False,
|
||||
'access_token': pos_config.access_token,
|
||||
**pos_config._get_self_order_data(),
|
||||
},
|
||||
"base_url": request.env['pos.session'].get_base_url(),
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@ from datetime import timedelta
|
||||
import uuid
|
||||
from odoo import http, fields, Command
|
||||
from odoo.http import request
|
||||
from odoo.addons.pos_self_order.controllers.utils import reduce_privilege
|
||||
from werkzeug.exceptions import NotFound, BadRequest, Unauthorized
|
||||
|
||||
class PosSelfOrderController(http.Controller):
|
||||
@http.route("/pos-self-order/process-new-order", auth="public", type="json", website=True)
|
||||
def process_new_order(self, order, access_token, table_identifier):
|
||||
lines = order.get('lines')
|
||||
|
||||
pos_config_sudo, table_sudo = self._verify_authorization(access_token, table_identifier)
|
||||
pos_session_sudo = pos_config_sudo.current_session_id
|
||||
sequence_number = self._get_sequence_number(table_sudo.id, pos_session_sudo.id)
|
||||
unique_id = self._generate_unique_id(pos_session_sudo.id, table_sudo.id, sequence_number)
|
||||
pos_config, table = self._verify_authorization(access_token, table_identifier)
|
||||
pos_session = pos_config.current_session_id
|
||||
sequence_number = self._get_sequence_number(table.id, pos_session.id)
|
||||
unique_id = self._generate_unique_id(pos_session.id, table.id, sequence_number)
|
||||
|
||||
# Create the order without lines and prices computed
|
||||
# We need to remap the order because some required fields are not used in the frontend.
|
||||
@@ -26,11 +26,11 @@ class PosSelfOrderController(http.Controller):
|
||||
'user_id': request.session.uid,
|
||||
'sequence_number': sequence_number,
|
||||
'access_token': uuid.uuid4().hex,
|
||||
'pos_session_id': pos_session_sudo.id,
|
||||
'table_id': table_sudo.id if table_sudo else False,
|
||||
'pos_session_id': pos_session.id,
|
||||
'table_id': table.id if table else False,
|
||||
'partner_id': False,
|
||||
'creation_date': str(fields.Datetime.now()),
|
||||
'fiscal_position_id': pos_config_sudo.default_fiscal_position_id,
|
||||
'fiscal_position_id': pos_config.default_fiscal_position_id.id,
|
||||
'statement_ids': [],
|
||||
'lines': [],
|
||||
'amount_tax': 0,
|
||||
@@ -39,36 +39,32 @@ class PosSelfOrderController(http.Controller):
|
||||
'amount_return': 0,
|
||||
},
|
||||
'to_invoice': False,
|
||||
'session_id': pos_session_sudo.id,
|
||||
'session_id': pos_session.id,
|
||||
}
|
||||
|
||||
# Save the order in the database to get the id
|
||||
posted_order_id = request.env['pos.order'].sudo().create_from_ui([order], draft=True)[0].get('id')
|
||||
posted_order_id = pos_config.env['pos.order'].create_from_ui([order], draft=True)[0].get('id')
|
||||
|
||||
# Process the lines and get their prices computed
|
||||
lines = self._process_lines(lines, pos_config_sudo, posted_order_id)
|
||||
lines = self._process_lines(lines, pos_config, posted_order_id)
|
||||
|
||||
# Compute the order prices
|
||||
amount_total, amount_untaxed = self._get_order_prices(lines)
|
||||
|
||||
# Update the order with the computed prices and lines
|
||||
order_sudo = request.env["pos.order"].sudo().browse(posted_order_id)
|
||||
order_sudo.write({
|
||||
order = pos_config.env["pos.order"].browse(posted_order_id)
|
||||
order.write({
|
||||
'lines': [Command.create(line) for line in lines],
|
||||
'amount_tax': amount_total - amount_untaxed,
|
||||
'amount_total': amount_total,
|
||||
})
|
||||
|
||||
return order_sudo._export_for_self_order()
|
||||
return order._export_for_self_order()
|
||||
|
||||
@http.route('/pos-self-order/get-orders-taxes', auth='public', type='json', website=True)
|
||||
def get_order_taxes(self, order, access_token):
|
||||
pos_config_sudo = request.env['pos.config'].sudo().search([('access_token', '=', access_token)], limit=1)
|
||||
|
||||
if not pos_config_sudo or not pos_config_sudo.self_order_table_mode or not pos_config_sudo.has_active_session:
|
||||
raise Unauthorized("Invalid access token")
|
||||
|
||||
lines = self._process_lines(order.get('lines'), pos_config_sudo, 0)
|
||||
pos_config = self._verify_pos_config(access_token)
|
||||
lines = self._process_lines(order.get('lines'), pos_config, 0)
|
||||
amount_total, amount_untaxed = self._get_order_prices(lines)
|
||||
|
||||
return {
|
||||
@@ -85,88 +81,87 @@ class PosSelfOrderController(http.Controller):
|
||||
def update_existing_order(self, order, access_token, table_identifier):
|
||||
order_id = order.get('id')
|
||||
order_access_token = order.get('access_token')
|
||||
pos_config_sudo, table_sudo = self._verify_authorization(access_token, table_identifier)
|
||||
pos_config, table = self._verify_authorization(access_token, table_identifier)
|
||||
session = pos_config.current_session_id
|
||||
|
||||
order_sudo = request.env['pos.order'].sudo().search([
|
||||
pos_order = session.order_ids.filtered_domain([
|
||||
('id', '=', order_id),
|
||||
('access_token', '=', order_access_token),
|
||||
('table_id', '=', table_sudo.id)
|
||||
('table_id', '=', table.id)
|
||||
])
|
||||
|
||||
if not order_sudo:
|
||||
if not pos_order:
|
||||
raise Unauthorized("Order not found in the server !")
|
||||
elif order_sudo.state != 'draft':
|
||||
elif pos_order.state != 'draft':
|
||||
raise Unauthorized("Order is not in draft state")
|
||||
|
||||
lines = self._process_lines(order.get('lines'), pos_config_sudo, order_sudo.id)
|
||||
lines = self._process_lines(order.get('lines'), pos_config, pos_order.id)
|
||||
for line in lines:
|
||||
if line.get('id'):
|
||||
line_sudo = order_sudo.lines.filtered(lambda l: l.id == line.get('id'))
|
||||
order_line = pos_order.lines.browse(line.get('id'))
|
||||
|
||||
if line.get('qty') < line_sudo.qty:
|
||||
line.set('qty', line_sudo.qty)
|
||||
if line.get('qty') < order_line.qty:
|
||||
line.set('qty', order_line.qty)
|
||||
|
||||
line_sudo.write({
|
||||
order_line.write({
|
||||
**line,
|
||||
})
|
||||
else:
|
||||
order_sudo.lines.create(line)
|
||||
pos_order.lines.create(line)
|
||||
|
||||
amount_total, amount_untaxed = self._get_order_prices(lines)
|
||||
order_sudo.write({
|
||||
pos_order.write({
|
||||
'amount_tax': amount_total - amount_untaxed,
|
||||
'amount_total': amount_total,
|
||||
})
|
||||
|
||||
return order_sudo._export_for_self_order()
|
||||
return pos_order._export_for_self_order()
|
||||
|
||||
@http.route('/pos-self-order/get-orders', auth='public', type='json', website=True)
|
||||
def get_orders_by_access_token(self, order_access_tokens):
|
||||
orders_sudo = request.env["pos.order"].sudo().search([
|
||||
def get_orders_by_access_token(self, access_token, order_access_tokens):
|
||||
pos_config = self._verify_pos_config(access_token)
|
||||
session = pos_config.current_session_id
|
||||
orders = session.order_ids.filtered_domain([
|
||||
("access_token", "in", order_access_tokens),
|
||||
("date_order", ">=", fields.Datetime.now() - timedelta(days=7)),
|
||||
])
|
||||
|
||||
if not orders_sudo:
|
||||
if not orders:
|
||||
raise NotFound("Orders not found")
|
||||
|
||||
orders = []
|
||||
for order in orders_sudo:
|
||||
for order in orders:
|
||||
orders.append(order._export_for_self_order())
|
||||
|
||||
return orders
|
||||
|
||||
@http.route('/pos-self-order/get-tables', auth='public', type='json', website=True)
|
||||
def get_tables(self, access_token):
|
||||
pos_config_sudo = request.env['pos.config'].sudo().search([('access_token', '=', access_token)], limit=1)
|
||||
|
||||
if not pos_config_sudo or not pos_config_sudo.self_order_table_mode or not pos_config_sudo.has_active_session:
|
||||
raise Unauthorized("Invalid access token")
|
||||
|
||||
tables = pos_config_sudo.floor_ids.table_ids.filtered(lambda t: t.active).read(['id', 'name', 'identifier', 'floor_id'])
|
||||
pos_config = self._verify_pos_config(access_token)
|
||||
tables = pos_config.floor_ids.table_ids.filtered(lambda t: t.active).read(['id', 'name', 'identifier', 'floor_id'])
|
||||
|
||||
for table in tables:
|
||||
table['floor_name'] = table.get('floor_id')[1]
|
||||
|
||||
return tables
|
||||
|
||||
def _process_lines(self, lines, pos_config_sudo, pos_order_id):
|
||||
def _process_lines(self, lines, pos_config, pos_order_id):
|
||||
newLines = []
|
||||
pricelist = request.env['product.pricelist'].sudo().browse(pos_config_sudo.pricelist_id.id)
|
||||
pricelist = pos_config.pricelist_id
|
||||
|
||||
for line in lines:
|
||||
product_sudo = request.env["product.product"].sudo().browse(int(line.get("product_id")))
|
||||
product = pos_config.env['product.product'].browse(line.get('product_id'))
|
||||
# todo take into account the price extra
|
||||
price_unit = pricelist._get_product_price(product_sudo, quantity=1) if pricelist else product_sudo.lst_price
|
||||
price_unit = pricelist._get_product_price(product, quantity=line.get('qty')) if pricelist else product.lst_price
|
||||
|
||||
config_fiscal_pos = pos_config_sudo.default_fiscal_position_id
|
||||
selected_account_tax = config_fiscal_pos.map_tax(product_sudo.taxes_id) if config_fiscal_pos else product_sudo.taxes_id
|
||||
config_fiscal_pos = pos_config.default_fiscal_position_id
|
||||
selected_account_tax = config_fiscal_pos.map_tax(product.taxes_id) if config_fiscal_pos else product.taxes_id
|
||||
|
||||
tax_results = selected_account_tax.compute_all(
|
||||
price_unit,
|
||||
pos_config_sudo.currency_id,
|
||||
pos_config.currency_id,
|
||||
line.get('qty'),
|
||||
product_sudo,
|
||||
product,
|
||||
)
|
||||
|
||||
newLines.append({
|
||||
@@ -176,7 +171,7 @@ class PosSelfOrderController(http.Controller):
|
||||
'price_extra': 0,
|
||||
'id': line.get('id'),
|
||||
'order_id': pos_order_id,
|
||||
'tax_ids': product_sudo.taxes_id,
|
||||
'tax_ids': product.taxes_id,
|
||||
'uuid': line.get('uuid'),
|
||||
'product_id': line.get('product_id'),
|
||||
'qty': line.get('qty'),
|
||||
@@ -212,14 +207,29 @@ class PosSelfOrderController(http.Controller):
|
||||
|
||||
return (order_sudo.sequence_number + 1) or 1
|
||||
|
||||
def _verify_authorization(self, access_token, table_identifier):
|
||||
table_sudo = request.env["restaurant.table"].sudo().search([('identifier', '=', table_identifier)], limit=1)
|
||||
def _verify_pos_config(self, access_token):
|
||||
"""
|
||||
Finds the pos.config with the given access_token and returns a record with reduced privileges.
|
||||
The record is has no sudo access and is in the context of the record's company and current pos.session's user.
|
||||
"""
|
||||
pos_config_sudo = request.env['pos.config'].sudo().search([('access_token', '=', access_token)], limit=1)
|
||||
|
||||
if not pos_config_sudo or not pos_config_sudo.self_order_table_mode or not pos_config_sudo.has_active_session:
|
||||
raise Unauthorized("Invalid access token")
|
||||
company = pos_config_sudo.company_id
|
||||
user = pos_config_sudo.current_session_id.user_id
|
||||
return reduce_privilege(pos_config_sudo, company, user)
|
||||
|
||||
def _verify_authorization(self, access_token, table_identifier):
|
||||
"""
|
||||
Similar to _verify_pos_config but also looks for the restaurant.table of the given identifier.
|
||||
The restaurant.table record is also returned with reduced privileges.
|
||||
"""
|
||||
table_sudo = request.env["restaurant.table"].sudo().search([('identifier', '=', table_identifier)], limit=1)
|
||||
if not table_sudo:
|
||||
raise Unauthorized("Table not found")
|
||||
|
||||
return pos_config_sudo, table_sudo
|
||||
pos_config = self._verify_pos_config(access_token)
|
||||
company = pos_config.company_id
|
||||
user = pos_config.current_session_id.user_id
|
||||
table = reduce_privilege(table_sudo, company, user)
|
||||
return pos_config, table
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
import werkzeug
|
||||
from typing import Optional
|
||||
|
||||
from odoo.http import request
|
||||
from odoo.addons.pos_self_order.models.pos_config import PosConfig
|
||||
@@ -16,14 +15,18 @@ def get_any_pos_config_sudo() -> PosConfig:
|
||||
request.env["pos.config"].sudo().search([("self_order_view_mode", "=", True)], limit=1)
|
||||
) or _raise(werkzeug.exceptions.NotFound())
|
||||
|
||||
|
||||
def get_table_sudo(identifier):
|
||||
return identifier and (
|
||||
request.env["restaurant.table"]
|
||||
.sudo()
|
||||
.search([("identifier", "=", identifier), ("active", "=", True)], limit=1)
|
||||
)
|
||||
|
||||
|
||||
def _raise(e):
|
||||
raise e
|
||||
|
||||
def reduce_privilege(record_sudo, company, user=None):
|
||||
"""
|
||||
Returns a record with reduced privileges based on company and user.
|
||||
If user is not provided, we keep the sudo privilege, but still, the record
|
||||
will be scoped to the company.
|
||||
"""
|
||||
if record_sudo:
|
||||
if user:
|
||||
return record_sudo.sudo(False).with_company(company).with_user(user)
|
||||
else:
|
||||
return record_sudo.with_company(company)
|
||||
return None
|
||||
|
||||
@@ -144,7 +144,6 @@ class PosConfig(models.Model):
|
||||
self.ensure_one()
|
||||
return (
|
||||
self.env["pos_self_order.custom_link"]
|
||||
.sudo()
|
||||
.search_read(
|
||||
[
|
||||
"|",
|
||||
@@ -163,7 +162,6 @@ class PosConfig(models.Model):
|
||||
self.ensure_one()
|
||||
return (
|
||||
self.env["product.product"]
|
||||
.sudo()
|
||||
.search(
|
||||
[
|
||||
("available_in_pos", "=", True),
|
||||
@@ -186,7 +184,7 @@ class PosConfig(models.Model):
|
||||
"show_prices_with_tax_included": self.iface_tax_included == "total",
|
||||
"custom_links": self._get_self_order_custom_links(),
|
||||
"products": self._get_available_products()._get_self_order_data(self),
|
||||
"pos_category": self.env['pos.category'].sudo().search_read(fields=["name", "sequence"], order="sequence"),
|
||||
"pos_category": self.env['pos.category'].search_read(fields=["name", "sequence"], order="sequence"),
|
||||
"has_active_session": self.has_active_session,
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class ProductProduct(models.Model):
|
||||
self.ensure_one()
|
||||
|
||||
attributes = self._filter_applicable_attributes(
|
||||
self.env["pos.session"].sudo()._get_attributes_by_ptal_id()
|
||||
self.env["pos.session"]._get_attributes_by_ptal_id()
|
||||
)
|
||||
return self._add_price_info_to_attributes(
|
||||
attributes,
|
||||
|
||||
@@ -32,10 +32,4 @@ export class ProductCard extends Component {
|
||||
const productId = this.props.line.product_id;
|
||||
return `${this.props.line.qty} x ${this.selfOrder.productByIds[productId].prices}`;
|
||||
}
|
||||
|
||||
getTotalPriceString() {
|
||||
const productPriceWithTax = this.props.product.prices;
|
||||
const quantity = this.props.line?.qty ? this.props.line.qty : 1;
|
||||
return this.selfOrder.formatMonetary(productPriceWithTax * quantity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
t-if="quantityInCart and selfOrder.ordering"
|
||||
t-esc="`${quantityInCart}x`"
|
||||
/>
|
||||
<span class="card-text small" t-esc="getTotalPriceString()" />
|
||||
<span class="card-text small" t-esc="selfOrder.formatMonetary(props.product.prices)" />
|
||||
</div>
|
||||
<p
|
||||
t-if="props.product.description_sale"
|
||||
@@ -27,7 +27,6 @@
|
||||
t-attf-src="/menu/get-image/{{ props.product.id }}"
|
||||
alt="Product image"
|
||||
loading="lazy"
|
||||
onerror="this.remove()"
|
||||
/>
|
||||
<span t-if="quantityInCart and selfOrder.ordering" class="position-absolute top-0 start-0 h-100 border-start border-5 border-primary" />
|
||||
</div>
|
||||
|
||||
@@ -178,6 +178,7 @@ export class SelfOrder {
|
||||
|
||||
try {
|
||||
const orders = await this.rpc(`/pos-self-order/get-orders/`, {
|
||||
access_token: this.access_token,
|
||||
order_access_tokens: accessTokens,
|
||||
});
|
||||
|
||||
|
||||
@@ -3,12 +3,48 @@
|
||||
|
||||
import odoo.tests
|
||||
|
||||
from odoo import Command
|
||||
|
||||
|
||||
@odoo.tests.tagged("post_install", "-at_install")
|
||||
class SelfOrderCommonTest(odoo.tests.HttpCase):
|
||||
browser_size = "375x667"
|
||||
touch_enabled = True
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.pos_user = cls.env['res.users'].create({
|
||||
'name': 'POS User',
|
||||
'login': 'pos_user',
|
||||
'password': 'pos_user',
|
||||
'groups_id': [
|
||||
(4, cls.env.ref('base.group_user').id),
|
||||
(4, cls.env.ref('point_of_sale.group_pos_user').id),
|
||||
],
|
||||
})
|
||||
|
||||
def _add_tax_to_product_from_different_company(self):
|
||||
new_company = self.env['res.company'].create({
|
||||
'name': 'Test Company',
|
||||
'currency_id': self.env.ref('base.USD').id,
|
||||
'country_id': self.env.ref('base.us').id,
|
||||
})
|
||||
|
||||
new_tax = self.env['account.tax'].with_company(new_company).create({
|
||||
'name': 'Tax that should not be used',
|
||||
'amount': 50,
|
||||
'amount_type': 'percent',
|
||||
'tax_group_id': self.env['account.tax.group'].with_company(new_company).create({
|
||||
'name': 'Tax Group that should not be used',
|
||||
}).id,
|
||||
'company_id': new_company.id,
|
||||
})
|
||||
|
||||
self.env['product.product'].search([]).with_company(new_company).write({
|
||||
'taxes_id': [Command.link(id) for id in new_tax.ids],
|
||||
})
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.pos_config = self.env["pos.config"].create(
|
||||
@@ -28,3 +64,7 @@ class SelfOrderCommonTest(odoo.tests.HttpCase):
|
||||
'amount': 15,
|
||||
'amount_type': 'percent',
|
||||
})
|
||||
|
||||
# A new tax is added to each product and this tax is from a different company.
|
||||
# This is important in the test because the added tax should not be used in the tour.
|
||||
self._add_tax_to_product_from_different_company()
|
||||
|
||||
@@ -19,7 +19,7 @@ class TestFrontendMobile(SelfOrderCommonTest):
|
||||
def test_self_order_pay_after_meal_tour(self):
|
||||
self.pos_config.self_order_table_mode = True
|
||||
self.pos_config.self_order_pay_after = "meal"
|
||||
self.pos_config.open_ui()
|
||||
self.pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour(
|
||||
self.pos_config._get_self_order_route(),
|
||||
"self_order_after_meal_cart_tour",
|
||||
|
||||
Reference in New Issue
Block a user