-
-
Notifications
You must be signed in to change notification settings - Fork 698
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4370 from Tecnativa/16.0-ou_add-delivery
[16.0][OU-ADD] delivery: Migration scripts
- Loading branch information
Showing
3 changed files
with
215 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
# 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 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 | ||
|
||
|
||
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 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: | ||
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}" | ||
) | ||
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) |
35 changes: 35 additions & 0 deletions
35
openupgrade_scripts/scripts/delivery/16.0.1.0/upgrade_analysis_work.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
---Models in module 'delivery'--- | ||
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: New feature for indicating to the providers the insurance percentage covered. | ||
|
||
delivery / delivery.carrier / zip_from (char) : DEL | ||
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 | ||
# 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: 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 | ||
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: noupdate=0 records handled by ORM. |