[ADD] pos_online_payment_self_order, *: add module

*: pos_self_order

Adds online payment support for self-order flow in the Point of Sale app.

 - Adds a configurable online payment method specific to the self-order flow, which is optional in "Pay after meal" mode, required in "Pay after each" mode.
The POS config of a restaurant can use 2 different online payment methods, one for the frontend cashier flow, and another for the self-order flow, or can use the same for both.
By default, if an online payment method is configured for the self-order flow, any new order paid online will be paid with that payment method.
But if the cashier requests an online payment with a different online payment method, that payment method will be used for that order during the time the cashier keeps his online payment popup open (without cancelling the online payment) (after cancelling the online payment, the order could potentially still be paid online, and if so it will use the online payment method of the self-order if one is configured, otherwise the online payment method of the cashier flow).
 - Allows the customer to open the online payment page of an order from the self-order UI.
In "Pay after meal" mode, if an online payment method is configured, the "Pay" button is displayed when the customer order is saved on the server, otherwise the "Order" button is displayed (even when the order has been sent to the server and then modified without sending it again).
Otherwise, if no online payment method is configured, the "Pay at cashier" unclickable button is displayed.
In "Pay after each" mode, the "Pay" button is displayed everytime.
 - Replaces the self_order_after_each_cart_tour test.

closes odoo/odoo#127869

