Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3 api rc #194

Merged
merged 64 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
ec1938e
added http client
adgsantos Oct 18, 2024
bcfeb11
moved old to v2
adgsantos Oct 18, 2024
5cea972
moved v3 to top-level
adgsantos Oct 18, 2024
409a3bc
version
adgsantos Oct 18, 2024
257a366
moved tests
adgsantos Oct 18, 2024
487c9d6
remove ipynb
adgsantos Oct 18, 2024
bdf9362
fixed imports
adgsantos Oct 18, 2024
3d396f9
add more overrides to requests
adgsantos Oct 18, 2024
0c62fc6
cleaned up signatures
adgsantos Oct 18, 2024
de90077
flake8
adgsantos Oct 18, 2024
7f940f1
updated errors
adgsantos Oct 18, 2024
412842a
renamed to TransactionInput
adgsantos Oct 18, 2024
912f132
export errors
adgsantos Oct 18, 2024
15dc4cf
imports
adgsantos Oct 20, 2024
25a2c55
fixed tests
adgsantos Oct 21, 2024
002f36c
keepalive
adgsantos Oct 21, 2024
5f210de
typing
adgsantos Oct 21, 2024
a7ce64f
path
adgsantos Oct 21, 2024
e1dc3b8
Add webhooks resource
0e4ef622 Oct 21, 2024
d609da8
Add rules resource
0e4ef622 Oct 21, 2024
70c3b85
Add sdk.webhooks.patch
0e4ef622 Oct 21, 2024
44392c0
api_key fixture
adgsantos Oct 21, 2024
29dc02e
recurring groups
adgsantos Oct 21, 2024
453ebfb
rename create
adgsantos Oct 22, 2024
c628f6e
Use request id from response
0e4ef622 Oct 22, 2024
bb44a54
remove group_id
adgsantos Oct 22, 2024
d49401d
bank_statements: add error
adgsantos Oct 22, 2024
4597e52
bank_statements: fix schema
adgsantos Oct 22, 2024
6e62863
wait_for_results
adgsantos Oct 22, 2024
3b21cdc
fixes
adgsantos Oct 22, 2024
68ed9ff
optional
adgsantos Oct 22, 2024
8f89745
versions
adgsantos Oct 22, 2024
504710f
Bump version: 4.26.0 → 5.0.0
adgsantos Oct 22, 2024
10523fa
Bump version: 5.0.0 → 5.0.0rc1
adgsantos Oct 22, 2024
e5af925
version
adgsantos Oct 22, 2024
1186dfe
add transaction ids
adgsantos Oct 24, 2024
53dc758
update webhook
adgsantos Oct 25, 2024
cf3f531
added categories
adgsantos Oct 25, 2024
8728185
widen mcc validation
adgsantos Oct 28, 2024
69ef4a2
remove intermediary type
adgsantos Oct 28, 2024
11ab649
update schemas
adgsantos Oct 28, 2024
b0d19a1
transactions: remove recurrence group
adgsantos Oct 28, 2024
c7dc802
lint
adgsantos Oct 29, 2024
a416a91
overview -> verify
adgsantos Oct 29, 2024
a52313b
added entities
adgsantos Oct 29, 2024
a13c6de
msg
adgsantos Oct 29, 2024
489fec5
added reports resources
adgsantos Oct 29, 2024
7ce15d1
Add __all__ to __init__.py
0e4ef622 Oct 29, 2024
7eb280d
Bump version: 5.0.0rc1 → 5.0.0rc2
0e4ef622 Oct 29, 2024
bab653e
Update requirements_dev.txt
0e4ef622 Oct 29, 2024
29ff82b
Fix some types and add delete methods
0e4ef622 Oct 31, 2024
61f4725
Fix batch post
0e4ef622 Oct 31, 2024
55d2d17
Fixes
0e4ef622 Nov 1, 2024
12fb1db
Allow str for account holder type
0e4ef622 Nov 1, 2024
17aff0a
ah, txs: add created_at
adgsantos Nov 4, 2024
01cd493
test 404
adgsantos Nov 4, 2024
a26af5a
typing
adgsantos Nov 4, 2024
0419f55
fixes
adgsantos Nov 4, 2024
657bf5e
categories: return results
adgsantos Nov 4, 2024
7180fa8
Update rules resource
0e4ef622 Nov 5, 2024
333b377
sdk: accept session
adgsantos Nov 5, 2024
2433e8b
sdk: filter out null params
adgsantos Nov 5, 2024
0f6821b
Add BankStatementTransaction.to_transaction_input
0e4ef622 Nov 5, 2024
fc51d7e
Bump version: 5.0.0rc2 → 5.0.1
adgsantos Nov 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,21 @@ $ python3 -m pip install --upgrade 'ntropy-sdk'
Enriching your first transaction requires an `SDK` object and an input `Transaction` object. The API key can be set in the environment variable `NTROPY_API_KEY` or in the `SDK` constructor:

