Repository: stabacco/stake-python (language: python)

Issue:
funding module not working
the funding endpoint has disappeared.


Discussion / hints:

Fix patch:
diff --git a/coverage.svg b/coverage.svg
index 3438732..0fa9649 100644
--- a/coverage.svg
+++ b/coverage.svg
@@ -15,7 +15,7 @@
     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
         <text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
         <text x="31.5" y="14">coverage</text>
-        <text x="80" y="15" fill="#010101" fill-opacity=".3">97%</text>
-        <text x="80" y="14">97%</text>
+        <text x="80" y="15" fill="#010101" fill-opacity=".3">98%</text>
+        <text x="80" y="14">98%</text>
     </g>
 </svg>
diff --git a/stake/constant.py b/stake/constant.py
index 019253a..ff39870 100644
--- a/stake/constant.py
+++ b/stake/constant.py
@@ -10,7 +10,7 @@ class Url(str, Enum):
     create_session: str = "sessions/v2/createSession"
     equity_positions: str = "users/accounts/v2/equityPositions"
     fund_details: str = "fund/details"
-    fundings: str = "utils/activityLog/fundingOnly"
+    fundings: str = "users/accounts/transactionHistory"
     market_status: str = "utils/marketStatus"
     orders: str = "users/accounts/v2/orders"
     quotes: str = "quotes/marketData/${symbols}"
diff --git a/stake/funding.py b/stake/funding.py
index ea1dc3b..0553b98 100644
--- a/stake/funding.py
+++ b/stake/funding.py
@@ -1,45 +1,17 @@
 """Your current fundings."""
-from datetime import date, datetime, timedelta
+import json
+from datetime import datetime
 from typing import List, Optional
 
 from pydantic import BaseModel, Field
-from pydantic.types import UUID4
 
 from stake.common import BaseClient, camelcase
 from stake.constant import Url
-
-__all__ = ["FundingRequest"]
-
-
-class FundingRequest(BaseModel):
-    """Request to be issued to the fundings endpoint."""
-
-    end_date: date = Field(default_factory=date.today)
-    start_date: date = Field(
-        default_factory=lambda *_: date.today() - timedelta(days=365)
-    )
-
-
-class Funding(BaseModel):
-    id: UUID4
-    timestamp: datetime
-    order_type: str
-    event_type: str
-    status: str
-    title: str
-    amount: str
-    description: str
-    currency_from: str
-    currency_to: str
-    spot_rate: float
-    total_fee: float
-    amount_from: float
-    amount_to: float
-    rate: float
-    reference_number: str
-
-    class Config:
-        alias_generator = camelcase
+from stake.transaction import (
+    TransactionHistoryElement,
+    TransactionHistoryType,
+    TransactionRecordRequest,
+)
 
 
 class CashSettlement(BaseModel):
@@ -80,14 +52,16 @@ class Config:
 
 
 class FundingsClient(BaseClient):
-    async def list(self, request: FundingRequest) -> List[Funding]:
-        payload = {
-            "endDate": request.end_date.strftime("%d/%m/%Y"),
-            "startDate": request.start_date.strftime("%d/%m/%Y"),
-        }
+    async def list(
+        self, request: TransactionRecordRequest
+    ) -> List[TransactionHistoryElement]:
+        payload = json.loads(request.json(by_alias=True))
         data = await self._client.post(Url.fundings, payload=payload)
-
-        return [Funding(**d) for d in data]
+        return [
+            TransactionHistoryElement(**d)
+            for d in data
+            if d["referenceType"] == TransactionHistoryType.FUNDING.value
+        ]
 
     async def in_flight(self) -> List[FundsInFlight]:
         """Returns the funds currently in flight."""
diff --git a/stake/transaction.py b/stake/transaction.py
index 8f1fc51..7c577a8 100644
--- a/stake/transaction.py
+++ b/stake/transaction.py
@@ -1,3 +1,5 @@
+import enum
+import json
 from datetime import datetime, timedelta
 from enum import Enum
 from typing import Dict, List, Optional
@@ -19,7 +21,7 @@ class TransactionRecordEnumDirection(str, Enum):
 class TransactionRecordRequest(BaseModel):
     to: datetime = Field(default_factory=datetime.utcnow)
     from_: datetime = Field(
-        default_factory=lambda *_: datetime.utcnow() - timedelta(days=365)
+        default_factory=lambda *_: datetime.utcnow() - timedelta(days=365), alias="from"
     )
     limit: int = 1000
     offset: Optional[int]
