From 3d9748b9cc373cdb194c271259cdcbbf912afa31 Mon Sep 17 00:00:00 2001 From: Iulian Masar Date: Thu, 21 Nov 2024 12:23:29 +0200 Subject: [PATCH 1/2] implemented VirtualAccounts --- mangopay/fields.py | 59 ++++++++++++++++++++++++++++++++++- mangopay/resources.py | 35 ++++++++++++++++++++- mangopay/utils.py | 50 +++++++++++++++++++++++++++++ tests/test_base.py | 15 ++++++++- tests/test_virtual_account.py | 43 +++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 tests/test_virtual_account.py diff --git a/mangopay/fields.py b/mangopay/fields.py index 6e85dde..8460b52 100644 --- a/mangopay/fields.py +++ b/mangopay/fields.py @@ -10,7 +10,7 @@ Reason, ReportTransactionsFilters, ReportWalletsFilters, \ PlatformCategorization, Billing, SecurityInfo, Birthplace, ApplepayPaymentData, GooglepayPaymentData, \ ScopeBlocked, BrowserInfo, Shipping, CurrentState, FallbackReason, InstantPayout, CountryAuthorizationData, \ - PayinsLinked, ConversionRate, CardInfo + PayinsLinked, ConversionRate, CardInfo, LocalAccountDetails, InternationalAccountDetails, VirtualAccountCapabilities class FieldDescriptor(object): @@ -935,3 +935,60 @@ def api_value(self, value): } return value + + +class LocalAccountDetailsField(Field): + def python_value(self, value): + if value is not None: + return LocalAccountDetails(address=value['Address'], account=value['Account']) + return value + + def api_value(self, value): + value = super(LocalAccountDetailsField, self).api_value(value) + + if isinstance(value, LocalAccountDetails): + value = { + 'Address': value.address, + 'Account': value.account + } + + return value + + +class InternationalAccountDetailsField(Field): + def python_value(self, value): + if value is not None: + return InternationalAccountDetails(address=value['Address'], account=value['Account']) + return value + + def api_value(self, value): + value = super(InternationalAccountDetailsField, self).api_value(value) + + if isinstance(value, InternationalAccountDetails): + value = { + 'Address': value.address, + 'Account': value.account + } + + return value + + +class VirtualAccountCapabilitiesField(Field): + def python_value(self, value): + if value is not None: + return VirtualAccountCapabilities(local_pay_in_available=value['LocalPayinAvailable'], + international_pay_in_available=value['InternationalPayinAvailable'], + currencies=value['Currencies']) + return value + + def api_value(self, value): + value = super(VirtualAccountCapabilitiesField, self).api_value(value) + + if isinstance(value, VirtualAccountCapabilities): + value = { + 'LocalPayinAvailable': value.local_pay_in_available, + 'InternationalPayinAvailable': value.international_pay_in_available, + 'Currencies': value.currencies + } + + return value diff --git a/mangopay/resources.py b/mangopay/resources.py index 4d5fc60..21d1b83 100644 --- a/mangopay/resources.py +++ b/mangopay/resources.py @@ -14,7 +14,8 @@ ReportWalletsFiltersField, BillingField, SecurityInfoField, PlatformCategorizationField, BirthplaceField, ApplepayPaymentDataField, GooglepayPaymentDataField, ScopeBlockedField, BrowserInfoField, ShippingField, CurrentStateField, FallbackReasonField, InstantPayoutField, - CountryAuthorizationDataField, PayinsLinkedField, ConversionRateField, CardInfoField) + CountryAuthorizationDataField, PayinsLinkedField, ConversionRateField, CardInfoField, + LocalAccountDetailsField, VirtualAccountCapabilitiesField) from .query import InsertQuery, UpdateQuery, SelectQuery, ActionQuery @@ -2256,3 +2257,35 @@ class Meta: SelectQuery.identifier: '/deposit-preauthorizations/', UpdateQuery.identifier: '/deposit-preauthorizations/' } + + +class VirtualAccount(BaseModel): + wallet_id = CharField(api_name='WalletId', required=True) + credited_user_id = CharField(api_name='CreditedUserId') + virtual_account_purpose = CharField(api_name='VirtualAccountPurpose', required=True) + country = CharField(api_name='Country', required=True) + status = CharField(api_name='Status') + active = BooleanField(api_name='Active') + account_owner = CharField(api_name='AccountOwner') + local_account_details = LocalAccountDetailsField(api_name='LocalAccountDetails') + international_account_details = ListField(api_name='InternationalAccountDetails') + capabilities = VirtualAccountCapabilitiesField(api_name='Capabilities') + + class Meta: + verbose_name = 'virtual_account' + verbose_name_plural = 'virtual_accounts' + + url = '/wallets/%(wallet_id)s/virtual-accounts' + + +class VirtualAccountAvailability(BaseModel): + collection = ListField(api_name='Collection') + user_owned = ListField(api_name='UserOwned') + + class Meta: + verbose_name = 'virtual_account_availability' + verbose_name_plural = 'virtual_account_availabilities' + + url = { + SelectQuery.identifier: '/virtual-accounts/availability' + } diff --git a/mangopay/utils.py b/mangopay/utils.py index b62a961..526baee 100644 --- a/mangopay/utils.py +++ b/mangopay/utils.py @@ -1024,3 +1024,53 @@ def to_api_json(self): "Carrier": self.carrier, "NotifyBuyer": self.notify_buyer } + + +class LocalAccountDetails(object): + def __init__(self, address=None, account=None): + self.address = address + self.account = account + + def __str__(self): + return 'LocalAccountDetails: %s %s' % \ + (self.address, self.account) + + def to_api_json(self): + return { + "Address": self.address, + "Account": self.account + } + + +class InternationalAccountDetails(object): + def __init__(self, address=None, account=None): + self.address = address + self.account = account + + def __str__(self): + return 'InternationalAccountDetails: %s %s' % \ + (self.address, self.account) + + def to_api_json(self): + return { + "Address": self.address, + "Account": self.account + } + + +class VirtualAccountCapabilities(object): + def __init__(self, local_pay_in_available=None, international_pay_in_available=None, currencies=None): + self.local_pay_in_available = local_pay_in_available + self.international_pay_in_available = international_pay_in_available + self.currencies = currencies + + def __str__(self): + return 'VirtualAccountCapabilities: %s %s %s' % \ + (self.local_pay_in_available, self.international_pay_in_available, self.currencies) + + def to_api_json(self): + return { + "LocalPayinAvailable": self.local_pay_in_available, + "InternationalPayinAvailable": self.international_pay_in_available, + "Currencies": self.currencies + } \ No newline at end of file diff --git a/tests/test_base.py b/tests/test_base.py index 34692bb..869a361 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -10,7 +10,8 @@ from mangopay import APIRequest from mangopay import get_default_handler from mangopay.auth import AuthorizationTokenManager, StaticStorageStrategy -from mangopay.resources import BankAccount, Document, ReportTransactions, UboDeclaration, Ubo, Deposit, DirectPayIn +from mangopay.resources import BankAccount, Document, ReportTransactions, UboDeclaration, Ubo, Deposit, DirectPayIn, \ + VirtualAccount from mangopay.utils import Address, ReportTransactionsFilters, Birthplace, BrowserInfo from tests import settings from tests.mocks import RegisteredMocks @@ -619,6 +620,18 @@ def create_new_card_registration_for_deposit(): return CardRegistration(**card_registration.save()) + @staticmethod + def create_new_virtual_account(): + BaseTestLive.get_john() + wallet = BaseTestLive.get_johns_wallet() + + virtual_account = VirtualAccount() + virtual_account.wallet_id = wallet.id + virtual_account.country = 'FR' + virtual_account.virtual_account_purpose = 'COLLECTION' + + return VirtualAccount(**virtual_account.save()) + def test_handler(self): api_url = "test_api_url" sandbox_url = "test_sandbox_url" diff --git a/tests/test_virtual_account.py b/tests/test_virtual_account.py new file mode 100644 index 0000000..8abb3a8 --- /dev/null +++ b/tests/test_virtual_account.py @@ -0,0 +1,43 @@ +from mangopay.resources import VirtualAccount, \ + VirtualAccountAvailability +from tests.test_base import BaseTestLive + + +class VirtualAccountTest(BaseTestLive): + + def test_create_virtual_account(self): + virtual_account = BaseTestLive.create_new_virtual_account() + + self.assertIsNotNone(virtual_account) + self.assertEqual(virtual_account.status, 'ACTIVE') + + def test_get_virtual_account(self): + virtual_account = BaseTestLive.create_new_virtual_account() + wallet = BaseTestLive.get_johns_wallet() + fetched = VirtualAccount.get(virtual_account.id, **{'wallet_id': wallet.id}) + + self.assertIsNotNone(fetched) + self.assertEqual(virtual_account.id, fetched.id) + + def test_get_all_virtual_accounts(self): + BaseTestLive.create_new_virtual_account() + wallet = BaseTestLive.get_johns_wallet() + fetched = VirtualAccount.all(**{'wallet_id': wallet.id}) + + self.assertIsNotNone(fetched) + self.assertEqual(1, len(fetched)) + + def test_deactivate_virtual_account(self): + virtual_account = BaseTestLive.create_new_virtual_account() + wallet = BaseTestLive.get_johns_wallet() + deactivated = VirtualAccount.update(virtual_account.id, **{'wallet_id': wallet.id}) + + self.assertIsNotNone(deactivated) + self.assertEqual(virtual_account.id, deactivated.id) + self.assertEqual(deactivated.status, "CLOSED") + + def test_get_availabilities(self): + availabilities = VirtualAccountAvailability.all() + self.assertIsNotNone(availabilities) + self.assertEqual(1, len(availabilities)) + From 5a3bbd91572a3b36ef25cd08733d910849da4c50 Mon Sep 17 00:00:00 2001 From: Iulian Masar Date: Thu, 21 Nov 2024 23:10:49 +0200 Subject: [PATCH 2/2] updated test --- tests/test_virtual_account.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_virtual_account.py b/tests/test_virtual_account.py index 8abb3a8..0ed0c0a 100644 --- a/tests/test_virtual_account.py +++ b/tests/test_virtual_account.py @@ -30,7 +30,9 @@ def test_get_all_virtual_accounts(self): def test_deactivate_virtual_account(self): virtual_account = BaseTestLive.create_new_virtual_account() wallet = BaseTestLive.get_johns_wallet() - deactivated = VirtualAccount.update(virtual_account.id, **{'wallet_id': wallet.id}) + + result_dict = VirtualAccount.update(virtual_account.id, **{'wallet_id': wallet.id}).execute() + deactivated = VirtualAccount(**result_dict) self.assertIsNotNone(deactivated) self.assertEqual(virtual_account.id, deactivated.id)