Skip to content

Commit 7453795

Browse files
rogelioLpzpachCode
andauthored
Wallets (#181)
* wallets base model * Add base wallet account * WalletTransaction * update, delete for savings * not currency for now * more changes savings * query wallet transactions * balance entries * update cuenca-validations * test for savings * wallet_id in balance_entries * serialize datetime * test * PR comments * Record cassettes for tests * Otional fields and some fixes * Deactivable * bump version * lint Co-authored-by: pachCode <arturo@cuenca.com>
1 parent 5a86635 commit 7453795

22 files changed

+1283
-80
lines changed

cuenca/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
'Commission',
1313
'Deposit',
1414
'LoginToken',
15+
'Saving',
1516
'ServiceProvider',
1617
'Statement',
1718
'Transfer',
1819
'UserCredential',
1920
'UserLogin',
21+
'WalletTransaction',
2022
'WhatsappTransfer',
2123
'configure',
2224
'get_balance',
@@ -38,11 +40,13 @@
3840
Commission,
3941
Deposit,
4042
LoginToken,
43+
Saving,
4144
ServiceProvider,
4245
Statement,
4346
Transfer,
4447
UserCredential,
4548
UserLogin,
49+
WalletTransaction,
4650
WhatsappTransfer,
4751
)
4852
from .version import __version__

cuenca/http/client.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime as dt
12
import json
23
import os
34
from typing import Optional, Tuple
@@ -104,6 +105,12 @@ def request(
104105
if self.jwt_token.is_expired:
105106
self.jwt_token = Jwt.create(self)
106107
self.session.headers['X-Cuenca-Token'] = self.jwt_token.token
108+
109+
if data is not None:
110+
for key, value in data.items():
111+
if isinstance(value, dt.date):
112+
data[key] = value.isoformat()
113+
107114
resp = self.session.request(
108115
method=method,
109116
url='https://' + self.host + urljoin('/', endpoint),

cuenca/resources/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
'Commission',
1212
'Deposit',
1313
'LoginToken',
14+
'Saving',
1415
'ServiceProvider',
1516
'Statement',
1617
'Transfer',
1718
'UserLogin',
19+
'WalletTransaction',
1820
'WhatsappTransfer',
1921
]
2022

@@ -31,11 +33,13 @@
3133
from .deposits import Deposit
3234
from .login_tokens import LoginToken
3335
from .resources import RESOURCES
36+
from .savings import Saving
3437
from .service_providers import ServiceProvider
3538
from .statements import Statement
3639
from .transfers import Transfer
3740
from .user_credentials import UserCredential
3841
from .user_logins import UserLogin
42+
from .wallet_transactions import WalletTransaction
3943
from .whatsapp_transfers import WhatsappTransfer
4044

4145
# avoid circular imports
@@ -52,11 +56,13 @@
5256
Commission,
5357
Deposit,
5458
LoginToken,
59+
Saving,
5560
ServiceProvider,
5661
Statement,
5762
Transfer,
5863
UserCredential,
5964
UserLogin,
65+
WalletTransaction,
6066
WhatsappTransfer,
6167
]
6268
for resource_cls in resource_classes:

cuenca/resources/balance_entries.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class BalanceEntry(Retrievable, Queryable):
2626
type: EntryType
2727
related_transaction_uri: str
2828
funding_instrument_uri: str
29+
wallet_id: str
2930

3031
@property # type: ignore
3132
def related_transaction(self) -> Transaction:

