From ef749f3fc92b11e69152774ff5f57662c678361e Mon Sep 17 00:00:00 2001 From: Samuel Vasco Date: Tue, 10 Jun 2025 07:20:35 -0400 Subject: [PATCH 1/4] feat: add received payment marked for return event --- unit/__init__.py | 2 ++ unit/models/codecs.py | 2 ++ unit/models/event.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/unit/__init__.py b/unit/__init__.py index 7be2e41..8c40448 100644 --- a/unit/__init__.py +++ b/unit/__init__.py @@ -27,6 +27,7 @@ from unit.api.account_end_of_day_resource import AccountEndOfDayResource from unit.api.reward_resource import RewardResource from unit.api.dispute_resource import DisputeResource +from unit.api.received_payment_resource import ReceivedPaymentResource __all__ = ["api", "models", "utils"] @@ -62,3 +63,4 @@ def __init__(self, api_url, token): self.check_payments = CheckPaymentResource(api_url, token) self.check_stop_payments = CheckStopPaymentResource(api_url, token) self.disputes = DisputeResource(api_url, token) + self.received_payments = ReceivedPaymentResource(api_url, token) diff --git a/unit/models/codecs.py b/unit/models/codecs.py index b8fbec3..9b21cbf 100644 --- a/unit/models/codecs.py +++ b/unit/models/codecs.py @@ -370,6 +370,8 @@ "negativeBalanceCoverageTransaction": lambda _id, _type, attributes, relationships: NegativeBalanceCoverageTransactionDTO.from_json_api(_id, _type, attributes, relationships), + "receivedPayment.markedForReturn": lambda _id, _type, attributes, relationships: + ReceivedPaymentMarkedForReturnEvent.from_json_api(_id, _type, attributes, relationships), } diff --git a/unit/models/event.py b/unit/models/event.py index 64092e2..9b1fa48 100644 --- a/unit/models/event.py +++ b/unit/models/event.py @@ -761,6 +761,48 @@ def from_json_api(_id, _type, attributes, relationships): return DisputeStatusChangedEvent(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["previousStatus"], attributes["newStatus"], attributes.get("tags"), relationships) +class ReceivedPaymentMarkedForReturnEvent(BaseEvent): + def __init__(self, id: str, created_at: datetime, + status: str, + type: str, + amount: int, + completion_date: date, + company_name: str, + counterparty_routing_number: str, + description: str, + trace_number: str, + sec_code: str, + return_cutoff_time: datetime, + can_be_reprocessed: str, + addenda: str, + tags: Optional[Dict[str, str]], + relationships: Optional[Dict[str, Relationship]]): + BaseEvent.__init__(self, id, created_at, tags, relationships) + self.attributes["status"] = status + self.attributes["type"] = type + self.attributes["amount"] = amount + self.attributes["completionDate"] = completion_date + self.attributes["companyName"] = company_name + self.attributes["counterpartyRoutingNumber"] = counterparty_routing_number + self.attributes["description"] = description + self.attributes["traceNumber"] = trace_number + self.attributes["secCode"] = sec_code + self.attributes["returnCutoffTime"] = return_cutoff_time + self.attributes["canBeReprocessed"] = can_be_reprocessed + self.attributes["addenda"] = addenda + + self.type = 'receivedPayment.markedForReturn' + + @staticmethod + def from_json_api(_id, _type, attributes, relationships): + return ReceivedPaymentMarkedForReturnEvent(_id, date_utils.to_datetime(attributes["createdAt"]), + attributes["status"], attributes["type"], attributes["amount"], + attributes["completionDate"], attributes["companyName"], + attributes["counterpartyRoutingNumber"], attributes["description"], + attributes["traceNumber"], attributes["secCode"], + attributes["returnCutoffTime"], attributes["canBeReprocessed"], + attributes["addenda"], attributes.get("tags"), relationships) + EventDTO = Union[ AccountClosedEvent, AccountFrozenEvent, ApplicationDeniedEvent, ApplicationAwaitingDocumentsEvent, From 0159679c326e825cc869473cab923b886e299c6d Mon Sep 17 00:00:00 2001 From: Samuel Vasco Date: Wed, 11 Jun 2025 11:35:55 -0400 Subject: [PATCH 2/4] feat: add reprocess fields and resources --- unit/api/received_payment_resource.py | 8 ++++++++ unit/models/payment.py | 9 ++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/unit/api/received_payment_resource.py b/unit/api/received_payment_resource.py index b453d6a..888fd89 100644 --- a/unit/api/received_payment_resource.py +++ b/unit/api/received_payment_resource.py @@ -38,6 +38,14 @@ def list(self, params: ListReceivedPaymentParams = None) -> Union[UnitResponse[L def advance(self, payment_id: str) -> Union[UnitResponse[AchReceivedPaymentDTO], UnitError]: response = super().post(f"{self.resource}/{payment_id}/advance") + if response.status_code == 200: + data = response.json().get("data") + return UnitResponse[AchReceivedPaymentDTO](DtoDecoder.decode(data), None) + else: + return UnitError.from_json_api(response.json()) + + def reprocess(self, payment_id: str) -> Union[UnitResponse[AchReceivedPaymentDTO], UnitError]: + response = super().post(f"{self.resource}/{payment_id}/reprocess") if response.status_code == 200: data = response.json().get("data") return UnitResponse[AchReceivedPaymentDTO](DtoDecoder.decode(data), None) diff --git a/unit/models/payment.py b/unit/models/payment.py index 984c69b..971b173 100644 --- a/unit/models/payment.py +++ b/unit/models/payment.py @@ -149,13 +149,15 @@ class AchReceivedPaymentDTO(object): def __init__(self, id: str, created_at: datetime, status: AchReceivedPaymentStatus, was_advanced: bool, completion_date: datetime, return_reason: Optional[str], amount: int, description: str, addenda: Optional[str], company_name: str, counterparty_routing_number: str, trace_number: str, - sec_code: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]]): + sec_code: Optional[str], return_cutoff_time: Optional[datetime], can_be_reprocessed: Optional[bool], + tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]]): self.type = "achReceivedPayment" self.attributes = {"createdAt": created_at, "status": status, "wasAdvanced": was_advanced, "completionDate": completion_date, "returnReason": return_reason, "description": description, "amount": amount, "addenda": addenda, "companyName": company_name, "counterpartyRoutingNumber": counterparty_routing_number, "traceNumber": trace_number, - "secCode": sec_code, "tags": tags} + "secCode": sec_code, "returnCutoffTime": return_cutoff_time, "canBeReprocessed": can_be_reprocessed, + "tags": tags} self.relationships = relationships @staticmethod @@ -165,7 +167,8 @@ def from_json_api(_id, _type, attributes, relationships): attributes.get("returnReason"),attributes["amount"], attributes["description"], attributes.get("addenda"), attributes.get("companyName"), attributes.get("counterpartyRoutingNumber"), attributes.get("traceNumber"), - attributes.get("secCode"), attributes.get("tags"), relationships) + attributes.get("secCode"), attributes.get("returnCutoffTime"), attributes.get("canBeReprocessed"), + attributes.get("tags"), relationships) class CreatePaymentBaseRequest(UnitRequest): def __init__(self, amount: int, description: str, relationships: Dict[str, Relationship], From 995c1339f725c330c6a6acee174829dac35f7982 Mon Sep 17 00:00:00 2001 From: Samuel Vasco Date: Wed, 11 Jun 2025 17:24:46 -0400 Subject: [PATCH 3/4] refactor: rename ReceivedPaymentMarkedForReturn to ReceivedPaymentCreated event --- unit/models/codecs.py | 4 ++-- unit/models/event.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/unit/models/codecs.py b/unit/models/codecs.py index 9b21cbf..6e78950 100644 --- a/unit/models/codecs.py +++ b/unit/models/codecs.py @@ -370,8 +370,8 @@ "negativeBalanceCoverageTransaction": lambda _id, _type, attributes, relationships: NegativeBalanceCoverageTransactionDTO.from_json_api(_id, _type, attributes, relationships), - "receivedPayment.markedForReturn": lambda _id, _type, attributes, relationships: - ReceivedPaymentMarkedForReturnEvent.from_json_api(_id, _type, attributes, relationships), + "receivedPayment.created": lambda _id, _type, attributes, relationships: + ReceivedPaymentCreatedEvent.from_json_api(_id, _type, attributes, relationships), } diff --git a/unit/models/event.py b/unit/models/event.py index 9b1fa48..5fe5df4 100644 --- a/unit/models/event.py +++ b/unit/models/event.py @@ -761,7 +761,7 @@ def from_json_api(_id, _type, attributes, relationships): return DisputeStatusChangedEvent(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["previousStatus"], attributes["newStatus"], attributes.get("tags"), relationships) -class ReceivedPaymentMarkedForReturnEvent(BaseEvent): +class ReceivedPaymentCreatedEvent(BaseEvent): def __init__(self, id: str, created_at: datetime, status: str, type: str, @@ -791,11 +791,11 @@ def __init__(self, id: str, created_at: datetime, self.attributes["canBeReprocessed"] = can_be_reprocessed self.attributes["addenda"] = addenda - self.type = 'receivedPayment.markedForReturn' + self.type = 'receivedPayment.created' @staticmethod def from_json_api(_id, _type, attributes, relationships): - return ReceivedPaymentMarkedForReturnEvent(_id, date_utils.to_datetime(attributes["createdAt"]), + return ReceivedPaymentCreatedEvent(_id, date_utils.to_datetime(attributes["createdAt"]), attributes["status"], attributes["type"], attributes["amount"], attributes["completionDate"], attributes["companyName"], attributes["counterpartyRoutingNumber"], attributes["description"], @@ -820,7 +820,7 @@ def from_json_api(_id, _type, attributes, relationships): CustomerCreatedEvent, PaymentClearingEvent, PaymentSentEvent, PaymentReturnedEvent, StatementsCreatedEvent, TransactionCreatedEvent, AccountReopenedEvent, RawUnitObject, StopPaymentCreatedEvent, StopPaymentPaymentStoppedEvent, StopPaymentDisabledEvent, - DisputeCreatedEvent, DisputeStatusChangedEvent, + DisputeCreatedEvent, DisputeStatusChangedEvent, ReceivedPaymentCreatedEvent ] From 16520ea612a44157856fa834951ba2d1c135908e Mon Sep 17 00:00:00 2001 From: Samuel Vasco Date: Mon, 16 Jun 2025 17:03:46 -0400 Subject: [PATCH 4/4] fix: optional fields on received payment created event --- unit/models/event.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/unit/models/event.py b/unit/models/event.py index 5fe5df4..17d421f 100644 --- a/unit/models/event.py +++ b/unit/models/event.py @@ -772,9 +772,9 @@ def __init__(self, id: str, created_at: datetime, description: str, trace_number: str, sec_code: str, - return_cutoff_time: datetime, - can_be_reprocessed: str, - addenda: str, + return_cutoff_time: Optional[datetime], + can_be_reprocessed: Optional[bool], + addenda: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]]): BaseEvent.__init__(self, id, created_at, tags, relationships) @@ -800,8 +800,8 @@ def from_json_api(_id, _type, attributes, relationships): attributes["completionDate"], attributes["companyName"], attributes["counterpartyRoutingNumber"], attributes["description"], attributes["traceNumber"], attributes["secCode"], - attributes["returnCutoffTime"], attributes["canBeReprocessed"], - attributes["addenda"], attributes.get("tags"), relationships) + attributes.get("returnCutoffTime"), attributes.get("canBeReprocessed"), + attributes.get("addenda"), attributes.get("tags"), relationships) EventDTO = Union[