From 1cf1e385e9e10c21eb3f9261fd4e2a36185fa497 Mon Sep 17 00:00:00 2001 From: Paulo Souza Date: Tue, 8 Jul 2025 19:56:05 -0300 Subject: [PATCH] Add invoice pull request and invoice pull subscription --- CHANGELOG.md | 6 + README.md | 196 +++++++++++++++++- starkbank/__init__.py | 6 + starkbank/invoicepullrequest/__init__.py | 3 + .../__invoicepullrequest.py | 155 ++++++++++++++ starkbank/invoicepullrequest/log/__init__.py | 1 + starkbank/invoicepullrequest/log/__log.py | 95 +++++++++ starkbank/invoicepullsubscription/__init__.py | 3 + .../__invoicepullsubscription.py | 171 +++++++++++++++ .../invoicepullsubscription/log/__init__.py | 1 + .../invoicepullsubscription/log/__log.py | 95 +++++++++ tests/sdk/test_invoice_pull_request.py | 49 +++++ tests/sdk/test_invoice_pull_request_log.py | 63 ++++++ tests/sdk/test_invoice_pull_subscription.py | 49 +++++ .../sdk/test_invoice_pull_subscription_log.py | 63 ++++++ 15 files changed, 955 insertions(+), 1 deletion(-) create mode 100644 starkbank/invoicepullrequest/__init__.py create mode 100644 starkbank/invoicepullrequest/__invoicepullrequest.py create mode 100644 starkbank/invoicepullrequest/log/__init__.py create mode 100644 starkbank/invoicepullrequest/log/__log.py create mode 100644 starkbank/invoicepullsubscription/__init__.py create mode 100644 starkbank/invoicepullsubscription/__invoicepullsubscription.py create mode 100644 starkbank/invoicepullsubscription/log/__init__.py create mode 100644 starkbank/invoicepullsubscription/log/__log.py create mode 100644 tests/sdk/test_invoice_pull_request.py create mode 100644 tests/sdk/test_invoice_pull_request_log.py create mode 100644 tests/sdk/test_invoice_pull_subscription.py create mode 100644 tests/sdk/test_invoice_pull_subscription_log.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 88364c39..4ebb2c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ Given a version number MAJOR.MINOR.PATCH, increment: ## [Unreleased] +### Added +- InvoicePullRequest resource for requesting payments from subscriptions +- InvoicePullRequest.Log sub-resource +- InvoicePullSubscription resource for creating recurring payment subscriptions +- InvoicePullSubscription.Log sub-resource +- Support for Automatic Pix feature including manual and automatic payment collection ## [2.28.1] - 2025-04-02 ### Added diff --git a/README.md b/README.md index 25e5d15f..ee8ee0c7 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ is as easy as sending a text message to your client! - [DictKeys](#get-dict-key): Pix Key queries to use with Transfers - [Institutions](#query-bacen-institutions): Institutions recognized by the Central Bank - [Invoices](#create-invoices): Reconciled receivables (dynamic Pix QR Codes) + - [InvoicePullRequests](#create-invoicepullrequests): Request payments from subscriptions + - [InvoicePullSubscriptions](#create-invoicepullsubscriptions): Create recurring payment subscriptions - [DynamicBrcode](#create-dynamicbrcodes): Simplified reconciled receivables (dynamic Pix QR Codes) - [Deposits](#query-deposits): Other cash-ins (static Pix QR Codes, DynamicBrcodes, manual Pix, etc) - [Boletos](#create-boletos): Boleto receivables @@ -757,6 +759,192 @@ paymentInformation = starkbank.invoice.payment("5155165527080960") print(paymentInformation) ``` +## Create InvoicePullRequests + +Invoice Pull Requests allow you to request payments from existing subscriptions with specific payment schedules. + +```python +import starkbank +from datetime import datetime, timedelta + +requests = starkbank.invoicepullrequest.create([ + starkbank.InvoicePullRequest( + subscription_id="5656565656565656", # Active subscription ID + invoice_id="4545454545454545", # Valid invoice ID + due=datetime.utcnow() + timedelta(days=3), # Min 2 days in future + attempt_type="default", # Options: "default", "retry" + display_description="Monthly subscription payment", + tags=["subscription", "monthly"], + external_id="unique-external-id-001" + ) +]) + +for request in requests: + print(request) +``` + +**Note**: Instead of using InvoicePullRequest objects, you can also pass each request element in dictionary format + +## Get an InvoicePullRequest + +After its creation, information on an InvoicePullRequest may be retrieved by its id. + +```python +import starkbank + +request = starkbank.invoicepullrequest.get("5155165527080960") + +print(request) +``` + +## Query InvoicePullRequests + +You can query multiple InvoicePullRequests according to filters. + +```python +import starkbank +from datetime import datetime + +requests = starkbank.invoicepullrequest.query( + status=["pending", "scheduled"], + subscription_ids=["5656565656565656"], + after=datetime(2020, 1, 1), + before=datetime(2020, 3, 1) +) + +for request in requests: + print(request) +``` + +## Cancel an InvoicePullRequest + +You can cancel an InvoicePullRequest that is in "pending" or "scheduled" status. + +```python +import starkbank + +request = starkbank.invoicepullrequest.cancel("5155165527080960") + +print(request) +``` + +## Query InvoicePullRequest logs + +Logs help you understand the life cycle of an InvoicePullRequest. + +```python +import starkbank + +logs = starkbank.invoicepullrequest.log.query( + request_ids=["5155165527080960"], + limit=50 +) + +for log in logs: + print(log) +``` + +## Get an InvoicePullRequest log + +You can get a single log by its id. + +```python +import starkbank + +log = starkbank.invoicepullrequest.log.get("5155165527080960") + +print(log) +``` + +## Create InvoicePullSubscriptions + +Invoice Pull Subscriptions allow you to create recurring payment agreements with your customers. These subscriptions define the payment schedule, amounts, and collection methods. + +```python +import starkbank +from datetime import datetime, timedelta + +subscriptions = starkbank.invoicepullsubscription.create([ + starkbank.InvoicePullSubscription( + start=datetime.today() + timedelta(days=1), + interval="month", # Options: "week", "month", "quarter", "semester", "year" + pull_mode="manual", # Options: "manual", "automatic" + pull_retry_limit=3, # Options: 0, 3 + type="qrcode", # Options: "push", "qrcode", "qrcodeAndPayment", "paymentAndOrQrcode" + amount=5000, # R$ 50.00 in cents + display_description="Monthly subscription", + reference_code="SUB-2024-001", + name="John Doe", + tax_id="01234567890", + tags=["subscription", "monthly", "premium"], + external_id="unique-subscription-001" + ) +]) + +for subscription in subscriptions: + print(subscription) +``` + +**Note**: Instead of using InvoicePullSubscription objects, you can also pass each subscription element in dictionary format + +## Get an InvoicePullSubscription + +After its creation, information on an InvoicePullSubscription may be retrieved by its id. + +```python +import starkbank + +subscription = starkbank.invoicepullsubscription.get("5155165527080960") + +print(subscription) +``` + +## Query InvoicePullSubscriptions + +You can query multiple InvoicePullSubscriptions according to filters. + +```python +import starkbank +from datetime import datetime + +subscriptions = starkbank.invoicepullsubscription.query( + status=["active"], + after=datetime(2020, 1, 1), + before=datetime(2020, 3, 1) +) + +for subscription in subscriptions: + print(subscription) +``` + +## Query InvoicePullSubscription logs + +Logs help you understand the life cycle of an InvoicePullSubscription. + +```python +import starkbank + +logs = starkbank.invoicepullsubscription.log.query( + subscription_ids=["5155165527080960"], + limit=50 +) + +for log in logs: + print(log) +``` + +## Get an InvoicePullSubscription log + +You can get a single log by its id. + +```python +import starkbank + +log = starkbank.invoicepullsubscription.log.get("5155165527080960") + +print(log) +``` + ## Create DynamicBrcodes You can create simplified dynamic QR Codes to receive money using Pix transactions. @@ -2550,7 +2738,7 @@ import starkbank webhook = starkbank.webhook.create( url="https://webhook.site/dd784f26-1d6a-4ca6-81cb-fda0267761ec", - subscriptions=["transfer", "boleto", "boleto-payment", "boleto-holmes", "brcode-payment", "utility-payment", "deposit", "invoice"], + subscriptions=["transfer", "boleto", "boleto-payment", "boleto-holmes", "brcode-payment", "utility-payment", "deposit", "invoice", "invoice-pull-request", "invoice-pull-subscription"], ) print(webhook) @@ -2632,6 +2820,12 @@ elif event.subscription == "deposit": elif event.subscription == "invoice": print(event.log.invoice) + +elif event.subscription == "invoice-pull-request": + print(event.log.request) + +elif event.subscription == "invoice-pull-subscription": + print(event.log.subscription) ``` ## Query webhook events diff --git a/starkbank/__init__.py b/starkbank/__init__.py index 80e491f0..ca20b628 100644 --- a/starkbank/__init__.py +++ b/starkbank/__init__.py @@ -106,6 +106,12 @@ from . import invoice from .invoice.__invoice import Invoice +from . import invoicepullrequest +from .invoicepullrequest.__invoicepullrequest import InvoicePullRequest + +from . import invoicepullsubscription +from .invoicepullsubscription.__invoicepullsubscription import InvoicePullSubscription + from . import dictkey from .dictkey.__dictkey import DictKey diff --git a/starkbank/invoicepullrequest/__init__.py b/starkbank/invoicepullrequest/__init__.py new file mode 100644 index 00000000..1062616b --- /dev/null +++ b/starkbank/invoicepullrequest/__init__.py @@ -0,0 +1,3 @@ +from .__invoicepullrequest import create, get, query, page, cancel +from .log.__log import Log +from . import log \ No newline at end of file diff --git a/starkbank/invoicepullrequest/__invoicepullrequest.py b/starkbank/invoicepullrequest/__invoicepullrequest.py new file mode 100644 index 00000000..69b29c13 --- /dev/null +++ b/starkbank/invoicepullrequest/__invoicepullrequest.py @@ -0,0 +1,155 @@ +from ..utils import rest +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_datetime_or_date, check_date + + +class InvoicePullRequest(Resource): + """# InvoicePullRequest object + When you initialize an InvoicePullRequest, the entity will not be automatically + sent to the Stark Bank API. The 'create' function sends the objects + to the Stark Bank API and returns the list of created objects. + ## Parameters (required): + - subscription_id [string]: Unique of the InvoicePullSubscription related to the invoice. ex: "5656565656565656" + - invoice_id [string]: Id of the invoice previously created to be sent for payment. ex: "5656565656565656" + - due [datetime.datetime or string]: payment scheduled date in UTC ISO format. ex: "2023-10-28T17:59:26.249976+00:00" + ## Parameters (optional): + - attempt_type [string, default "default"]: attempt type for the payment. Options: "default", "retry". + - tags [list of strings, default []]: list of strings for tagging + - external_id [string, default None]: a string that must be unique among all your InvoicePullRequests. Duplicated external_ids will cause failures. ex: "my-external-id" + - display_description [string, default None]: Description to be shown to the payer. ex: "Payment for services" + ## Attributes (return-only): + - id [string]: unique id returned when InvoicePullRequest is created. ex: "5656565656565656" + - status [string]: current InvoicePullRequest status. ex: "pending", "scheduled", "success", "failed", "canceled" + - installment_id [string]: unique id of the installment related to this request. ex: "5656565656565656" + - created [datetime.datetime]: creation datetime for the InvoicePullRequest. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + - updated [datetime.datetime]: latest update datetime for the InvoicePullRequest. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, subscription_id, invoice_id, due, attempt_type=None, tags=None, external_id=None, + display_description=None, id=None, status=None, installment_id=None, + created=None, updated=None): + Resource.__init__(self, id=id) + + self.subscription_id = subscription_id + self.invoice_id = invoice_id + self.due = check_datetime_or_date(due) + self.attempt_type = attempt_type + self.tags = tags + self.external_id = external_id + self.display_description = display_description + self.status = status + self.installment_id = installment_id + self.created = check_datetime(created) + self.updated = check_datetime(updated) + + +_resource = {"class": InvoicePullRequest, "name": "InvoicePullRequest"} + + +def create(requests, user=None): + """# Create InvoicePullRequests + Send a list of InvoicePullRequest objects for creation in the Stark Bank API + ## Parameters (required): + - requests [list of InvoicePullRequest objects]: list of InvoicePullRequest objects to be created in the API + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of InvoicePullRequest objects with updated attributes + """ + return rest.post_multi(resource=_resource, entities=requests, user=user) + + +def get(id, user=None): + """# Retrieve a specific InvoicePullRequest + Receive a single InvoicePullRequest object previously created in the Stark Bank API by its id + ## Parameters (required): + - id [string]: object unique id. ex: "5656565656565656" + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - InvoicePullRequest object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, status=None, invoice_ids=None, subscription_ids=None, external_ids=None, + tags=None, ids=None, after=None, before=None, user=None): + """# Retrieve InvoicePullRequests + Receive a generator of InvoicePullRequest objects previously created in the Stark Bank API + ## Parameters (optional): + - limit [integer, default None]: maximum number of objects to be retrieved. Unlimited if None. ex: 35 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - status [list of strings, default None]: filter for status of retrieved objects. ex: ["success", "failed"] + - invoice_ids [list of strings, default None]: list of Invoice ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - subscription_ids [list of strings, default None]: list of InvoicePullSubscription ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - external_ids [list of strings, default None]: list of external_ids to filter retrieved objects. ex: ["my-external-id-1", "my-external-id-2"] + - tags [list of strings, default None]: tags to filter retrieved objects. ex: ["tony", "stark"] + - ids [list of strings, default None]: list of ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - generator of InvoicePullRequest objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + status=status, + invoice_ids=invoice_ids, + subscription_ids=subscription_ids, + external_ids=external_ids, + tags=tags, + ids=ids, + user=user, + ) + + +def page(cursor=None, limit=None, status=None, invoice_ids=None, subscription_ids=None, external_ids=None, + tags=None, ids=None, after=None, before=None, user=None): + """# Retrieve paged InvoicePullRequests + Receive a list of up to 100 InvoicePullRequest objects previously created in the Stark Bank API and the cursor to the next page. + Use this function instead of query if you want to manually page your requests. + ## Parameters (optional): + - cursor [string, default None]: cursor returned on the previous page function call + - limit [integer, default 100]: maximum number of objects to be retrieved. It must be an integer between 1 and 100. ex: 50 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - status [list of strings, default None]: filter for status of retrieved objects. ex: ["success", "failed"] + - invoice_ids [list of strings, default None]: list of Invoice ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - subscription_ids [list of strings, default None]: list of InvoicePullSubscription ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - external_ids [list of strings, default None]: list of external_ids to filter retrieved objects. ex: ["my-external-id-1", "my-external-id-2"] + - tags [list of strings, default None]: tags to filter retrieved objects. ex: ["tony", "stark"] + - ids [list of strings, default None]: list of ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of InvoicePullRequest objects with updated attributes + - cursor to retrieve the next page of InvoicePullRequest objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + status=status, + invoice_ids=invoice_ids, + subscription_ids=subscription_ids, + external_ids=external_ids, + tags=tags, + ids=ids, + user=user, + ) + + +def cancel(id, user=None): + """# Cancel an InvoicePullRequest entity + Cancel an InvoicePullRequest entity previously created in the Stark Bank API + ## Parameters (required): + - id [string]: InvoicePullRequest unique id. ex: '5656565656565656' + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - canceled InvoicePullRequest object + """ + return rest.delete_id(resource=_resource, id=id, user=user) \ No newline at end of file diff --git a/starkbank/invoicepullrequest/log/__init__.py b/starkbank/invoicepullrequest/log/__init__.py new file mode 100644 index 00000000..5fbbba65 --- /dev/null +++ b/starkbank/invoicepullrequest/log/__init__.py @@ -0,0 +1 @@ +from .__log import get, query, page, Log \ No newline at end of file diff --git a/starkbank/invoicepullrequest/log/__log.py b/starkbank/invoicepullrequest/log/__log.py new file mode 100644 index 00000000..d83a6596 --- /dev/null +++ b/starkbank/invoicepullrequest/log/__log.py @@ -0,0 +1,95 @@ +from ...utils import rest +from starkcore.utils.api import from_api_json +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_date +from ..__invoicepullrequest import _resource as _invoice_pull_request_resource + + +class Log(Resource): + """# invoicepullrequest.Log object + Every time an InvoicePullRequest entity is updated, a corresponding invoicepullrequest.Log + is generated for the entity. This log is never generated by the + user, but it can be retrieved to check additional information on the InvoicePullRequest. + ## Attributes (return-only): + - id [string]: unique id returned when the log is created. ex: "5656565656565656" + - request [InvoicePullRequest]: InvoicePullRequest entity to which the log refers to. + - errors [list of strings]: list of errors linked to this InvoicePullRequest event + - type [string]: type of the InvoicePullRequest event which triggered the log creation. ex: "pending" or "success" + - created [datetime.datetime]: creation datetime for the log. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, id, created, type, errors, request): + Resource.__init__(self, id=id) + + self.created = check_datetime(created) + self.type = type + self.errors = errors + self.request = from_api_json(_invoice_pull_request_resource, request) + + +_resource = {"class": Log, "name": "InvoicePullRequestLog"} + + +def get(id, user=None): + """# Retrieve a specific invoicepullrequest.Log + Receive a single invoicepullrequest.Log object previously created by the Stark Bank API by its id + ## Parameters (required): + - id [string]: object unique id. ex: "5656565656565656" + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - invoicepullrequest.Log object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, after=None, before=None, types=None, request_ids=None, user=None): + """# Retrieve invoicepullrequest.Logs + Receive a generator of invoicepullrequest.Log objects previously created in the Stark Bank API + ## Parameters (optional): + - limit [integer, default None]: maximum number of objects to be retrieved. Unlimited if None. ex: 35 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - types [list of strings, default None]: filter for log event types. ex: ["success" or "failed"] + - request_ids [list of strings, default None]: list of InvoicePullRequest ids to filter logs. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - generator of invoicepullrequest.Log objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + request_ids=request_ids, + user=user, + ) + + +def page(cursor=None, after=None, before=None, types=None, request_ids=None, limit=None, user=None): + """# Retrieve paged invoicepullrequest.Logs + Receive a list of up to 100 invoicepullrequest.Log objects previously created in the Stark Bank API and the cursor to the next page. + Use this function instead of query if you want to manually page your requests. + ## Parameters (optional): + - cursor [string, default None]: cursor returned on the previous page function call + - limit [integer, default 100]: maximum number of objects to be retrieved. It must be an integer between 1 and 100. ex: 50 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - types [list of strings, default None]: filter for log event types. ex: ["success" or "failed"] + - request_ids [list of strings, default None]: list of InvoicePullRequest ids to filter logs. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of invoicepullrequest.Log objects with updated attributes + - cursor to retrieve the next page of invoicepullrequest.Log objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + request_ids=request_ids, + user=user, + ) \ No newline at end of file diff --git a/starkbank/invoicepullsubscription/__init__.py b/starkbank/invoicepullsubscription/__init__.py new file mode 100644 index 00000000..87d48671 --- /dev/null +++ b/starkbank/invoicepullsubscription/__init__.py @@ -0,0 +1,3 @@ +from .__invoicepullsubscription import create, get, query, page, cancel +from .log.__log import Log +from . import log \ No newline at end of file diff --git a/starkbank/invoicepullsubscription/__invoicepullsubscription.py b/starkbank/invoicepullsubscription/__invoicepullsubscription.py new file mode 100644 index 00000000..0b5a30e4 --- /dev/null +++ b/starkbank/invoicepullsubscription/__invoicepullsubscription.py @@ -0,0 +1,171 @@ +from ..utils import rest +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_datetime_or_date, check_date + + +class InvoicePullSubscription(Resource): + """# InvoicePullSubscription object + When you initialize an InvoicePullSubscription, the entity will not be automatically + sent to the Stark Bank API. The 'create' function sends the objects + to the Stark Bank API and returns the list of created objects. + ## Parameters (required): + - start [datetime.date or string]: subscription start date. ex: "2022-04-01" + - interval [string]: subscription installment interval. Options: "week", "month", "quarter", "semester", "year" + - pull_mode [string]: subscription pull mode. Options: "manual", "automatic". Automatic mode will create the Invoice Pull Requests automatically + - pull_retry_limit [integer]: subscription pull retry limit. Options: 0, 3 + - type [string]: subscription type. Options: "push", "qrcode", "qrcodeAndPayment", "paymentAndOrQrcode" + ## Parameters (conditionally required): + - amount [integer, default 0]: subscription amount in cents. Required if an amount_min_limit is not informed. Minimum = 1 (R$ 0.01). ex: 100 (= R$ 1.00) + - amount_min_limit [integer, 0 None]: subscription minimum amount in cents. Required if an amount is not informed. Minimum = 1 (R$ 0.01). ex: 100 (= R$ 1.00) + ## Parameters (optional): + - display_description [string, default None]: Invoice description to be shown to the payer. ex: "Subscription payment" + - due [datetime.timedelta or integer, default None]: subscription invoice due offset. Available only for type "push". ex: timedelta(days=7) + - external_id [string, default None]: string that must be unique among all your InvoicePullSubscriptions. Duplicated external_ids will cause failures. ex: "my-external-id" + - reference_code [string, default None]: reference code for reconciliation. ex: "REF123456" + - end [datetime.date or string, default None]: subscription end date. ex: "2023-04-01" + - data [dictionary, default None]: additional data for the subscription based on type + - name [string, default None]: subscription debtor name. ex: "Iron Bank S.A." + - tax_id [string, default None]: subscription debtor tax ID (CPF or CNPJ) with or without formatting. ex: "01234567890" or "20.018.183/0001-80" + - tags [list of strings, default []]: list of strings for tagging + ## Attributes (return-only): + - id [string]: unique id returned when InvoicePullSubscription is created. ex: "5656565656565656" + - status [string]: current InvoicePullSubscription status. ex: "active", "canceled" + - bacen_id [string]: unique authentication id at the Central Bank. ex: "RR2001818320250616dtsPkBVaBYs" + - brcode [string]: Brcode string for the InvoicePullSubscription. ex: "00020101021126580014br.gov.bcb.pix0114+5599999999990210starkbank.com.br520400005303986540410000000000005802BR5913Stark Bank S.A.6009SAO PAULO62070503***6304D2B1" + - created [datetime.datetime]: creation datetime for the InvoicePullSubscription. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + - updated [datetime.datetime]: latest update datetime for the InvoicePullSubscription. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, start, interval, pull_mode, pull_retry_limit, type, amount=None, amount_min_limit=None, + display_description=None, due=None, external_id=None, reference_code=None, end=None, data=None, + name=None, tax_id=None, tags=None, id=None, status=None, bacen_id=None, created=None, updated=None): + Resource.__init__(self, id=id) + + self.start = check_datetime_or_date(start) + self.interval = interval + self.pull_mode = pull_mode + self.pull_retry_limit = pull_retry_limit + self.type = type + self.amount = amount + self.amount_min_limit = amount_min_limit + self.display_description = display_description + self.due = due + self.external_id = external_id + self.reference_code = reference_code + self.end = check_datetime_or_date(end) + self.data = data + self.name = name + self.tax_id = tax_id + self.tags = tags + self.status = status + self.bacen_id = bacen_id + self.created = check_datetime(created) + self.updated = check_datetime(updated) + + +_resource = {"class": InvoicePullSubscription, "name": "InvoicePullSubscription"} + + +def create(subscriptions, user=None): + """# Create InvoicePullSubscriptions + Send a list of InvoicePullSubscription objects for creation in the Stark Bank API + ## Parameters (required): + - subscriptions [list of InvoicePullSubscription objects]: list of InvoicePullSubscription objects to be created in the API + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of InvoicePullSubscription objects with updated attributes + """ + return rest.post_multi(resource=_resource, entities=subscriptions, user=user) + + +def get(id, user=None): + """# Retrieve a specific InvoicePullSubscription + Receive a single InvoicePullSubscription object previously created in the Stark Bank API by its id + ## Parameters (required): + - id [string]: object unique id. ex: "5656565656565656" + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - InvoicePullSubscription object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, status=None, invoice_ids=None, external_ids=None, tags=None, + ids=None, after=None, before=None, user=None): + """# Retrieve InvoicePullSubscriptions + Receive a generator of InvoicePullSubscription objects previously created in the Stark Bank API + ## Parameters (optional): + - limit [integer, default None]: maximum number of objects to be retrieved. Unlimited if None. ex: 35 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - status [list of strings, default None]: filter for status of retrieved objects. ex: ["active", "canceled"] + - invoice_ids [list of strings, default None]: list of Invoice ids linked to the subscriptions. ex: ["5656565656565656", "4545454545454545"] + - external_ids [list of strings, default None]: list of external_ids to filter retrieved objects. ex: ["my-external-id-1", "my-external-id-2"] + - tags [list of strings, default None]: tags to filter retrieved objects. ex: ["tony", "stark"] + - ids [list of strings, default None]: list of ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - generator of InvoicePullSubscription objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + status=status, + invoice_ids=invoice_ids, + external_ids=external_ids, + tags=tags, + ids=ids, + user=user, + ) + + +def page(cursor=None, limit=None, status=None, invoice_ids=None, external_ids=None, + tags=None, ids=None, after=None, before=None, user=None): + """# Retrieve paged InvoicePullSubscriptions + Receive a list of up to 100 InvoicePullSubscription objects previously created in the Stark Bank API and the cursor to the next page. + Use this function instead of query if you want to manually page your requests. + ## Parameters (optional): + - cursor [string, default None]: cursor returned on the previous page function call + - limit [integer, default 100]: maximum number of objects to be retrieved. It must be an integer between 1 and 100. ex: 50 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - status [list of strings, default None]: filter for status of retrieved objects. ex: ["active", "canceled"] + - invoice_ids [list of strings, default None]: list of Invoice ids linked to the subscriptions. ex: ["5656565656565656", "4545454545454545"] + - external_ids [list of strings, default None]: list of external_ids to filter retrieved objects. ex: ["my-external-id-1", "my-external-id-2"] + - tags [list of strings, default None]: tags to filter retrieved objects. ex: ["tony", "stark"] + - ids [list of strings, default None]: list of ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of InvoicePullSubscription objects with updated attributes + - cursor to retrieve the next page of InvoicePullSubscription objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + status=status, + invoice_ids=invoice_ids, + external_ids=external_ids, + tags=tags, + ids=ids, + user=user, + ) + + +def cancel(id, user=None): + """# Cancel an InvoicePullSubscription entity + Cancel an InvoicePullSubscription entity previously created in the Stark Bank API + ## Parameters (required): + - id [string]: InvoicePullSubscription unique id. ex: '5656565656565656' + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - canceled InvoicePullSubscription object + """ + return rest.delete_id(resource=_resource, id=id, user=user) diff --git a/starkbank/invoicepullsubscription/log/__init__.py b/starkbank/invoicepullsubscription/log/__init__.py new file mode 100644 index 00000000..5fbbba65 --- /dev/null +++ b/starkbank/invoicepullsubscription/log/__init__.py @@ -0,0 +1 @@ +from .__log import get, query, page, Log \ No newline at end of file diff --git a/starkbank/invoicepullsubscription/log/__log.py b/starkbank/invoicepullsubscription/log/__log.py new file mode 100644 index 00000000..c138f729 --- /dev/null +++ b/starkbank/invoicepullsubscription/log/__log.py @@ -0,0 +1,95 @@ +from ...utils import rest +from starkcore.utils.api import from_api_json +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_date +from ..__invoicepullsubscription import _resource as _invoice_pull_subscription_resource + + +class Log(Resource): + """# invoicepullsubscription.Log object + Every time an InvoicePullSubscription entity is updated, a corresponding invoicepullsubscription.Log + is generated for the entity. This log is never generated by the + user, but it can be retrieved to check additional information on the InvoicePullSubscription. + ## Attributes (return-only): + - id [string]: unique id returned when the log is created. ex: "5656565656565656" + - subscription [InvoicePullSubscription]: InvoicePullSubscription entity to which the log refers to. + - errors [list of strings]: list of errors linked to this InvoicePullSubscription event + - type [string]: type of the InvoicePullSubscription event which triggered the log creation. ex: "active" or "canceled" + - created [datetime.datetime]: creation datetime for the log. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, id, created, type, errors, subscription): + Resource.__init__(self, id=id) + + self.created = check_datetime(created) + self.type = type + self.errors = errors + self.subscription = from_api_json(_invoice_pull_subscription_resource, subscription) + + +_resource = {"class": Log, "name": "InvoicePullSubscriptionLog"} + + +def get(id, user=None): + """# Retrieve a specific invoicepullsubscription.Log + Receive a single invoicepullsubscription.Log object previously created by the Stark Bank API by its id + ## Parameters (required): + - id [string]: object unique id. ex: "5656565656565656" + ## Parameters (optional): + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - invoicepullsubscription.Log object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, after=None, before=None, types=None, subscription_ids=None, user=None): + """# Retrieve invoicepullsubscription.Logs + Receive a generator of invoicepullsubscription.Log objects previously created in the Stark Bank API + ## Parameters (optional): + - limit [integer, default None]: maximum number of objects to be retrieved. Unlimited if None. ex: 35 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - types [list of strings, default None]: filter for log event types. ex: ["active" or "canceled"] + - subscription_ids [list of strings, default None]: list of InvoicePullSubscription ids to filter logs. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - generator of invoicepullsubscription.Log objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + subscription_ids=subscription_ids, + user=user, + ) + + +def page(cursor=None, after=None, before=None, types=None, subscription_ids=None, limit=None, user=None): + """# Retrieve paged invoicepullsubscription.Logs + Receive a list of up to 100 invoicepullsubscription.Log objects previously created in the Stark Bank API and the cursor to the next page. + Use this function instead of query if you want to manually page your requests. + ## Parameters (optional): + - cursor [string, default None]: cursor returned on the previous page function call + - limit [integer, default 100]: maximum number of objects to be retrieved. It must be an integer between 1 and 100. ex: 50 + - after [datetime.date or string, default None] date filter for objects created only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None] date filter for objects created only before specified date. ex: datetime.date(2020, 3, 10) + - types [list of strings, default None]: filter for log event types. ex: ["active" or "canceled"] + - subscription_ids [list of strings, default None]: list of InvoicePullSubscription ids to filter logs. ex: ["5656565656565656", "4545454545454545"] + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of invoicepullsubscription.Log objects with updated attributes + - cursor to retrieve the next page of invoicepullsubscription.Log objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + subscription_ids=subscription_ids, + user=user, + ) \ No newline at end of file diff --git a/tests/sdk/test_invoice_pull_request.py b/tests/sdk/test_invoice_pull_request.py new file mode 100644 index 00000000..35d5ccd4 --- /dev/null +++ b/tests/sdk/test_invoice_pull_request.py @@ -0,0 +1,49 @@ +import starkbank +from datetime import datetime, timedelta +from unittest import TestCase, main +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestInvoicePullRequestQuery(TestCase): + + def test_success(self): + requests = list(starkbank.invoicepullrequest.query(limit=5)) + print(f"Number of InvoicePullRequests: {len(requests)}") + for request in requests: + self.assertIsNotNone(request.id) + print(request) + + +class TestInvoicePullRequestPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + requests, cursor = starkbank.invoicepullrequest.page(limit=2, cursor=cursor) + for request in requests: + print(request) + self.assertFalse(request.id in ids) + ids.append(request.id) + if cursor is None: + break + print(f"Total unique InvoicePullRequests: {len(ids)}") + + +class TestInvoicePullRequestGet(TestCase): + + def test_success(self): + requests = starkbank.invoicepullrequest.query(limit=1) + for request in requests: + request_id = request.id + request = starkbank.invoicepullrequest.get(request_id) + self.assertEqual(request.id, request_id) + print(request) + break + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tests/sdk/test_invoice_pull_request_log.py b/tests/sdk/test_invoice_pull_request_log.py new file mode 100644 index 00000000..c1417ad1 --- /dev/null +++ b/tests/sdk/test_invoice_pull_request_log.py @@ -0,0 +1,63 @@ +import starkbank +from datetime import datetime, timedelta +from unittest import TestCase, main +from tests.utils.date import randomPastDate +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestInvoicePullRequestLogQuery(TestCase): + + def test_success(self): + logs = list(starkbank.invoicepullrequest.log.query(limit=10)) + print(f"Number of InvoicePullRequest logs: {len(logs)}") + for log in logs: + self.assertIsNotNone(log.id) + self.assertIsNotNone(log.request.id) + print(log) + + def test_success_with_filters(self): + after = randomPastDate(days=10) + before = datetime.today() + logs = starkbank.invoicepullrequest.log.query( + after=after.date(), + before=before.date(), + limit=10 + ) + for log in logs: + self.assertTrue(after.date() <= log.created.date() <= (before + timedelta(hours=3)).date()) + print(log) + + +class TestInvoicePullRequestLogPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + logs, cursor = starkbank.invoicepullrequest.log.page(limit=2, cursor=cursor) + for log in logs: + print(log) + self.assertFalse(log.id in ids) + ids.append(log.id) + if cursor is None: + break + print(f"Total unique InvoicePullRequest logs: {len(ids)}") + + +class TestInvoicePullRequestLogGet(TestCase): + + def test_success(self): + logs = starkbank.invoicepullrequest.log.query(limit=1) + for log in logs: + log_id = log.id + log = starkbank.invoicepullrequest.log.get(log_id) + self.assertEqual(log.id, log_id) + print(log) + break + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tests/sdk/test_invoice_pull_subscription.py b/tests/sdk/test_invoice_pull_subscription.py new file mode 100644 index 00000000..1f0ea051 --- /dev/null +++ b/tests/sdk/test_invoice_pull_subscription.py @@ -0,0 +1,49 @@ +import starkbank +from datetime import datetime, timedelta +from unittest import TestCase, main +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestInvoicePullSubscriptionQuery(TestCase): + + def test_success(self): + subscriptions = list(starkbank.invoicepullsubscription.query(limit=5)) + print(f"Number of InvoicePullSubscriptions: {len(subscriptions)}") + for subscription in subscriptions: + self.assertIsNotNone(subscription.id) + print(subscription) + + +class TestInvoicePullSubscriptionPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + subscriptions, cursor = starkbank.invoicepullsubscription.page(limit=2, cursor=cursor) + for subscription in subscriptions: + print(subscription) + self.assertFalse(subscription.id in ids) + ids.append(subscription.id) + if cursor is None: + break + print(f"Total unique InvoicePullSubscriptions: {len(ids)}") + + +class TestInvoicePullSubscriptionGet(TestCase): + + def test_success(self): + subscriptions = starkbank.invoicepullsubscription.query(limit=1) + for subscription in subscriptions: + subscription_id = subscription.id + subscription = starkbank.invoicepullsubscription.get(subscription_id) + self.assertEqual(subscription.id, subscription_id) + print(subscription) + break + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tests/sdk/test_invoice_pull_subscription_log.py b/tests/sdk/test_invoice_pull_subscription_log.py new file mode 100644 index 00000000..8519ceb9 --- /dev/null +++ b/tests/sdk/test_invoice_pull_subscription_log.py @@ -0,0 +1,63 @@ +import starkbank +from datetime import datetime, timedelta +from unittest import TestCase, main +from tests.utils.date import randomPastDate +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestInvoicePullSubscriptionLogQuery(TestCase): + + def test_success(self): + logs = list(starkbank.invoicepullsubscription.log.query(limit=10)) + print(f"Number of InvoicePullSubscription logs: {len(logs)}") + for log in logs: + self.assertIsNotNone(log.id) + self.assertIsNotNone(log.subscription.id) + print(log) + + def test_success_with_filters(self): + after = randomPastDate(days=10) + before = datetime.today() + logs = starkbank.invoicepullsubscription.log.query( + after=after.date(), + before=before.date(), + limit=10 + ) + for log in logs: + self.assertTrue(after.date() <= log.created.date() <= (before + timedelta(hours=3)).date()) + print(log) + + +class TestInvoicePullSubscriptionLogPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + logs, cursor = starkbank.invoicepullsubscription.log.page(limit=2, cursor=cursor) + for log in logs: + print(log) + self.assertFalse(log.id in ids) + ids.append(log.id) + if cursor is None: + break + print(f"Total unique InvoicePullSubscription logs: {len(ids)}") + + +class TestInvoicePullSubscriptionLogGet(TestCase): + + def test_success(self): + logs = starkbank.invoicepullsubscription.log.query(limit=1) + for log in logs: + log_id = log.id + log = starkbank.invoicepullsubscription.log.get(log_id) + self.assertEqual(log.id, log_id) + print(log) + break + + +if __name__ == '__main__': + main() \ No newline at end of file