Skip to content

Commit bcd5dbe

Browse files
committed
Currency model implementation
1 parent bb166ea commit bcd5dbe

File tree

107 files changed

+1379
-932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+1379
-932
lines changed

src/hope/admin/currency.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.contrib import admin
2+
3+
from hope.admin.utils import HOPEModelAdminBase
4+
from hope.models import Currency
5+
6+
7+
@admin.register(Currency)
8+
class CurrencyAdmin(HOPEModelAdminBase):
9+
list_display = ("code", "name", "is_crypto")
10+
list_filter = ("is_crypto",)
11+
search_fields = ("code", "name")
12+
ordering = ("code",)

src/hope/admin/payment_plan.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class PaymentPlanAdmin(HOPEModelAdminBase, PaymentPlanCeleryTasksMixin):
9090
("business_area", AutoCompleteFilter),
9191
("program_cycle__program", AutoCompleteFilter),
9292
("program_cycle__program__id", ValueFilter),
93-
("currency", AutoCompleteFilter),
93+
("currency__code", AutoCompleteFilter),
9494
("status", ChoicesFieldComboFilter),
9595
("background_action_status", ChoicesFieldComboFilter),
9696
("build_status", ChoicesFieldComboFilter),

src/hope/apps/core/api/views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
GetKoboAssetListSerializer,
2727
KoboAssetObjectSerializer,
2828
)
29-
from hope.apps.core.currencies import CURRENCY_CHOICES
3029
from hope.apps.core.field_attributes.fields_types import TYPE_STRING
3130
from hope.apps.core.languages import Languages
3231
from hope.apps.core.utils import (
@@ -146,7 +145,10 @@ class ChoicesViewSet(ViewSet):
146145
@extend_schema(responses={200: ChoiceSerializer(many=True)})
147146
@action(detail=False, methods=["get"], url_path="currencies")
148147
def currencies(self, request: Request) -> Response:
149-
resp = ChoiceSerializer(to_choice_object([c for c in CURRENCY_CHOICES if c[0] != ""]), many=True).data
148+
from hope.models.currency import Currency
149+
150+
choices = Currency.objects.values_list("code", "name").order_by("code")
151+
resp = ChoiceSerializer(to_choice_object(list(choices)), many=True).data
150152
return Response(resp)
151153

152154
@extend_schema(responses={200: ChoiceSerializer(many=True)})

src/hope/apps/core/field_attributes/core_fields_attributes.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
registration_data_import_query,
3232
)
3333
from hope.apps.core.countries import Countries
34-
from hope.apps.core.currencies import CURRENCY_CHOICES
3534
from hope.apps.core.field_attributes.fields_types import (
3635
_HOUSEHOLD,
3736
_INDIVIDUAL,
@@ -74,7 +73,6 @@
7473
)
7574
from hope.apps.core.languages import Languages
7675
from hope.apps.household.const import (
77-
BLANK,
7876
DATA_SHARING_CHOICES,
7977
DISABILITY_CHOICES,
8078
MARITAL_STATUS_CHOICE,
@@ -89,6 +87,7 @@
8987
WORK_STATUS_CHOICE,
9088
)
9189
from hope.models import Area, Country
90+
from hope.models.currency import Currency
9291
from hope.models.registration_data_import import RegistrationDataImport
9392

