diff --git a/n26/cli.py b/n26/cli.py index 0419e2a..9e2e4df 100644 --- a/n26/cli.py +++ b/n26/cli.py @@ -5,7 +5,7 @@ from tabulate import tabulate import n26.api as api -from n26.const import AMOUNT, CURRENCY, REFERENCE_TEXT, ATM_WITHDRAW +from n26.const import AMOUNT, CURRENCY, REFERENCE_TEXT, ATM_WITHDRAW, CARD_STATUS_ACTIVE API_CLIENT = api.Api() @@ -136,6 +136,27 @@ def spaces(): click.echo(text) +@cli.command() +def cards(): + """ Shows a list of cards """ + cards_data = API_CLIENT.get_cards() + + headers = ['Id', 'Masked Pan', 'Type', 'Design', 'Status', 'Activated', 'Pin defined', 'Expires'] + keys = [ + 'id', + 'maskedPan', + 'cardType', + 'design', + lambda x: "active" if (x.get('status') == CARD_STATUS_ACTIVE) else x.get('status'), + _datetime_extractor('cardActivated'), + _datetime_extractor('pinDefined'), + _datetime_extractor('expirationDate', date_only=True), + ] + text = _create_table_from_dict(headers=headers, value_functions=keys, data=cards_data, numalign='right') + + click.echo(text.strip()) + + @cli.command() @click.option('--card', default=None, type=str, help='ID of the card to block. Omitting this will block all cards.') def card_block(card: str): @@ -299,10 +320,10 @@ def standing_orders(): values = ['partnerName', lambda x: "{} {}".format(x.get('amount'), x.get('currencyCode').get('currencyCode')), 'executionFrequency', - _datetime_extractor('stopTS'), + _datetime_extractor('stopTS', date_only=True), _day_of_month_extractor('initialDayOfMonth'), - _datetime_extractor('firstExecutingTS'), - _datetime_extractor('nextExecutingTS'), + _datetime_extractor('firstExecutingTS', date_only=True), + _datetime_extractor('nextExecutingTS', date_only=True), 'executionCounter', _datetime_extractor('created'), _datetime_extractor('updated')] @@ -340,7 +361,12 @@ def statistics(param_from: int, to: int): def _timestamp_ms_to_date(epoch_ms: int) -> datetime or None: - """Convert millisecond timestamp to datetime.""" + """ + Convert millisecond timestamp to UTC datetime. + + :param epoch_ms: milliseconds since 1970 in CET + :return: a UTC datetime object + """ if epoch_ms: return datetime.fromtimestamp(epoch_ms / 1000, timezone.utc) @@ -378,13 +404,29 @@ def _create_table_from_dict(headers: list, value_functions: list, data: list, ** return tabulate(tabular_data=lines, headers=headers, **tabulate_args) -def _datetime_extractor(key: str): +def _datetime_extractor(key: str, date_only: bool = False): """ Helper function to extract a datetime value from a dict :param key: the dictionary key used to access the value + :param date_only: removes the time from the output :return: an extractor function """ - return lambda x: _timestamp_ms_to_date(x.get(key)) + + if date_only: + fmt = "%x" + else: + fmt = "%x %X" + + def extractor(dictionary: dict): + value = dictionary.get(key) + time = _timestamp_ms_to_date(value) + if time is None: + return None + else: + time = time.astimezone() + return time.strftime(fmt) + + return extractor def _insert_newlines(text: str, n=40): diff --git a/n26/const.py b/n26/const.py index e18f407..cc2c610 100644 --- a/n26/const.py +++ b/n26/const.py @@ -13,5 +13,7 @@ AMOUNT = 'amount' REFERENCE_TEXT = 'referenceText' +CARD_STATUS_ACTIVE = 'M_ACTIVE' + DAILY_WITHDRAWAL_LIMIT = 'ATM_DAILY_ACCOUNT' DAILY_PAYMENT_LIMIT = 'POS_DAILY_ACCOUNT' diff --git a/tests/test_cards.py b/tests/test_cards.py index 22155c5..a4785d3 100644 --- a/tests/test_cards.py +++ b/tests/test_cards.py @@ -5,10 +5,15 @@ class CardsTests(N26TestBase): """Cards tests""" + @mock_config() @mock_requests(method=GET, response_file="cards.json") - def test_get_cards(self): - result = self._underTest.get_cards() - self.assertIsNotNone(result) + def test_cards_cli(self): + from n26.cli import cards + result = self._run_cli_cmd(cards) + self.assertIn('MASTERCARD', result.output) + self.assertIn('MAESTRO', result.output) + self.assertIn('active', result.output) + self.assertIn('123456******1234', result.output) @mock_config() @mock_requests(method=GET, response_file="cards.json") diff --git a/tests/test_standing_orders.py b/tests/test_standing_orders.py index e788a67..d9e7051 100644 --- a/tests/test_standing_orders.py +++ b/tests/test_standing_orders.py @@ -19,4 +19,4 @@ def test_standing_orders_cli(self): self.assertIn('WEEKLY', result.output) self.assertIn('MONTHLY', result.output) self.assertIn('YEARLY', result.output) - self.assertIn('2019-04-01 00:29:49.461000+00:00', result.output) + self.assertIn('10/30/18', result.output)