@@ -68,6 +70,40 @@ class Config:
         alias_generator = camelcase
 
 
+class TransactionHistoryType(str, enum.Enum):
+    BUY = "Buy"
+    CORPORATE_ACTION = "Corporate Action"
+    DIVIDEND = "Dividend"
+    DIVIDEND_TAX = "Dividend Tax"
+    FUNDING = "Funding"
+    SELL = "Sell"
+
+
+class TransactionHistorySide(str, enum.Enum):
+    CREDIT = "CREDIT"
+    DEBIT = "DEBIT"
+
+
+class TransactionHistoryElement(BaseModel):
+    transaction_type: TransactionHistoryType
+    fin_tran_type_id: Optional[str] = None
+    timestamp: datetime
+    tran_amount: Optional[float] = None
+    fee_amount: Optional[float] = None
+    side: TransactionHistorySide
+    text: str
+    comment: str
+    amount_per_share: float
+    tax_rate: float
+    order_id: Optional[str] = None
+    symbol: Optional[str] = None
+    reference: Optional[str] = None
+    reference_type: Optional[TransactionHistoryType] = None
+
+    class Config:
+        alias_generator = camelcase
+
+
 class TransactionsClient(BaseClient):
     async def list(self, request: TransactionRecordRequest) -> List[Transaction]:
         """Returns the transactions executed by the user.
@@ -79,10 +115,7 @@ async def list(self, request: TransactionRecordRequest) -> List[Transaction]:
         Returns:
             List[Transaction]: the transactions executed in the time frame.
         """
-        payload = request.dict()
-        payload.update(
-            {"to": payload["to"].isoformat(), "from": payload.pop("from_").isoformat()}
-        )
+        payload = json.loads(request.json(by_alias=True))
 
         data = await self._client.post(Url.account_transactions, payload=payload)
         transactions = []


Test patch:
diff --git a/tests/cassettes/test_funding/test_funds_in_flight.yaml b/tests/cassettes/test_funding/test_funds_in_flight.yaml
index ab8aa73..194badf 100644
--- a/tests/cassettes/test_funding/test_funds_in_flight.yaml
+++ b/tests/cassettes/test_funding/test_funds_in_flight.yaml
@@ -27,41 +27,7 @@ interactions:
         "fxSpeed": "Regular", "facilitaStatus": null, "dateOfBirth": null, "upToDateDetails2021":
         "NO_REQUIREMENTS", "stakeKycStatus": "KYC_APPROVED", "awxMigrationDocsRequired":
         null, "documentsStatus": "NO_ACTION", "mfaenabled": false}'
-    headers:
-      Access-Control-Allow-Headers:
-      - Content-type, Accept, Stake-Session-Token, stake_tid
-      Access-Control-Allow-Methods:
-      - GET, POST, DELETE, PUT
-      Access-Control-Allow-Origin:
-      - '*'
-      Connection:
-      - keep-alive
-      Content-Length:
-      - '1187'
-      Content-Type:
-      - application/json
-      Date:
-      - Wed, 19 Jan 2022 23:47:25 GMT
-      Via:
-      - 1.1 e3d6764a647541ed814ff5842b8b1476.cloudfront.net (CloudFront)
-      X-Amz-Cf-Id:
-      - k3bkL5K_B72p2N5kVZDNcc1Y40RN6yIA731WDQscLeiZ9Cb8aBQ9aA==
-      X-Amz-Cf-Pop:
-      - SYD62-P2
-      X-Cache:
-      - Miss from cloudfront
-      stake_tid:
-      - 656bf946-1cca-49b2-8c30-8ed012bf8467
-      x-amz-apigw-id:
-      - MN5qBERFywMF-sQ=
-      x-amzn-Remapped-Content-Length:
-      - '1187'
-      x-amzn-Remapped-Date:
-      - Wed, 19 Jan 2022 23:47:24 GMT
-      x-amzn-Remapped-Server:
-      - Jetty(9.4.44.v20210927)
-      x-amzn-RequestId:
-      - fc247b8a-2fcc-42d0-9ff2-4e1f17397d60
+    headers: {}
     status:
       code: 200
       message: OK
@@ -77,54 +43,8 @@ interactions:
     uri: https://global-prd-api.hellostake.com/api/fund/details
   response:
     body:
