browser.py 4.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# -*- 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 <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

from weboob.browser.filters.standard import CleanDecimal, CleanText, DateTime
from weboob.browser.filters.json import Dict
24 25
from weboob.browser.exceptions import ClientError
from weboob.exceptions import BrowserIncorrectPassword
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

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()
42 43 44 45 46 47
        self.credentials = {
            'user': {
                'email': login,
                'password': password,
            }
        }
48 49 50 51 52 53

    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.
        """
54 55 56 57 58 59 60 61
        try:
            response = self.open('/api/v0/users/login', data=self.credentials)
        except ClientError as e:
            json = e.response.json()
            if e.response.status_code == 401:
                message = json['result']['error']['message']
                raise BrowserIncorrectPassword(message)
            raise e
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
        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
89

90
            for payment in Dict('payments_history')(json):
91 92 93 94 95 96 97 98 99
                if 'refunding_transaction' in payment:
                    refund = self._parse_transaction(payment['refunding_transaction'])
                    refund.type = Transaction.TYPE_CARD
                    yield refund

                transaction = self._parse_transaction(payment)
                if transaction:
                    yield transaction

100 101 102
            page += 1
            if page >= Dict('pagination/pages_count')(json):
                break
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

    def _parse_transaction(self, payment):
        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:
            return
        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,
            # type can be null for refunds
        }
        transaction.type = types.get(Dict('type')(payment), Transaction.TYPE_UNKNOWN)
        transaction.label = Dict('name')(payment)
        transaction.amount = CleanDecimal(Dict('amount/value'))(payment)
        return transaction