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

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

2 

3import logging 

4 

5from django.db import migrations 

6 

7from moneyed import CURRENCIES 

8from django.db import migrations, connection 

9from company.models import SupplierPriceBreak 

10 

11 

12logger = logging.getLogger('inventree') 

13 

14 

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. 

19 

20 Previously, we created a custom Currency model, 

21 which was very simplistic. 

22 

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

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

25 """ 

26 

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

28 

29 # A list of available currency codes 

30 currency_codes = CURRENCIES.keys() 

31 

32 cursor = connection.cursor() 

33 

34 # The 'suffix' field denotes the currency code 

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

36 

37 results = cursor.fetchall() 

38 

39 remap = {} 

40 

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 

43 

44 suffix = suffix.strip().upper() 

45 

46 if suffix not in currency_codes: 

47 print("Missing suffix:", suffix) 

48 

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

54 

55 if pk not in remap.keys(): 

56 remap[pk] = suffix 

57 

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

60 

61 results = cursor.fetchall() 

62 

63 count = 0 

64 

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 

67 

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

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

70 

71 # Extract the updated currency code 

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

73 

74 # Update the currency code 

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

76 

77 count += 1 

78 

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

81 

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

83 """ 

84 Reverse the "update" process. 

85 

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

89 

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

91 

92 cursor = connection.cursor() 

93 

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

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

96 

97 results = cursor.fetchall() 

98 

99 codes_in_use = set() 

100 

101 for index, row in enumerate(results): 

102 pk, price, code = row 

103 

104 codes_in_use.add(code) 

105 

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

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

108 

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

110 code_map = {} 

111 

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

116 

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] 

124 

125 # Create a new object in the database 

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

127 

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

130 

131 response = cursor.execute(query) 

132 

133 code_map[code] = cursor.lastrowid 

134 

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] 

138 

139 # Update the table to point to the Currency objects 

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

141 

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

143 

144 

145class Migration(migrations.Migration): 

146 

147 atomic = False 

148 

149 dependencies = [ 

150 ('part', '0055_auto_20201110_1001'), 

151 ] 

152 

153 operations = [ 

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

155 ]