Task-id: 3171698
Related: odoo/enterprise#44055
Signed-off-by: Robin Heinz (rhe) <rhe@odoo.com>
This commit is contained in:
Theo VINCENT (thvi)
2023-07-20 14:22:57 +02:00
parent 6504612cf2
commit b81a049a4e
23 changed files with 362 additions and 129 deletions
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'POS Self-Order / Online Payment',
'category': 'Sales/Point of Sale',
'summary': 'Support online payment in self-order',
'version': '1.0',
'depends': ['pos_online_payment', 'pos_self_order'],
'data': [
'views/res_config_settings_views.xml',
],
'installable': True,
'auto_install': True,
'assets': {
'pos_self_order.assets_self_order': [
'pos_online_payment_self_order/static/src/**/*',
],
'pos_self_order.assets_tests': [
'pos_online_payment_self_order/static/tests/tours/**/*',
],
},
'license': 'LGPL-3',
}
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import pos_config
from . import pos_order
from . import res_config_settings
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from typing import Dict
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class PosConfig(models.Model):
_inherit = 'pos.config'
self_order_online_payment_method_id = fields.Many2one('pos.payment.method', string='Online payment method', help="The online payment method to use when a customer pays a self-order online.", domain=[('is_online_payment', '=', True)], compute='_compute_self_order_online_payment_method_id', store=True, readonly=False)
@api.constrains('self_order_online_payment_method_id')
def _check_self_order_online_payment_method_id(self):
if any(config.self_order_online_payment_method_id and not config.self_order_online_payment_method_id._get_online_payment_providers(config.id, error_if_invalid=True) for config in self):
raise ValidationError(_("The online payment method used for self-order in a POS config must have at least one published payment provider supporting the currency of that POS config."))
@api.constrains('self_order_table_mode', 'self_order_pay_after', 'self_order_online_payment_method_id')
def _check_self_order_pay_after_each(self):
if any(config.self_order_table_mode and config.self_order_pay_after == 'each' and not config.self_order_online_payment_method_id for config in self):
raise ValidationError(_("The POS self-order mode with payment after each order requires an online payment method to be configured."))
@api.depends('company_id', 'self_order_table_mode', 'self_order_pay_after', 'self_order_online_payment_method_id')
def _compute_self_order_online_payment_method_id(self):
for config in self:
if not config.self_order_table_mode:
config.self_order_online_payment_method_id = False
elif config.self_order_pay_after == 'each' and (not config.self_order_online_payment_method_id or not config.self_order_online_payment_method_id.is_online_payment):
config.self_order_online_payment_method_id = self.env['pos.payment.method'].sudo()._get_or_create_online_payment_method(config.company_id.id, config.id)
def _get_self_order_data(self) -> Dict:
res = super()._get_self_order_data()
res['has_self_order_online_payment_method'] = bool(self.self_order_online_payment_method_id)
return res
@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, tools
from odoo.osv import expression
class PosOrder(models.Model):
_inherit = 'pos.order'
use_self_order_online_payment = fields.Boolean(compute='_compute_use_self_order_online_payment', store=True, readonly=True)
@api.depends('config_id.self_order_online_payment_method_id')
def _compute_use_self_order_online_payment(self):
for order in self:
order.use_self_order_online_payment = bool(order.config_id.self_order_online_payment_method_id)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if 'use_self_order_online_payment' not in vals or vals['use_self_order_online_payment']:
session = self.env['pos.session'].browse(vals['session_id'])
config = session.config_id
vals['use_self_order_online_payment'] = bool(config.self_order_online_payment_method_id)
return super().create(vals_list)
def write(self, vals):
# Because use_self_order_online_payment is not intended to be changed manually,
# avoid to raise an error.
if 'use_self_order_online_payment' not in vals:
return super().write(vals)
can_change_self_order_domain = [('state', '=', 'draft')]
if vals['use_self_order_online_payment']:
can_change_self_order_domain = expression.AND([can_change_self_order_domain, [('config_id.self_order_online_payment_method_id', '!=', False)]])
can_change_self_order_orders = self.filtered_domain(can_change_self_order_domain)
cannot_change_self_order_orders = self - can_change_self_order_orders
res = True
if can_change_self_order_orders:
res = super(PosOrder, can_change_self_order_orders).write(vals) and res
if cannot_change_self_order_orders:
clean_vals = vals.copy()
clean_vals.pop('use_self_order_online_payment', None)
res = super(PosOrder, cannot_change_self_order_orders).write(clean_vals) and res
return res
@api.depends('use_self_order_online_payment', 'config_id.self_order_online_payment_method_id', 'config_id.payment_method_ids')
def _compute_online_payment_method_id(self):
for order in self:
if order.use_self_order_online_payment:
# It is expected to use the self order online payment method.
# If for any reason it is not defined, then the online payment
# of the order is set to null to make the problem noticeable.
order.online_payment_method_id = order.config_id.self_order_online_payment_method_id
else:
super(PosOrder, order)._compute_online_payment_method_id()
def get_and_set_online_payments_data(self, next_online_payment_amount=False):
res = super().get_and_set_online_payments_data(next_online_payment_amount)
if 'paid_order' not in res and not res.get('deleted', False) and not isinstance(next_online_payment_amount, bool):
# This method is only called in the POS frontend flow, not self order.
# If the next online payment is 0, then the online payment of the frontend
# flow is cancelled, and the default flow is self order if it is configured.
self.use_self_order_online_payment = tools.float_is_zero(next_online_payment_amount, precision_rounding=self.currency_id.rounding) and self.config_id.self_order_online_payment_method_id
return res
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
pos_self_order_online_payment_method_id = fields.Many2one(related='pos_config_id.self_order_online_payment_method_id', readonly=False)
@@ -0,0 +1,71 @@
/** @odoo-module */
import { patch } from "@web/core/utils/patch";
import { OrderCart } from "@pos_self_order/pages/order_cart/order_cart";
import { _t } from "@web/core/l10n/translation";
patch(OrderCart.prototype, "pos_online_payment_self_order.OrderCart", {
get buttonToShow() {
if (this.selfOrder.self_order_mode === "each") {
return { label: _t("Pay"), disabled: false };
} else if (this.selfOrder.self_order_mode === "meal") {
const order = this.selfOrder.currentOrder;
if (!order) {
return { label: "", disabled: true };
}
if (!order.isSavedOnServer) {
return { label: _t("Order"), disabled: false };
} else {
if (this.selfOrder.has_self_order_online_payment_method) {
return { label: _t("Pay"), disabled: false };
} else {
return { label: _t("Pay at cashier"), disabled: true };
}
}
} else {
return this._super(...arguments);
}
},
async processOrder() {
if (this.sendInProgress) {
return;
}
if (!this.selfOrder.table) {
this.state.selectTable = true;
return;
}
if (this.selfOrder.self_order_mode === "meal" && this.selfOrder.has_self_order_online_payment_method) {
const order = this.selfOrder.currentOrder;
if (!order) {
this.selfOrder.notification.add(_t("The current order is invalid."), { type: "danger" });
return;
}
if (!order.isSavedOnServer) {
this.sendInProgress = true;
await this.selfOrder.sendDraftOrderToServer();
this.sendInProgress = false;
} else {
this.checkAndOpenPaymentPage(order);
}
} else if (this.selfOrder.self_order_mode === "each") {
this.sendInProgress = true;
const order = await this.selfOrder.sendDraftOrderToServer();
this.sendInProgress = false;
this.checkAndOpenPaymentPage(order);
} else {
return this._super(...arguments);
}
},
checkAndOpenPaymentPage(order) {
if (order) {
if (order.state === "draft") {
this.selfOrder.openOnlinePaymentPage(order);
} else {
this.selfOrder.notification.add(_t("The current order cannot be paid (maybe it is already paid)."), { type: "danger" });
}
} else {
this.selfOrder.notification.add(_t("The order could not be saved, therefore its payment is unavailable."), { type: "danger" });
}
},
});
@@ -0,0 +1,17 @@
/** @odoo-module */
import { patch } from "@web/core/utils/patch";
import { SelfOrder } from "@pos_self_order/self_order_service";
import { session } from "@web/session";
patch(SelfOrder.prototype, "pos_online_payment_self_order.SelfOrder", {
openOnlinePaymentPage({ id: order_id, access_token: order_access_token, pos_config_id: order_pos_config_id }) {
const baseUrl = session.base_url;
let exitRouteUrl = baseUrl + "/menu/" + order_pos_config_id + "?access_token=" + this.access_token;
const tableIdentifier = this.table?.identifier;
if (tableIdentifier) {
exitRouteUrl += "&table_identifier=" + tableIdentifier;
}
const exitRoute = encodeURIComponent(exitRouteUrl);
window.open(baseUrl + `/pos/pay/${order_id}?access_token=${order_access_token}&exit_route=${exitRoute}`, "_self");
},
});
@@ -0,0 +1,19 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { PosSelf } from "@pos_self_order/../tests/tours/tour_utils";
registry.category("web_tour.tours").add("self_order_after_each_cart_tour", {
test: true,
steps: () => [
// Check that the self is open
PosSelf.check.isNotNotification(),
PosSelf.action.clickPrimaryBtn("View Menu"),
...PosSelf.action.addProduct("Office Chair Black", 1),
PosSelf.action.clickPrimaryBtn("Review"),
PosSelf.check.isOrderline("Office Chair Black", "138.58", ""),
PosSelf.check.isPrimaryBtn("Pay"), // Not clicked on because it would open another page, losing the tour setup.
],
});
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_self_order_frontend
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from unittest.mock import patch
import odoo.tests
from odoo.addons.pos_self_order.tests.self_order_common_test import SelfOrderCommonTest
from odoo.addons.pos_online_payment.models.pos_payment_method import PosPaymentMethod
@odoo.tests.tagged("post_install", "-at_install")
class TestSelfOrderFrontendMobile(SelfOrderCommonTest):
def test_self_order_pay_after_each_tour(self):
self.pos_config.self_order_table_mode = True
self.self_order_online_payment_method_id = self.env['pos.payment.method'].sudo()._get_or_create_online_payment_method(self.pos_config.company_id.id, self.pos_config.id)
self.fake_provider = self.env['payment.provider'].create({
'name': 'SelfOrderTest',
})
real_get_online_payment_providers = PosPaymentMethod._get_online_payment_providers
def _fake_get_online_payment_providers(method_self, pos_config_id=False, error_if_invalid=True):
if method_self.id == self.self_order_online_payment_method_id.id:
return self.fake_provider
else:
return real_get_online_payment_providers(method_self, pos_config_id, error_if_invalid)
with patch.object(PosPaymentMethod, '_get_online_payment_providers', _fake_get_online_payment_providers):
self.pos_config.update({
'self_order_pay_after': 'each',
'self_order_online_payment_method_id': self.self_order_online_payment_method_id,
})
self.pos_config.open_ui()
self.start_tour(
self.pos_config._get_self_order_route(),
"self_order_after_each_cart_tour",
login=None,
)
self.fake_provider.unlink()
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<odoo>
<record id="res_config_settings_view_form_menu" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.pos_online_payment.view</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="pos_restaurant.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='pos_self_order_pay_after']" position="after">
<div>
<label for="pos_self_order_online_payment_method_id" class="me-2" />
<field name="pos_self_order_online_payment_method_id" attrs="{'required': ['&amp;', ('pos_self_order_table_mode', '=', True), ('pos_self_order_pay_after', '=', 'each')]}" placeholder="Select a payment method" />
<button name="%(point_of_sale.action_payment_methods_tree)d" icon="fa-arrow-right" type="action" string="Payment Methods" class="btn-link" />
</div>
</xpath>
</field>
</record>
</odoo>
@@ -67,6 +67,7 @@ class PosQRMenuController(http.Controller):
'access_token': pos_config_access_token,
**pos_config_sudo._get_self_order_data(),
},
"base_url": request.env['pos.session'].get_base_url(),
}
}
)
+1 -1
View File
@@ -34,7 +34,7 @@ class PosConfig(models.Model):
help="Allow customers to Order from their phones",
)
self_order_pay_after = fields.Selection(
[("each", "Each Order"), ("meal", "Meal")],
[("each", "Each Order (mobile payment only)"), ("meal", "Meal (mobile payment or cashier)")],
string="Pay After:",
default="meal",
help="Choose when the customer will pay",
@@ -14,7 +14,7 @@ class ResConfigSettings(models.TransientModel):
compute="_compute_pos_module_pos_self_order", store=True, readonly=False
)
pos_self_order_pay_after = fields.Selection(
[("each", "Each Order"), ("meal", "Meal")],
[("each", "Each Order (mobile payment only)"), ("meal", "Meal (mobile payment or cashier)")],
string="Pay After:",
default="meal",
help="Choose when the customer will pay",
@@ -40,7 +40,7 @@ class ResConfigSettings(models.TransientModel):
{
"pos_self_order_view_mode": False,
"pos_self_order_table_mode": False,
"pos_self_order_pay_after": "each",
"pos_self_order_pay_after": "meal",
"pos_self_order_image": False,
"pos_self_order_image_name": False,
}
@@ -20,10 +20,7 @@ export class Lines extends Component {
clickOnLine(line) {
const order = this.props.order;
this.selfOrder.editedLine = line;
if (
!order.access_token ||
(order.state === "draft" && this.selfOrder.self_order_mode === "meal")
) {
if (order.state === "draft") {
this.selfOrder.editedOrder = order;
this.router.navigate("product", { id: line.product_id });
} else {
@@ -67,7 +67,7 @@ export class Order extends Reactive {
}, {});
}
isChange() {
hasNotAllLinesSent() {
return this.lines.find((line) => {
const lastSend = this.lastChangesSent[line.uuid];
@@ -78,4 +78,7 @@ export class Order extends Reactive {
return lastSend.qty !== line.qty || line.isChange(lastSend);
});
}
get isSavedOnServer() {
return this.isAlreadySent && !this.hasNotAllLinesSent();
}
}
@@ -29,7 +29,10 @@ export class OrderCart extends Component {
}
get buttonToShow() {
return this.selfOrder.self_order_mode === "each" ? "Pay" : "Order";
return {
label: this.selfOrder.self_order_mode === "each" ? _t("Pay") : _t("Order"),
disabled: false,
};
}
get orderToPay() {
@@ -13,7 +13,7 @@
<div class="d-flex align-items-center w-100 p-3 bg-white shadow-lg">
<div t-attf-class="{{ state.cancelConfirmation ? 'flex-row-reverse' : '' }} d-flex mt-2 flex-fill">
<button
t-if="order.isChange() and order.lines.length > 0"
t-if="order.hasNotAllLinesSent() and order.lines.length > 0"
t-on-click.prevent="cancelToggle"
t-attf-class="{{ state.cancelConfirmation ? 'btn-primary' : 'btn-secondary' }} o_self-cancel-toggle-btn btn"
t-attf-style="{{ state.cancelConfirmation ? 'margin-left: 10px;' : 'margin-right: 10px;' }}"
@@ -23,10 +23,9 @@
<button
t-if="!state.cancelConfirmation"
t-on-click="processOrder"
t-attf-class="{{ !orderToPay and !order.isChange() ? 'disabled' : '' }} o_self_order_main_button btn btn-primary px-2 py-3 flex-grow-1"
t-attf-class="{{ buttonToShow.disabled ? 'disabled' : '' }} o_self_order_main_button btn btn-primary px-2 py-3 flex-grow-1"
>
<span t-if="orderToPay">Pay</span>
<span t-else="">Order</span>
<t t-esc="buttonToShow.label" />
<t t-if="!selfOrder.priceLoading">
<span> | <t t-esc="selfOrder.formatMonetary(order.amount_total)"/></span>
</t>
@@ -1,79 +0,0 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { PosSelf } from "./tour_utils";
registry.category("web_tour.tours").add("self_order_after_each_cart_tour", {
test: true,
steps: () => [
// Verify if the self is open and My Orders is not displayed because we are in "meal" mode
PosSelf.check.isNotNotification(),
PosSelf.check.isNotPrimaryBtn("My Orders"),
PosSelf.action.clickPrimaryBtn("View Menu"),
// Add some products
...PosSelf.action.addProduct("Office Chair Black", 1),
...PosSelf.action.addProduct("Office Chair Black", 2, "Description"),
...PosSelf.action.addProduct("Large Cabinet", 2),
PosSelf.action.clickPrimaryBtn("Review"),
// Here we're looking at whether when an orderline is clicked on from
// the cart and edited, the changes are made to the orderline clicked on.
PosSelf.check.isOrderline("Office Chair Black", "138.58", ""),
...PosSelf.action.editOrderline("Office Chair Black", "138.58", "", 5, "no wheels"),
PosSelf.check.isOrderline("Office Chair Black", "692.90", "no wheels"),
...PosSelf.action.editOrderline("Office Chair Black", "692.90", "no wheels", -4, "kidding"),
PosSelf.check.isOrderline("Office Chair Black", "138.58", "kidding"),
PosSelf.action.clickBack(),
// Once an order has been sent to the server, the user can no
// longer reduce the quantity of his orderlines. We check this behaviour.
PosSelf.action.clickPrimaryBtn("Review"),
...PosSelf.action.editOrderline("Large Cabinet", "736.00", "", -1),
PosSelf.check.isOrderline("Large Cabinet", "368.00", ""),
// Here we look at whether the user can reduce the quantity
// and delete a product that has not yet been sent
PosSelf.action.clickBack(),
...PosSelf.action.addProduct("Funghi", 1),
PosSelf.action.clickPrimaryBtn("Review"),
...PosSelf.action.editOrderline("Funghi", "8.05", "", -1),
PosSelf.check.isNotOrderline("Funghi", "8.05", ""),
// Here we're looking at whether adding a product with the same description
// as the same product already in the basket merges the two products.
// We also check whether we can reduce the quantity of the part not yet sent to
// the server and whether the quantity of the part sent to the server is fixed.
PosSelf.action.clickBack(),
...PosSelf.action.addProduct("Office Chair Black", 1, "kidding"),
PosSelf.action.clickPrimaryBtn("Review"),
PosSelf.check.isOrderline("Office Chair Black", "277.16", "kidding"),
...PosSelf.action.editOrderline("Office Chair Black", "277.16", "kidding", -1),
PosSelf.check.isOrderline("Office Chair Black", "138.58", "kidding"),
...PosSelf.action.editOrderline("Office Chair Black", "138.58", "kidding", -1),
PosSelf.check.isNotOrderline("Office Chair Black", "138.58", ""),
PosSelf.action.clickBack(),
// Here we check that the product attributes are correctly selected.
...PosSelf.action.addProduct("Desk Organizer", 1, "kidding", {
radio: { name: "Size", value: "M" },
select: { name: "Fabric", value: "Leather" },
}),
...PosSelf.action.addProduct("Desk Organizer", 2, "okkk", {
radio: { name: "Size", value: "L" },
select: { name: "Fabric", value: "Custom" },
}),
PosSelf.action.clickPrimaryBtn("Review"),
PosSelf.check.isOrderline("Desk Organizer", "5.87", "kidding", "M, Leather"),
PosSelf.check.isOrderline("Desk Organizer", "11.74", "okkk", "L, Custom"),
// Check if we can edit the product attributes, and if the changes are made to the orderline
...PosSelf.action.editOrderline("Desk Organizer", "5.87", "kidding", 0, "dav", {
radio: { name: "Size", value: "S" },
select: { name: "Fabric", value: "Custom" },
}),
PosSelf.check.isOrderline("Desk Organizer", "5.87", "dav", "S, Custom"),
PosSelf.check.isOrderline("Desk Organizer", "11.74", "okkk", "L, Custom"),
PosSelf.action.clickBack(),
],
});
@@ -71,10 +71,9 @@ registry.category("web_tour.tours").add("self_order_after_meal_cart_tour", {
PosSelf.check.isOrderline("Office Chair Black", "138.58", "kidding"),
...PosSelf.action.editSentOrderline("Office Chair Black", "138.58", "kidding", -1),
PosSelf.check.isNotification("You cannot reduce the quantity"),
PosSelf.action.clickPrimaryBtn("Order"),
PosSelf.action.clickBack(),
// Here we check that the product attributes are correctly selected.
PosSelf.action.clickPrimaryBtn("View Menu"),
...PosSelf.action.addProduct("Desk Organizer", 1, "kidding", {
radio: { name: "Size", value: "M" },
select: { name: "Fabric", value: "Leather" },
@@ -96,7 +95,6 @@ registry.category("web_tour.tours").add("self_order_after_meal_cart_tour", {
PosSelf.check.isOrderline("Desk Organizer", "11.74", "okkk", "L, Custom"),
PosSelf.action.clickPrimaryBtn("Order"),
PosSelf.action.clickBack(),
PosSelf.check.isPrimaryBtn("My Orders"),
PosSelf.action.clickPrimaryBtn("My Orders"),
PosSelf.action.clickBack(),
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
@odoo.tests.tagged("post_install", "-at_install")
class SelfOrderCommonTest(odoo.tests.HttpCase):
browser_size = "375x667"
touch_enabled = True
def setUp(self):
super().setUp()
self.pos_config = self.env["pos.config"].create(
{
"name": "BarTest",
"module_pos_restaurant": True,
"self_order_view_mode": True,
"floor_ids": self.env["restaurant.floor"].search([]),
"self_order_table_mode": False,
}
)
# we need a default tax fixed at 15% to all product because in the test prices are based on this tax.
# some time with the localization this may not be the case. So we force it.
self.env['product.product'].search([]).taxes_id = self.env['account.tax'].create({
'name': 'Default Tax for Self Order',
'amount': 15,
'amount_type': 'percent',
})
+2 -34
View File
@@ -2,32 +2,11 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
from odoo.addons.pos_self_order.tests.self_order_common_test import SelfOrderCommonTest
@odoo.tests.tagged("post_install", "-at_install")
class TestFrontendMobile(odoo.tests.HttpCase):
browser_size = "375x667"
touch_enabled = True
def setUp(self):
super().setUp()
self.pos_config = self.env["pos.config"].create(
{
"name": "BarTest",
"module_pos_restaurant": True,
"self_order_view_mode": True,
"floor_ids": self.env["restaurant.floor"].search([]),
"self_order_table_mode": False,
}
)
# we need a default tax fixed at 15% to all product because in the test prices are based on this tax.
# some time with the localization this may not be the case. So we force it.
self.env['product.product'].search([]).taxes_id = self.env['account.tax'].create({
'name': 'Default Tax for Self Order',
'amount': 15,
'amount_type': 'percent',
})
class TestFrontendMobile(SelfOrderCommonTest):
def test_self_order_menu_only_tour(self):
self.pos_config.self_order_table_mode = False
@@ -51,14 +30,3 @@ class TestFrontendMobile(odoo.tests.HttpCase):
"self_order_after_meal_product_tour",
login=None,
)
def test_self_order_pay_after_each_tour(self):
self.pos_config.self_order_table_mode = True
self.pos_config.self_order_pay_after = "each"
self.pos_config.open_ui()
self.start_tour(
self.pos_config._get_self_order_route(),
"self_order_after_each_cart_tour",
login=None,
)