cuenca/resources/base.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ def _update(
7979
return cls._from_dict(resp)
8080

8181

82+
@dataclass
83+
class Deactivable(Resource):
84+
deactivated_at: dt.datetime
85+
86+
@classmethod
87+
def deactivate(
88+
cls, id: str, *, session: Session = global_session, **data
89+
) -> Resource:
90+
resp = session.delete(f'/{cls._resource}/{id}', data)
91+
return cls._from_dict(resp)
92+
93+
@property
94+
def is_active(self):
95+
return not self.deactivated_at
96+
97+
8298
@dataclass
8399
class Downloadable(Resource):
84100
@classmethod
@@ -168,3 +184,13 @@ class Transaction(Retrievable, Queryable):
168184
amount: int # in centavos
169185
status: TransactionStatus
170186
descriptor: str # how it appears for the customer
187+
188+
189+
@dataclass
190+
class Wallet(Creatable, Deactivable, Retrievable, Queryable):
191+
user_id: str
192+
balance: int
193+
194+
@property
195+
def wallet_uri(self):
196+
return f'/{self._resource}/{self.id}'

cuenca/resources/savings.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import datetime as dt
2+
from dataclasses import dataclass
3+
from typing import ClassVar, Optional, cast
4+
5+
from cuenca_validations.types import (
6+
SavingCategory,
7+
SavingRequest,
8+
SavingUpdateRequest,
9+
StrictPositiveInt,
10+
WalletQuery,
11+
)
12+
13+
from .base import Updateable, Wallet
14+
15+
16+
@dataclass
17+
class Saving(Wallet, Updateable):
18+
_resource: ClassVar = 'savings'
19+
_query_params: ClassVar = WalletQuery
20+
name: str
21+
category: SavingCategory
22+
goal_amount: Optional[StrictPositiveInt]
23+
goal_date: Optional[dt.datetime]
24+
25+
@classmethod
26+
def create(
27+
cls,
28+
name: str,
29+
category: SavingCategory,
30+
goal_amount: Optional[int] = None,
31+
goal_date: Optional[dt.datetime] = None,
32+
):
33+
request = SavingRequest(
34+
name=name,
35+
category=category,
36+
goal_amount=goal_amount,
37+
goal_date=goal_date,
38+
)
39+
return cast('Saving', cls._create(**request.dict()))
40+
41+
@classmethod
42+
def update(
43+
cls,
44+
saving_id: str,
45+
name: Optional[str] = None,
46+
category: Optional[SavingCategory] = None,
47+
goal_amount: Optional[int] = None,
48+
goal_date: Optional[dt.datetime] = None,
49+
) -> 'Saving':
50+
request = SavingUpdateRequest(
51+
name=name,
52+
category=category,
53+
goal_amount=goal_amount,
54+
goal_date=goal_date,
55+
)
56+
return cast('Saving', cls._update(id=saving_id, **request.dict()))
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from dataclasses import dataclass
2+
from typing import ClassVar, Optional, cast
3+
4+
from cuenca_validations.types import (
5+
WalletTransactionQuery,
6+
WalletTransactionRequest,
7+
WalletTransactionType,
8+
)
9+
10+
from cuenca.resources.base import Creatable, Transaction
11+
from cuenca.resources.resources import retrieve_uri
12+
13+
from .base import Wallet
14+
15+
16+
@dataclass
17+
class WalletTransaction(Transaction, Creatable):
18+
_resource: ClassVar = 'wallet_transactions'
19+
_query_params: ClassVar = WalletTransactionQuery
20+
21+
transaction_type: WalletTransactionType
22+
wallet_uri: str
23+
24+
@property
25+
def wallet(self) -> Optional['Wallet']:
26+
return cast('Wallet', retrieve_uri(self.wallet_uri))
27+
28+
@classmethod
29+
def create(
30+
cls,
31+
wallet_uri: str,
32+
transaction_type: WalletTransactionType,
33+
amount: int,
34+
):
35+
request = WalletTransactionRequest(
36+
wallet_uri=wallet_uri,
37+
transaction_type=transaction_type,
38+
amount=amount,
39+
)
40+
return cast('WalletTransaction', cls._create(**request.dict()))

cuenca/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
__version__ = '0.7.11'
1+
__version__ = '0.7.12'
22
CLIENT_VERSION = __version__
33
API_VERSION = '2020-03-19'

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
requests==2.26.0
2-
cuenca-validations==0.9.10
2+
cuenca-validations==0.9.11
33
dataclasses>=0.7;python_version<"3.7"

0 commit comments

Comments
 (0)