Skip to content

Commit e733186

Browse files
committed
chore: imrpove vat validation
Avoid modifing outside objects and store cached data separately. This makes the code cleaner and type-checkable.
1 parent 6ded37b commit e733186

File tree

2 files changed

+39
-26
lines changed

2 files changed

+39
-26
lines changed

weblate_web/payments/validators.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import NotRequired, TypedDict
2+
13
import sentry_sdk
24
from django.core.cache import cache
35
from django.core.exceptions import ValidationError
@@ -7,53 +9,64 @@
79
from zeep.exceptions import Error
810

911

10-
def cache_vies_data(value):
11-
if isinstance(value, str):
12-
value = VATIN.from_str(value)
13-
key = f"VAT-{value}"
14-
data = cache.get(key)
12+
class VatinValidation(TypedDict):
13+
valid: bool
14+
fault_message: NotRequired[str]
15+
fault_code: NotRequired[str]
16+
17+
18+
def cache_vies_data(value: str | VATIN) -> tuple[VATIN, VatinValidation]:
19+
result = value if isinstance(value, VATIN) else VATIN.from_str(value)
20+
key = f"VAT-{result}"
21+
data: VatinValidation | None = cache.get(key)
1522
if data is None:
23+
# Offline validation
1624
try:
17-
value.verify_country_code()
18-
value.verify_regex()
25+
result.verify_country_code()
26+
result.verify_regex()
1927
except ValidationError:
20-
return value
28+
return result, {"valid": False}
29+
30+
# Online validation
2131
try:
22-
data = {}
23-
for item in value.data:
24-
data[item] = value.data[item]
25-
cache.set(key, data, 3600 * 24 * 7)
32+
vies_data = result.data
2633
except Error as error:
2734
data = {
2835
"valid": False,
2936
"fault_code": getattr(error, "code", "other:Error"),
3037
"fault_message": str(error),
3138
}
3239
sentry_sdk.capture_exception()
33-
value.__dict__["vies_data"] = data
40+
else:
41+
data = {
42+
"valid": vies_data.valid,
43+
"fault_code": vies_data.get("fault_code", ""),
44+
"fault_message": vies_data.get("fault_message", ""),
45+
}
46+
cache.set(key, data, 3600 * 24 * 7)
3447

35-
return value
48+
return result, data
3649

3750

38-
def validate_vatin(value) -> None:
39-
value = cache_vies_data(value)
51+
def validate_vatin(value: str | VATIN) -> None:
52+
vatin, vies_data = cache_vies_data(value)
4053
try:
41-
value.verify_country_code()
54+
vatin.verify_country_code()
4255
except ValidationError as error:
4356
msg = _("{} is not a valid country code for any European Union member.")
44-
raise ValidationError(msg.format(value.country_code)) from error
57+
raise ValidationError(msg.format(vatin.country_code)) from error
4558
try:
46-
value.verify_regex()
59+
vatin.verify_regex()
4760
except ValidationError as error:
4861
msg = _("{} does not match the country's VAT ID specifications.")
49-
raise ValidationError(msg.format(value)) from error
62+
raise ValidationError(msg.format(vatin)) from error
5063

51-
if not value.vies_data["valid"]:
64+
if not vies_data["valid"]:
5265
retry_errors = {"MS_UNAVAILABLE", "MS_MAX_CONCURRENT_REQ", "TIMEOUT"}
5366
retry_codes = {"soap:Server", "other:Error", "env:Server"}
5467
if (
55-
value.vies_data.get("fault_message") in retry_errors
56-
or value.vies_data.get("fault_code") in retry_codes
68+
vies_data.get("fault_message") in retry_errors
69+
or vies_data.get("fault_code") in retry_codes
5770
):
5871
msg = format_html(
5972
'{} <a href="{}" target="_blank">{}</a>',
@@ -64,5 +77,5 @@ def validate_vatin(value) -> None:
6477
_("View service status."),
6578
)
6679
else:
67-
msg = _("{} is not a valid VAT ID.").format(value)
80+
msg = _("{} is not a valid VAT ID.").format(vatin)
6881
raise ValidationError(msg)

weblate_web/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ def api_support(request: HttpRequest) -> JsonResponse:
357357
def fetch_vat(request: AuthenticatedHttpRequest) -> JsonResponse:
358358
if "vat" not in request.POST:
359359
raise SuspiciousOperation("Missing needed parameters")
360-
vat = cache_vies_data(request.POST["vat"])
361-
return JsonResponse(data=getattr(vat, "vies_data", {"valid": False}))
360+
_vatin, vies_data = cache_vies_data(request.POST["vat"])
361+
return JsonResponse(data=vies_data)
362362

363363

364364
class PaymentView(FormView, SingleObjectMixin):

0 commit comments

Comments
 (0)