From 37ba78d1c2db283380d4aaffbcd859cb70f69c15 Mon Sep 17 00:00:00 2001 From: Iulian <40763147+iulian03@users.noreply.github.com> Date: Tue, 10 Jun 2025 15:30:37 +0300 Subject: [PATCH 1/2] handle fetching disputes for payin (#424) Co-authored-by: Iulian Masar --- mangopay/resources.py | 4 ++++ tests/test_disputes.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/mangopay/resources.py b/mangopay/resources.py index 8570074..9e19abc 100644 --- a/mangopay/resources.py +++ b/mangopay/resources.py @@ -779,6 +779,10 @@ class Meta: verbose_name_plural = 'payins' url = '/payins' + def __init__(self, *args, **kwargs): + super(PayIn, self).__init__(*args, **kwargs) + self.disputes = RelatedManager(self, Dispute) + @classmethod def cast(cls, result): if cls.__name__ == "RecurringPayInCIT": diff --git a/tests/test_disputes.py b/tests/test_disputes.py index 34f0c1b..4dc6cf1 100644 --- a/tests/test_disputes.py +++ b/tests/test_disputes.py @@ -75,6 +75,23 @@ def test_GetDisputesForUser(self): self.assertIsNotNone(disputes) self.assertTrue(disputes) + def test_GetDisputesForPayIn(self): + dispute = None + + for d in self._client_disputes : + if d.initial_transaction_id is not None: + dispute = d + break + + self.assertIsNotNone(dispute, 'Cannot test getting disputes for wallet because there\'s no dispute with transaction ID in the disputes list.') + pay_in = PayIn.get(dispute.initial_transaction_id) + + self.assertIsNotNone(pay_in) + + result = pay_in.disputes.all() + + self.assertIsNotNone(result) + def test_GetDisputesPendingSettlement(self): disputes_pending = Dispute.get_pending_settlement() From f0a8ca4df1ffe65129d9e209e8eedd524bd8e929 Mon Sep 17 00:00:00 2001 From: Iulian <40763147+iulian03@users.noreply.github.com> Date: Tue, 10 Jun 2025 15:32:25 +0300 Subject: [PATCH 2/2] [feature] handle reports v2 (#420) * handle reports v2 * added event types * fixed tests --------- Co-authored-by: Iulian Masar --- mangopay/constants.py | 5 +++- mangopay/fields.py | 26 +++++++++++++++++++- mangopay/resources.py | 26 +++++++++++++++++++- mangopay/utils.py | 27 +++++++++++++++++++++ tests/test_reports_v2.py | 51 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 tests/test_reports_v2.py diff --git a/mangopay/constants.py b/mangopay/constants.py index 689ee50..b211777 100644 --- a/mangopay/constants.py +++ b/mangopay/constants.py @@ -220,7 +220,10 @@ ('INSTANT_CONVERSION_FAILED', 'instant_conversion_failed', 'Instant Conversion Failed'), ('QUOTED_CONVERSION_CREATED', 'quoted_conversion_created', 'Quoted Conversion Created'), ('QUOTED_CONVERSION_SUCCEEDED', 'quoted_conversion_succeeded', 'Quoted Conversion Succeeded'), - ('QUOTED_CONVERSION_FAILED', 'quoted_conversion_failed', 'Quoted Conversion Failed') + ('QUOTED_CONVERSION_FAILED', 'quoted_conversion_failed', 'Quoted Conversion Failed'), + + ('REPORT_GENERATED', 'report_generated', 'Report Generated'), + ('REPORT_FAILED', 'report_failed', 'Report Failed') ) NOTIFICATION_STATUS_CHOICES = Choices( diff --git a/mangopay/fields.py b/mangopay/fields.py index 8a16270..b35a566 100644 --- a/mangopay/fields.py +++ b/mangopay/fields.py @@ -13,7 +13,7 @@ PayinsLinked, ConversionRate, CardInfo, LocalAccountDetails, InternationalAccountDetails, \ VirtualAccountCapabilities, PaymentRef, PendingUserAction, LegalRepresentative, IndividualRecipient, \ BusinessRecipient, RecipientPropertySchema, IndividualRecipientPropertySchema, BusinessRecipientPropertySchema, \ - CompanyNumberValidation + CompanyNumberValidation, ReportFilter class FieldDescriptor(object): @@ -1205,3 +1205,27 @@ def api_value(self, value): } return value + + +class ReportFilterField(Field): + def python_value(self, value): + if value is not None: + return ReportFilter(currency=value.get('Currency', None), user_id=value.get('UserId', None), + wallet_id=value.get('WalletId', None)) + + return value + + def api_value(self, value): + value = super(ReportFilterField, self).api_value(value) + + if isinstance(value, ReportFilter): + result = {} + if value.currency is not None: + result['Currency'] = value.currency + if value.user_id is not None: + result['UserId'] = value.user_id + if value.wallet_id is not None: + result['WalletId'] = value.wallet_id + return result + + return value diff --git a/mangopay/resources.py b/mangopay/resources.py index 9e19abc..760196f 100644 --- a/mangopay/resources.py +++ b/mangopay/resources.py @@ -18,7 +18,7 @@ LocalAccountDetailsField, VirtualAccountCapabilitiesField, PaymentRefField, PendingUserActionField, LegalRepresentativeField, IndividualRecipientField, BusinessRecipientField, RecipientPropertySchemaField, IndividualRecipientPropertySchemaField, - BusinessRecipientPropertySchemaField, CompanyNumberValidationField) + BusinessRecipientPropertySchemaField, CompanyNumberValidationField, ReportFilterField) from .query import InsertQuery, UpdateQuery, SelectQuery, ActionQuery, DeleteQuery @@ -2405,6 +2405,30 @@ class Meta: } +class ReportV2(BaseModel): + creation_date = DateTimeField(api_name='CreationDate') + report_date = DateTimeField(api_name='ReportDate') + status = CharField(api_name='Status') + result_code = CharField(api_name='ResultCode') + result_message = CharField(api_name='ResultMessage') + download_format = CharField(api_name='DownloadFormat', required=True) + download_url = CharField(api_name='DownloadURL') + report_type = CharField(api_name='ReportType', required=True) + sort = CharField(api_name='Sort') + after_date = DateTimeField(api_name='AfterDate', required=True) + before_date = DateTimeField(api_name='BeforeDate', required=True) + filters = ReportFilterField(api_name='Filters') + columns = ListField(api_name='Columns') + + class Meta: + verbose_name = 'reportv2' + verbose_name_plural = 'reportsv2' + url = { + InsertQuery.identifier: '/reporting/reports', + SelectQuery.identifier: '/reporting/reports' + } + + class BankingAlias(BaseModel): tag = CharField(api_name='Tag') credited_user = ForeignKeyField(User, api_name='CreditedUserId') diff --git a/mangopay/utils.py b/mangopay/utils.py index 48aff9e..50a8f04 100644 --- a/mangopay/utils.py +++ b/mangopay/utils.py @@ -1325,3 +1325,30 @@ def to_api_json(self): "IsValid": self.is_valid, "ValidationRules": self.validation_rules } + + +@add_camelcase_aliases +class ReportFilter(object): + def __init__(self, currency=None, user_id=None, wallet_id=None): + self.currency = currency + self.user_id = user_id + self.wallet_id = wallet_id + + def __str__(self): + return 'ReportFilter: %s , %s, %s' % \ + (self.currency, self.user_id, self.wallet_id) + + def __eq__(self, other): + if isinstance(other, ReportFilter): + stat = ((self.currency == other.currency) and + (self.user_id == other.user_id) and + (self.wallet_id == other.wallet_id)) + return stat + return False + + def to_api_json(self): + return { + "Currency": self.currency, + "UserId": self.user_id, + "WalletId": self.wallet_id + } diff --git a/tests/test_reports_v2.py b/tests/test_reports_v2.py new file mode 100644 index 0000000..5aa5da2 --- /dev/null +++ b/tests/test_reports_v2.py @@ -0,0 +1,51 @@ +from mangopay.resources import ReportV2 +from mangopay.utils import ReportFilter +from tests.test_base import BaseTestLive + + +class ReportsV2TestLive(BaseTestLive): + def test_ReportCreate(self): + report = ReportV2() + report.report_type = 'COLLECTED_FEES' + report.download_format = 'CSV' + report.after_date = 1740787200 + report.before_date = 1743544740 + result = report.save() + + self.assertIsNotNone(result) + self.assertTrue(result['id']) + self.assertEqual(result['report_type'], 'COLLECTED_FEES') + self.assertEqual(result['status'], 'PENDING') + + def test_ReportFilteredCreate(self): + report = ReportV2() + report.report_type = 'USER_WALLET_TRANSACTIONS' + report.download_format = 'CSV' + report.after_date = 1740787200 + report.before_date = 1743544740 + report.filters = ReportFilter() + report.filters.currency = 'EUR' + result = report.save() + + self.assertIsNotNone(result) + self.assertTrue(result['id']) + self.assertEqual(result['report_type'], 'USER_WALLET_TRANSACTIONS') + self.assertEqual(result['status'], 'PENDING') + + def test_ReportGet(self): + report = ReportV2() + report.report_type = 'COLLECTED_FEES' + report.download_format = 'CSV' + report.after_date = 1740787200 + report.before_date = 1743544740 + created = report.save() + result = ReportV2.get(created['id']) + + self.assertEqual(report.id, result.id) + + def test_Reports_All(self): + page = ReportV2.all(page=1, per_page=1) + result = page.data + + self.assertIsNotNone(result) + self.assertTrue(len(result) > 0)