```python
from ntropy_sdk import SDK, Transaction
from ntropy_sdk import SDK

sdk = SDK("YOUR-API-KEY")
tx = Transaction(
description = "AMAZON WEB SERVICES",
entry_type = "outgoing",
amount = 12042.37,
iso_currency_code = "USD",
date = "2021-11-01",
transaction_id = "4yp49x3tbj9mD8DB4fM8DDY6Yxbx8YP14g565Xketw3tFmn",
country = "US",
account_holder_id = "id-1",
account_holder_type = "business",
account_holder_name = "Robin's Tacos",
r = sdk.transactions.create(
id="4yp49x3tbj9mD8DB4fM8DDY6Yxbx8YP14g565Xketw3tFmn",
description="AMAZON WEB SERVICES",
entry_type="outgoing",
amount=12042.37,
currency="USD",
date="2021-11-01",
location=dict(
country="US"
),
)

enriched_tx = sdk.add_transactions([tx])[0]
print(enriched_tx.merchant)
print(r)
```

The returned `EnrichedTransaction` contains the added information by Ntropy API. You can consult the Enrichment section of the documentation for more information on the parameters for both `Transaction` and `EnrichedTransaction`.
Expand Down
70 changes: 48 additions & 22 deletions ntropy_sdk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,57 @@
__version__ = "4.26.0"

