diff --git a/pytr/accountdetails.py b/pytr/accountdetails.py new file mode 100644 index 0000000..cbcdf0c --- /dev/null +++ b/pytr/accountdetails.py @@ -0,0 +1,99 @@ +from typing import TypedDict, Optional, List +from typing import cast + +class Name(TypedDict): + first: str + last: str + +class Email(TypedDict): + address: str + verified: bool + +class PostalAddress(TypedDict): + street: str + houseNo: str + zip: str + city: str + country: str + +class Birthplace(TypedDict): + birthplace: str + birthcountry: str + +class TaxResidency(TypedDict): + tin: str + countryCode: str + +class TaxExemptionOrder(TypedDict): + minimum: int + maximum: int + current: int + applied: int + syncStatus: int + validFrom: int + validUntil: int + +class CashAccount(TypedDict): + iban: str + bic: str + bankName: str + logoUrl: Optional[str] + +class ReferenceAccount(TypedDict): + iban: str + bic: Optional[str] + bankName: Optional[str] + logoUrl: Optional[str] + +class Experience(TypedDict): + tradeCount: int + level: str + showsRiskWarning: bool + +class InvestmentExperience(TypedDict): + stock: Experience + fund: Experience + derivative: Experience + crypto: Experience + bond: Experience + +class SupportDocuments(TypedDict): + accountClosing: str + imprint: str + addressConfirmation: str + +class TinFormat(TypedDict): + placeholder: str + keyboardLayout: str + +class AccountDetails(TypedDict): + phoneNumber: str + jurisdiction: str + name: Name + email: Email + duplicateTradingEmail: Optional[str] + postalAddress: PostalAddress + birthdate: str + birthplace: Birthplace + mainNationality: str + additionalNationalities: List[str] + mainTaxResidency: TaxResidency + usTaxResidency: bool + additionalTaxResidencies: List[TaxResidency] + taxInformationSyncTimestamp: int + taxExemptionOrder: TaxExemptionOrder + registrationAccount: bool + cashAccount: CashAccount + referenceAccount: ReferenceAccount + referenceAccountV2: Optional[str] + referenceAccountList: List[ReferenceAccount] + securitiesAccountNumber: str + experience: InvestmentExperience + referralDetails: Optional[str] + supportDocuments: SupportDocuments + tinFormat: TinFormat + personId: str + + def from_dict(d): + account_details: AccountDetails = cast(AccountDetails, d) + return account_details diff --git a/pytr/api.py b/pytr/api.py index ff2ff10..a31103d 100644 --- a/pytr/api.py +++ b/pytr/api.py @@ -256,6 +256,13 @@ def resume_websession(self): return True return False + def get_account_details(self): + r = self._websession.get( + f"{self._host}/api/v2/auth/account", + ) + j = r.json() + return j + def _web_request(self, url_path, payload=None, method="GET"): if self._web_session_token_expires_at < time.time(): r = self._websession.get(f"{self._host}/api/v1/auth/web/session") diff --git a/pytr/main.py b/pytr/main.py index 0052e7d..9114e9f 100644 --- a/pytr/main.py +++ b/pytr/main.py @@ -3,6 +3,7 @@ import argparse import asyncio import signal +import json from datetime import datetime, timedelta from importlib.metadata import version from pathlib import Path @@ -198,7 +199,24 @@ def formatter(prog): help="Format the date column in ISO8601 including the time.", action="store_true", ) - + # accountdetails + info = "Show account details" + parser_accountdetails = parser_cmd.add_parser( + "accountdetails", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + parents=[parser_login_args], + help=info, + description=info, + ) + parser_accountdetails.add_argument( + "-o", + "--outfile", + help='Output path of JSON file. [default: "-" (stdout)]', + metavar="PATH", + type=argparse.FileType("w"), + default="-", + ) + # completion info = "Print shell tab completion" parser_completion = parser_cmd.add_parser( "completion", @@ -310,6 +328,10 @@ def main(): installed_version = version("pytr") print(installed_version) check_version(installed_version) + elif args.command == "accountdetails": + tr = login(phone_no=args.phone_no, pin=args.pin, web=not args.applogin) + account_details = tr.get_account_details() + args.jsonoutput.write(json.dumps(account_details)) else: parser.print_help() diff --git a/tests/sample_account_details.json b/tests/sample_account_details.json new file mode 100644 index 0000000..bb0f75b --- /dev/null +++ b/tests/sample_account_details.json @@ -0,0 +1,37 @@ +{ + "phoneNumber":"+491xxxx", + "jurisdiction":"DE", + "name":{"first":"xxfirstnamexx", "last":"xxx"}, + "email":{"address":"xxxx@xxxx.de", "verified":true}, + "duplicateTradingEmail":null, + "postalAddress":{"street":"SomeStreet", "houseNo":"4", "zip":"123456", "city":"Somecity", "country":"DE"}, + "birthdate":"1902-01-01", + "birthplace":{"birthplace":"Somecity", "birthcountry":"DE"}, + "mainNationality":"DE", + "additionalNationalities":[], + "mainTaxResidency":{"tin":"12345987", "countryCode":"DE"}, + "usTaxResidency":false, + "additionalTaxResidencies":[], + "taxInformationSyncTimestamp":172177300000, + "taxExemptionOrder":{"minimum":0, "maximum":9900, "current":111, "applied":2131, "syncStatus":12414, "validFrom":1242, "validUntil":2312}, + "registrationAccount":false, + "cashAccount":{"iban":"DE00000000000000000000", "bic":"TRBKDEBBXXX", "bankName":"J.P. Morgan SE", "logoUrl":null}, + "referenceAccount":{"iban":"-", "bic":null}, + "referenceAccountV2":null, + "referenceAccountList":[{"iban":"DE00012134874564878747", "bic":null, "bankName":"Bank", "logoUrl":"logos/bank_bank/v2"}], + "securitiesAccountNumber":"321354657", + "experience":{"stock":{"tradeCount":0, "level":"LOSER", "showsRiskWarning":true}, + "fund":{"tradeCount":0, "level":"LOSER", "showsRiskWarning":true}, + "derivative":{"tradeCount":0, "level":"LOSER", "showsRiskWarning":true}, + "crypto":{"tradeCount":100, "level":"GODMODE", "showsRiskWarning":true}, + "bond":{"level":"xxxx", "showsRiskWarning":true}}, + "referralDetails":null, + "supportDocuments":{ + "accountClosing":"https://assets.traderepublic.com/assets/files/foilename.pdf", + "imprint":"https://traderepublic.com/de-de/imprint", + "addressConfirmation":"https://support.traderepublic.com/de-de/102"}, + "tinFormat":{"placeholder":"99999999999", + "keyboardLayout":"numerical" + }, + "personId":"babdbddb-5441-23-124-423423542532112" +} \ No newline at end of file diff --git a/tests/test_account_details.py b/tests/test_account_details.py new file mode 100644 index 0000000..ad99abf --- /dev/null +++ b/tests/test_account_details.py @@ -0,0 +1,17 @@ +import json + +from pytr.accountdetails import AccountDetails + + +def test_account_details_from_dict(): + # Load the sample JSON file + with open("tests/sample_account_details.json", "r") as file: + sample_data = json.load(file) + + # Parse the JSON data using the from_dict function + ad = AccountDetails.from_dict(sample_data) + + # Assert the expected values + assert ad["phoneNumber"] == "+491xxxx" + assert ad["name"]["first"] == "xxfirstnamexx" + assert ad["taxExemptionOrder"]["current"] == 111