dime-python-sdk 1.3.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dime_payments/client.py +10 -0
- dime_payments/config.py +1 -1
- dime_payments/data_objects/__init__.py +27 -0
- dime_payments/data_objects/application_status.py +38 -0
- dime_payments/data_objects/chargeback.py +63 -0
- dime_payments/data_objects/document.py +49 -0
- dime_payments/data_objects/document_upload_result.py +42 -0
- dime_payments/data_objects/fund_release.py +63 -0
- dime_payments/data_objects/held_balance.py +50 -0
- dime_payments/data_objects/releasable_transactions.py +57 -0
- dime_payments/data_objects/subscribe_result.py +29 -0
- dime_payments/data_objects/subscription.py +61 -0
- dime_payments/data_objects/subscription_item.py +29 -0
- dime_payments/data_objects/subscription_payment_method.py +31 -0
- dime_payments/data_objects/subscription_plan.py +46 -0
- dime_payments/http/error_handler.py +18 -5
- dime_payments/http/transport.py +40 -2
- dime_payments/resources/chargebacks.py +34 -0
- dime_payments/resources/documents.py +81 -0
- dime_payments/resources/funds.py +77 -0
- dime_payments/resources/invoices.py +8 -1
- dime_payments/resources/merchants.py +10 -0
- dime_payments/resources/subscription_plans.py +97 -0
- dime_payments/resources/subscriptions.py +53 -0
- dime_payments/resources/transactions.py +31 -0
- {dime_python_sdk-1.3.0.dist-info → dime_python_sdk-1.4.0.dist-info}/METADATA +141 -4
- {dime_python_sdk-1.3.0.dist-info → dime_python_sdk-1.4.0.dist-info}/RECORD +29 -12
- {dime_python_sdk-1.3.0.dist-info → dime_python_sdk-1.4.0.dist-info}/WHEEL +1 -1
- {dime_python_sdk-1.3.0.dist-info → dime_python_sdk-1.4.0.dist-info}/licenses/LICENSE +0 -0
dime_payments/client.py
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
from .config import Config
|
|
2
2
|
from .http.transport import Transport
|
|
3
3
|
from .resources.addresses import Addresses
|
|
4
|
+
from .resources.chargebacks import Chargebacks
|
|
4
5
|
from .resources.customers import Customers
|
|
5
6
|
from .resources.deposits import Deposits
|
|
7
|
+
from .resources.documents import Documents
|
|
8
|
+
from .resources.funds import Funds
|
|
6
9
|
from .resources.invoices import Invoices
|
|
7
10
|
from .resources.merchants import Merchants
|
|
8
11
|
from .resources.payment_methods import PaymentMethods
|
|
9
12
|
from .resources.recurring_invoices import RecurringInvoices
|
|
10
13
|
from .resources.recurring_payments import RecurringPayments
|
|
14
|
+
from .resources.subscription_plans import SubscriptionPlans
|
|
15
|
+
from .resources.subscriptions import Subscriptions
|
|
11
16
|
from .resources.transactions import Transactions
|
|
12
17
|
|
|
13
18
|
|
|
@@ -29,6 +34,11 @@ class Client:
|
|
|
29
34
|
self.recurring_payments = RecurringPayments(transport)
|
|
30
35
|
self.invoices = Invoices(transport)
|
|
31
36
|
self.recurring_invoices = RecurringInvoices(transport)
|
|
37
|
+
self.chargebacks = Chargebacks(transport)
|
|
38
|
+
self.documents = Documents(transport)
|
|
39
|
+
self.funds = Funds(transport)
|
|
40
|
+
self.subscription_plans = SubscriptionPlans(transport)
|
|
41
|
+
self.subscriptions = Subscriptions(transport)
|
|
32
42
|
|
|
33
43
|
def config(self) -> Config:
|
|
34
44
|
return self._config
|
dime_payments/config.py
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
from .address import Address
|
|
2
|
+
from .application_status import ApplicationStatus
|
|
3
|
+
from .chargeback import Chargeback
|
|
2
4
|
from .customer import Customer
|
|
3
5
|
from .deposit import Deposit
|
|
4
6
|
from .deposit_group import DepositGroup
|
|
5
7
|
from .deposit_with_transactions import DepositWithTransactions
|
|
8
|
+
from .document import Document
|
|
9
|
+
from .document_upload_result import DocumentUploadFailure, DocumentUploadResult
|
|
6
10
|
from .form_link import FormLink
|
|
11
|
+
from .fund_release import FundRelease, FundReleaseResult
|
|
12
|
+
from .held_balance import HeldBalance
|
|
7
13
|
from .invoice import Invoice
|
|
8
14
|
from .invoice_customer import InvoiceCustomer
|
|
9
15
|
from .invoice_event import InvoiceEvent
|
|
@@ -17,6 +23,12 @@ from .payment_method import PaymentMethod
|
|
|
17
23
|
from .recurring_invoice import RecurringInvoice, RecurringInvoiceRun
|
|
18
24
|
from .recurring_payment import RecurringPayment
|
|
19
25
|
from .recurring_payment_method import RecurringPaymentMethod
|
|
26
|
+
from .releasable_transactions import ReleasableTransaction, ReleasableTransactions
|
|
27
|
+
from .subscribe_result import SubscribeResult
|
|
28
|
+
from .subscription import Subscription
|
|
29
|
+
from .subscription_item import SubscriptionItem
|
|
30
|
+
from .subscription_payment_method import SubscriptionPaymentMethod
|
|
31
|
+
from .subscription_plan import SubscriptionPlan
|
|
20
32
|
from .tokenize_result import TokenizeResult
|
|
21
33
|
from .transaction import Transaction
|
|
22
34
|
from .transaction_address import TransactionAddress
|
|
@@ -27,6 +39,7 @@ __all__ = [
|
|
|
27
39
|
'Customer',
|
|
28
40
|
'PaymentMethod',
|
|
29
41
|
'Merchant',
|
|
42
|
+
'ApplicationStatus',
|
|
30
43
|
'Address',
|
|
31
44
|
'Deposit',
|
|
32
45
|
'DepositGroup',
|
|
@@ -45,4 +58,18 @@ __all__ = [
|
|
|
45
58
|
'LineItem',
|
|
46
59
|
'RecurringInvoice',
|
|
47
60
|
'RecurringInvoiceRun',
|
|
61
|
+
'Chargeback',
|
|
62
|
+
'Document',
|
|
63
|
+
'DocumentUploadResult',
|
|
64
|
+
'DocumentUploadFailure',
|
|
65
|
+
'HeldBalance',
|
|
66
|
+
'ReleasableTransaction',
|
|
67
|
+
'ReleasableTransactions',
|
|
68
|
+
'FundRelease',
|
|
69
|
+
'FundReleaseResult',
|
|
70
|
+
'SubscriptionPlan',
|
|
71
|
+
'Subscription',
|
|
72
|
+
'SubscriptionItem',
|
|
73
|
+
'SubscriptionPaymentMethod',
|
|
74
|
+
'SubscribeResult',
|
|
48
75
|
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_bool, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ApplicationStatus:
|
|
9
|
+
"""
|
|
10
|
+
Where a merchant sits in onboarding.
|
|
11
|
+
|
|
12
|
+
``status`` is the headline: one of ``lead``, ``discovery``, ``proposal``,
|
|
13
|
+
``application_in_progress``, ``underwriting``, ``live``,
|
|
14
|
+
``cancellation_pending``, ``churned`` or ``declined`` (``None`` if onboarding
|
|
15
|
+
has not started). ``application_status`` is the underlying application —
|
|
16
|
+
``draft``, ``pending_review``, ``submitted``, ``approved``,
|
|
17
|
+
``needs_documents``, ``failed`` or ``None`` — and is the field to read while
|
|
18
|
+
``status`` is ``underwriting``, since only ``needs_documents`` asks you to
|
|
19
|
+
act. ``boarded`` is the ground truth for whether the merchant can take money.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
sid: str | None = None
|
|
23
|
+
name: str | None = None
|
|
24
|
+
status: str | None = None
|
|
25
|
+
application_status: str | None = None
|
|
26
|
+
boarded: bool = False
|
|
27
|
+
application_submitted_at: str | None = None
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def from_dict(cls, data: dict[str, Any]) -> 'ApplicationStatus':
|
|
31
|
+
return cls(
|
|
32
|
+
sid=arr_string(data, 'sid'),
|
|
33
|
+
name=arr_string(data, 'name'),
|
|
34
|
+
status=arr_string(data, 'status'),
|
|
35
|
+
application_status=arr_string(data, 'application_status'),
|
|
36
|
+
boarded=arr_bool(data, 'boarded'),
|
|
37
|
+
application_submitted_at=arr_string(data, 'application_submitted_at'),
|
|
38
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_bool, arr_int, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Chargeback:
|
|
9
|
+
"""
|
|
10
|
+
A chargeback raised against a merchant. The same field set the chargeback
|
|
11
|
+
webhooks carry.
|
|
12
|
+
|
|
13
|
+
``transaction_info_id`` is the processor's stable identifier for the
|
|
14
|
+
chargeback; ``parent_transaction_info_id`` identifies the disputed payment.
|
|
15
|
+
``representment_status`` and ``result`` are free text from the processor;
|
|
16
|
+
``resolved`` says whether the dispute has reached a terminal state.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
transaction_info_id: str | None = None
|
|
20
|
+
parent_transaction_info_id: str | None = None
|
|
21
|
+
gateway_transaction_id: str | None = None
|
|
22
|
+
transaction_number: str | None = None
|
|
23
|
+
invoice_number: str | None = None
|
|
24
|
+
chargeback_date: str | None = None
|
|
25
|
+
merchant_chargeback_date: str | None = None
|
|
26
|
+
transaction_amount: str | None = None
|
|
27
|
+
chargeback_amount: str | None = None
|
|
28
|
+
card_brand: str | None = None
|
|
29
|
+
cc_last_four: str | None = None
|
|
30
|
+
payee_name: str | None = None
|
|
31
|
+
days_to_represent: int | None = None
|
|
32
|
+
representment_date: str | None = None
|
|
33
|
+
merchant_representment_date: str | None = None
|
|
34
|
+
representment_status: str | None = None
|
|
35
|
+
result: str | None = None
|
|
36
|
+
chargeback_code: str | None = None
|
|
37
|
+
chargeback_response_code: str | None = None
|
|
38
|
+
resolved: bool = False
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_dict(cls, data: dict[str, Any]) -> 'Chargeback':
|
|
42
|
+
return cls(
|
|
43
|
+
transaction_info_id=arr_string(data, 'transaction_info_id'),
|
|
44
|
+
parent_transaction_info_id=arr_string(data, 'parent_transaction_info_id'),
|
|
45
|
+
gateway_transaction_id=arr_string(data, 'gateway_transaction_id'),
|
|
46
|
+
transaction_number=arr_string(data, 'transaction_number'),
|
|
47
|
+
invoice_number=arr_string(data, 'invoice_number'),
|
|
48
|
+
chargeback_date=arr_string(data, 'chargeback_date'),
|
|
49
|
+
merchant_chargeback_date=arr_string(data, 'merchant_chargeback_date'),
|
|
50
|
+
transaction_amount=arr_string(data, 'transaction_amount'),
|
|
51
|
+
chargeback_amount=arr_string(data, 'chargeback_amount'),
|
|
52
|
+
card_brand=arr_string(data, 'card_brand'),
|
|
53
|
+
cc_last_four=arr_string(data, 'cc_last_four'),
|
|
54
|
+
payee_name=arr_string(data, 'payee_name'),
|
|
55
|
+
days_to_represent=arr_int(data, 'days_to_represent'),
|
|
56
|
+
representment_date=arr_string(data, 'representment_date'),
|
|
57
|
+
merchant_representment_date=arr_string(data, 'merchant_representment_date'),
|
|
58
|
+
representment_status=arr_string(data, 'representment_status'),
|
|
59
|
+
result=arr_string(data, 'result'),
|
|
60
|
+
chargeback_code=arr_string(data, 'chargeback_code'),
|
|
61
|
+
chargeback_response_code=arr_string(data, 'chargeback_response_code'),
|
|
62
|
+
resolved=arr_bool(data, 'resolved'),
|
|
63
|
+
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_int, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Document:
|
|
9
|
+
"""
|
|
10
|
+
A document held for a merchant.
|
|
11
|
+
|
|
12
|
+
``doc_type`` is one of ``Verification``, ``FraudHolds``, ``Underwriting`` or
|
|
13
|
+
``RetrievalRequest``. ``uploaded_via`` is ``api`` for documents sent through
|
|
14
|
+
:meth:`Documents.upload`. The upload response carries only ``uuid``,
|
|
15
|
+
``file_name``, ``doc_type`` and ``size``; the rest are filled by
|
|
16
|
+
:meth:`Documents.list`.
|
|
17
|
+
|
|
18
|
+
``sent_to_processor_at`` and ``processor_status`` record when our team
|
|
19
|
+
forwarded the document to the processor and what it answered. Both are
|
|
20
|
+
``None`` until it has been forwarded.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
uuid: str | None = None
|
|
24
|
+
file_name: str | None = None
|
|
25
|
+
doc_type: str | None = None
|
|
26
|
+
chargeback_transaction_info_id: str | None = None
|
|
27
|
+
size: int | None = None
|
|
28
|
+
uploaded_at: str | None = None
|
|
29
|
+
uploaded_via: str | None = None
|
|
30
|
+
sent_to_processor_at: str | None = None
|
|
31
|
+
processor_status: str | None = None
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_dict(cls, data: dict[str, Any]) -> 'Document':
|
|
35
|
+
# The API reports forwarding as a [timestamp, processor status] pair.
|
|
36
|
+
sent = data.get('sent_to_processor')
|
|
37
|
+
pair = dict(zip(('at', 'status'), sent)) if isinstance(sent, list) else {'at': sent}
|
|
38
|
+
|
|
39
|
+
return cls(
|
|
40
|
+
uuid=arr_string(data, 'uuid'),
|
|
41
|
+
file_name=arr_string(data, 'file_name'),
|
|
42
|
+
doc_type=arr_string(data, 'doc_type'),
|
|
43
|
+
chargeback_transaction_info_id=arr_string(data, 'chargeback_transaction_info_id'),
|
|
44
|
+
size=arr_int(data, 'size'),
|
|
45
|
+
uploaded_at=arr_string(data, 'uploaded_at'),
|
|
46
|
+
uploaded_via=arr_string(data, 'uploaded_via'),
|
|
47
|
+
sent_to_processor_at=arr_string(pair, 'at'),
|
|
48
|
+
processor_status=arr_string(pair, 'status'),
|
|
49
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_array, arr_string
|
|
5
|
+
from .document import Document
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class DocumentUploadFailure:
|
|
10
|
+
"""A file from an upload that could not be stored. Re-send just this one."""
|
|
11
|
+
|
|
12
|
+
file_name: str | None = None
|
|
13
|
+
reason: str | None = None
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def from_dict(cls, data: dict[str, Any]) -> 'DocumentUploadFailure':
|
|
17
|
+
return cls(
|
|
18
|
+
file_name=arr_string(data, 'file_name'),
|
|
19
|
+
reason=arr_string(data, 'reason'),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class DocumentUploadResult:
|
|
25
|
+
"""
|
|
26
|
+
The outcome of :meth:`Documents.upload`.
|
|
27
|
+
|
|
28
|
+
Files are stored independently, so an upload can partly succeed: ``documents``
|
|
29
|
+
lists what was stored and ``failed`` what was not.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
message: str | None = None
|
|
33
|
+
documents: list[Document] = field(default_factory=list)
|
|
34
|
+
failed: list[DocumentUploadFailure] = field(default_factory=list)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_dict(cls, data: dict[str, Any]) -> 'DocumentUploadResult':
|
|
38
|
+
return cls(
|
|
39
|
+
message=arr_string(data, 'message'),
|
|
40
|
+
documents=[Document.from_dict(d) for d in arr_array(data, 'documents') if isinstance(d, dict)],
|
|
41
|
+
failed=[DocumentUploadFailure.from_dict(f) for f in arr_array(data, 'failed') if isinstance(f, dict)],
|
|
42
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_array, arr_bool, arr_int, arr_object, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class FundRelease:
|
|
9
|
+
"""
|
|
10
|
+
A request to pay out held funds.
|
|
11
|
+
|
|
12
|
+
``status`` is ``released`` (sent), ``failed`` (declined; nothing moved) or
|
|
13
|
+
``unknown`` (no confirmation came back, so it may have gone through — its
|
|
14
|
+
amount stays held back from ``releasable`` until it is reconciled).
|
|
15
|
+
``transaction_info_ids`` is empty when the release was requested by amount.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
id: int | None = None
|
|
19
|
+
amount: str | None = None
|
|
20
|
+
fee: str | None = None
|
|
21
|
+
status: str | None = None
|
|
22
|
+
status_label: str | None = None
|
|
23
|
+
idempotency_key: str | None = None
|
|
24
|
+
transaction_info_ids: list[str] = field(default_factory=list)
|
|
25
|
+
failure_reason: str | None = None
|
|
26
|
+
requested_at: str | None = None
|
|
27
|
+
completed_at: str | None = None
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def from_dict(cls, data: dict[str, Any]) -> 'FundRelease':
|
|
31
|
+
return cls(
|
|
32
|
+
id=arr_int(data, 'id'),
|
|
33
|
+
amount=arr_string(data, 'amount'),
|
|
34
|
+
fee=arr_string(data, 'fee'),
|
|
35
|
+
status=arr_string(data, 'status'),
|
|
36
|
+
status_label=arr_string(data, 'status_label'),
|
|
37
|
+
idempotency_key=arr_string(data, 'idempotency_key'),
|
|
38
|
+
transaction_info_ids=[str(t) for t in arr_array(data, 'transaction_info_ids') if t is not None],
|
|
39
|
+
failure_reason=arr_string(data, 'failure_reason'),
|
|
40
|
+
requested_at=arr_string(data, 'requested_at'),
|
|
41
|
+
completed_at=arr_string(data, 'completed_at'),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class FundReleaseResult:
|
|
47
|
+
"""
|
|
48
|
+
The response to :meth:`Funds.release`. ``replayed`` is true when the
|
|
49
|
+
``idempotency_key`` had been used before and the original release is being
|
|
50
|
+
returned rather than a new one sent.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
sid: str | None = None
|
|
54
|
+
replayed: bool = False
|
|
55
|
+
release: FundRelease = field(default_factory=FundRelease)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_dict(cls, data: dict[str, Any]) -> 'FundReleaseResult':
|
|
59
|
+
return cls(
|
|
60
|
+
sid=arr_string(data, 'sid'),
|
|
61
|
+
replayed=arr_bool(data, 'replayed'),
|
|
62
|
+
release=FundRelease.from_dict(arr_object(data, 'release')),
|
|
63
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_bool, arr_int, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class HeldBalance:
|
|
9
|
+
"""
|
|
10
|
+
A held-funds merchant's balance at the processor, in dollars.
|
|
11
|
+
|
|
12
|
+
``releasable`` is the figure that matters and the one a release is checked
|
|
13
|
+
against: ``available`` less ``at_risk`` (ACH still inside the return window),
|
|
14
|
+
``owed_to_split`` (takings promised to another account), ``unresolved``
|
|
15
|
+
(releases requested and not yet confirmed) and ``release_fee``, never below
|
|
16
|
+
zero and never above ``ach_out_limit_remaining``.
|
|
17
|
+
|
|
18
|
+
Money is kept as strings, consistent with the rest of the SDK, to avoid float
|
|
19
|
+
rounding.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
sid: str | None = None
|
|
23
|
+
available: str | None = None
|
|
24
|
+
pending: str | None = None
|
|
25
|
+
reserve: str | None = None
|
|
26
|
+
at_risk: str | None = None
|
|
27
|
+
owed_to_split: str | None = None
|
|
28
|
+
unresolved: str | None = None
|
|
29
|
+
release_fee: str | None = None
|
|
30
|
+
releasable: str | None = None
|
|
31
|
+
ach_settlement_days: int | None = None
|
|
32
|
+
ach_out_enabled: bool = False
|
|
33
|
+
ach_out_limit_remaining: str | None = None
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def from_dict(cls, data: dict[str, Any]) -> 'HeldBalance':
|
|
37
|
+
return cls(
|
|
38
|
+
sid=arr_string(data, 'sid'),
|
|
39
|
+
available=arr_string(data, 'available'),
|
|
40
|
+
pending=arr_string(data, 'pending'),
|
|
41
|
+
reserve=arr_string(data, 'reserve'),
|
|
42
|
+
at_risk=arr_string(data, 'at_risk'),
|
|
43
|
+
owed_to_split=arr_string(data, 'owed_to_split'),
|
|
44
|
+
unresolved=arr_string(data, 'unresolved'),
|
|
45
|
+
release_fee=arr_string(data, 'release_fee'),
|
|
46
|
+
releasable=arr_string(data, 'releasable'),
|
|
47
|
+
ach_settlement_days=arr_int(data, 'ach_settlement_days'),
|
|
48
|
+
ach_out_enabled=arr_bool(data, 'ach_out_enabled'),
|
|
49
|
+
ach_out_limit_remaining=arr_string(data, 'ach_out_limit_remaining'),
|
|
50
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_array, arr_bool, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ReleasableTransaction:
|
|
9
|
+
"""
|
|
10
|
+
A held-funds payment that can be released now. ``amount`` is what releasing
|
|
11
|
+
it would pay the merchant: ``net_amount`` less ``split_amount``. ``type`` is
|
|
12
|
+
``CC`` or ``ACH``.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
transaction_info_id: str | None = None
|
|
16
|
+
type: str | None = None
|
|
17
|
+
transaction_date: str | None = None
|
|
18
|
+
gross_amount: str | None = None
|
|
19
|
+
net_amount: str | None = None
|
|
20
|
+
split_amount: str | None = None
|
|
21
|
+
amount: str | None = None
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_dict(cls, data: dict[str, Any]) -> 'ReleasableTransaction':
|
|
25
|
+
return cls(
|
|
26
|
+
transaction_info_id=arr_string(data, 'transaction_info_id'),
|
|
27
|
+
type=arr_string(data, 'type'),
|
|
28
|
+
transaction_date=arr_string(data, 'transaction_date'),
|
|
29
|
+
gross_amount=arr_string(data, 'gross_amount'),
|
|
30
|
+
net_amount=arr_string(data, 'net_amount'),
|
|
31
|
+
split_amount=arr_string(data, 'split_amount'),
|
|
32
|
+
amount=arr_string(data, 'amount'),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ReleasableTransactions:
|
|
38
|
+
"""
|
|
39
|
+
The payments a held-funds merchant can release, newest first, up to 500.
|
|
40
|
+
``truncated`` is true when there are more than were listed.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
sid: str | None = None
|
|
44
|
+
transactions: list[ReleasableTransaction] = field(default_factory=list)
|
|
45
|
+
total: str | None = None
|
|
46
|
+
truncated: bool = False
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def from_dict(cls, data: dict[str, Any]) -> 'ReleasableTransactions':
|
|
50
|
+
return cls(
|
|
51
|
+
sid=arr_string(data, 'sid'),
|
|
52
|
+
transactions=[
|
|
53
|
+
ReleasableTransaction.from_dict(t) for t in arr_array(data, 'transactions') if isinstance(t, dict)
|
|
54
|
+
],
|
|
55
|
+
total=arr_string(data, 'total'),
|
|
56
|
+
truncated=arr_bool(data, 'truncated'),
|
|
57
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_int, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class SubscribeResult:
|
|
9
|
+
"""
|
|
10
|
+
The response to :meth:`SubscriptionPlans.subscribe`: the new subscription's
|
|
11
|
+
id and status, and the first payment that was charged to start it.
|
|
12
|
+
Fetch the full record with :meth:`Subscriptions.show`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
subscription_id: int | None = None
|
|
16
|
+
status: str | None = None
|
|
17
|
+
next_run_date: str | None = None
|
|
18
|
+
transaction_number: str | None = None
|
|
19
|
+
amount: str | None = None
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_dict(cls, data: dict[str, Any]) -> 'SubscribeResult':
|
|
23
|
+
return cls(
|
|
24
|
+
subscription_id=arr_int(data, 'subscription_id'),
|
|
25
|
+
status=arr_string(data, 'status'),
|
|
26
|
+
next_run_date=arr_string(data, 'next_run_date'),
|
|
27
|
+
transaction_number=arr_string(data, 'transaction_number'),
|
|
28
|
+
amount=arr_string(data, 'amount'),
|
|
29
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_array, arr_int, arr_object, arr_string
|
|
5
|
+
from .subscription_item import SubscriptionItem
|
|
6
|
+
from .subscription_payment_method import SubscriptionPaymentMethod
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Subscription:
|
|
11
|
+
"""
|
|
12
|
+
A customer's enrollment in a :class:`SubscriptionPlan`.
|
|
13
|
+
|
|
14
|
+
``status`` is one of ``Active``, ``Failed``, ``Paused``, ``Cancelled`` or
|
|
15
|
+
``Ended``. ``items`` is populated by :meth:`Subscriptions.show` only; list
|
|
16
|
+
and lifecycle responses leave it empty.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
id: int | None = None
|
|
20
|
+
subscription_plan_id: int | None = None
|
|
21
|
+
plan_name: str | None = None
|
|
22
|
+
amount: str | None = None
|
|
23
|
+
recurrence_schedule: str | None = None
|
|
24
|
+
start_date: str | None = None
|
|
25
|
+
end_date: str | None = None
|
|
26
|
+
last_run_date: str | None = None
|
|
27
|
+
last_run_status: str | None = None
|
|
28
|
+
last_run_failed_count: int | None = None
|
|
29
|
+
next_run_date: str | None = None
|
|
30
|
+
status: str | None = None
|
|
31
|
+
paused_until_date: str | None = None
|
|
32
|
+
cancelled_at: str | None = None
|
|
33
|
+
cancelled_by: str | None = None
|
|
34
|
+
customer_uuid: str | None = None
|
|
35
|
+
error: str | None = None
|
|
36
|
+
payment_method: SubscriptionPaymentMethod = field(default_factory=SubscriptionPaymentMethod)
|
|
37
|
+
items: list[SubscriptionItem] = field(default_factory=list)
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_dict(cls, data: dict[str, Any]) -> 'Subscription':
|
|
41
|
+
return cls(
|
|
42
|
+
id=arr_int(data, 'id'),
|
|
43
|
+
subscription_plan_id=arr_int(data, 'subscription_plan_id'),
|
|
44
|
+
plan_name=arr_string(data, 'plan_name'),
|
|
45
|
+
amount=arr_string(data, 'amount'),
|
|
46
|
+
recurrence_schedule=arr_string(data, 'recurrence_schedule'),
|
|
47
|
+
start_date=arr_string(data, 'start_date'),
|
|
48
|
+
end_date=arr_string(data, 'end_date'),
|
|
49
|
+
last_run_date=arr_string(data, 'last_run_date'),
|
|
50
|
+
last_run_status=arr_string(data, 'last_run_status'),
|
|
51
|
+
last_run_failed_count=arr_int(data, 'last_run_failed_count'),
|
|
52
|
+
next_run_date=arr_string(data, 'next_run_date'),
|
|
53
|
+
status=arr_string(data, 'status'),
|
|
54
|
+
paused_until_date=arr_string(data, 'paused_until_date'),
|
|
55
|
+
cancelled_at=arr_string(data, 'cancelled_at'),
|
|
56
|
+
cancelled_by=arr_string(data, 'cancelled_by'),
|
|
57
|
+
customer_uuid=arr_string(data, 'customer_uuid'),
|
|
58
|
+
error=arr_string(data, 'error'),
|
|
59
|
+
payment_method=SubscriptionPaymentMethod.from_dict(arr_object(data, 'payment_method')),
|
|
60
|
+
items=[SubscriptionItem.from_dict(i) for i in arr_array(data, 'items') if isinstance(i, dict)],
|
|
61
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class SubscriptionItem:
|
|
9
|
+
"""
|
|
10
|
+
A line on a subscription plan or subscription. ``amount`` (quantity times
|
|
11
|
+
unit price) is reported on a :class:`Subscription`'s items only; it is
|
|
12
|
+
``None`` on a :class:`SubscriptionPlan`'s.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
name: str | None = None
|
|
16
|
+
description: str | None = None
|
|
17
|
+
quantity: str | None = None
|
|
18
|
+
unit_price: str | None = None
|
|
19
|
+
amount: str | None = None
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_dict(cls, data: dict[str, Any]) -> 'SubscriptionItem':
|
|
23
|
+
return cls(
|
|
24
|
+
name=arr_string(data, 'name'),
|
|
25
|
+
description=arr_string(data, 'description'),
|
|
26
|
+
quantity=arr_string(data, 'quantity'),
|
|
27
|
+
unit_price=arr_string(data, 'unit_price'),
|
|
28
|
+
amount=arr_string(data, 'amount'),
|
|
29
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_int, arr_string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class SubscriptionPaymentMethod:
|
|
9
|
+
"""
|
|
10
|
+
The saved payment method a subscription charges. ``type`` is ``cc`` or
|
|
11
|
+
``ach``; ``last_four`` and ``expiration`` are set for a card, ``bank_name``
|
|
12
|
+
and ``account_type`` for a bank account.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
id: int | None = None
|
|
16
|
+
type: str | None = None
|
|
17
|
+
last_four: str | None = None
|
|
18
|
+
expiration: str | None = None
|
|
19
|
+
bank_name: str | None = None
|
|
20
|
+
account_type: str | None = None
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def from_dict(cls, data: dict[str, Any]) -> 'SubscriptionPaymentMethod':
|
|
24
|
+
return cls(
|
|
25
|
+
id=arr_int(data, 'id'),
|
|
26
|
+
type=arr_string(data, 'type'),
|
|
27
|
+
last_four=arr_string(data, 'last_four'),
|
|
28
|
+
expiration=arr_string(data, 'expiration'),
|
|
29
|
+
bank_name=arr_string(data, 'bank_name'),
|
|
30
|
+
account_type=arr_string(data, 'account_type'),
|
|
31
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..support.arr import arr_array, arr_bool, arr_int, arr_string
|
|
5
|
+
from .subscription_item import SubscriptionItem
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class SubscriptionPlan:
|
|
10
|
+
"""
|
|
11
|
+
A recurring offering customers subscribe to.
|
|
12
|
+
|
|
13
|
+
``status`` is ``draft``, ``active`` or ``archived``; only an active plan
|
|
14
|
+
accepts new subscribers. ``recurrence_schedule`` is one of ``Weekly``,
|
|
15
|
+
``Biweekly``, ``FirstFifteenth``, ``Monthly`` or ``Yearly``.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
id: int | None = None
|
|
19
|
+
name: str | None = None
|
|
20
|
+
description: str | None = None
|
|
21
|
+
recurrence_schedule: str | None = None
|
|
22
|
+
status: str | None = None
|
|
23
|
+
subtotal: str | None = None
|
|
24
|
+
total: str | None = None
|
|
25
|
+
token: str | None = None
|
|
26
|
+
public_url: str | None = None
|
|
27
|
+
allow_public: bool = False
|
|
28
|
+
created_at: str | None = None
|
|
29
|
+
items: list[SubscriptionItem] = field(default_factory=list)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_dict(cls, data: dict[str, Any]) -> 'SubscriptionPlan':
|
|
33
|
+
return cls(
|
|
34
|
+
id=arr_int(data, 'id'),
|
|
35
|
+
name=arr_string(data, 'name'),
|
|
36
|
+
description=arr_string(data, 'description'),
|
|
37
|
+
recurrence_schedule=arr_string(data, 'recurrence_schedule'),
|
|
38
|
+
status=arr_string(data, 'status'),
|
|
39
|
+
subtotal=arr_string(data, 'subtotal'),
|
|
40
|
+
total=arr_string(data, 'total'),
|
|
41
|
+
token=arr_string(data, 'token'),
|
|
42
|
+
public_url=arr_string(data, 'public_url'),
|
|
43
|
+
allow_public=arr_bool(data, 'allow_public'),
|
|
44
|
+
created_at=arr_string(data, 'created_at'),
|
|
45
|
+
items=[SubscriptionItem.from_dict(i) for i in arr_array(data, 'items') if isinstance(i, dict)],
|
|
46
|
+
)
|