From a3cfe04da254c960425b20d9bbfe3afbdc3643e3 Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Thu, 31 Aug 2023 10:58:13 +0200 Subject: [PATCH 1/2] [OU-ADD] delivery Signed-off-by: Carmen Bianca BAKKER --- docsource/modules150-160.rst | 2 +- .../delivery/16.0.1.0/post-migration.py | 136 ++++++++++++++++++ .../16.0.1.0/upgrade_analysis_work.txt | 28 ++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py create mode 100644 openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt diff --git a/docsource/modules150-160.rst b/docsource/modules150-160.rst index deecb925c1b0..d064a731dfbd 100644 --- a/docsource/modules150-160.rst +++ b/docsource/modules150-160.rst @@ -116,7 +116,7 @@ Module coverage 15.0 -> 16.0 +-------------------------------------------------+----------------------+-------------------------------------------------+ | |new| data_recycle | | | +-------------------------------------------------+----------------------+-------------------------------------------------+ -| delivery | | | +| delivery | Done | | +-------------------------------------------------+----------------------+-------------------------------------------------+ | delivery_mondialrelay | |No DB layout changes. | +-------------------------------------------------+----------------------+-------------------------------------------------+ diff --git a/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py b/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py new file mode 100644 index 000000000000..b6678318d709 --- /dev/null +++ b/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py @@ -0,0 +1,136 @@ +# SPDX-FileCopyrightText: 2023 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import logging +import string +from inspect import cleandoc + +from openupgradelib import openupgrade + +_logger = logging.getLogger(__name__) + +ALPHANUM = string.digits + string.ascii_uppercase + + +def increment_alphanum(value): + result = [] + carry = False + first = True + for digit in reversed(value): + # Preserve spaces and hyphens + if digit in [" ", "-"]: + result.append(digit) + elif digit == "Z" and (first or carry): + result.append("0") + carry = True + elif carry or first: + result.append(ALPHANUM[ALPHANUM.index(digit) + 1]) + carry = False + else: + result.append(digit) + first = False + if carry: + result.append("1") + return "".join(result[::-1]) + + +def fill_prefix(prefix, length, item, spaces, dashes): + result = prefix + (length * item) + for index in spaces: + result = result[:index] + " " + result[index + 1 :] + for index in dashes: + result = result[:index] + "-" + result[index + 1 :] + return result + + +def prefix_works(prefix, start, end, spaces, dashes): + # Get the highest and lowest values for the prefix, and compare them against + # the two extremes. + fill_length = len(start) - len(prefix) + highest = fill_prefix(prefix, fill_length, "Z", spaces, dashes) + lowest = fill_prefix(prefix, fill_length, "0", spaces, dashes) + return lowest >= start and highest <= end + + +def next_alphanum(prefix, length, end, spaces, dashes): + result = increment_alphanum(prefix) + fill_length = length - len(prefix) + if fill_length: + result = fill_prefix(result, length - len(prefix), "0", spaces, dashes) + if result > end: + return None + return result + + +def find_occurrences(item, iterable): + return [i for i, val in enumerate(iterable) if val == item] + + +def range_to_prefixes(start, end): + if len(start) != len(end): + raise ValueError(f"{start!r} and {end!r} do not have an equal length") + # Implementation detail: It is assumed that spaces and dashes occur in + # identical places in start and end. If this is not true, the whole thing + # doesn't work. + spaces = find_occurrences(" ", start) + dashes = find_occurrences("-", start) + if find_occurrences(" ", end) != spaces or find_occurrences("-", end) != dashes: + raise ValueError( + f"{start!r} and {end!r} do not have spaces or dashes in identical" + f" locations" + ) + + prefixes = set() + not_prefixes = set() + alphanum = start + while alphanum: + prefix = alphanum + candidate = prefix + while prefix: + if prefix in not_prefixes: + break + if prefix_works(prefix, start, end, spaces, dashes): + candidate = prefix + prefix = prefix[:-1] + else: + not_prefixes.add(prefix) + break + prefixes.add(candidate) + alphanum = next_alphanum(candidate, len(start), end, spaces, dashes) + return prefixes + + +@openupgrade.migrate() +def migrate(env, version): + delivery_methods = env["delivery.carrier"].search([]) + if not delivery_methods: + return + _logger.warning( + cleandoc( + """ + TODO: warn that this creates weird results that are technically + correct. + """ + ) + ) + for method in delivery_methods: + try: + prefixes = range_to_prefixes(method.zip_from, method.zip_to) + except Exception as error: + _logger.error( + f"Failed to convert the zip range '{method.zip_from} --" + f" {method.zip_to}'of delivery method {method!r} to a set of" + f" prefixes. Got error:\n\n{error}" + ) + continue + + for prefix in prefixes: + try: + prefix_record = env["delivery.zip.prefix"].create({"name": prefix}) + # TODO: which exception? + except Exception: + prefix_record = env["delivery.zip.prefix"].search( + [("name", "=", prefix)] + ) + method.zip_prefix_ids |= prefix_record diff --git a/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt new file mode 100644 index 000000000000..f74468f54e98 --- /dev/null +++ b/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt @@ -0,0 +1,28 @@ +---Models in module 'delivery'--- +new model delivery.zip.prefix +---Fields in module 'delivery'--- +delivery / delivery.carrier / carrier_description (text) : NEW +delivery / delivery.carrier / shipping_insurance (integer) : NEW hasdefault: default +# NOTHING TO DO +delivery / delivery.carrier / zip_from (char) : DEL +delivery / delivery.carrier / zip_prefix_ids (many2many) : NEW relation: delivery.zip.prefix +delivery / delivery.carrier / zip_to (char) : DEL +delivery / delivery.zip.prefix / name (char) : NEW required +# TODO +delivery / product.template / country_of_origin (many2one) : NEW relation: res.country +delivery / stock.move.line / carrier_name (char) : NEW isrelated: related, stored +# NOTHING TO DO +---XML records in module 'delivery'--- +NEW ir.actions.act_window: delivery.action_delivery_zip_prefix_list +NEW ir.model.access: delivery.access_delivery_carrier_system +NEW ir.model.access: delivery.access_delivery_zip_prefix +NEW ir.model.access: delivery.access_delivery_zip_prefix_stock_manager +NEW ir.model.constraint: delivery.constraint_delivery_carrier_shipping_insurance_is_percentage +NEW ir.model.constraint: delivery.constraint_delivery_zip_prefix_name_uniq +NEW ir.ui.menu: delivery.menu_delivery_zip_prefix +NEW ir.ui.view: delivery.delivery_report_saleorder_document +NEW ir.ui.view: delivery.label_package_template_view_delivery +NEW ir.ui.view: delivery.stock_move_line_view_search_delivery +NEW ir.ui.view: delivery.view_picking_type_form_delivery +NEW ir.ui.view: delivery.view_stock_rule_form_delivery +# NOTHING TO DO From 4fc2f4cfab24a8808d0c23499c793ce8494b49c0 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Mon, 1 Apr 2024 20:17:42 +0200 Subject: [PATCH 2/2] [OU-IMP] delivery: Added specific method for handling numeric ranges The other algorithm is not OK when dealing numeric ranges, as it also generates the prefixes for the rest of the alphanumeric values, when it's clear that we are not wanting such cases (although previous v15 string comparison allowed it without intent). TT43606 --- .../delivery/16.0.1.0/post-migration.py | 109 ++++++++++++------ .../16.0.1.0/upgrade_analysis_work.txt | 17 ++- 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py b/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py index b6678318d709..24d8350eff72 100644 --- a/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py +++ b/openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py @@ -1,10 +1,9 @@ # SPDX-FileCopyrightText: 2023 Coop IT Easy SC -# +# SPDX-FileCopyrightText: 2024 Tecnativa - Pedro M. Baeza # SPDX-License-Identifier: AGPL-3.0-or-later import logging import string -from inspect import cleandoc from openupgradelib import openupgrade @@ -80,7 +79,6 @@ def range_to_prefixes(start, end): f"{start!r} and {end!r} do not have spaces or dashes in identical" f" locations" ) - prefixes = set() not_prefixes = set() alphanum = start @@ -101,36 +99,81 @@ def range_to_prefixes(start, end): return prefixes -@openupgrade.migrate() -def migrate(env, version): - delivery_methods = env["delivery.carrier"].search([]) - if not delivery_methods: - return - _logger.warning( - cleandoc( - """ - TODO: warn that this creates weird results that are technically - correct. - """ - ) +def numerical_range_to_prefixes(min_, max_): + """Adapted from https://github.com/voronind/range-regex.""" + + def fill_by_nines(integer, nines_count): + return int(str(integer)[:-nines_count] + "9" * nines_count) + + def fill_by_zeros(integer, zeros_count): + return integer - integer % 10**zeros_count + + def split_to_ranges(min_, max_): + stops = {max_} + nines_count = 1 + stop = fill_by_nines(min_, nines_count) + while min_ <= stop < max_: + stops.add(stop) + nines_count += 1 + stop = fill_by_nines(min_, nines_count) + zeros_count = 1 + stop = fill_by_zeros(max_ + 1, zeros_count) - 1 + while min_ < stop <= max_: + stops.add(stop) + zeros_count += 1 + stop = fill_by_zeros(max_ + 1, zeros_count) - 1 + stops = list(stops) + stops.sort() + return stops + + subpatterns = [] + start = min_ + for stop in split_to_ranges(min_, max_): + pattern = "" + any_digit_count = 0 + for start_digit, stop_digit in zip(str(start), str(stop)): + if start_digit == stop_digit: + pattern += start_digit + elif start_digit != "0" or stop_digit != "9": + pattern += "[{}-{}]".format(start_digit, stop_digit) + else: + any_digit_count += 1 + if any_digit_count: + pattern += r"\d" + if any_digit_count > 1: + pattern += "{{{}}}".format(any_digit_count) + subpatterns.append(pattern) + start = stop + 1 + return subpatterns + + +def _convert_carrier_zip_ranges(env): + """Transform the previous zip_from and zip_to fields to the new prefixes system.""" + env.cr.execute( + "SELECT id, zip_from, zip_to FROM delivery_carrier " + "WHERE zip_from IS NOT NULL AND zip_to IS NOT NULL" ) - for method in delivery_methods: - try: - prefixes = range_to_prefixes(method.zip_from, method.zip_to) - except Exception as error: - _logger.error( - f"Failed to convert the zip range '{method.zip_from} --" - f" {method.zip_to}'of delivery method {method!r} to a set of" - f" prefixes. Got error:\n\n{error}" - ) - continue - - for prefix in prefixes: + for carrier_id, zip_from, zip_to in env.cr.fetchall(): + if zip_from.isnumeric() and zip_to.isnumeric(): + prefixes = numerical_range_to_prefixes(int(zip_from), int(zip_to)) + else: try: - prefix_record = env["delivery.zip.prefix"].create({"name": prefix}) - # TODO: which exception? - except Exception: - prefix_record = env["delivery.zip.prefix"].search( - [("name", "=", prefix)] + prefixes = range_to_prefixes(zip_from, zip_to) + except Exception as error: + _logger.error( + f"Failed to convert the zip range '{zip_from} --" + f" {zip_to}'of delivery method {carrier_id} to a set of" + f" prefixes. Got error:\n\n{error}" ) - method.zip_prefix_ids |= prefix_record + continue + carrier = env["delivery.carrier"].browse(carrier_id) + for prefix in prefixes: + prefix_record = env["delivery.zip.prefix"].search([("name", "=", prefix)]) + if not prefix_record: + prefix_record = env["delivery.zip.prefix"].create({"name": prefix}) + carrier.zip_prefix_ids |= prefix_record + + +@openupgrade.migrate() +def migrate(env, version): + _convert_carrier_zip_ranges(env) diff --git a/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt index f74468f54e98..14ebdc503b58 100644 --- a/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt +++ b/openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt @@ -2,16 +2,23 @@ new model delivery.zip.prefix ---Fields in module 'delivery'--- delivery / delivery.carrier / carrier_description (text) : NEW +# NOTHING TO DO: New feature for showing in the sales order a description for the delivery method. + delivery / delivery.carrier / shipping_insurance (integer) : NEW hasdefault: default -# NOTHING TO DO +# NOTHING TO DO: New feature for indicating to the providers the insurance percentage covered. + delivery / delivery.carrier / zip_from (char) : DEL -delivery / delivery.carrier / zip_prefix_ids (many2many) : NEW relation: delivery.zip.prefix delivery / delivery.carrier / zip_to (char) : DEL +delivery / delivery.carrier / zip_prefix_ids (many2many) : NEW relation: delivery.zip.prefix delivery / delivery.zip.prefix / name (char) : NEW required -# TODO +# DONE: post-migration: Extract prefixes as regexp. + delivery / product.template / country_of_origin (many2one) : NEW relation: res.country +# NOTHING TO DO: New field for Intrastat. May should be filled from OCA Intrastat modules + delivery / stock.move.line / carrier_name (char) : NEW isrelated: related, stored -# NOTHING TO DO +# NOTHING TO DO: Related stored already handled in a fast way by ORM. + ---XML records in module 'delivery'--- NEW ir.actions.act_window: delivery.action_delivery_zip_prefix_list NEW ir.model.access: delivery.access_delivery_carrier_system @@ -25,4 +32,4 @@ NEW ir.ui.view: delivery.label_package_template_view_delivery NEW ir.ui.view: delivery.stock_move_line_view_search_delivery NEW ir.ui.view: delivery.view_picking_type_form_delivery NEW ir.ui.view: delivery.view_stock_rule_form_delivery -# NOTHING TO DO +# NOTHING TO DO: noupdate=0 records handled by ORM.