1# -*- coding: utf-8 -*-
2
3from odoo import api, models, fields, _
4from odoo.exceptions import UserError
5
6class ResPartnerBank(models.Model):
7    _inherit = 'res.partner.bank'
8
9    def build_qr_code_url(self, amount, free_communication, structured_communication, currency, debtor_partner, qr_method=None, silent_errors=True):
10        """ Returns the QR-code report URL to pay to this account with the given parameters,
11        or None if no QR-code could be generated.
12
13        :param amount: The amount to be paid
14        :param free_communication: Free communication to add to the payment when generating one with the QR-code
15        :param structured_communication: Structured communication to add to the payment when generating one with the QR-code
16        :param currency: The currency in which amount is expressed
17        :param debtor_partner: The partner to which this QR-code is aimed (so the one who will have to pay)
18        :param qr_method: The QR generation method to be used to make the QR-code. If None, the first one giving a result will be used.
19        :param silent_errors: If true, forbids errors to be raised if some tested QR-code format can't be generated because of incorrect data.
20        """
21        if not self:
22            return None
23
24        self.ensure_one()
25
26        if not currency:
27            raise UserError(_("Currency must always be provided in order to generate a QR-code"))
28
29        available_qr_methods = self.get_available_qr_methods_in_sequence()
30        candidate_methods = qr_method and [(qr_method, dict(available_qr_methods)[qr_method])] or available_qr_methods
31        for candidate_method, candidate_name in candidate_methods:
32            if self._eligible_for_qr_code(candidate_method, debtor_partner, currency):
33                error_message = self._check_for_qr_code_errors(candidate_method, amount, currency, debtor_partner, free_communication, structured_communication)
34
35                if not error_message:
36                    return self._get_qr_code_url(candidate_method, amount, currency, debtor_partner, free_communication, structured_communication)
37
38                elif not silent_errors:
39                    error_header = _("The following error prevented '%s' QR-code to be generated though it was detected as eligible: ", candidate_name)
40                    raise UserError( error_header + error_message)
41
42        return None
43
44    def _get_qr_code_url(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
45        """ Hook for extension, to support the different QR generation methods.
46        This function uses the provided qr_method to try generation a QR-code for
47        the given data. It it succeeds, it returns the report URL to make this
48        QR-code; else None.
49
50        :param qr_method: The QR generation method to be used to make the QR-code.
51        :param amount: The amount to be paid
52        :param currency: The currency in which amount is expressed
53        :param debtor_partner: The partner to which this QR-code is aimed (so the one who will have to pay)
54        :param free_communication: Free communication to add to the payment when generating one with the QR-code
55        :param structured_communication: Structured communication to add to the payment when generating one with the QR-code
56        """
57        return None
58
59    @api.model
60    def _get_available_qr_methods(self):
61        """ Returns the QR-code generation methods that are available on this db,
62        in the form of a list of (code, name, sequence) elements, where
63        'code' is a unique string identifier, 'name' the name to display
64        to the user to designate the method, and 'sequence' is a positive integer
65        indicating the order in which those mehtods need to be checked, to avoid
66        shadowing between them (lower sequence means more prioritary).
67        """
68        return []
69
70    @api.model
71    def get_available_qr_methods_in_sequence(self):
72        """ Same as _get_available_qr_methods but without returning the sequence,
73        and using it directly to order the returned list.
74        """
75        all_available = self._get_available_qr_methods()
76        all_available.sort(key=lambda x: x[2])
77        return [(code, name) for (code, name, sequence) in all_available]
78
79
80    def _eligible_for_qr_code(self, qr_method, debtor_partner, currency):
81        """ Tells whether or not the criteria to apply QR-generation
82        method qr_method are met for a payment on this account, in the
83        given currency, by debtor_partner. This does not impeach generation errors,
84        it only checks that this type of QR-code *should be* possible to generate.
85        Consistency of the required field needs then to be checked by _check_for_qr_code_errors().
86        """
87        return False
88
89    def _check_for_qr_code_errors(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
90        """ Checks the data before generating a QR-code for the specified qr_method
91        (this method must have been checked for eligbility by _eligible_for_qr_code() first).
92
93        Returns None if no error was found, or a string describing the first error encountered
94        so that it can be reported to the user.
95        """
96        return None