Coverage for src/backend/InvenTree/part/migrations/0056_auto_20201110_1125.py: 32%
65 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1# Generated by Django 3.0.7 on 2020-11-10 11:25
3import logging
5from django.db import migrations
7from moneyed import CURRENCIES
8from django.db import migrations, connection
9from company.models import SupplierPriceBreak
12logger = logging.getLogger('inventree')
15def migrate_currencies(apps, schema_editor):
16 """
17 Migrate from the 'old' method of handling currencies,
18 to the new method which uses the django-money library.
20 Previously, we created a custom Currency model,
21 which was very simplistic.
23 Here we will attempt to map each existing "currency" reference
24 for the SupplierPriceBreak model, to a new django-money compatible currency.
25 """
27 logger.debug("Updating currency references for SupplierPriceBreak model...")
29 # A list of available currency codes
30 currency_codes = CURRENCIES.keys()
32 cursor = connection.cursor()
34 # The 'suffix' field denotes the currency code
35 response = cursor.execute('SELECT id, suffix, description from common_currency;')
37 results = cursor.fetchall()
39 remap = {}
41 for index, row in enumerate(results): # pragma: no cover 41 ↛ 42line 41 didn't jump to line 42 because the loop on line 41 never started
42 pk, suffix, description = row
44 suffix = suffix.strip().upper()
46 if suffix not in currency_codes:
47 print("Missing suffix:", suffix)
49 while suffix not in currency_codes:
50 # Ask the user to input a valid currency
51 print(f"Could not find a valid currency matching '{suffix}'.")
52 print("Please enter a valid currency code")
53 suffix = str(input("> ")).strip()
55 if pk not in remap.keys():
56 remap[pk] = suffix
58 # Now iterate through each PartSellPriceBreak and update the rows
59 response = cursor.execute('SELECT id, cost, currency_id, price, price_currency from part_partsellpricebreak;')
61 results = cursor.fetchall()
63 count = 0
65 for index, row in enumerate(results): # pragma: no cover 65 ↛ 66line 65 didn't jump to line 66 because the loop on line 65 never started
66 pk, cost, currency_id, price, price_currency = row
68 # Copy the 'cost' field across to the 'price' field
69 response = cursor.execute(f'UPDATE part_partsellpricebreak set price={cost} where id={pk};')
71 # Extract the updated currency code
72 currency_code = remap.get(currency_id, 'USD')
74 # Update the currency code
75 response = cursor.execute(f"UPDATE part_partsellpricebreak set price_currency='{currency_code}' where id={pk};")
77 count += 1
79 if count > 0: # pragma: no cover 79 ↛ 80line 79 didn't jump to line 80 because the condition on line 79 was never true
80 print(f"Updated {count} SupplierPriceBreak rows")
82def reverse_currencies(apps, schema_editor): # pragma: no cover
83 """
84 Reverse the "update" process.
86 Here we may be in the situation that the legacy "Currency" table is empty,
87 and so we have to re-populate it based on the new price_currency codes.
88 """
90 print("Reversing currency migration...")
92 cursor = connection.cursor()
94 # Extract a list of currency codes which are in use
95 response = cursor.execute(f'SELECT id, price, price_currency from part_partsellpricebreak;')
97 results = cursor.fetchall()
99 codes_in_use = set()
101 for index, row in enumerate(results):
102 pk, price, code = row
104 codes_in_use.add(code)
106 # Copy the 'price' field back into the 'cost' field
107 response = cursor.execute(f'UPDATE part_partsellpricebreak set cost={price} where id={pk};')
109 # Keep a dict of which currency objects map to which code
110 code_map = {}
112 # For each currency code in use, check if we have a matching Currency object
113 for code in codes_in_use:
114 response = cursor.execute(f"SELECT id, suffix from common_currency where suffix='{code}';")
115 row = cursor.fetchone()
117 if row is not None:
118 # A match exists!
119 pk, suffix = row
120 code_map[suffix] = pk
121 else:
122 # No currency object exists!
123 description = CURRENCIES[code]
125 # Create a new object in the database
126 print(f"Creating new Currency object for {code}")
128 # Construct a query to create a new Currency object
129 query = f"INSERT into common_currency (symbol, suffix, description, value, base) VALUES ('$', '{code}', '{description}', 1.0, False);"
131 response = cursor.execute(query)
133 code_map[code] = cursor.lastrowid
135 # Ok, now we know how each suffix maps to a Currency object
136 for suffix in code_map.keys():
137 pk = code_map[suffix]
139 # Update the table to point to the Currency objects
140 print(f"Currency {suffix} -> pk {pk}")
142 response = cursor.execute(f"UPDATE part_partsellpricebreak set currency_id={pk} where price_currency='{suffix}';")
145class Migration(migrations.Migration):
147 atomic = False
149 dependencies = [
150 ('part', '0055_auto_20201110_1001'),
151 ]
153 operations = [
154 migrations.RunPython(migrate_currencies, reverse_code=reverse_currencies),
155 ]