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

1# Generated by Django 3.0.7 on 2020-11-10 10:11 

2 

3import logging 

4import sys 

5 

6from moneyed import CURRENCIES 

7from django.db import migrations, connection 

8from company.models import SupplierPriceBreak 

9 

10 

11logger = logging.getLogger('inventree') 

12 

13 

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. 

18 

19 Previously, we created a custom Currency model, 

20 which was very simplistic. 

21 

22 Here we will attempt to map each existing "currency" reference 

23 for the SupplierPriceBreak model, to a new django-money compatible currency. 

24 """ 

25 

26 logger.debug("Updating currency references for SupplierPriceBreak model...") 

27 

28 # A list of available currency codes 

29 currency_codes = CURRENCIES.keys() 

30 

31 cursor = connection.cursor() 

32 

33 # The 'suffix' field denotes the currency code 

34 response = cursor.execute('SELECT id, suffix, description from common_currency;') 

35 

36 results = cursor.fetchall() 

37 

38 remap = {} 

39 

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 

42 

43 suffix = suffix.strip().upper() 

44 

45 if suffix not in currency_codes: # pragma: no cover 

46 logger.warning(f"Missing suffix: '{suffix}'") 

47 

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() 

53 

54 if pk not in remap.keys(): 

55 remap[pk] = suffix 

56 

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;') 

59 

60 results = cursor.fetchall() 

61 

62 count = 0 

63 

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 

66 

67 # Copy the 'cost' field across to the 'price' field 

68 response = cursor.execute(f'UPDATE part_supplierpricebreak set price={cost} where id={pk};') 

69 

70 # Extract the updated currency code 

71 currency_code = remap.get(currency_id, 'USD') 

72 

73 # Update the currency code 

74 response = cursor.execute(f"UPDATE part_supplierpricebreak set price_currency= '{currency_code}' where id={pk};") 

75 

76 count += 1 

77 

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") 

80 

81def reverse_currencies(apps, schema_editor): # pragma: no cover 

82 """ 

83 Reverse the "update" process. 

84 

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 """ 

88 

89 print("Reversing currency migration...") 

90 

91 cursor = connection.cursor() 

92 

93 # Extract a list of currency codes which are in use 

94 response = cursor.execute(f'SELECT id, price, price_currency from part_supplierpricebreak;') 

95 

96 results = cursor.fetchall() 

97 

98 codes_in_use = set() 

99 

100 for index, row in enumerate(results): 

101 pk, price, code = row 

102 

103 codes_in_use.add(code) 

104 

105 # Copy the 'price' field back into the 'cost' field 

106 response = cursor.execute(f'UPDATE part_supplierpricebreak set cost={price} where id={pk};') 

107 

108 # Keep a dict of which currency objects map to which code 

109 code_map = {} 

110 

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() 

115 

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] 

123 

124 # Create a new object in the database 

125 print(f"Creating new Currency object for {code}") 

126 

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);' 

129 

130 response = cursor.execute(query) 

131 

132 code_map[code] = cursor.lastrowid 

133 

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] 

137 

138 # Update the table to point to the Currency objects 

139 print(f"Currency {suffix} -> pk {pk}") 

140 

141 response = cursor.execute(f"UPDATE part_supplierpricebreak set currency_id={pk} where price_currency='{suffix}';") 

142 

143 

144class Migration(migrations.Migration): 

145 

146 atomic = False 

147 

148 dependencies = [ 

149 ('company', '0025_auto_20201110_1001'), 

150 ] 

151 

152 operations = [ 

153 migrations.RunPython(migrate_currencies, reverse_code=reverse_currencies), 

154 ]