From d6c42bba009c8a710ac5a41de07a07ec2e457a2a Mon Sep 17 00:00:00 2001 From: Joseph Caburnay Date: Fri, 6 Oct 2023 10:01:48 +0200 Subject: [PATCH] [FIX] pos_self_order,*: modifying the splash screen images **Steps to reproduce** - Open general settings of pos. - Select/Create a Point of Sale that is kiosk to see the `Splash screens` field. - The field is pre-filled with 3 images. - ISSUE: Try removing the images and save, they won't be removed. **FIX** - This is because of the `write` operation made from the `res.config.settings` model to the `pos.config`. - When removing an image, the field will be given `link` commands, linking the remaining images. This is wrong because it won't unlink the images that are deleted. - To ensure the deletion, we reinterpret the command to the splash screen images field if the command comes from the res.config.settings. - We introduce a context called 'from_settings_view' such that it's set to true when the write is from the `res.config.settings` view. - And specific to the pos_self_order, we compute the items that should be unlinked and we append the unlink commands to the original set of commands for the splash screen field. closes odoo/odoo#137819 Signed-off-by: Robin Heinz (rhe) --- .../models/res_config_settings.py | 2 +- addons/pos_self_order/models/pos_config.py | 19 ++++++++++++++- addons/pos_self_order/tests/test_frontend.py | 24 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/addons/point_of_sale/models/res_config_settings.py b/addons/point_of_sale/models/res_config_settings.py index a30fd024f81..8b5f1bf08f7 100644 --- a/addons/point_of_sale/models/res_config_settings.py +++ b/addons/point_of_sale/models/res_config_settings.py @@ -150,7 +150,7 @@ class ResConfigSettings(models.TransientModel): # STEP: Finally, we write the value of 'pos' fields to 'pos_config_id'. for pos_config_id, pos_fields_vals in pos_config_id_to_fields_vals_map.items(): pos_config = self.env['pos.config'].browse(pos_config_id) - pos_config.write(pos_fields_vals) + pos_config.with_context(from_settings_view=True).write(pos_fields_vals) return result diff --git a/addons/pos_self_order/models/pos_config.py b/addons/pos_self_order/models/pos_config.py index 48146d3fca7..2fba64aa115 100644 --- a/addons/pos_self_order/models/pos_config.py +++ b/addons/pos_self_order/models/pos_config.py @@ -11,7 +11,7 @@ from werkzeug.urls import url_quote from odoo.exceptions import UserError from odoo.tools import image_to_base64 -from odoo import api, fields, models, _, service +from odoo import api, fields, models, _, service, Command from odoo.tools import file_open, split_every @@ -153,6 +153,23 @@ class PosConfig(models.Model): if (not vals.get('module_pos_restaurant') and not record.module_pos_restaurant) and vals.get('self_ordering_mode') == 'mobile': vals['self_ordering_pay_after'] = 'each' + if 'self_ordering_image_home_ids' in vals and self.env.context.get('from_settings_view'): + linked_ids = set(record.self_ordering_image_home_ids.ids) + + # Changes in the splash screen field always results to an array of link commands or a single set command. + # We inspect the commands to determine which attachments should be unlinked. + # We only care about the link command. We can consider set command as absolute as it will replace all. + for command in vals['self_ordering_image_home_ids']: + if command[0] == 4: + _id = command[1] + if _id in linked_ids: + linked_ids.remove(_id) + + # Remaining items in linked_ids should be unlinked. + unlink_commands = [Command.unlink(_id) for _id in linked_ids] + + vals['self_ordering_image_home_ids'] = unlink_commands + vals['self_ordering_image_home_ids'] + return super().write(vals) @api.depends("module_pos_restaurant") diff --git a/addons/pos_self_order/tests/test_frontend.py b/addons/pos_self_order/tests/test_frontend.py index 8549c37a273..969d6b8ec71 100644 --- a/addons/pos_self_order/tests/test_frontend.py +++ b/addons/pos_self_order/tests/test_frontend.py @@ -70,3 +70,27 @@ class TestFrontendMobile(SelfOrderCommonTest): result = response.json() order_id = result['result']['id'] self.assertEqual(self.env['pos.order'].browse(order_id).fiscal_position_id.id, alternative_fp.id) + + def test_properly_delete_splash_screen_images(self): + """ Simulate what is done from the res.config.settings view when removing an image. """ + + self.pos_config.write({ + 'self_ordering_image_home_ids': [ + Command.clear(), + Command.create({'name': 'a1', 'datas': b'blob1234', 'mimetype': 'image/png'}), + Command.create({'name': 'a2', 'datas': b'blob2345', 'mimetype': 'image/png'}), + Command.create({'name': 'a3', 'datas': b'blob3456', 'mimetype': 'image/png'}), + ] + }) + + linked_ids = self.pos_config.self_ordering_image_home_ids.ids + second_id = linked_ids[1] + + # We'll unlink the second image and then save the settings. + # It will be a set of link commands for the images except the one we want to delete. + commands = [Command.link(id) for id in linked_ids if id != second_id] + self.pos_config.with_context(from_settings_view=True).write({ + 'self_ordering_image_home_ids': commands + }) + + self.assertTrue(second_id not in self.pos_config.self_ordering_image_home_ids.ids)