from ntropy_sdk.ntropy_sdk import (
AccountHolder,
AccountHolderType,
Transaction,
SDK,
Batch,
__version__ = "5.0.1"

from typing import TYPE_CHECKING, Optional
import requests


if TYPE_CHECKING:
from typing_extensions import TypedDict

class ExtraKwargs(TypedDict, total=False):
request_id: Optional[str]
api_key: Optional[str]
session: Optional[requests.Session]
retries: int
timeout: int
retry_on_unhandled_exception: bool
extra_headers: Optional[dict]


from .sdk import SDK
from .v2.errors import (
NtropyError,
NtropyBatchError,
EnrichedTransaction,
EnrichedTransactionList,
BankStatement,
BankStatementRequest,
Report,
NtropyDatasourceError,
NtropyTimeoutError,
NtropyHTTPError,
NtropyValidationError,
NtropyQuotaExceededError,
NtropyNotSupportedError,
NtropyResourceOccupiedError,
NtropyServerConnectionError,
NtropyRateLimitError,
NtropyNotFoundError,
NtropyNotAuthorizedError,
NtropyValueError,
NtropyRuntimeError,
)


__all__ = (
"AccountHolder",
"AccountHolderType",
"Transaction",
"SDK",
"Batch",
"NtropyError",
"NtropyBatchError",
"EnrichedTransaction",
"EnrichedTransactionList",
"BankStatement",
"BankStatementRequest",
"Report",
"NtropyDatasourceError",
"NtropyTimeoutError",
"NtropyHTTPError",
"NtropyValidationError",
"NtropyQuotaExceededError",
"NtropyNotSupportedError",
"NtropyResourceOccupiedError",
"NtropyServerConnectionError",
"NtropyRateLimitError",
"NtropyNotFoundError",
"NtropyNotAuthorizedError",
"NtropyValueError",
"NtropyRuntimeError",
)
162 changes: 162 additions & 0 deletions ntropy_sdk/account_holders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import uuid
from datetime import datetime
from enum import Enum
from typing import Optional, TYPE_CHECKING, Union

from pydantic import BaseModel, Field

from ntropy_sdk.paging import PagedResponse
from ntropy_sdk.transactions import RecurrenceGroup, RecurrenceGroups
from ntropy_sdk.utils import pydantic_json

if TYPE_CHECKING:
from ntropy_sdk import ExtraKwargs
from ntropy_sdk import SDK
from typing_extensions import Unpack


class AccountHolderType(str, Enum):
consumer = "consumer"
business = "business"


class AccountHolderCreate(BaseModel):
id: str = Field(
description="The unique ID of the account holder of the transaction",
min_length=1,
)
type: AccountHolderType = Field(
description="The type of the account holder. ",
)
name: Optional[str] = Field(
default=None,
description="The name of the account holder",
)
request_id: Optional[str] = None


class AccountHolderResponse(AccountHolderCreate):
created_at: datetime = Field(
...,
description="Date of creation of the account holder",
)


class AccountHoldersResource:
def __init__(self, sdk: "SDK"):
self._sdk = sdk

def list(
self,
*,
created_before: Optional[datetime] = None,
created_after: Optional[datetime] = None,
cursor: Optional[str] = None,
limit: Optional[int] = None,
**extra_kwargs: "Unpack[ExtraKwargs]",
) -> PagedResponse[AccountHolderResponse]:
"""List all account holders"""

request_id = extra_kwargs.get("request_id")
if request_id is None:
request_id = uuid.uuid4().hex
extra_kwargs["request_id"] = request_id
resp = self._sdk.retry_ratelimited_request(
method="GET",
url="/v3/account_holders",
params={
"created_before": created_before,
"created_after": created_after,
"cursor": cursor,
"limit": limit,
},
**extra_kwargs,
)
page = PagedResponse[AccountHolderResponse](
**resp.json(),
request_id=resp.headers.get("x-request-id", request_id),
_resource=self,
_extra_kwargs=extra_kwargs,
)
for t in page.data:
t.request_id = request_id
return page

def get(
self, id: str, **extra_kwargs: "Unpack[ExtraKwargs]"
) -> AccountHolderResponse:
"""Retrieve an account holder"""

request_id = extra_kwargs.get("request_id")
if request_id is None:
request_id = uuid.uuid4().hex
extra_kwargs["request_id"] = request_id
resp = self._sdk.retry_ratelimited_request(
method="GET",
url=f"/v3/account_holders/{id}",
**extra_kwargs,
)
return AccountHolderResponse(
**resp.json(), request_id=resp.headers.get("x-request-id", request_id)
)

def create(
self,
id: str,
type: Union[AccountHolderType, str],
name: Optional[str] = None,
**extra_kwargs: "Unpack[ExtraKwargs]",
) -> AccountHolderResponse:
"""Create an account holder"""

request_id = extra_kwargs.get("request_id")
if request_id is None:
request_id = uuid.uuid4().hex
extra_kwargs["request_id"] = request_id
resp = self._sdk.retry_ratelimited_request(
method="POST",
url="/v3/account_holders",
payload_json_str=pydantic_json(
AccountHolderCreate(
id=id,
type=type,
name=name,
)
),
**extra_kwargs,
)
return AccountHolderResponse(
**resp.json(), request_id=resp.headers.get("x-request-id", request_id)
)

def recurring_groups(
self,
id: str,
**extra_kwargs: "Unpack[ExtraKwargs]",
) -> RecurrenceGroups:
request_id = extra_kwargs.get("request_id")
if request_id is None:
request_id = uuid.uuid4().hex
extra_kwargs["request_id"] = request_id
resp = self._sdk.retry_ratelimited_request(
method="POST",
url=f"/v3/account_holders/{id}/recurring_groups",
**extra_kwargs,
)
return RecurrenceGroups(
groups=[RecurrenceGroup(**r) for r in resp.json()],
request_id=resp.headers.get("x-request-id", request_id),
)

def delete(self, id: str, **extra_kwargs: "Unpack[ExtraKwargs]"):
"""Retrieve an account holder"""

request_id = extra_kwargs.get("request_id")
if request_id is None:
request_id = uuid.uuid4().hex
extra_kwargs["request_id"] = request_id
self._sdk.retry_ratelimited_request(
method="DELETE",
url=f"/v3/account_holders/{id}",
**extra_kwargs,
)
Loading
Loading