From 01b3a2e4c24fe24bb7b8bb74fc6d2e2edaa96e87 Mon Sep 17 00:00:00 2001 From: "David Monnom (moda)" Date: Thu, 3 Aug 2023 12:12:12 +0000 Subject: [PATCH] [REF] point_of_sale, pos_*: only use export_for_ui for serializing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit *:pos_hr,pos_hr_restaurant,pos_loyalty,pos_restaurant Before when serializing a pos.orderĀ from the server, we are using several methods for different use cases. - table syncing: get_table_draft_orders - order sharing: get_draft_share_order_ids - ticket screen: export_for_ui All of these methods had their own logic. Now, to improve the maintainability of point_of_sale, order serialization is only performed via export_for_ui. Enterprise PR: https://github.com/odoo/enterprise/pull/45151 closes odoo/odoo#130695 Taskid: 3449870 Related: odoo/enterprise#45151 Signed-off-by: Joseph Caburnay (jcb) --- addons/point_of_sale/models/pos_order.py | 185 +----------------- addons/point_of_sale/models/pos_payment.py | 1 + .../static/src/app/store/models.js | 2 +- .../static/src/app/store/pos_store.js | 2 +- addons/pos_hr/models/pos_order.py | 14 -- addons/pos_hr_restaurant/__init__.py | 2 - addons/pos_hr_restaurant/models/__init__.py | 4 - addons/pos_hr_restaurant/models/pos_order.py | 17 -- addons/pos_loyalty/models/pos_order.py | 15 -- addons/pos_loyalty/models/pos_order_line.py | 3 + addons/pos_restaurant/models/pos_order.py | 72 +------ .../static/src/overrides/models/pos_store.js | 2 +- addons/pos_restaurant/tests/test_frontend.py | 10 +- 13 files changed, 26 insertions(+), 303 deletions(-) delete mode 100644 addons/pos_hr_restaurant/models/__init__.py delete mode 100644 addons/pos_hr_restaurant/models/pos_order.py diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 3d0070a353d..0399d09e901 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -1039,169 +1039,9 @@ class PosOrder(models.Model): mail = self.env['mail.mail'].sudo().create(self._prepare_mail_values(name, client, ticket)) mail.send() - def _get_order_lines(self, orders): - """Add pos_order_lines to the orders. - - The function doesn't return anything but adds the results directly to the orders. - - :param orders: orders for which the order_lines are to be requested. - :type orders: pos.order. - """ - order_lines = self.env['pos.order.line'].search_read( - domain=[('order_id', 'in', [to['id'] for to in orders])], - fields=self._get_fields_for_order_line()) - - if order_lines != []: - self._get_pack_lot_lines(order_lines) - - extended_order_lines = [] - for order_line in order_lines: - extended_order_lines.append([0, 0, self._prepare_order_line(order_line)]) - - for order_id, order_lines in groupby(extended_order_lines, key=lambda x: x[2]['order_id']): - next(order for order in orders if order['id'] == order_id[0])['lines'] = list(order_lines) - - def _get_pack_lot_lines(self, order_lines): - """Add pack_lot_lines to the order_lines. - - The function doesn't return anything but adds the results directly to the order_lines. - - :param order_lines: order_lines for which the pack_lot_lines are to be requested. - :type order_lines: pos.order.line. - """ - pack_lots = self.env['pos.pack.operation.lot'].search_read( - domain=[('pos_order_line_id', 'in', [order_line['id'] for order_line in order_lines])], - fields=[ - 'id', - 'lot_name', - 'pos_order_line_id' - ]) - for pack_lot in pack_lots: - pack_lot['order_line'] = pack_lot['pos_order_line_id'][0] - pack_lot['server_id'] = pack_lot['id'] - - del pack_lot['pos_order_line_id'] - del pack_lot['id'] - - for order_line_id, pack_lot_ids in groupby(pack_lots, key=lambda x: x['order_line']): - next(order_line for order_line in order_lines if order_line['id'] == order_line_id)['pack_lot_ids'] = list(pack_lot_ids) - - def _prepare_order_line(self, order_line): - """Method that will allow the cleaning of values to send the correct information. - :param order_line: order_line that will be cleaned. - :type order_line: pos.order.line. - :returns: dict -- dict representing the order line's values. - """ - order_line["product_id"] = order_line["product_id"][0] - order_line["server_id"] = order_line["id"] - - del order_line["id"] - if not "pack_lot_ids" in order_line: - order_line["pack_lot_ids"] = [] - else: - order_line["pack_lot_ids"] = [[0, 0, lot] for lot in order_line["pack_lot_ids"]] - return order_line - - def _get_fields_for_payment_lines(self): - return [ - 'id', - 'amount', - 'pos_order_id', - 'payment_method_id', - 'card_type', - 'cardholder_name', - 'transaction_id', - 'payment_status' - ] - - def _get_payments_lines_list(self, orders): - payment_lines = self.env['pos.payment'].search_read( - domain=[('pos_order_id', 'in', [po['id'] for po in orders])], - fields=self._get_fields_for_payment_lines()) - - extended_payment_lines = [] - for payment_line in payment_lines: - payment_line['server_id'] = payment_line['id'] - payment_line['payment_method_id'] = payment_line['payment_method_id'][0] - - del payment_line['id'] - extended_payment_lines.append([0, 0, payment_line]) - return extended_payment_lines - - def _get_payment_lines(self, orders): - """Add account_bank_statement_lines to the orders. - - The function doesn't return anything but adds the results directly to the orders. - - :param orders: orders for which the payment_lines are to be requested. - :type orders: pos.order. - """ - extended_payment_lines = self._get_payments_lines_list(orders) - for order_id, payment_lines in groupby(extended_payment_lines, key=lambda x: x[2]['pos_order_id']): - next(order for order in orders if order['id'] == order_id[0])['statement_ids'] = list(payment_lines) - - def _get_fields_for_draft_order(self): - return [ - 'id', - 'pricelist_id', - 'partner_id', - 'sequence_number', - 'session_id', - 'pos_reference', - 'create_uid', - 'create_date', - 'fiscal_position_id', - 'last_order_preparation_change', - 'to_invoice', - 'access_token', - 'ticket_code', - ] - - @api.model - def get_draft_share_order_ids(self, config_id): - """Search for 'draft' orders that satisfy the given domain.""" - config = self.env['pos.config'].browse(config_id) - default_domain = ['&', ('state', '=', 'draft'), '|', ('config_id', '=', config_id), ('config_id', 'in', config.trusted_config_ids.ids)] - orders = self.search_read( - domain=default_domain, - fields=self._get_fields_for_draft_order()) - - self._get_order_lines(orders) - self._get_payment_lines(orders) - - self._prepare_order(orders) - - return orders - def is_already_paid(self): return self.state == "paid" - @api.model - def _prepare_order(self, orders): - timezone = pytz.timezone(self._context.get('tz') or self.env.user.tz or 'UTC') - for order in orders: - order['pos_session_id'] = order['session_id'][0] - order['uid'] = re.search(r"\d{5,}-\d{3,}-\d{4,}", order['pos_reference']).group(0) - order['name'] = order['pos_reference'] - order['creation_date'] = order['create_date'].astimezone(timezone) - order['server_id'] = order['id'] - if order['fiscal_position_id']: - order['fiscal_position_id'] = order['fiscal_position_id'][0] - if order['pricelist_id']: - order['pricelist_id'] = order['pricelist_id'][0] - if order['partner_id']: - order['partner_id'] = order['partner_id'][0] - - if not 'lines' in order: - order['lines'] = [] - if not 'statement_ids' in order: - order['statement_ids'] = [] - - del order['id'] - del order['session_id'] - del order['pos_reference'] - del order['create_date'] - @api.model def remove_from_ui(self, server_ids): """ Remove orders from the frontend PoS application @@ -1275,24 +1115,14 @@ class PosOrder(models.Model): 'tip_amount': order.tip_amount, 'access_token': order.access_token, 'ticket_code': order.ticket_code, + 'last_order_preparation_change': order.last_order_preparation_change, } - def _get_fields_for_order_line(self): - """This function is here to be overriden""" - fields = [ - 'id', - 'uuid', - 'discount', - 'skip_change', - 'product_id', - 'price_unit', - 'order_id', - 'qty', - 'full_product_name', - 'customer_note', - 'price_extra', - ] - return fields + @api.model + def export_for_ui_shared_order(self, config_id): + config = self.env['pos.config'].browse(config_id) + orders = self.env['pos.order'].search(['&', ('state', '=', 'draft'), '|', ('config_id', '=', config_id), ('config_id', 'in', config.trusted_config_ids.ids)]) + return orders.export_for_ui() def export_for_ui(self): """ Returns a list of dict with each item having similar signature as the return of @@ -1473,7 +1303,7 @@ class PosOrderLine(models.Model): 'refunded_qty': orderline.refunded_qty, 'price_extra': orderline.price_extra, 'full_product_name': orderline.full_product_name, - 'refunded_orderline_id': orderline.refunded_orderline_id, + 'refunded_orderline_id': orderline.refunded_orderline_id.id, } def export_for_ui(self): @@ -1602,6 +1432,7 @@ class PosOrderLineLot(models.Model): def _export_for_ui(self, lot): return { 'lot_name': lot.lot_name, + 'order_line': lot.pos_order_line_id.id, } def export_for_ui(self): diff --git a/addons/point_of_sale/models/pos_payment.py b/addons/point_of_sale/models/pos_payment.py index 014eb83da61..bd5d2d843e3 100644 --- a/addons/point_of_sale/models/pos_payment.py +++ b/addons/point_of_sale/models/pos_payment.py @@ -51,6 +51,7 @@ class PosPayment(models.Model): return { 'payment_method_id': payment.payment_method_id.id, 'amount': payment.amount, + 'pos_order_id': payment.pos_order_id.id, 'payment_status': payment.payment_status, 'card_type': payment.card_type, 'cardholder_name': payment.cardholder_name, diff --git a/addons/point_of_sale/static/src/app/store/models.js b/addons/point_of_sale/static/src/app/store/models.js index 9f717b4f814..0a98b8af596 100644 --- a/addons/point_of_sale/static/src/app/store/models.js +++ b/addons/point_of_sale/static/src/app/store/models.js @@ -1317,7 +1317,7 @@ export class Order extends PosModel { this.name = sprintf(_t("Order %s"), this.uid); } this.validation_date = json.creation_date; - this.server_id = json.server_id ? json.server_id : false; + this.server_id = json.server_id || json.id || false; this.user_id = json.user_id; this.firstDraft = false; diff --git a/addons/point_of_sale/static/src/app/store/pos_store.js b/addons/point_of_sale/static/src/app/store/pos_store.js index 4bc1940ed41..621d0143221 100644 --- a/addons/point_of_sale/static/src/app/store/pos_store.js +++ b/addons/point_of_sale/static/src/app/store/pos_store.js @@ -749,7 +749,7 @@ export class PosStore extends Reactive { return message; } async _getOrdersJson() { - return await this.orm.call("pos.order", "get_draft_share_order_ids", [], { + return await this.orm.call("pos.order", "export_for_ui_shared_order", [], { config_id: this.config.id, }); } diff --git a/addons/pos_hr/models/pos_order.py b/addons/pos_hr/models/pos_order.py index e7804d19f39..f11c6c2e2d2 100644 --- a/addons/pos_hr/models/pos_order.py +++ b/addons/pos_hr/models/pos_order.py @@ -28,17 +28,3 @@ class PosOrder(models.Model): 'employee_id': order.employee_id.id, }) return result - - def _get_fields_for_draft_order(self): - fields = super(PosOrder, self)._get_fields_for_draft_order() - fields.append('employee_id') - return fields - - @api.model - def get_draft_share_order_ids(self, config_id): - orders = super(PosOrder, self).get_draft_share_order_ids(config_id) - for order in orders: - if order['employee_id']: - order['employee_id'] = order['employee_id'][0] - - return orders diff --git a/addons/pos_hr_restaurant/__init__.py b/addons/pos_hr_restaurant/__init__.py index dc5e6b693d1..67dee8c60db 100644 --- a/addons/pos_hr_restaurant/__init__.py +++ b/addons/pos_hr_restaurant/__init__.py @@ -1,4 +1,2 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import models diff --git a/addons/pos_hr_restaurant/models/__init__.py b/addons/pos_hr_restaurant/models/__init__.py deleted file mode 100644 index 04f8c2cc55d..00000000000 --- a/addons/pos_hr_restaurant/models/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import pos_order diff --git a/addons/pos_hr_restaurant/models/pos_order.py b/addons/pos_hr_restaurant/models/pos_order.py deleted file mode 100644 index f6ed5afa9b1..00000000000 --- a/addons/pos_hr_restaurant/models/pos_order.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models, api - - -class PosOrder(models.Model): - _inherit = "pos.order" - - @api.model - def get_table_draft_orders(self, table_ids): - table_orders = super().get_table_draft_orders(table_ids) - for order in table_orders: - if order['employee_id']: - order['employee_id'] = order['employee_id'][0] - - return table_orders diff --git a/addons/pos_loyalty/models/pos_order.py b/addons/pos_loyalty/models/pos_order.py index ff72d0f03c3..40ae1d3a4ed 100644 --- a/addons/pos_loyalty/models/pos_order.py +++ b/addons/pos_loyalty/models/pos_order.py @@ -145,21 +145,6 @@ class PosOrder(models.Model): 'coupon_report': coupon_per_report, } - def _prepare_order_line(self, order_line): - order_line = super(PosOrder, self)._prepare_order_line(order_line) - - if order_line.get("reward_id"): - order_line["reward_id"] = order_line["reward_id"][0] - if order_line.get("coupon_id"): - order_line["coupon_id"] = order_line["coupon_id"][0] - - return order_line - - def _get_fields_for_order_line(self): - fields = super(PosOrder, self)._get_fields_for_order_line() - fields.extend(['is_reward_line', 'reward_id', 'coupon_id', 'reward_identifier_code', 'points_cost']) - return fields - def _add_mail_attachment(self, name, ticket): attachment = super()._add_mail_attachment(name, ticket) gift_card_programs = self.config_id._get_program_ids().filtered(lambda p: p.program_type == 'gift_card' and diff --git a/addons/pos_loyalty/models/pos_order_line.py b/addons/pos_loyalty/models/pos_order_line.py index 2018b4823ba..8bb028be080 100644 --- a/addons/pos_loyalty/models/pos_order_line.py +++ b/addons/pos_loyalty/models/pos_order_line.py @@ -33,4 +33,7 @@ class PosOrderLine(models.Model): result = super()._export_for_ui(orderline) result['is_reward_line'] = orderline.is_reward_line result['reward_id'] = orderline.reward_id.id + result['coupon_id'] = orderline.coupon_id.id + result['reward_identifier_code'] = orderline.reward_identifier_code + result['points_cost'] = orderline.points_cost return result diff --git a/addons/pos_restaurant/models/pos_order.py b/addons/pos_restaurant/models/pos_order.py index 9ab46c6289b..f774f7b6204 100644 --- a/addons/pos_restaurant/models/pos_order.py +++ b/addons/pos_restaurant/models/pos_order.py @@ -1,11 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tools import groupby -from re import search from functools import partial -import pytz - from odoo import api, fields, models @@ -21,39 +17,6 @@ class PosOrder(models.Model): table_id = fields.Many2one('restaurant.table', string='Table', help='The table where this order was served', index='btree_not_null', readonly=True) customer_count = fields.Integer(string='Guests', help='The amount of customers that have been served by this order.', readonly=True) - def _get_fields_for_order_line(self): - fields = super(PosOrder, self)._get_fields_for_order_line() - fields.extend([ - 'note', - 'full_product_name', - 'customer_note', - 'price_extra', - 'refunded_orderline_id', - ]) - return fields - - def _prepare_order_line(self, order_line): - order_line = super(PosOrder, self)._prepare_order_line(order_line) - order_line["refunded_orderline_id"] = order_line["refunded_orderline_id"] and \ - order_line["refunded_orderline_id"][0] - return order_line - - def _get_fields_for_draft_order(self): - fields = super()._get_fields_for_draft_order() - fields.extend([ - 'table_id', - 'customer_count', - ]) - return fields - - def _get_domain_for_draft_orders(self, table_ids): - """ Get the domain to search for draft orders on a table. - :param table_ids: Ids of the selected tables. - :type table_ids: list of int. - "returns: list -- list of tuples that represents a domain. - """ - return [('state', '=', 'draft'), ('table_id', 'in', table_ids)] - @api.model def remove_from_ui(self, server_ids): tables = self.env['pos.order'].search([('id', 'in', server_ids)]).table_id @@ -75,35 +38,6 @@ class PosOrder(models.Model): messages.append((config_cur_session._get_bus_channel_name(), 'TABLE_ORDER_COUNT', order_count)) self.env['bus.bus']._sendmany(messages) - @api.model - def get_table_draft_orders(self, table_ids): - """Generate an object of all draft orders for the given table. - - Generate and return an JSON object with all draft orders for the given table, to send to the - front end application. - - :param table_ids: Ids of the selected tables. - :type table_ids: list of int. - :returns: list -- list of dict representing the table orders - """ - table_orders = self.search_read( - domain=self._get_domain_for_draft_orders(table_ids), - fields=self._get_fields_for_draft_order()) - - self._get_order_lines(table_orders) - self._get_payment_lines(table_orders) - - self._prepare_order(table_orders) - - return table_orders - - @api.model - def _prepare_order(self, orders): - super(PosOrder, self)._prepare_order(orders) - for order in orders: - if order['table_id']: - order['table_id'] = order['table_id'][0] - def set_tip(self, tip_line_vals): """Set tip to `self` based on values in `tip_line_vals`.""" @@ -152,4 +86,10 @@ class PosOrder(models.Model): def _export_for_ui(self, order): result = super(PosOrder, self)._export_for_ui(order) result['table_id'] = order.table_id.id + result['customer_count'] = order.customer_count return result + + @api.model + def export_for_ui_table_draft(self, table_ids): + orders = self.env['pos.order'].search([('state', '=', 'draft'), ('table_id', 'in', table_ids)]) + return orders.export_for_ui() diff --git a/addons/pos_restaurant/static/src/overrides/models/pos_store.js b/addons/pos_restaurant/static/src/overrides/models/pos_store.js index ae95b04ee44..82f7729575d 100644 --- a/addons/pos_restaurant/static/src/overrides/models/pos_store.js +++ b/addons/pos_restaurant/static/src/overrides/models/pos_store.js @@ -141,7 +141,7 @@ patch(PosStore.prototype, { // FIXME POSREF timeout const orders = await this.env.services.orm.silent.call( "pos.order", - "get_table_draft_orders", + "export_for_ui_table_draft", [tableIds] ); this.set_synch("connected"); diff --git a/addons/pos_restaurant/tests/test_frontend.py b/addons/pos_restaurant/tests/test_frontend.py index 9a074e84829..bcb1d0534f0 100644 --- a/addons/pos_restaurant/tests/test_frontend.py +++ b/addons/pos_restaurant/tests/test_frontend.py @@ -198,11 +198,11 @@ class TestFrontend(odoo.tests.HttpCase): self.pos_config.with_user(self.env.ref('base.user_demo')).open_ui() self.start_tour("/pos/ui?config_id=%d" % self.pos_config.id, 'PosResTipScreenTour', login="demo") - order1 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0001')]) - order2 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0002')]) - order3 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0003')]) - order4 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0004')]) - order5 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0005')]) + order1 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0001')], limit=1, order='id desc') + order2 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0002')], limit=1, order='id desc') + order3 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0003')], limit=1, order='id desc') + order4 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0004')], limit=1, order='id desc') + order5 = self.env['pos.order'].search([('pos_reference', 'ilike', '%-0005')], limit=1, order='id desc') self.assertTrue(order1.is_tipped and order1.tip_amount == 0.40) self.assertTrue(order2.is_tipped and order2.tip_amount == 1.00)