Skip to content

Commit

Permalink
Merge pull request #4370 from Tecnativa/16.0-ou_add-delivery
Browse files Browse the repository at this point in the history
[16.0][OU-ADD] delivery: Migration scripts
  • Loading branch information
pedrobaeza authored Apr 1, 2024
2 parents 956d6df + 4fc2f4c commit 7057299
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docsource/modules150-160.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Module coverage 15.0 -> 16.0
+-------------------------------------------------+----------------------+-------------------------------------------------+
| |new| data_recycle | | |
+-------------------------------------------------+----------------------+-------------------------------------------------+
| delivery | | |
| delivery | Done | |
+-------------------------------------------------+----------------------+-------------------------------------------------+
| delivery_mondialrelay | |No DB layout changes. |
+-------------------------------------------------+----------------------+-------------------------------------------------+
Expand Down
179 changes: 179 additions & 0 deletions openupgrade_scripts/scripts/delivery/16.0.1.0/post-migration.py
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)
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.

0 comments on commit 7057299

Please sign in to comment.