-      string: |
-        '{"fundsInFlight": [
-                    {
-                        "type": "Funding",
-                        "insertDateTime": "17 Sep 2020 05:21AM",
-                        "estimatedArrivalTime": "19 Sep 2020 05:00AM",
-                        "estimatedArrivalTimeUS": "Fri 1:00pm NY time",
-                        "transactionType": "Poli",
-                        "toAmount": 1512.0,
-                        "fromAmount": 2100.0
-                    }
-                ]}
-                '
-    headers:
-      Access-Control-Allow-Headers:
-      - Content-type, Accept, Stake-Session-Token, stake_tid
-      Access-Control-Allow-Methods:
-      - GET, POST, DELETE, PUT
-      Access-Control-Allow-Origin:
-      - '*'
-      Connection:
-      - keep-alive
-      Content-Length:
-      - '20'
-      Content-Type:
-      - application/json
-      Date:
-      - Wed, 19 Jan 2022 23:47:25 GMT
-      Via:
-      - 1.1 b96ad58427ffff8b9d3959350f8c9f16.cloudfront.net (CloudFront)
-      X-Amz-Cf-Id:
-      - ya0CFD1VuJq5VOB_JdqS4gLyUgtFQBrdZI8OMv7PFkzxYQ-gqLtnuw==
-      X-Amz-Cf-Pop:
-      - SYD62-P2
-      X-Cache:
-      - Miss from cloudfront
-      stake_tid:
-      - 179618fa-5fb5-4281-8e0e-1a28093ed963
-      x-amz-apigw-id:
-      - MN5qHEYpSwMF74w=
-      x-amzn-Remapped-Content-Length:
-      - '20'
-      x-amzn-Remapped-Date:
-      - Wed, 19 Jan 2022 23:47:25 GMT
-      x-amzn-Remapped-Server:
-      - Jetty(9.4.44.v20210927)
-      x-amzn-RequestId:
-      - 513d1f21-81a5-4a7d-b960-f6cdc9f96dde
+      string: '{"fundsInFlight": [{"type": "Funding","insertDateTime": "17 Sep 2020 05:21AM","estimatedArrivalTime": "19 Sep 2020 05:00AM","estimatedArrivalTimeUS": "Fri 1:00pm NY time","transactionType": "Poli", "toAmount": 1512.0,"fromAmount": 2100.0}]}'
+    headers: {}
     status:
       code: 200
       message: OK
diff --git a/tests/cassettes/test_funding/test_list_fundings.yaml b/tests/cassettes/test_funding/test_list_fundings.yaml
index 14d48f5..bfec192 100644
--- a/tests/cassettes/test_funding/test_list_fundings.yaml
+++ b/tests/cassettes/test_funding/test_list_fundings.yaml
@@ -27,43 +27,26 @@ interactions:
         "fxSpeed": "Regular", "facilitaStatus": null, "dateOfBirth": null, "upToDateDetails2021":
         "NO_REQUIREMENTS", "stakeKycStatus": "KYC_APPROVED", "awxMigrationDocsRequired":
         null, "documentsStatus": "NO_ACTION", "mfaenabled": false}'
+    headers: {}
+    status:
+      code: 200
+      message: OK
+    url: https://global-prd-api.hellostake.com/api/user
+- request:
+    body: null
     headers:
-      Access-Control-Allow-Headers:
-      - Content-type, Accept, Stake-Session-Token, stake_tid
-      Access-Control-Allow-Methods:
-      - GET, POST, DELETE, PUT
-      Access-Control-Allow-Origin:
-      - '*'
-      Connection:
-      - keep-alive
-      Content-Length:
-      - '1187'
+      Accept:
+      - application/json
       Content-Type:
       - application/json
