Skip to content

Commit 3f2c662

Browse files
committed
Some fixes
2 parents 69f43bd + 8c636de commit 3f2c662

File tree

3 files changed

+136
-46
lines changed

3 files changed

+136
-46
lines changed

src/hope_country_report/apps/hope/models/_inspect.py

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class BusinessArea(HopeModel):
3838
deduplication_batch_duplicates_allowed = models.IntegerField(null=True)
3939
deduplication_golden_record_duplicates_percentage = models.IntegerField(null=True)
4040
deduplication_golden_record_duplicates_allowed = models.IntegerField(null=True)
41-
screen_beneficiary = models.BooleanField(null=True)
4241
deduplication_ignore_withdraw = models.BooleanField(null=True)
4342
biometric_deduplication_threshold = models.FloatField(null=True)
4443
is_accountability_applicable = models.BooleanField(null=True)
@@ -47,6 +46,9 @@ class BusinessArea(HopeModel):
4746
parent = models.ForeignKey(
4847
"self", on_delete=models.DO_NOTHING, related_name="businessarea_parent", blank=True, null=True
4948
)
49+
office_country = models.ForeignKey(
50+
"Country", on_delete=models.DO_NOTHING, related_name="businessarea_office_country", blank=True, null=True
51+
)
5052

5153
class Meta:
5254
managed = False
@@ -76,6 +78,23 @@ class Tenant:
7678
tenant_filter_field: str = "__all__"
7779

7880

81+
class BusinessareaPaymentCountries(HopeModel):
82+
id = models.BigAutoField(primary_key=True)
83+
businessarea = models.ForeignKey(
84+
BusinessArea, on_delete=models.DO_NOTHING, related_name="businessareapaymentcountries_businessarea", null=True
85+
)
86+
country = models.ForeignKey(
87+
"Country", on_delete=models.DO_NOTHING, related_name="businessareapaymentcountries_country", null=True
88+
)
89+
90+
class Meta:
91+
managed = False
92+
db_table = "core_businessarea_payment_countries"
93+
94+
class Tenant:
95+
tenant_filter_field: str = "__all__"
96+
97+
7998
class Businessareapartnerthrough(HopeModel):
8099
id = models.UUIDField(primary_key=True)
81100
created_at = models.DateTimeField(null=True)
@@ -890,35 +909,6 @@ class Tenant:
890909
tenant_filter_field: str = "__all__"
891910

892911

893-
class BankaccountInfo(HopeModel):
894-
id = models.UUIDField(primary_key=True)
895-
rdi_merge_status = models.CharField(max_length=10, null=True)
896-
is_original = models.BooleanField(null=True)
897-
created_at = models.DateTimeField(null=True)
898-
updated_at = models.DateTimeField(null=True)
899-
is_removed = models.BooleanField(null=True)
900-
removed_date = models.DateTimeField(blank=True, null=True)
901-
last_sync_at = models.DateTimeField(blank=True, null=True)
902-
bank_name = models.CharField(max_length=255, null=True)
903-
bank_account_number = models.CharField(max_length=64, null=True)
904-
debit_card_number = models.CharField(max_length=255, null=True)
905-
bank_branch_name = models.CharField(max_length=255, null=True)
906-
account_holder_name = models.CharField(max_length=255, null=True)
907-
copied_from = models.ForeignKey(
908-
"self", on_delete=models.DO_NOTHING, related_name="bankaccountinfo_copied_from", blank=True, null=True
909-
)
910-
individual = models.ForeignKey(
911-
"Individual", on_delete=models.DO_NOTHING, related_name="bankaccountinfo_individual", null=True
912-
)
913-
914-
class Meta:
915-
managed = False
916-
db_table = "household_bankaccountinfo"
917-
918-
class Tenant:
919-
tenant_filter_field: str = "__all__"
920-
921-
922912
class Document(HopeModel):
923913
id = models.UUIDField(primary_key=True)
924914
rdi_merge_status = models.CharField(max_length=10, null=True)
@@ -1140,6 +1130,8 @@ class Household(HopeModel):
11401130
unknown_sex_group_count = models.IntegerField(blank=True, null=True)
11411131
latitude = models.FloatField(blank=True, null=True)
11421132
longitude = models.FloatField(blank=True, null=True)
1133+
collision_flag = models.BooleanField(null=True)
1134+
identification_key = models.CharField(max_length=255, blank=True, null=True)
11431135

