diff --git a/modules/lunchr/__init__.py b/modules/lunchr/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8763034765e73714352b192b12b23a2cca668e35
--- /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 0000000000000000000000000000000000000000..d3910e6b00c820aea6cb43f448a4fd6bdc5100a4
--- /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 0000000000000000000000000000000000000000..7413ce3ece02b527ff4bd9c9726fda292717e18a
--- /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)