-      Date:
-      - Wed, 19 Jan 2022 23:47:22 GMT
-      Via:
-      - 1.1 f1add8f4c4c2d3927809bab0bfad9b82.cloudfront.net (CloudFront)
-      X-Amz-Cf-Id:
-      - x4D2vnxhunv51D7owRTp1faZ6Au0cDkdVnFiZiL_ns05SW8nhzwnYA==
-      X-Amz-Cf-Pop:
-      - SYD62-P2
-      X-Cache:
-      - Miss from cloudfront
-      stake_tid:
-      - 1d0beda3-3154-4fd2-bc31-139b5d5a2b5d
-      x-amz-apigw-id:
-      - MN5poG8mywMFY2Q=
-      x-amzn-Remapped-Content-Length:
-      - '1187'
-      x-amzn-Remapped-Date:
-      - Wed, 19 Jan 2022 23:47:22 GMT
-      x-amzn-Remapped-Server:
-      - Jetty(9.4.44.v20210927)
-      x-amzn-RequestId:
-      - 329118f9-1a4d-4acd-980b-940d0970b644
+    method: POST
+    uri: https://global-prd-api.hellostake.com/api/users/accounts/transactionHistory
+  response:
+    body:
+      string: '[{"transactionType": "Funding","finTranTypeID": "JNLC","timestamp": "2021-09-30T15:45:50.425Z","tranAmount": 1000,"feeAmount": 0.0,"orderID": "HHI.1cf93550-8eb4-4c32-a229-826cf8c1be59","symbol": null,"side": "CREDIT","text": "Deposit","comment": "S7-1945193t","amountPerShare": 0.0,"taxRate": 0.0,"reference": "P0-3814688Z","referenceType": "Funding"},{"transactionType": "Funding","finTranTypeID": "JNLC","timestamp": "2021-09-30T15:45:50.425Z","tranAmount": 1000,"feeAmount": 0.0,"orderID": "HHI.1cf93550-8eb4-4c32-a229-826cf8c1be59","symbol": null,"side": "CREDIT","text": "Deposit","comment": "S7-1945193t","amountPerShare": 0.0,"taxRate": 0.0,"reference": "P0-3814688Z","referenceType": "Funding"}]'
+    headers: {}
     status:
       code: 200
       message: OK
-    url: https://global-prd-api.hellostake.com/api/user
+    url: https://global-prd-api.hellostake.com/api/users/accounts/transactionHistory
 version: 1
diff --git a/tests/conftest.py b/tests/conftest.py
index 17fa2b0..bb2756b 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -61,6 +61,9 @@ def redact_sensitive_data(response):
         "cashAvailableForWithdrawal": 1000,
         "cashAvailableForTrade": 800,
         "dwCashAvailableForWithdrawal": 1000,
+        "reference": fake.pystr_format(),
+        "comment": fake.pystr_format(),
+        "tranAmount": 1000,
     }
 
     def _redact_response_body(body):
diff --git a/tests/test_funding.py b/tests/test_funding.py
index 9084fc1..8da026e 100644
--- a/tests/test_funding.py
+++ b/tests/test_funding.py
@@ -1,23 +1,26 @@
-# import pytest
+import pytest
 
-# from stake.funding import FundingRequest
+from stake.funding import TransactionRecordRequest
 
-# @pytest.mark.vcr()
-# @pytest.mark.asyncio
-# async def test_list_fundings(tracing_client):
-#     fundings = await tracing_client.fundings.list(FundingRequest())
-#     assert len(fundings) == 11
 
-# @pytest.mark.vcr()
-# @pytest.mark.asyncio
-# async def test_cash_available(tracing_client):
-#     cash_available = await tracing_client.fundings.cash_available()
-#     assert cash_available.cash_available_for_withdrawal == 1000.0
-#     assert cash_available.cash_settlement[0].utc_time.month == 1
+@pytest.mark.vcr()
+@pytest.mark.asyncio
+async def test_list_fundings(tracing_client):
+    fundings = await tracing_client.fundings.list(TransactionRecordRequest())
+    assert len(fundings) == 2
 
-# @pytest.mark.vcr()
-# @pytest.mark.asyncio
-# async def test_funds_in_flight(tracing_client):
-#     funds_in_flight = await tracing_client.fundings.in_flight()
-#     assert len(funds_in_flight) == 1
-#     assert funds_in_flight[0].transaction_type == "Poli"
+
+@pytest.mark.vcr()
+@pytest.mark.asyncio
+async def test_cash_available(tracing_client):
+    cash_available = await tracing_client.fundings.cash_available()
+    assert cash_available.cash_available_for_withdrawal == 1000.0
+    assert cash_available.cash_settlement[0].utc_time.month == 1
+
+
+@pytest.mark.vcr()
+@pytest.mark.asyncio
+async def test_funds_in_flight(tracing_client):
+    funds_in_flight = await tracing_client.fundings.in_flight()
+    assert len(funds_in_flight) == 1
+    assert funds_in_flight[0].transaction_type == "Poli"