Skip to content

Commit

Permalink
Staging (#65)
Browse files Browse the repository at this point in the history
* hopefix

* rollback ascii fix 203607 (#58)

* 203608 Make Delivery Mechanism Mandatory in Configurations (#59)

* 203615 service provider code (#60)

* 203615 service provider code

* 203615-ServiceProviderCode

* change default

* remove constraint

* Dev 2 staging (#64)

* 203607-export-api (#61)

* 203936 race condition (#62)
  • Loading branch information
domdinicola authored Jun 11, 2024
1 parent 4eceff2 commit 33117a1
Show file tree
Hide file tree
Showing 27 changed files with 408 additions and 66 deletions.
10 changes: 10 additions & 0 deletions src/hope_payment_gateway/api/fsp/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from hope_payment_gateway.apps.gateway.models import (
DeliveryMechanism,
ExportTemplate,
FinancialServiceProvider,
FinancialServiceProviderConfig,
PaymentInstruction,
Expand Down Expand Up @@ -65,3 +66,12 @@ class Meta:
"parent__remote_id": ["exact", "in"],
"status": ["exact", "in"],
}


class ExportTemplateFilter(filters.FilterSet):
class Meta:
model = ExportTemplate
fields = {
"fsp": ["exact"],
"config_key": ["exact"],
}
9 changes: 9 additions & 0 deletions src/hope_payment_gateway/api/fsp/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from hope_payment_gateway.apps.gateway.models import (
DeliveryMechanism,
ExportTemplate,
FinancialServiceProvider,
FinancialServiceProviderConfig,
PaymentInstruction,
Expand Down Expand Up @@ -179,3 +180,11 @@ class Meta:
"payload",
"payout_amount",
)


class ExportTemplateSerializer(serializers.ModelSerializer):
fsp = serializers.PrimaryKeyRelatedField(queryset=FinancialServiceProvider.objects.all())

class Meta:
model = ExportTemplate
fields = ("query", "fsp", "config_key")
30 changes: 30 additions & 0 deletions src/hope_payment_gateway/api/fsp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
from hope_api_auth.views import LoggingAPIViewSet
from hope_payment_gateway.api.fsp.filters import (
DeliveryMechanismFilter,
ExportTemplateFilter,
FinancialServiceProviderConfigFilter,
FinancialServiceProviderFilter,
PaymentInstructionFilter,
PaymentRecordFilter,
)
from hope_payment_gateway.api.fsp.serializers import (
DeliveryMechanismSerializer,
ExportTemplateSerializer,
FinancialServiceProviderConfigSerializer,
FinancialServiceProviderSerializer,
PaymentInstructionSerializer,
Expand All @@ -23,8 +25,11 @@
)
from hope_payment_gateway.apps.core.models import System
from hope_payment_gateway.apps.fsp.western_union.endpoints.cancel import cancel
from hope_payment_gateway.apps.gateway.actions import TemplateExportForm, export_as_template, export_as_template_impl
from hope_payment_gateway.apps.gateway.admin import PaymentInstructionAdmin
from hope_payment_gateway.apps.gateway.models import (
DeliveryMechanism,
ExportTemplate,
FinancialServiceProvider,
FinancialServiceProviderConfig,
PaymentInstruction,
Expand Down Expand Up @@ -131,6 +136,24 @@ def add_records(self, request, remote_id=None):
}
return Response({"remote_id": obj.remote_id, "errors": error_dict}, status=HTTP_400_BAD_REQUEST)

@action(detail=True) # , methods=["post"])
def download(self, request, remote_id=None):

obj = self.get_object()
try:
dm = DeliveryMechanism.objects.get(code=obj.extra.get("delivery_mechanism", None))
export = ExportTemplate.objects.get(
fsp=obj.fsp, config_key=obj.extra.get("config_key", None), delivery_mechanism=dm
)
queryset = PaymentRecord.objects.filter(parent=obj).select_related("parent__fsp")

return export_as_template_impl(
queryset,
export.query.split("\r\n"),
)
except ExportTemplate.DoesNotExist as exc:
return Response({"status_error": str(exc)}, status=HTTP_400_BAD_REQUEST)


class PaymentRecordViewSet(ProtectedMixin, LoggingAPIViewSet):
serializer_class = PaymentRecordSerializer
Expand All @@ -152,3 +175,10 @@ def cancel(self, request):
return Response({"message": "cancel triggered"})
except TransitionNotAllowed as exc:
return Response({"status_error": str(exc)}, status=HTTP_400_BAD_REQUEST)


class ExportTemplateViewSet(ProtectedMixin, LoggingAPIViewSet):
serializer_class = ExportTemplateSerializer
queryset = ExportTemplate.objects.select_related("fsp")
filterset_class = ExportTemplateFilter
search_fields = ("config_key",)
2 changes: 2 additions & 0 deletions src/hope_payment_gateway/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
router.register(r"fsp", views.FinancialServiceProviderViewSet, basename="fsp")
router.register(r"payment_instructions", views.PaymentInstructionViewSet, basename="payment-instruction")
router.register(r"payment_records", views.PaymentRecordViewSet, basename="payment-record")
router.register(r"export_templates", views.ExportTemplateViewSet, basename="export-template")
router.register(r"config", views.ConfigurationViewSet, basename="config")

router.register(r"wu/corridors", wu_views.CorridorViewSet, basename="wu-corridor")
router.register(r"wu/provider_code", wu_views.ServiceProviderCodeViewSet, basename="wu-service-provider-code")


urlpatterns = router.urls
13 changes: 12 additions & 1 deletion src/hope_payment_gateway/api/western_union/filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django_filters import rest_framework as filters

from hope_payment_gateway.apps.fsp.western_union.models import Corridor
from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode


class CorridorFilter(filters.FilterSet):
Expand All @@ -12,3 +12,14 @@ class Meta:
"destination_currency": ["exact"],
"template_code": ["exact"],
}


class ServiceProviderCodeFilter(filters.FilterSet):
class Meta:
model = ServiceProviderCode
fields = {
"description": ["exact", "icontains"],
"code": ["exact", "icontains"],
"country": ["exact"],
"currency": ["exact"],
}
8 changes: 7 additions & 1 deletion src/hope_payment_gateway/api/western_union/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
from rest_framework import serializers

from hope_payment_gateway.apps.fsp.western_union.models import Corridor
from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode


class CorridorSerializer(serializers.ModelSerializer):
class Meta:
model = Corridor
fields = ("id", "description", "destination_country", "destination_currency", "template_code", "template")


class ServiceProviderCodeSerializer(serializers.ModelSerializer):
class Meta:
model = ServiceProviderCode
fields = ("description", "code", "country", "currency")
14 changes: 11 additions & 3 deletions src/hope_payment_gateway/api/western_union/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from rest_framework.viewsets import ModelViewSet

from hope_payment_gateway.api.western_union.filters import CorridorFilter
from hope_payment_gateway.api.western_union.serializers import CorridorSerializer
from hope_payment_gateway.apps.fsp.western_union.models import Corridor
from hope_payment_gateway.api.western_union.filters import CorridorFilter, ServiceProviderCodeFilter
from hope_payment_gateway.api.western_union.serializers import CorridorSerializer, ServiceProviderCodeSerializer
from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode


class ProtectedMixin:
Expand All @@ -16,3 +16,11 @@ class CorridorViewSet(ProtectedMixin, ModelViewSet):

filterset_class = CorridorFilter
search_fields = ["description"]


class ServiceProviderCodeViewSet(ProtectedMixin, ModelViewSet):
serializer_class = ServiceProviderCodeSerializer
queryset = ServiceProviderCode.objects.all()

filterset_class = ServiceProviderCodeFilter
search_fields = ["description", "code"]
2 changes: 0 additions & 2 deletions src/hope_payment_gateway/apps/core/permissions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from django.conf import settings

from constance import config
from rest_framework import permissions

Expand Down
43 changes: 8 additions & 35 deletions src/hope_payment_gateway/apps/fsp/western_union/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
das_origination_currencies,
)
from hope_payment_gateway.apps.fsp.western_union.endpoints.request import requests_request
from hope_payment_gateway.apps.fsp.western_union.models import Corridor
from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode


@admin.register(Corridor)
Expand Down Expand Up @@ -137,38 +137,11 @@ def delivery_option_template(self, request, pk) -> TemplateResponse:
f"PARAM: template_code"
)
context.update(das_delivery_option_template(destination_country, destination_currency, template_code))
if "content" in context:
rows = context["content"]["MTML"]["REPLY"]["DATA_CONTEXT"]["RECORDSET"]["GETDELIVERYOPTIONTEMPLATE"]
template = {}
structure = []
if not obj.template:
for row in rows:
t_index = row["T_INDEX"]
if t_index != "000":
first_value = row["DESCRIPTION"].split(";")[0].split(".")

if len(first_value) == 1:
description = row["DESCRIPTION"].split(";")[2].strip()
base = template
for item in structure[:-1]:
base = base[item]
if not base[structure[-1]]:
base[structure[-1]] = description
elif isinstance(base[structure[-1]], list):
base[structure[-1]].append(description)
else:
base[structure[-1]] = [base[structure[-1]], description]
else:
base = template
structure = first_value
for i in range(len(first_value)):
field = first_value[i]
if i == len(first_value) - 1:
base[field] = None
else:
if field not in base:
base[field] = {}
base = base[field]
obj.template = template
obj.save()
return TemplateResponse(request, "western_union.html", context)


@admin.register(ServiceProviderCode)
class ServiceProviderCodeAdmin(admin.ModelAdmin):
list_display = ("code", "description", "country", "currency")
search_fields = ("code", "description", "country", "currency")
list_filter = ("country", "currency")
6 changes: 3 additions & 3 deletions src/hope_payment_gateway/apps/fsp/western_union/apps.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from django.apps import AppConfig as BaseAppConfig

from hope_payment_gateway.apps.gateway.registry import registry
from hope_payment_gateway.apps.gateway.registry import export_registry, registry


class AppConfig(BaseAppConfig):
name = __name__.rpartition(".")[0]
verbose_name = "Western Union"

def ready(self) -> None:
from .handlers import WesternUnionHandler
from .handlers import CSVExportStrategy, WesternUnionHandler

registry.register(WesternUnionHandler)

export_registry.register(CSVExportStrategy)
from . import tasks # noqa
61 changes: 59 additions & 2 deletions src/hope_payment_gateway/apps/fsp/western_union/endpoints/das.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from hope_payment_gateway.apps.fsp.western_union.endpoints.client import WesternUnionClient
from hope_payment_gateway.apps.fsp.western_union.endpoints.config import unicef
from hope_payment_gateway.apps.fsp.western_union.models import Corridor
from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode


def create_usd():
Expand Down Expand Up @@ -123,6 +123,7 @@ def das_delivery_services(destination_country, destination_currency, create_corr


def das_delivery_option_template(destination_country, destination_currency, template_code):

wu_env = config.WESTERN_UNION_WHITELISTED_ENV
payload = {
"name": "GetDeliveryOptionTemplate",
Expand All @@ -136,4 +137,60 @@ def das_delivery_option_template(destination_country, destination_currency, temp
},
}
client = WesternUnionClient("DAS_Service_H2HService.wsdl")
return client.response_context("DAS_Service", payload, "DAS_Service_H2H", f"SOAP_HTTP_Port_{wu_env}")
context = client.response_context("DAS_Service", payload, "DAS_Service_H2H", f"SOAP_HTTP_Port_{wu_env}")

if "content" in context:
rows = context["content"]["MTML"]["REPLY"]["DATA_CONTEXT"]["RECORDSET"]
template = {}
structure = []
service_provider_code = False
if rows:
try:
obj = Corridor.objects.get(
destination_country=destination_country, destination_currency=destination_currency
)
except Corridor.DoesNotExist:
obj = None
if obj and not obj.template:
for row in rows["GETDELIVERYOPTIONTEMPLATE"]:
t_index = row["T_INDEX"]
if t_index != "000":
first_value = row["DESCRIPTION"].split(";")[0].split(".")

if len(first_value) == 1:
code = row["DESCRIPTION"].split(";")[2].strip()
description = row["DESCRIPTION"].split(";")[3].strip()
base = template
for item in structure[:-1]:
base = base[item]
if not base[structure[-1]]:
base[structure[-1]] = code
elif isinstance(base[structure[-1]], list):
base[structure[-1]].append(code)
else:
base[structure[-1]] = [base[structure[-1]], code]
if service_provider_code:
sp, created = ServiceProviderCode.objects.get_or_create(
code=code,
description=description,
country=destination_country,
currency=destination_currency,
)
else:
base = template
structure = first_value
for i in range(len(first_value)):
field = first_value[i]
if i == len(first_value) - 1:
base[field] = None
else:
if field not in base:
base[field] = {}
base = base[field]
if first_value == ["wallet_details", "service_provider_code"]:
service_provider_code = True
else:
service_provider_code = False
obj.template = template
obj.save()
return context
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import sentry_sdk
from django_fsm import TransitionNotAllowed
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST
from rest_framework.views import APIView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ def create_validation_payload(hope_payload):

receiver = {
"name": {
# "first_name": hope_payload["first_name"],
# "last_name": hope_payload["last_name"],
"first_name": str(hope_payload["first_name"].encode("utf-8"))[2:-1],
"last_name": str(hope_payload["last_name"].encode("utf-8"))[2:-1],
"first_name": hope_payload["first_name"],
"last_name": hope_payload["last_name"],
# "first_name": str(hope_payload["first_name"].encode("utf-8"))[2:-1],
# "last_name": str(hope_payload["last_name"].encode("utf-8"))[2:-1],
"name_type": "D",
},
"contact_phone": phone_number,
Expand Down Expand Up @@ -141,12 +141,13 @@ def send_money(hope_payload):
pr = PaymentRecord.objects.get(record_code=record_code, status=PaymentRecord.PENDING)
except PaymentRecord.DoesNotExist:
return None

try:
payload = create_validation_payload(hope_payload)
response = send_money_validation(payload)
pr.refresh_from_db()
if response["code"] != 200:
pr.message = f"Validation failed: {response['error']}"
pr.success = False
pr.save()
return pr
smv_payload = serialize_object(response["content"])
Expand Down Expand Up @@ -185,6 +186,7 @@ def send_money(hope_payload):
payload[key] = value

response = send_money_store(payload)
pr.refresh_from_db()
if response["code"] == 200:
pr.message, pr.success = "Send Money Store: Success", True
pr.store()
Expand Down
Loading

0 comments on commit 33117a1

Please sign in to comment.