From a167e9f772d314f69cdd25f0ad54f651545edea8 Mon Sep 17 00:00:00 2001 From: Wendel de Oliveira Silvestre Date: Thu, 26 Oct 2023 17:26:59 -0300 Subject: [PATCH] Add Split and SplitReceiver resources --- CHANGELOG.md | 5 + README.md | 110 +++++++++++++++++ starkbank/__init__.py | 6 + starkbank/darfpayment/__darfpayment.py | 2 +- starkbank/invoice/__invoice.py | 17 ++- starkbank/split/__init__.py | 3 + starkbank/split/__split.py | 114 ++++++++++++++++++ starkbank/split/log/__init__.py | 1 + starkbank/split/log/__log.py | 96 +++++++++++++++ starkbank/splitreceiver/__init__.py | 3 + starkbank/splitreceiver/__splitreceiver.py | 133 +++++++++++++++++++++ starkbank/splitreceiver/log/__init__.py | 1 + starkbank/splitreceiver/log/__log.py | 96 +++++++++++++++ tests/sdk/test_split.py | 86 +++++++++++++ tests/sdk/test_split_log.py | 43 +++++++ tests/sdk/test_split_receiver.py | 78 ++++++++++++ tests/sdk/test_split_receiver_log.py | 43 +++++++ tests/utils/invoice.py | 19 ++- tests/utils/split.py | 28 +++++ tests/utils/splitReceiver.py | 27 +++++ 20 files changed, 907 insertions(+), 4 deletions(-) create mode 100644 starkbank/split/__init__.py create mode 100644 starkbank/split/__split.py create mode 100644 starkbank/split/log/__init__.py create mode 100644 starkbank/split/log/__log.py create mode 100644 starkbank/splitreceiver/__init__.py create mode 100644 starkbank/splitreceiver/__splitreceiver.py create mode 100644 starkbank/splitreceiver/log/__init__.py create mode 100644 starkbank/splitreceiver/log/__log.py create mode 100644 tests/sdk/test_split.py create mode 100644 tests/sdk/test_split_log.py create mode 100644 tests/sdk/test_split_receiver.py create mode 100644 tests/sdk/test_split_receiver_log.py create mode 100644 tests/utils/split.py create mode 100644 tests/utils/splitReceiver.py diff --git a/CHANGELOG.md b/CHANGELOG.md index ed18594c..59fe8bc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ Given a version number MAJOR.MINOR.PATCH, increment: ## [Unreleased] +### Added +- Split resource +- SplitLog resource +- SplitReceiver resource +- SplitReceiverLog resource ## [2.22.0] - 2023-09-18 ### Removed diff --git a/README.md b/README.md index c39a30cc..586a4def 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ is as easy as sending a text message to your client! - [CorporateBalance](#get-your-corporatebalance): View your corporate balance - [CorporateTransactions](#query-corporatetransactions): View the transactions that have affected your corporate balance - [CorporateEnums](#corporate-enums): Query enums related to the corporate purchases, such as merchant categories, countries and card purchase methods + - [Split](#query-a-split): Split invoices + - [SplitReceiver](#query-a-split-receiver): Receiver of an invoice split - [Webhooks](#create-a-webhook-subscription): Configure your webhook endpoints and subscriptions - [WebhookEvents](#process-webhook-events): Manage webhook events - [WebhookEventAttempts](#query-failed-webhook-event-delivery-attempts-information): Query failed webhook event deliveries @@ -2167,6 +2169,114 @@ for method in methods: print(method) ``` +## Split + +Split an invoice to different receivers + +## Query a Split + +You can get a list of created splits given some filters. + +```python +import starkbank + +splits = starkbank.split.query(limit=10) + +for split in splits: + print(split) +``` + +## Get a Split + +To get a single Split by its id, run: + +```python +import starkbank + +split = starkbank.split.get("5155165527080960") + +print(split) +``` + +## Query split logs + +You can query split logs to check additional information + +```python +import starkbank + +logs = starkbank.split.log.query( + split_ids=["5155165527080960", "76551659167801921"], +) + +for log in logs: + print(log) +``` + +## Get a split log + +You can also get a split log by specifying its id. + +```python +import starkbank + +log = starkbank.split.log.get("5155165527080960") + +print(log) +``` + +## Query a split receiver + +To take a look at the receivers created to your workspace, just run the following: + +```python +import starkbank + +receivers = starkbank.splitreceiver.query(limit=10) + +for receiver in receivers: + print(receiver) +``` + +## Get a split receiver + +To get a single Receiver by its id, run: + +```python +import starkbank + +receiver = starkbank.splitreceiver.get("5155165527080960") + +print(receiver) +``` + +## Query a split receiver logs + +You can query split receiver logs to check additional information + +```python +import starkbank + +logs = starkbank.splitreceiver.log.query( + receiver_ids =["5155165527080960", "76551659167801921"], +) + +for log in logs: + print(log) +``` + +## Get a split receiver log + +You can also get a split receiver log by specifying its id. + +```python +import starkbank + +log = starkbank.splitreceiver.log.get("5155165527080960") + +print(log) +``` + ## Create a webhook subscription To create a webhook subscription and be notified whenever an event occurs, run: diff --git a/starkbank/__init__.py b/starkbank/__init__.py index 4977c707..eb4a512e 100644 --- a/starkbank/__init__.py +++ b/starkbank/__init__.py @@ -101,3 +101,9 @@ from . import deposit from .deposit.__deposit import Deposit + +from . import split +from .split.__split import Split + +from . import splitreceiver +from .splitreceiver.__splitreceiver import SplitReceiver diff --git a/starkbank/darfpayment/__darfpayment.py b/starkbank/darfpayment/__darfpayment.py index 6ebe3331..873badc2 100644 --- a/starkbank/darfpayment/__darfpayment.py +++ b/starkbank/darfpayment/__darfpayment.py @@ -27,7 +27,7 @@ class DarfPayment(Resource): - amount [int]: Total amount due calculated from other amounts. ex: 24146 (= R$ 241.46) - fee [integer]: fee charged when the DarfPayment is processed. ex: 0 (= R$ 0.00) - transaction_ids [list of strings]: ledger transaction ids linked to this DarfPayment. ex: ["19827356981273"] - - updated [datetime.datetime]: creation datetime for the payment. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + - updated [datetime.datetime]: update datetime for the payment. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) - created [datetime.datetime]: creation datetime for the payment. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) """ def __init__(self, description, revenue_code, tax_id, competence, nominal_amount, fine_amount, interest_amount, diff --git a/starkbank/invoice/__invoice.py b/starkbank/invoice/__invoice.py index b7f8e224..fc5f6d31 100644 --- a/starkbank/invoice/__invoice.py +++ b/starkbank/invoice/__invoice.py @@ -5,6 +5,7 @@ from .__payment import _sub_resource as _payment_sub_resource from .rule.__rule import Rule from .rule.__rule import _sub_resource as _rule_resource +from ..split.__split import _resource as _split_resource, Split class Invoice(Resource): @@ -25,6 +26,7 @@ class Invoice(Resource): - interest [float, default 1.0]: Invoice monthly interest for overdue payment in %. ex: 5.2 - discounts [list of dictionaries, default []]: list of dictionaries with "percentage":float and "due":datetime.datetime or string pairs - rules [list of Invoice.Rules, default []]: list of Invoice.Rule objects for modifying invoice behavior. ex: [Invoice.Rule(key="allowedTaxIds", value=[ "012.345.678-90", "45.059.493/0001-73" ])] + - splits [list of Split.Splits, default []]: list of Split.Splits objects to indicate payment receivers. ex: [Invoice.Split(amount=141, receiverId="5706627130851328")] - tags [list of strings, default []]: list of strings for tagging - descriptions [list of dictionaries, default []]: list of dictionaries with "key":string and (optional) "value":string pairs ## Attributes (return-only): @@ -45,7 +47,7 @@ class Invoice(Resource): def __init__(self, amount, tax_id, name, due=None, expiration=None, fine=None, interest=None, discounts=None, rules=None, tags=None, descriptions=None, pdf=None, link=None, nominal_amount=None, fine_amount=None, - interest_amount=None, discount_amount=None, id=None, brcode=None, status=None, fee=None, + interest_amount=None, discount_amount=None, id=None, brcode=None, status=None, fee=None, splits=None, transaction_ids=None, created=None, updated=None): Resource.__init__(self, id=id) @@ -62,6 +64,7 @@ def __init__(self, amount, tax_id, name, due=None, expiration=None, fine=None, i self.interest = interest self.discounts = discounts self.rules = _parse_rules(rules) + self.splits = _parse_splits(splits) self.tags = tags self.pdf = pdf self.link = link @@ -89,6 +92,18 @@ def _parse_rules(rules): return parsed_rules +def _parse_splits(splits): + if splits is None: + return None + parsed_splits = [] + for split in splits: + if isinstance(split, Split): + parsed_splits.append(split) + continue + parsed_splits.append(from_api_json(_split_resource, split)) + return parsed_splits + + def create(invoices, user=None): """# Create Invoices Send a list of Invoice objects for creation in the Stark Bank API diff --git a/starkbank/split/__init__.py b/starkbank/split/__init__.py new file mode 100644 index 00000000..561e8eca --- /dev/null +++ b/starkbank/split/__init__.py @@ -0,0 +1,3 @@ +from .__split import get, query, page +from .log.__log import Log +from . import log diff --git a/starkbank/split/__split.py b/starkbank/split/__split.py new file mode 100644 index 00000000..38ee6896 --- /dev/null +++ b/starkbank/split/__split.py @@ -0,0 +1,114 @@ +from ..utils import rest +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_date + + +class Split(Resource): + + """# Split object + When you initialize a Split, the entity will not be automatically + created in the Stark Bank API. The 'create' function sends the objects + to the Stark Bank API and returns the list of created objects. + ## Parameters (required): + - amount [int]: value to send to receivers. ex: 1000 (= R$ 10.00) + - receiver_id [string]: split receiver unique id. ex: "5656565656565656" + ## Attributes (return-only): + - id [string]: unique id returned when split is created. ex: "5656565656565656" + - source [string]: source receivable which generated this split object. ex: "5656565656565656" + - external_id [string]: unique id, generated by the system, to avoid duplicated splits. ex: "invoice/1234/receiver/5678" + - tags [list of strings, default None]: list of strings for tagging + - scheduled [datetime.date, datetime.datetime or string, default now]: payment scheduled date or datetime. ex: datetime.datetime(2020, 3, 10, 15, 17, 3) + - status [string]: current payment status. ex: "success" or "failed" + - created [datetime.datetime]: creation datetime for the payment. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + - updated [datetime.datetime]: update datetime for the payment. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, amount, receiver_id, id=None, source=None, external_id=None, + tags=None, scheduled=None, status=None, created=None, updated=None): + Resource.__init__(self, id=id) + + self.amount = amount + self.receiver_id = receiver_id + self.source = source + self.external_id = external_id + self.tags = tags + self.scheduled = check_datetime(scheduled) + self.status = status + self.created = check_datetime(created) + self.updated = check_datetime(updated) + + +_resource = {"class": Split, "name": "Split"} + + +def get(id, user=None): + """# Retrieve a specific Split + Receive a single Split 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: + - Split object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, after=None, before=None, tags=None, ids=None, receiver_ids=None, status=None, user=None): + """# Retrieve Splits + Receive a generator of Split 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) + - 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"] + - receiver_ids [list of strings, default None]: list of receiver ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - status [string, default None]: filter for status of retrieved objects. ex: "success" + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - generator of Split objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + tags=tags, + ids=ids, + receiver_ids=receiver_ids, + status=status, + user=user, + ) + + +def page(cursor=None, after=None, before=None, tags=None, ids=None, receiver_ids=None, status=None, limit=None, user=None): + """# Retrieve paged Splits + Receive a list of up to 100 Split 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) + - 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"] + - receiver_ids [list of strings, default None]: list of receiver ids to filter retrieved objects. ex: ["5656565656565656", "4545454545454545"] + - status [string, default None]: filter for status of retrieved objects. ex: "success" + - user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkbank.user was set before function call + ## Return: + - list of Split objects with updated attributes + - cursor to retrieve the next page of Split objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + tags=tags, + ids=ids, + receiver_ids=receiver_ids, + status=status, + user=user, + ) diff --git a/starkbank/split/log/__init__.py b/starkbank/split/log/__init__.py new file mode 100644 index 00000000..329366b4 --- /dev/null +++ b/starkbank/split/log/__init__.py @@ -0,0 +1 @@ +from .__log import get, query, page diff --git a/starkbank/split/log/__log.py b/starkbank/split/log/__log.py new file mode 100644 index 00000000..3dc49203 --- /dev/null +++ b/starkbank/split/log/__log.py @@ -0,0 +1,96 @@ +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 ..__split import _resource as _split_resource + + +class Log(Resource): + """# split.Log object + Every time a Split entity is modified, a corresponding split.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 Split. + ## Attributes (return-only): + - id [string]: unique id returned when the log is created. ex: "5656565656565656" + - split [Split]: Split entity to which the log refers to. + - errors [list of strings]: list of errors linked to this Split event. + - type [string]: type of the Split event which triggered the log creation. ex: "success" or "failed" + - 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, split): + Resource.__init__(self, id=id) + + self.created = check_datetime(created) + self.type = type + self.errors = errors + self.split = from_api_json(_split_resource, split) + + +_resource = {"class": Log, "name": "SplitLog"} + + +def get(id, user=None): + """# Retrieve a specific split.Log + Receive a single split.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: + - split.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, split_ids=None, user=None): + """# Retrieve split.Logs + Receive a generator of split.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 retrieved objects by event types. ex: "processing" or "success" + - split_ids [list of strings, default None]: list of Split 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 split.Log objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + split_ids=split_ids, + user=user, + ) + + +def page(cursor=None, limit=None, after=None, before=None, types=None, split_ids=None, user=None): + """# Retrieve paged split.Logs + Receive a list of up to 100 split.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 retrieved objects by event types. ex: "processing" or "success" + - split_ids [list of strings, default None]: list of Split 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 split.Log objects with updated attributes + - cursor to retrieve the next page of split.Log objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + split_ids=split_ids, + user=user, + ) diff --git a/starkbank/splitreceiver/__init__.py b/starkbank/splitreceiver/__init__.py new file mode 100644 index 00000000..13d87fd6 --- /dev/null +++ b/starkbank/splitreceiver/__init__.py @@ -0,0 +1,3 @@ +from .__splitreceiver import create, get, query, page +from .log.__log import Log +from . import log diff --git a/starkbank/splitreceiver/__splitreceiver.py b/starkbank/splitreceiver/__splitreceiver.py new file mode 100644 index 00000000..62d6e29f --- /dev/null +++ b/starkbank/splitreceiver/__splitreceiver.py @@ -0,0 +1,133 @@ +from ..utils import rest +from starkcore.utils.resource import Resource +from starkcore.utils.checks import check_datetime, check_date + + +class SplitReceiver(Resource): + """# SplitReceiver object + When you initialize a SplitReceiver, the entity will not be automatically + created in the Stark Bank API. The 'create' function sends the objects + to the Stark Bank API and returns the list of created objects. + ## Parameters (required): + - name [string]: receiver full name. ex: "Anthony Edward Stark" + - tax_id [string]: receiver account tax ID (CPF or CNPJ) with or without formatting. ex: "01234567890" or "20.018.183/0001-80" + - bank_code [string]: code of the receiver bank institution in Brazil. If an ISPB (8 digits) is informed, a PIX splitReceiver will be created, else a TED will be issued. ex: "20018183" or "341" + - branch_code [string]: receiver bank account branch. Use '-' in case there is a verifier digit. ex: "1357-9" + - account_number [string]: receiver bank account number. Use '-' before the verifier digit. ex: "876543-2" + - account_type [string]: Receiver bank account type. This parameter only has effect on Pix SplitReceivers. ex: "checking", "savings", "salary" or "payment" + ## Parameters (optional): + - tags [list of strings, default []]: list of strings for reference when searching for receivers. ex: ["seller/123456"] + ## Attributes (return-only): + - id [string]: unique id returned when the splitReceiver is created. ex: "5656565656565656" + - status [string]: current splitReceiver status. ex: "success" or "failed" + - created [datetime.datetime]: creation datetime for the splitReceiver. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + - updated [datetime.datetime]: latest update datetime for the splitReceiver. ex: datetime.datetime(2020, 3, 10, 10, 30, 0, 0) + """ + + def __init__(self, name, tax_id, bank_code, branch_code, account_number, account_type, + tags=None, id=None, status=None, created=None, updated=None): + Resource.__init__(self, id=id) + + self.name = name + self.tax_id = tax_id + self.bank_code = bank_code + self.branch_code = branch_code + self.account_number = account_number + self.account_type = account_type + self.tags = tags + self.status = status + self.created = check_datetime(created) + self.updated = check_datetime(updated) + + +_resource = {"class": SplitReceiver, "name": "SplitReceiver"} + + +def create(splitReceivers, user=None): + """# Create SplitReceivers + Send a list of SplitReceiver objects for creation in the Stark Bank API + ## Parameters (required): + - splitReceivers [list of SplitReceiver objects]: list of SplitReceiver 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 SplitReceiver objects with updated attributes + """ + return rest.post_multi(resource=_resource, entities=splitReceivers, user=user) + + +def get(id, user=None): + """# Retrieve a specific SplitReceiver + Receive a single SplitReceiver 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: + - SplitReceiver object with updated attributes + """ + return rest.get_id(resource=_resource, id=id, user=user) + + +def query(limit=None, after=None, before=None, transaction_ids=None, status=None, tax_id=None, sort=None, tags=None, ids=None, user=None): + """# Retrieve SplitReceivers + Receive a generator of SplitReceiver 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 or updated only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None]: date filter for objects created or updated only before specified date. ex: datetime.date(2020, 3, 10) + - transaction_ids [list of strings, default None]: list of transaction IDs linked to the desired splitReceivers. ex: ["5656565656565656", "4545454545454545"] + - status [string, default None]: filter for status of retrieved objects. ex: "success" or "failed" + - tax_id [string, default None]: filter for splitReceivers sent to the specified tax ID. ex: "012.345.678-90" + - sort [string, default "-created"]: sort order considered in response. Valid options are "created", "-created", "updated" or "-updated". + - 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 SplitReceiver objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + transaction_ids=transaction_ids, + status=status, + tax_id=tax_id, + sort=sort, + tags=tags, + ids=ids, + user=user, + ) + + +def page(cursor=None, limit=None, after=None, before=None, status=None, sort=None, tags=None, ids=None, user=None): + """# Retrieve paged SplitReceivers + Receive a list of up to 100 SplitReceiver 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 or updated only after specified date. ex: datetime.date(2020, 3, 10) + - before [datetime.date or string, default None]: date filter for objects created or updated only before specified date. ex: datetime.date(2020, 3, 10) + - status [string, default None]: filter for status of retrieved objects. ex: "success" or "failed" + - sort [string, default "-created"]: sort order considered in response. Valid options are "created", "-created", "updated" or "-updated". + - 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 SplitReceiver objects with updated attributes + - cursor to retrieve the next page of SplitReceiver objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + status=status, + sort=sort, + tags=tags, + ids=ids, + user=user, + ) diff --git a/starkbank/splitreceiver/log/__init__.py b/starkbank/splitreceiver/log/__init__.py new file mode 100644 index 00000000..329366b4 --- /dev/null +++ b/starkbank/splitreceiver/log/__init__.py @@ -0,0 +1 @@ +from .__log import get, query, page diff --git a/starkbank/splitreceiver/log/__log.py b/starkbank/splitreceiver/log/__log.py new file mode 100644 index 00000000..70b6f3b2 --- /dev/null +++ b/starkbank/splitreceiver/log/__log.py @@ -0,0 +1,96 @@ +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 ..__splitreceiver import _resource as _receiver_resource + + +class Log(Resource): + """# splitreceiver.Log object + Every time a splitreceiver entity is modified, a corresponding splitreceiver.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 splitreceiver. + ## Attributes (return-only): + - id [string]: unique id returned when the log is created. ex: "5656565656565656" + - receiver [splitreceiver]: splitreceiver entity to which the log refers to. + - errors [list of strings]: list of errors linked to this splitreceiver event. + - type [string]: type of the splitreceiver event which triggered the log creation. ex: "success" or "failed" + - 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, receiver): + Resource.__init__(self, id=id) + + self.created = check_datetime(created) + self.type = type + self.errors = errors + self.receiver = from_api_json(_receiver_resource, receiver) + + +_resource = {"class": Log, "name": "SplitReceiverLog"} + + +def get(id, user=None): + """# Retrieve a specific splitreceiver.Log + Receive a single splitreceiver.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: + - splitreceiver.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, receiver_ids=None, user=None): + """# Retrieve splitreceiver.Logs + Receive a generator of splitreceiver.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 retrieved objects by event types. ex: "processing" or "success" + - receiver_ids [list of strings, default None]: list of splitreceiver 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 splitreceiver.Log objects with updated attributes + """ + return rest.get_stream( + resource=_resource, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + receiver_ids=receiver_ids, + user=user, + ) + + +def page(cursor=None, limit=None, after=None, before=None, types=None, receiver_ids=None, user=None): + """# Retrieve paged splitreceiver.Logs + Receive a list of up to 100 splitreceiver.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 retrieved objects by event types. ex: "processing" or "success" + - receiver_ids [list of strings, default None]: list of splitreceiver 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 splitreceiver.Log objects with updated attributes + - cursor to retrieve the next page of splitreceiver.Log objects + """ + return rest.get_page( + resource=_resource, + cursor=cursor, + limit=limit, + after=check_date(after), + before=check_date(before), + types=types, + receiver_ids=receiver_ids, + user=user, + ) diff --git a/tests/sdk/test_split.py b/tests/sdk/test_split.py new file mode 100644 index 00000000..1065e55d --- /dev/null +++ b/tests/sdk/test_split.py @@ -0,0 +1,86 @@ +from time import sleep +import starkbank +from datetime import timedelta, date +from unittest import TestCase, main +from tests.utils.user import exampleProject +from tests.utils.split import generateExampleSplittedInvoices, paySplittedInvoices + + +starkbank.user = exampleProject + + +class TestSplitPost(TestCase): + + def test_success(self): + invoices = generateExampleSplittedInvoices(n=1) + payments = paySplittedInvoices(invoices) + for invoice in invoices: + print(invoice) + for payment in payments: + print(payment) + isInvoicePaid = False + while not isInvoicePaid: + for invoice in invoices: + if starkbank.invoice.get(invoice.id).status == "paid": + isInvoicePaid = True + sleep(2) + splits = list(starkbank.split.query(tags=["invoice/{id}".format(id=invoice.id) for invoice in invoices])) + for split in splits: + print(split) + self.assertIsNotNone(split.id) + + +class TestSplitQuery(TestCase): + + def test_success(self): + splits = list(starkbank.split.query(limit=10)) + assert len(splits) == 10 + + def test_success_with_params(self): + splits = starkbank.split.query( + limit=10, + after=date.today() - timedelta(days=100), + before=date.today(), + status="success", + tags=["iron", "bank"], + ) + self.assertEqual(len(list(splits)), 0) + + +class TestSplitPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + splits, cursor = starkbank.split.page(limit=2, cursor=cursor) + for split in splits: + print(split) + self.assertFalse(split.id in ids) + ids.append(split.id) + if cursor is None: + break + self.assertTrue(len(ids) == 4) + + +class TestSplitInfoGet(TestCase): + + def test_success(self): + splits = starkbank.split.query() + split_id = next(splits).id + split = starkbank.split.get(id=split_id) + self.assertIsNotNone(split.id) + self.assertEqual(split.id, split_id) + + def test_success_ids(self): + splits = starkbank.split.query(limit=5) + splits_ids_expected = [t.id for t in splits] + splits_ids_result = [t.id for t in starkbank.split.query(ids=splits_ids_expected)] + splits_ids_expected.sort() + splits_ids_result.sort() + self.assertTrue(splits_ids_result) + self.assertEqual(splits_ids_expected, splits_ids_result) + + +if __name__ == '__main__': + main() diff --git a/tests/sdk/test_split_log.py b/tests/sdk/test_split_log.py new file mode 100644 index 00000000..d1b1eeaa --- /dev/null +++ b/tests/sdk/test_split_log.py @@ -0,0 +1,43 @@ +import starkbank +from unittest import TestCase, main +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestSplitLogQuery(TestCase): + + def test_success(self): + logs = list(starkbank.split.log.query(limit=10)) + logs = list(starkbank.split.log.query(limit=10, split_ids={log.split.id for log in logs}, types={log.type for log in logs})) + self.assertEqual(10, len(logs)) + print("Number of logs:", len(logs)) + + +class TestSplitLogPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + logs, cursor = starkbank.split.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 + self.assertTrue(len(ids) == 4) + + +class TestSplitLogInfoGet(TestCase): + + def test_success(self): + logs = starkbank.split.log.query() + log_id = next(logs).id + logs = starkbank.split.log.get(id=log_id) + + +if __name__ == '__main__': + main() diff --git a/tests/sdk/test_split_receiver.py b/tests/sdk/test_split_receiver.py new file mode 100644 index 00000000..2d57d304 --- /dev/null +++ b/tests/sdk/test_split_receiver.py @@ -0,0 +1,78 @@ +import starkbank +from datetime import timedelta, date +from unittest import TestCase, main +from tests.utils.splitReceiver import generateExampleSplitReceiversJson +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestSplitReceiverPost(TestCase): + + def test_success(self): + splitreceivers = generateExampleSplitReceiversJson(n=2) + splitreceivers = starkbank.splitreceiver.create(splitreceivers) + self.assertEqual(len(splitreceivers), 2) + for splitreceiver in splitreceivers: + self.assertIsNotNone(splitreceiver.id) + + +class TestSplitReceiverQuery(TestCase): + + def test_success(self): + splitreceivers = list(starkbank.splitreceiver.query(limit=2)) + for receiver in splitreceivers: + print(receiver) + assert len(splitreceivers) == 2 + + def test_success_with_params(self): + splitreceivers = starkbank.splitreceiver.query( + limit=2, + after=date.today() - timedelta(days=100), + before=date.today(), + status="created", + tags=["test"], + ) + for receiver in splitreceivers: + print(receiver) + self.assertEqual(len(list(splitreceivers)), 0) + + +class TestSplitReceiverPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + splitreceivers, cursor = starkbank.splitreceiver.page(limit=1, cursor=cursor) + for splitreceiver in splitreceivers: + print(splitreceiver) + self.assertFalse(splitreceiver.id in ids) + ids.append(splitreceiver.id) + if cursor is None: + break + self.assertTrue(len(ids) == 2) + + +class TestSplitReceiverInfoGet(TestCase): + + def test_success(self): + splitreceivers = starkbank.splitreceiver.query() + splitreceiver_id = next(splitreceivers).id + splitreceiver = starkbank.splitreceiver.get(id=splitreceiver_id) + self.assertIsNotNone(splitreceiver.id) + self.assertEqual(splitreceiver.id, splitreceiver_id) + + def test_success_ids(self): + splitreceivers = starkbank.splitreceiver.query(limit=2) + splitreceivers_ids_expected = [t.id for t in splitreceivers] + splitreceivers_ids_result = [t.id for t in starkbank.splitreceiver.query(ids=splitreceivers_ids_expected)] + splitreceivers_ids_expected.sort() + splitreceivers_ids_result.sort() + self.assertTrue(splitreceivers_ids_result) + self.assertEqual(splitreceivers_ids_expected, splitreceivers_ids_result) + + +if __name__ == '__main__': + main() diff --git a/tests/sdk/test_split_receiver_log.py b/tests/sdk/test_split_receiver_log.py new file mode 100644 index 00000000..a24df1bb --- /dev/null +++ b/tests/sdk/test_split_receiver_log.py @@ -0,0 +1,43 @@ +import starkbank +from unittest import TestCase, main +from tests.utils.user import exampleProject + + +starkbank.user = exampleProject + + +class TestSplitReceiverLogQuery(TestCase): + + def test_success(self): + logs = list(starkbank.splitreceiver.log.query(limit=10)) + logs = list(starkbank.splitreceiver.log.query(limit=10, receiver_ids={log.receiver.id for log in logs}, types={log.type for log in logs})) + self.assertEqual(10, len(logs)) + print("Number of logs:", len(logs)) + + +class TestSplitReceiverLogPage(TestCase): + + def test_success(self): + cursor = None + ids = [] + for _ in range(2): + logs, cursor = starkbank.splitreceiver.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 + self.assertTrue(len(ids) == 4) + + +class TestSplitReceiverLogInfoGet(TestCase): + + def test_success(self): + logs = starkbank.splitreceiver.log.query() + log_id = next(logs).id + logs = starkbank.splitreceiver.log.get(id=log_id) + + +if __name__ == '__main__': + main() diff --git a/tests/utils/invoice.py b/tests/utils/invoice.py index c72d0db7..19efc913 100644 --- a/tests/utils/invoice.py +++ b/tests/utils/invoice.py @@ -2,7 +2,8 @@ from copy import deepcopy from random import randint from datetime import timedelta, datetime -from starkbank import Invoice +from starkbank import splitreceiver +from starkbank import Invoice, Split from starkbank.invoice import Rule from .names.names import get_full_name from .taxIdGenerator import TaxIdGenerator @@ -36,8 +37,13 @@ ) -def generateExampleInvoicesJson(n=1, amount=None, useRandomFutureDueDate=True, immediate=True): +def generateExampleInvoicesJson(n=1, amount=None, useRandomFutureDueDate=True, useSplit=False, immediate=True): invoices = [] + receivers = [] + receivers_length = 0 + if useSplit: + receivers_length = 2 + receivers = list(splitreceiver.query(limit=receivers_length, tags="sdk-receiver")) for _ in range(n): if amount is None: invoiceAmount = randint(205, 300) @@ -59,6 +65,15 @@ def generateExampleInvoicesJson(n=1, amount=None, useRandomFutureDueDate=True, i discount["due"] = discount["due"].date() if not immediate: example_invoice.due = example_invoice.due.date() + if useSplit: + example_invoice.rules = None + example_invoice.discounts = [] + amount_steps = sorted([0] + [randint(0, example_invoice.amount - receivers_length) for _ in receivers]) + receiver_amounts = [amount_steps[i+1] - amount_steps[i] + 1 for i in range(len(receivers))] + example_invoice.splits = [ + Split(amount=receiver_amount, receiver_id=receiver.id) + for receiver, receiver_amount in zip(receivers, receiver_amounts) + ] example_invoice.tax_id = TaxIdGenerator.taxId() invoices.append(deepcopy(example_invoice)) return invoices diff --git a/tests/utils/split.py b/tests/utils/split.py new file mode 100644 index 00000000..2848d3d3 --- /dev/null +++ b/tests/utils/split.py @@ -0,0 +1,28 @@ +from copy import deepcopy +import starkbank +from starkbank import BrcodePayment +from tests.utils.invoice import generateExampleInvoicesJson + +example_payment = BrcodePayment( + brcode="00020126580014br.gov.bcb.pix0136a629532e-7693-4846-852d-1bbff817b5a8520400005303986540510.005802BR5908T'Challa6009Sao Paulo62090505123456304B14A", + description="Split test", + tax_id="20.018.183/0001-80", +) + + +def generateExampleSplittedInvoices(n=1): + invoices = generateExampleInvoicesJson(n=n, immediate=True, useSplit=True) + + invoices = starkbank.invoice.create(invoices) + + return invoices + + +def paySplittedInvoices(invoices): + payments = [] + for invoice in invoices: + payment = deepcopy(example_payment) + payment.brcode = invoice.brcode + payments.append(payment) + payments = starkbank.brcodepayment.create(payments) + return payments diff --git a/tests/utils/splitReceiver.py b/tests/utils/splitReceiver.py new file mode 100644 index 00000000..0103014f --- /dev/null +++ b/tests/utils/splitReceiver.py @@ -0,0 +1,27 @@ +from copy import deepcopy +from random import choice, randint +from starkbank import SplitReceiver +from tests.utils.names.names import get_full_name +from tests.utils.taxIdGenerator import TaxIdGenerator + +example_receiver = SplitReceiver( + name="João", + tax_id="01234567890", + bank_code=choice(["18236120", "60701190"]), + branch_code="0001", + account_number="10000-0", + account_type="checking" +) + + +def generateExampleSplitReceiversJson(n=1): + receivers = [] + for _ in range(n): + receiver = deepcopy(example_receiver) + receiver.name = get_full_name() + receiver.branch_code = str(randint(1, 999)) + receiver.tax_id = TaxIdGenerator.taxId() + receiver.account_type = choice(["checking", "savings", "salary", "payment"]) + receiver.account_number = "{}-{}".format(randint(10000, 100000000), randint(0, 9)) + receivers.append(receiver) + return receivers