diff --git a/deployments/forms.py b/deployments/forms.py index 3e646b380..181751bc8 100644 --- a/deployments/forms.py +++ b/deployments/forms.py @@ -25,6 +25,28 @@ ) +def parse_csv_integer(value): + """ + Parse integer columns from 3W project CSV imports. + Decimal strings (e.g. budget amounts like 353873.10) are rounded to the nearest int. + """ + if value is None or value == "": + return None + try: + if isinstance(value, str): + value = value.strip() + if not value: + return None + if "." in value: + return int(round(float(value))) + return int(value) + if isinstance(value, float): + return int(round(value)) + return int(value) + except (ValueError, TypeError): + return None + + class ProjectForm(forms.ModelForm): """ Custom Form For Project @@ -160,13 +182,7 @@ def _parse_date(date, field, row_errors): row_errors[field] = [str(e)] def _parse_integer(integer): - try: - if isinstance(integer, str): - # ALL are integer fields. Change this if not - return int(integer) - return integer - except ValueError: - return None + return parse_csv_integer(integer) file.seek(0) reader = csv.DictReader( diff --git a/deployments/tests.py b/deployments/tests.py index 456f8fac7..dca1a0eba 100644 --- a/deployments/tests.py +++ b/deployments/tests.py @@ -820,3 +820,14 @@ def test_export_response(self): row2 = list(ws.iter_rows(min_row=4))[0] self.assertEqual(row2[0].value, "India") + + +class ParseCsvIntegerTest(APITestCase): + def test_rounds_decimal_strings(self): + from deployments.forms import parse_csv_integer + + self.assertEqual(parse_csv_integer("353873.10"), 353873) + self.assertEqual(parse_csv_integer("353873.60"), 353874) + self.assertEqual(parse_csv_integer("1000"), 1000) + self.assertEqual(parse_csv_integer(""), None) + self.assertEqual(parse_csv_integer("not-a-number"), None)