11441136
class Meta:
11451137
managed = False
@@ -1149,6 +1141,26 @@ class Tenant:
11491141
tenant_filter_field: str = "__all__"
11501142

11511143

1144+
class HouseholdExtraRdis(HopeModel):
1145+
id = models.BigAutoField(primary_key=True)
1146+
household = models.ForeignKey(
1147+
Household, on_delete=models.DO_NOTHING, related_name="householdextrardis_household", null=True
1148+
)
1149+
registrationdataimport = models.ForeignKey(
1150+
"DataRegistrationdataimport",
1151+
on_delete=models.DO_NOTHING,
1152+
related_name="householdextrardis_registrationdataimport",
1153+
null=True,
1154+
)
1155+
1156+
class Meta:
1157+
managed = False
1158+
db_table = "household_household_extra_rdis"
1159+
1160+
class Tenant:
1161+
tenant_filter_field: str = "__all__"
1162+
1163+
11521164
class HouseholdCollection(HopeModel):
11531165
id = models.BigAutoField(primary_key=True)
11541166
unicef_id = models.CharField(max_length=255, blank=True, null=True)
@@ -1369,7 +1381,7 @@ class Account(HopeModel):
13691381
)
13701382
is_unique = models.BooleanField(null=True)
13711383
account_type = models.ForeignKey(
1372-
"Accounttype", on_delete=models.DO_NOTHING, related_name="account_account_type", blank=True, null=True
1384+
"Accounttype", on_delete=models.DO_NOTHING, related_name="account_account_type", null=True
13731385
)
13741386
number = models.CharField(max_length=256, blank=True, null=True)
13751387
financial_institution = models.ForeignKey(
@@ -2090,6 +2102,8 @@ class Program(HopeModel):
20902102
beneficiary_group = models.ForeignKey(
20912103
Beneficiarygroup, on_delete=models.DO_NOTHING, related_name="program_beneficiary_group", null=True
20922104
)
2105+
collision_detection_enabled = models.BooleanField(null=True)
2106+
collision_detector = models.CharField(max_length=200, blank=True, null=True)
20932107

20942108
class Meta:
20952109
managed = False
@@ -2117,6 +2131,20 @@ class Tenant:
21172131
tenant_filter_field: str = "__all__"
21182132

21192133

2134+
class ProgramSanctionLists(HopeModel):
2135+
id = models.BigAutoField(primary_key=True)
2136+
program = models.ForeignKey(
2137+
Program, on_delete=models.DO_NOTHING, related_name="programsanctionlists_program", null=True
2138+
)
2139+
2140+
class Meta:
2141+
managed = False
2142+
db_table = "program_program_sanction_lists"
2143+
2144+
class Tenant:
2145+
tenant_filter_field: str = "__all__"
2146+
2147+
21202148
class ProgramCycle(HopeModel):
21212149
id = models.UUIDField(primary_key=True)
21222150
created_at = models.DateTimeField(null=True)

src/hope_country_report/apps/power_query/utils.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@
1111
from functools import wraps
1212
from io import BytesIO
1313
from pathlib import Path
14+
from urllib.parse import urljoin
1415

1516
from django.conf import settings
1617
from django.contrib.auth import authenticate
18+
from django.contrib.staticfiles.storage import staticfiles_storage
1719
from django.db.models import QuerySet
1820
from django.http import HttpRequest, HttpResponse
1921
from django.utils.safestring import mark_safe
2022

2123
import fitz
2224
import qrcode
25+
import requests
2326
import tablib
2427
from constance import config
2528
from PIL import ExifTags, Image, ImageDraw, ImageFont
@@ -149,20 +152,37 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
149152
return wrapper
150153

151154

155+
def get_font_url(font_filename: str) -> str:
156+
"""Constructs an absolute URL for a given font file."""
157+
font_path = f"fonts/{font_filename}"
158+
font_url = staticfiles_storage.url(font_path)
159+
if not font_url.startswith(("http://", "https://")):
160+
font_url = urljoin(settings.HOST, font_url)
161+
return font_url
162+
163+
152164
def load_font_for_language(language: str, font_size: int = 12) -> ImageFont.FreeTypeFont:
153-
"""Returns the appropriate font for the given language."""
154-
# Base directory for fonts
155-
base_font_path = Path(settings.STATIC_ROOT) / "fonts"
156-
font_files = {
157-
"arabic": base_font_path / "NotoNaskhArabic-Bold.ttf",
158-
"cyrillic": base_font_path / "FreeSansBold.ttf",
159-
"bengali": base_font_path / "NotoSansBengali-Bold.ttf",
160-
"burmese": base_font_path / "NotoSerifMyanmar-Bold.ttf",
165+
"""Returns the appropriate font for the given language by fetching it from its static URL."""
166+
font_filenames = {
167+
"arabic": "NotoNaskhArabic-Bold.ttf",
168+
"cyrillic": "FreeSansBold.ttf",
169+
"bengali": "NotoSansBengali-Bold.ttf",
170+
"burmese": "NotoSerifMyanmar-Bold.ttf",
161171
}
162172

163-
default_font = base_font_path / "FreeSansBold.ttf"
164-
font_path = font_files.get(language, default_font)
165-
return ImageFont.truetype(str(font_path), size=font_size)
173+
default_font_filename = "FreeSansBold.ttf"
174+
font_filename = font_filenames.get(language, default_font_filename)
175+
font_url = get_font_url(font_filename)
176+
177+
try:
178+
response = requests.get(font_url, timeout=10)
179+
response.raise_for_status()
180+
font_data = BytesIO(response.content)
181+
return ImageFont.truetype(font_data, size=font_size)
182+
except requests.exceptions.RequestException as e:
183+
logger.error(f"Failed to fetch font from {font_url}: {e}")
184+
capture_exception(e)
185+
raise
166186

167187

168188
def get_field_rect(document: fitz.Document, field_name: str) -> tuple[fitz.Rect, int] | None:

tests/power_query/test_pq_utils.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
convert_pdf_to_image_pdf,
2222
dict_hash,
2323
get_field_rect,
24+
get_font_url,
2425
get_sentry_url,
2526
insert_qr_code,
2627
insert_special_image,
@@ -203,7 +204,20 @@ def test_get_field_rect(sample_pdf: fitz.Document) -> None:
203204
assert page_index == 0
204205

205206

206-
def test_insert_special_language_image():
207+
def test_insert_special_language_image(mocked_responses):
208+
expected_font_name = "NotoNaskhArabic-Bold.ttf"
209+
font_url = get_font_url(expected_font_name)
210+
211+
font_file_path = resource_path(f"web/static/fonts/{expected_font_name}")
212+
with open(font_file_path, "rb") as f:
213+
font_content = f.read()
214+
215+
mocked_responses.add(
216+
"GET",
217+
font_url,
218+
body=font_content,
219+
status=200,
220+
)
207221
text = "الافترايفكتس و البريمير و الافد ميدا كومبوزر"
208222
rect = fitz.Rect(0, 0, 200, 200)
209223
language = "arabic"
@@ -219,7 +233,20 @@ def test_convert_pdf_to_image_pdf(sample_pdf):
219233
assert len(new_pdf) == 1
220234

221235

222-
def test_insert_special_image(sample_pdf: fitz.Document) -> None:
236+
def test_insert_special_image(mocked_responses, sample_pdf: fitz.Document) -> None:
237+
expected_font_name = "NotoNaskhArabic-Bold.ttf"
238+
font_url = get_font_url(expected_font_name)
239+
240+
font_file_path = resource_path(f"web/static/fonts/{expected_font_name}")
241+
with open(font_file_path, "rb") as f:
242+
font_content = f.read()
243+
244+
mocked_responses.add(
245+
"GET",
246+
font_url,
247+
body=font_content,
248+
status=200,
249+
)
223250
text_info = {"value": "الافترايفكتس و البريمير و الافد ميدا كومبوزر", "language": "arabic"}
224251
field_name = "Cognome_ar"
225252
page = sample_pdf[0]
@@ -263,9 +290,24 @@ def test_dict_hash():
263290
("unknown_language", "FreeSansBold.ttf"),
264291
],
265292
)
266-
def test_load_font_for_language(language, expected_font_name):
293+
def test_load_font_for_language(mocked_responses, language, expected_font_name):
294+
font_url = get_font_url(expected_font_name)
295+
296+
font_file_path = resource_path(f"web/static/fonts/{expected_font_name}")
297+
with open(font_file_path, "rb") as f:
298+
font_content = f.read()
299+
300+
mocked_responses.add(
301+
"GET",
302+
font_url,
303+
body=font_content,
304+
status=200,
305+
)
306+
267307
font = load_font_for_language(language)
268-
assert Path(font.path).name == expected_font_name
308+
assert font is not None
309+
assert len(mocked_responses.calls) == 1
310+
assert mocked_responses.calls[0].request.url == font_url
269311

270312

271313
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)