From 61b2796ac11a89dc5339ab5d4b08e6110c874418 Mon Sep 17 00:00:00 2001 From: Roger Philibert Date: Mon, 8 Oct 2018 14:43:08 +0200 Subject: [PATCH] [lunchr] new CapBank module --- modules/lunchr/__init__.py | 26 ++++++++++ modules/lunchr/browser.py | 97 ++++++++++++++++++++++++++++++++++++++ modules/lunchr/module.py | 60 +++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 modules/lunchr/__init__.py create mode 100644 modules/lunchr/browser.py create mode 100644 modules/lunchr/module.py diff --git a/modules/lunchr/__init__.py b/modules/lunchr/__init__.py new file mode 100644 index 0000000000..8763034765 --- /dev/null +++ b/modules/lunchr/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2018 Roger Philibert +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with weboob. If not, see . + +from __future__ import unicode_literals + + +from .module import LunchrModule + + +__all__ = ['LunchrModule'] diff --git a/modules/lunchr/browser.py b/modules/lunchr/browser.py new file mode 100644 index 0000000000..d3910e6b00 --- /dev/null +++ b/modules/lunchr/browser.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2018 Roger Philibert +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with weboob. If not, see . + +from __future__ import unicode_literals + +from weboob.browser.filters.standard import CleanDecimal, CleanText, DateTime +from weboob.browser.filters.json import Dict + +from weboob.browser.browsers import APIBrowser +from weboob.capabilities.bank import Account, Transaction + + +class LunchrBrowser(APIBrowser): + BASEURL = 'https://api.lunchr.fr' + + def __init__(self, login, password, *args, **kwargs): + """LunchrBrowser needs login and password to fetch Lunchr API""" + super(LunchrBrowser, self).__init__(*args, **kwargs) + # self.session.headers are the HTTP headers for Lunchr API requests + self.session.headers['x-api-key'] = '644a4ef497286a229aaf8205c2dc12a9086310a8' + self.session.headers['x-lunchr-app-version'] = 'b6c6ca66c79ca059222779fe8f1ac98c8485b9f0' + self.session.headers['x-lunchr-platform'] = 'web' + # self.credentials is the HTTP POST data used in self._auth() + self.credentials = {'user': { + 'email': login, + 'password': password, + }} + + def _auth(self): + """Authenticate to Lunchr API using self.credentials. + If authentication succeeds, authorization header is set in self.headers + and response's json payload is returned unwrapped into dictionary. + """ + response = self.open('/api/v0/users/login', data=self.credentials) + json = Dict('user')(response.json()) + self.session.headers['Authorization'] = 'Bearer ' + Dict('token')(json) + return json + + def get_account(self, id=None): + json = self._auth() + account = Account(id=Dict('id')(json)) + # weboob.capabilities.bank.BaseAccount + account.bank_name = 'Lunchr' + account.label = CleanText(Dict('first_name'))(json) + ' ' + CleanText(Dict('last_name'))(json) + account.currency = CleanText(Dict('meal_voucher_info/balance/currency/iso_3'))(json) + # weboob.capabilities.bank.Account + account.type = Account.TYPE_CHECKING + account.balance = CleanDecimal(Dict('meal_voucher_info/balance/value'))(json) + account.cardlimit = CleanDecimal(Dict('meal_voucher_info/daily_balance/value'))(json) + return account + + def iter_accounts(self): + yield self.get_account() + + def iter_history(self, account): + page = 0 + while True: + response = self.open('/api/v0/payments_history?page={:d}'.format(page)) + json = response.json() + if len(Dict('payments_history')(json)) == 0: + break + for payment in Dict('payments_history')(json): + transaction = Transaction() + transaction_id = Dict('transaction_number', default=None)(payment) + # Check if transaction_id is None which indicates failed transaction + if transaction_id is None: + continue + transaction.id = transaction_id + transaction.date = DateTime(Dict('executed_at'))(payment) + transaction.rdate = DateTime(Dict('created_at'))(payment) + types = { + 'LUNCHR_CARD_PAYMENT': Transaction.TYPE_CARD, + 'MEAL_VOUCHER_CREDIT': Transaction.TYPE_DEPOSIT, + } + transaction.type = types.get(Dict('type')(payment), Transaction.TYPE_UNKNOWN) + transaction.label = Dict('name')(payment) + transaction.amount = CleanDecimal(Dict('amount/value'))(payment) + yield transaction + page += 1 + if page >= Dict('pagination/pages_count')(json): + break diff --git a/modules/lunchr/module.py b/modules/lunchr/module.py new file mode 100644 index 0000000000..7413ce3ece --- /dev/null +++ b/modules/lunchr/module.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2018 Roger Philibert +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with weboob. If not, see . + +from __future__ import unicode_literals + +from weboob.tools.backend import Module, BackendConfig +from weboob.tools.value import ValueBackendPassword +from weboob.capabilities.base import find_object +from weboob.capabilities.bank import CapBank, AccountNotFound + +from .browser import LunchrBrowser + +__all__ = ['LunchrModule'] + + +class LunchrModule(Module, CapBank): + NAME = 'lunchr' + DESCRIPTION = 'Lunchr' + MAINTAINER = 'Roger Philibert' + EMAIL = 'roger.philibert@gmail.com' + LICENSE = 'LGPLv3+' + VERSION = '1.4' + + BROWSER = LunchrBrowser + + CONFIG = BackendConfig( + ValueBackendPassword('login', label='E-mail', masked=False), + ValueBackendPassword('password', label='Mot de passe'), + ) + + def create_default_browser(self): + return self.create_browser( + self.config['login'].get(), + self.config['password'].get(), + ) + + def get_account(self, id): + return find_object(self.iter_accounts(), id=id, error=AccountNotFound) + + def iter_accounts(self): + return self.browser.iter_accounts() + + def iter_history(self, account): + return self.browser.iter_history(account) -- GitLab