Coverage for src/backend/InvenTree/company/migrations/0026_auto_20201110_1011.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 10:11
3import logging
4import sys
6from moneyed import CURRENCIES
7from django.db import migrations, connection
8from company.models import SupplierPriceBreak
11logger = logging.getLogger('inventree')
14def migrate_currencies(apps, schema_editor):
15 """
16 Migrate from the 'old' method of handling currencies,
17 to the new method which uses the django-money library.
19 Previously, we created a custom Currency model,
20 which was very simplistic.
22 Here we will attempt to map each existing "currency" reference
23 for the SupplierPriceBreak model, to a new django-money compatible currency.
24 """
26 logger.debug("Updating currency references for SupplierPriceBreak model...")
28 # A list of available currency codes
29 currency_codes = CURRENCIES.keys()
31 cursor = connection.cursor()
33 # The 'suffix' field denotes the currency code
34 response = cursor.execute('SELECT id, suffix, description from common_currency;')
36 results = cursor.fetchall()
38 remap = {}
40 for index, row in enumerate(results): 40 ↛ 41line 40 didn't jump to line 41 because the loop on line 40 never started
41 pk, suffix, description = row
43 suffix = suffix.strip().upper()
45 if suffix not in currency_codes: # pragma: no cover
46 logger.warning(f"Missing suffix: '{suffix}'")
48 while suffix not in currency_codes:
49 # Ask the user to input a valid currency
50 print(f"Could not find a valid currency matching '{suffix}'.")
51 print("Please enter a valid currency code")
52 suffix = str(input("> ")).strip()
54 if pk not in remap.keys():
55 remap[pk] = suffix
57 # Now iterate through each SupplierPriceBreak and update the rows
58 response = cursor.execute('SELECT id, cost, currency_id, price, price_currency from part_supplierpricebreak;')
60 results = cursor.fetchall()
62 count = 0
64 for index, row in enumerate(results): 64 ↛ 65line 64 didn't jump to line 65 because the loop on line 64 never started
65 pk, cost, currency_id, price, price_currency = row
67 # Copy the 'cost' field across to the 'price' field
68 response = cursor.execute(f'UPDATE part_supplierpricebreak set price={cost} where id={pk};')
70 # Extract the updated currency code
71 currency_code = remap.get(currency_id, 'USD')
73 # Update the currency code
74 response = cursor.execute(f"UPDATE part_supplierpricebreak set price_currency= '{currency_code}' where id={pk};")
76 count += 1
78 if count > 0: 78 ↛ 79line 78 didn't jump to line 79 because the condition on line 78 was never true
79 logger.info(f"Updated {count} SupplierPriceBreak rows")
81def reverse_currencies(apps, schema_editor): # pragma: no cover
82 """
83 Reverse the "update" process.
85 Here we may be in the situation that the legacy "Currency" table is empty,
86 and so we have to re-populate it based on the new price_currency codes.
87 """
89 print("Reversing currency migration...")
91 cursor = connection.cursor()
93 # Extract a list of currency codes which are in use
94 response = cursor.execute(f'SELECT id, price, price_currency from part_supplierpricebreak;')
96 results = cursor.fetchall()
98 codes_in_use = set()
100 for index, row in enumerate(results):
101 pk, price, code = row
103 codes_in_use.add(code)
105 # Copy the 'price' field back into the 'cost' field
106 response = cursor.execute(f'UPDATE part_supplierpricebreak set cost={price} where id={pk};')
108 # Keep a dict of which currency objects map to which code
109 code_map = {}
111 # For each currency code in use, check if we have a matching Currency object
112 for code in codes_in_use:
113 response = cursor.execute(f"SELECT id, suffix from common_currency where suffix='{code}';")
114 row = cursor.fetchone()
116 if row is not None:
117 # A match exists!
118 pk, suffix = row
119 code_map[suffix] = pk
120 else:
121 # No currency object exists!
122 description = CURRENCIES[code]
124 # Create a new object in the database
125 print(f"Creating new Currency object for {code}")
127 # Construct a query to create a new Currency object
128 query = f'INSERT into common_currency (symbol, suffix, description, value, base) VALUES ("$", "{code}", "{description}", 1.0, False);'
130 response = cursor.execute(query)
132 code_map[code] = cursor.lastrowid
134 # Ok, now we know how each suffix maps to a Currency object
135 for suffix in code_map.keys():
136 pk = code_map[suffix]
138 # Update the table to point to the Currency objects
139 print(f"Currency {suffix} -> pk {pk}")
141 response = cursor.execute(f"UPDATE part_supplierpricebreak set currency_id={pk} where price_currency='{suffix}';")
144class Migration(migrations.Migration):
146 atomic = False
148 dependencies = [
149 ('company', '0025_auto_20201110_1001'),
150 ]
152 operations = [
153 migrations.RunPython(migrate_currencies, reverse_code=reverse_currencies),
154 ]