# Generated by Django 3.0.7 on 2020-11-10 10:11 import logging import sys from moneyed import CURRENCIES from django.db import migrations, connection from company.models import SupplierPriceBreak logger = logging.getLogger('inventree') def migrate_currencies(apps, schema_editor): """ Migrate from the 'old' method of handling currencies, to the new method which uses the django-money library. Previously, we created a custom Currency model, which was very simplistic. Here we will attempt to map each existing "currency" reference for the SupplierPriceBreak model, to a new django-money compatible currency. """ logger.info("Updating currency references for SupplierPriceBreak model...") # A list of available currency codes currency_codes = CURRENCIES.keys() cursor = connection.cursor() # The 'suffix' field denotes the currency code response = cursor.execute('SELECT id, suffix, description from common_currency;') results = cursor.fetchall() remap = {} for index, row in enumerate(results): pk, suffix, description = row suffix = suffix.strip().upper() if suffix not in currency_codes: # pragma: no cover logger.warning(f"Missing suffix: '{suffix}'") while suffix not in currency_codes: # Ask the user to input a valid currency print(f"Could not find a valid currency matching '{suffix}'.") print("Please enter a valid currency code") suffix = str(input("> ")).strip() if pk not in remap.keys(): remap[pk] = suffix # Now iterate through each SupplierPriceBreak and update the rows response = cursor.execute('SELECT id, cost, currency_id, price, price_currency from part_supplierpricebreak;') results = cursor.fetchall() count = 0 for index, row in enumerate(results): pk, cost, currency_id, price, price_currency = row # Copy the 'cost' field across to the 'price' field response = cursor.execute(f'UPDATE part_supplierpricebreak set price={cost} where id={pk};') # Extract the updated currency code currency_code = remap.get(currency_id, 'USD') # Update the currency code response = cursor.execute(f"UPDATE part_supplierpricebreak set price_currency= '{currency_code}' where id={pk};") count += 1 if count > 0: logger.info(f"Updated {count} SupplierPriceBreak rows") def reverse_currencies(apps, schema_editor): # pragma: no cover """ Reverse the "update" process. Here we may be in the situation that the legacy "Currency" table is empty, and so we have to re-populate it based on the new price_currency codes. """ print("Reversing currency migration...") cursor = connection.cursor() # Extract a list of currency codes which are in use response = cursor.execute(f'SELECT id, price, price_currency from part_supplierpricebreak;') results = cursor.fetchall() codes_in_use = set() for index, row in enumerate(results): pk, price, code = row codes_in_use.add(code) # Copy the 'price' field back into the 'cost' field response = cursor.execute(f'UPDATE part_supplierpricebreak set cost={price} where id={pk};') # Keep a dict of which currency objects map to which code code_map = {} # For each currency code in use, check if we have a matching Currency object for code in codes_in_use: response = cursor.execute(f"SELECT id, suffix from common_currency where suffix='{code}';") row = cursor.fetchone() if row is not None: # A match exists! pk, suffix = row code_map[suffix] = pk else: # No currency object exists! description = CURRENCIES[code] # Create a new object in the database print(f"Creating new Currency object for {code}") # Construct a query to create a new Currency object query = f'INSERT into common_currency (symbol, suffix, description, value, base) VALUES ("$", "{code}", "{description}", 1.0, False);' response = cursor.execute(query) code_map[code] = cursor.lastrowid # Ok, now we know how each suffix maps to a Currency object for suffix in code_map.keys(): pk = code_map[suffix] # Update the table to point to the Currency objects print(f"Currency {suffix} -> pk {pk}") response = cursor.execute(f"UPDATE part_supplierpricebreak set currency_id={pk} where price_currency='{suffix}';") class Migration(migrations.Migration): atomic = False dependencies = [ ('company', '0025_auto_20201110_1001'), ] operations = [ migrations.RunPython(migrate_currencies, reverse_code=reverse_currencies), ]