9493
logger = logging.getLogger(__name__)
@@ -722,10 +721,9 @@
722721
"required": False,
723722
"label": {"English(EN)": "Which currency will be used for financial questions?"},
724723
"hint": "",
725-
"choices": [
726-
{"label": {"English(EN)": currency_name}, "value": code}
727-
for code, currency_name in CURRENCY_CHOICES
728-
if code != BLANK
724+
"choices": [],
725+
"_choices": lambda *args, **kwargs: [
726+
{"label": {"English(EN)": c.name}, "value": c.code} for c in Currency.objects.all().order_by("code")
729727
],
730728
"associated_with": _HOUSEHOLD,
731729
"xlsx_field": "currency_h_c",

src/hope/apps/core/management/commands/initdemo.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@
4848
"""
4949

5050
from argparse import ArgumentParser
51+
import importlib
5152
import logging
5253
import os
5354
import time
5455
from typing import Any
5556

5657
from constance import config
58+
from django.apps import apps
5759
from django.conf import settings
5860
from django.core.management import BaseCommand, call_command
5961
from django.db import Error, OperationalError, connections
@@ -131,6 +133,9 @@ def _wait_for_database(self) -> None:
131133

132134
def _setup_base_fixtures(self) -> User:
133135
self.stdout.write("Loading fixtures...")
136+
self.stdout.write("Seeding currencies...")
137+
migration = importlib.import_module("hope.apps.core.migrations.0018_migration")
138+
migration.seed_currencies(apps, None)
134139
call_command("generateroles")
135140
generate_unicef_partners()
136141
call_command("loadcountries")
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
from django.db import migrations, models
2+
3+
CURRENCIES = [
4+
("AED", "United Arab Emirates dirham", False),
5+
("AFN", "Afghan afghani", False),
6+
("ALL", "Albanian lek", False),
7+
("AMD", "Armenian dram", False),
8+
("ANG", "Netherlands Antillean guilder", False),
9+
("AOA", "Angolan kwanza", False),
10+
("ARS", "Argentine peso", False),
11+
("AUD", "Australian dollar", False),
12+
("AWG", "Aruban florin", False),
13+
("AZN", "Azerbaijani manat", False),
14+
("BAM", "Bosnia and Herzegovina convertible mark", False),
15+
("BBD", "Barbados dollar", False),
16+
("BDT", "Bangladeshi taka", False),
17+
("BGN", "Bulgarian lev", False),
18+
("BHD", "Bahraini dinar", False),
19+
("BIF", "Burundian franc", False),
20+
("BMD", "Bermudian dollar", False),
21+
("BND", "Brunei dollar", False),
22+
("BOB", "Boliviano", False),
23+
("BOV", "Bolivian Mvdol (funds code)", False),
24+
("BRL", "Brazilian real", False),
25+
("BSD", "Bahamian dollar", False),
26+
("BTN", "Bhutanese ngultrum", False),
27+
("BWP", "Botswana pula", False),
28+
("BYN", "Belarusian ruble", False),
29+
("BZD", "Belize dollar", False),
30+
("CAD", "Canadian dollar", False),
31+
("CDF", "Congolese franc", False),
32+
("CHF", "Swiss franc", False),
33+
("CLP", "Chilean peso", False),
34+
("CNY", "Chinese yuan", False),
35+
("COP", "Colombian peso", False),
36+
("CRC", "Costa Rican colon", False),
37+
("CUC", "Cuban convertible peso", False),
38+
("CUP", "Cuban peso", False),
39+
("CVE", "Cape Verdean escudo", False),
40+
("CZK", "Czech koruna", False),
41+
("DJF", "Djiboutian franc", False),
42+
("DKK", "Danish krone", False),
43+
("DOP", "Dominican peso", False),
44+
("DZD", "Algerian dinar", False),
45+
("EGP", "Egyptian pound", False),
46+
("ERN", "Eritrean nakfa", False),
47+
("ETB", "Ethiopian birr", False),
48+
("EUR", "Euro", False),
49+
("FJD", "Fiji dollar", False),
50+
("FKP", "Falkland Islands pound", False),
51+
("GBP", "Pound sterling", False),
52+
("GEL", "Georgian lari", False),
53+
("GHS", "Ghanaian cedi", False),
54+
("GIP", "Gibraltar pound", False),
55+
("GMD", "Gambian dalasi", False),
56+
("GNF", "Guinean franc", False),
57+
("GTQ", "Guatemalan quetzal", False),
58+
("GYD", "Guyanese dollar", False),
59+
("HKD", "Hong Kong dollar", False),
60+
("HNL", "Honduran lempira", False),
61+
("HRK", "Croatian kuna", False),
62+
("HTG", "Haitian gourde", False),
63+
("HUF", "Hungarian forint", False),
64+
("IDR", "Indonesian rupiah", False),
65+
("ILS", "Israeli new shekel", False),
66+
("INR", "Indian rupee", False),
67+
("IQD", "Iraqi dinar", False),
68+
("IRR", "Iranian rial", False),
69+
("ISK", "Icelandic króna", False),
70+
("JMD", "Jamaican dollar", False),
71+
("JOD", "Jordanian dinar", False),
72+
("JPY", "Japanese yen", False),
73+
("KES", "Kenyan shilling", False),
74+
("KGS", "Kyrgyzstani som", False),
75+
("KHR", "Cambodian riel", False),
76+
("KMF", "Comoro franc", False),
77+
("KPW", "North Korean won", False),
78+
("KRW", "South Korean won", False),
79+
("KWD", "Kuwaiti dinar", False),
80+
("KYD", "Cayman Islands dollar", False),
81+
("KZT", "Kazakhstani tenge", False),
82+
("LAK", "Lao kip", False),
83+
("LBP", "Lebanese pound", False),
84+
("LKR", "Sri Lankan rupee", False),
85+
("LRD", "Liberian dollar", False),
86+
("LSL", "Lesotho loti", False),
87+
("LYD", "Libyan dinar", False),
88+
("MAD", "Moroccan dirham", False),
89+
("MDL", "Moldovan leu", False),
90+
("MGA", "Malagasy ariary", False),
91+
("MKD", "Macedonian denar", False),
92+
("MMK", "Myanmar kyat", False),
93+
("MNT", "Mongolian tögrög", False),
94+
("MOP", "Macanese pataca", False),
95+
("MRU", "Mauritanian ouguiya", False),
96+
("MUR", "Mauritian rupee", False),
97+
("MVR", "Maldivian rufiyaa", False),
98+
("MWK", "Malawian kwacha", False),
99+
("MXN", "Mexican peso", False),
100+
("MYR", "Malaysian ringgit", False),
101+
("MZN", "Mozambican metical", False),
102+
("NAD", "Namibian dollar", False),
103+
("NGN", "Nigerian naira", False),
104+
("NIO", "Nicaraguan córdoba", False),
105+
("NOK", "Norwegian krone", False),
106+
("NPR", "Nepalese rupee", False),
107+
("NZD", "New Zealand dollar", False),
108+
("OMR", "Omani rial", False),
109+
("PAB", "Panamanian balboa", False),
110+
("PEN", "Peruvian sol", False),
111+
("PGK", "Papua New Guinean kina", False),
112+
("PHP", "Philippine peso", False),
113+
("PKR", "Pakistani rupee", False),
114+
("PLN", "Polish złoty", False),
115+
("PYG", "Paraguayan guaraní", False),
116+
("QAR", "Qatari riyal", False),
117+
("RON", "Romanian leu", False),
118+
("RSD", "Serbian dinar", False),
119+
("RUB", "Russian ruble", False),
120+
("RWF", "Rwandan franc", False),
121+
("SAR", "Saudi riyal", False),
122+
("SBD", "Solomon Islands dollar", False),
123+
("SCR", "Seychelles rupee", False),
124+
("SDG", "Sudanese pound", False),
125+
("SEK", "Swedish krona/kronor", False),
126+
("SGD", "Singapore dollar", False),
127+
("SHP", "Saint Helena pound", False),
128+
("SLE", "Sierra Leonean leone", False),
129+
("SOS", "Somali shilling", False),
130+
("SRD", "Surinamese dollar", False),
131+
("SSP", "South Sudanese pound", False),
132+
("STN", "São Tomé and Príncipe dobra", False),
133+
("SVC", "Salvadoran colón", False),
134+
("SYP", "Syrian pound Old", False),
135+
("SYP01", "Syrian pound", False),
136+
("SZL", "Swazi lilangeni", False),
137+
("THB", "Thai baht", False),
138+
("TJS", "Tajikistani somoni", False),
139+
("TMT", "Turkmenistan manat", False),
140+
("TND", "Tunisian dinar", False),
141+
("TOP", "Tongan paʻanga", False),
142+
("TRY", "Turkish lira", False),
143+
("TTD", "Trinidad and Tobago dollar", False),
144+
("TWD", "New Taiwan dollar", False),
145+
("TZS", "Tanzanian shilling", False),
146+
("UAH", "Ukrainian hryvnia", False),
147+
("UGX", "Ugandan shilling", False),
148+
("USD", "United States dollar", False),
149+
("USDC", "USD Coin", True),
150+
("UYU", "Uruguayan peso", False),
151+
("UYW", "Unidad previsional[14]", False),
152+
("UZS", "Uzbekistan som", False),
153+
("VES", "Venezuelan bolívar soberano", False),
154+
("VND", "Vietnamese đồng", False),
155+
("VUV", "Vanuatu vatu", False),
156+
("WST", "Samoan tala", False),
157+
("XAF", "CFA franc BEAC", False),
158+
("XAG", "Silver (one troy ounce)", False),
159+
("XAU", "Gold (one troy ounce)", False),
160+
("XCD", "East Caribbean dollar", False),
161+
("XOF", "CFA franc BCEAO", False),
162+
("XPF", "CFP franc (franc Pacifique)", False),
163+
("YER", "Yemeni rial", False),
164+
("ZAR", "South African rand", False),
165+
("ZMW", "Zambian kwacha", False),
166+
("ZWL", "Zimbabwean dollar", False),
167+
]
168+
169+
170+
def seed_currencies(apps, schema_editor):
171+
Currency = apps.get_model("core", "Currency")
172+
currencies = [Currency(code=code, name=name, is_crypto=is_crypto) for code, name, is_crypto in CURRENCIES]
173+
Currency.objects.bulk_create(currencies)
174+
175+
176+
def reverse_seed(apps, schema_editor):
177+
Currency = apps.get_model("core", "Currency")
178+
Currency.objects.all().delete()
179+
180+
181+
class Migration(migrations.Migration):
182+
dependencies = [
183+
("core", "0017_migration"),
184+
]
185+
186+
operations = [
187+
migrations.CreateModel(
188+
name="Currency",
189+
fields=[
190+
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
191+
("code", models.CharField(db_index=True, max_length=5, unique=True)),
192+
("name", models.CharField(max_length=255)),
193+
(
194+
"is_crypto",
195+
models.BooleanField(default=False, help_text="Whether this is a cryptocurrency (e.g. USDC)"),
196+
),
197+
],
198+
options={
199+
"ordering": ["code"],
200+
"verbose_name_plural": "currencies",
201+
},
202+
),
203+
migrations.RunPython(seed_currencies, reverse_seed),
204+
]

src/hope/apps/core/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
from hope.models.currency import Currency # noqa
12
from hope.models.custom_model_entry import CustomDatabaseScheduler # noqa

src/hope/apps/dashboard/services.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def _get_payment_data(cls, base_queryset: models.QuerySet) -> models.QuerySet:
243243
month=ExtractMonth(date_field),
244244
business_area_name=Coalesce(F("business_area__name"), Value("Unknown Country")),
245245
region_name=Coalesce(F("business_area__region_name"), Value("Unknown Region")),
246-
currency_code=Coalesce(F("currency"), Value("UNK")),
246+
currency_code=Coalesce(F("currency__code"), Value("UNK")),
247247
admin1_name=Coalesce(F("household__admin1__name"), Value("Unknown Admin1")),
248248
program_name=Coalesce(
249249
F("program__name"),
@@ -338,7 +338,7 @@ def _get_payment_plan_counts(
338338
"month": ExtractMonth(date_field),
339339
"business_area_name": Coalesce(F("business_area__name"), Value("Unknown Country")),
340340
"region_name": Coalesce(F("business_area__region_name"), Value("Unknown Region")),
341-
"currency_code": Coalesce(F("currency"), Value("UNK")),
341+
"currency_code": Coalesce(F("currency__code"), Value("UNK")),
342342
"admin1_name": Coalesce(F("household__admin1__name"), Value("Unknown Admin1")),
343343
"program_name": Coalesce(
344344
F("program__name"),

src/hope/apps/grievance/services/data_change/individual_data_update_service.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from hope.apps.household.services.household_recalculate_data import recalculate_data
4747
from hope.apps.utils.phone import is_valid_phone_number
4848
from hope.models import Account, Area, Country, Document, Household, Individual, IndividualIdentity, log_create
49+
from hope.models.currency import Currency
4950

5051

5152
@dataclasses.dataclass
@@ -292,6 +293,8 @@ def _update_household_fields(self, household: Household, only_approved_data: dic
292293
hh_approved_data["country_origin"] = Country.objects.filter(iso_code3=hh_country_origin).first()
293294
if hh_country := hh_approved_data.get("country"):
294295
hh_approved_data["country"] = Country.objects.filter(iso_code3=hh_country).first()
296+
if hh_currency := hh_approved_data.get("currency"):
297+
hh_approved_data["currency"] = Currency.objects.filter(code=hh_currency).first()
295298
admin_area_title = hh_approved_data.pop("admin_area_title", None)
296299
Household.objects.filter(id=household.id).update(**hh_approved_data, updated_at=timezone.now())
297300
updated_household = Household.objects.get(id=household.id)

src/hope/apps/household/api/serializers/household.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class HouseholdListSerializer(serializers.ModelSerializer):
5858
program_name = serializers.CharField(source="program.name")
5959
program_code = serializers.CharField(source="program.code")
6060
facility_name = serializers.CharField(source="facility.name", read_only=True)
61+
currency = serializers.SlugRelatedField(slug_field="code", read_only=True, allow_null=True)
6162

6263
class Meta:
6364
model = Household
@@ -230,6 +231,7 @@ class HouseholdDetailSerializer(AdminUrlSerializerMixin, serializers.ModelSerial
230231
program = serializers.CharField(source="program.name")
231232
country = serializers.CharField(source="country.name", default="")
232233
country_origin = serializers.CharField(source="country_origin.name", default="")
234+
currency = serializers.SlugRelatedField(slug_field="code", read_only=True, allow_null=True)
233235
total_cash_received = serializers.DecimalField(max_digits=64, decimal_places=2)
234236
total_cash_received_usd = serializers.DecimalField(max_digits=64, decimal_places=2)
235237
has_duplicates = serializers.SerializerMethodField()

0 commit comments

Comments
 (0)