[REF] point_of_sale, pos_*: only use export_for_ui for serializing

*: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) <jcb@odoo.com>
This commit is contained in:
David Monnom (moda)
2023-08-08 18:40:52 +02:00
parent 1b8351038d
commit 01b3a2e4c2
13 changed files with 26 additions and 303 deletions
+8 -177
View File
@@ -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):
@@ -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,
@@ -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;
@@ -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,
});
}
-14
View File
@@ -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
-2
View File
@@ -1,4 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import pos_order
@@ -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
-15
View File
@@ -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
@@ -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
+6 -66
View File
@@ -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()
@@ -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");
+5 -5
View File
@@ -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)