1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
89
90
91
92
93
94
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import hashlib
import hmac
from werkzeug import urls
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from odoo.tools import ustr, consteq, float_compare
class PaymentLinkWizard(models.TransientModel):
_name = "payment.link.wizard"
_description = "Generate Payment Link"
@api.model
def default_get(self, fields):
res = super(PaymentLinkWizard, self).default_get(fields)
res_id = self._context.get('active_id')
res_model = self._context.get('active_model')
res.update({'res_id': res_id, 'res_model': res_model})
amount_field = 'amount_residual' if res_model == 'account.move' else 'amount_total'
if res_id and res_model == 'account.move':
record = self.env[res_model].browse(res_id)
res.update({
'description': record.payment_reference,
'amount': record[amount_field],
'currency_id': record.currency_id.id,
'partner_id': record.partner_id.id,
'amount_max': record[amount_field],
})
return res
res_model = fields.Char('Related Document Model', required=True)
res_id = fields.Integer('Related Document ID', required=True)
amount = fields.Monetary(currency_field='currency_id', required=True)
amount_max = fields.Monetary(currency_field='currency_id')
currency_id = fields.Many2one('res.currency')
partner_id = fields.Many2one('res.partner')
partner_email = fields.Char(related='partner_id.email')
link = fields.Char(string='Payment Link', compute='_compute_values')
description = fields.Char('Payment Ref')
access_token = fields.Char(compute='_compute_values')
company_id = fields.Many2one('res.company', compute='_compute_company')
@api.onchange('amount', 'description')
def _onchange_amount(self):
if float_compare(self.amount_max, self.amount, precision_rounding=self.currency_id.rounding or 0.01) == -1:
raise ValidationError(_("Please set an amount smaller than %s.") % (self.amount_max))
if self.amount <= 0:
raise ValidationError(_("The value of the payment amount must be positive."))
@api.depends('amount', 'description', 'partner_id', 'currency_id')
def _compute_values(self):
secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
for payment_link in self:
token_str = '%s%s%s' % (payment_link.partner_id.id, payment_link.amount, payment_link.currency_id.id)
payment_link.access_token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest()
# must be called after token generation, obvsly - the link needs an up-to-date token
self._generate_link()
@api.depends('res_model', 'res_id')
def _compute_company(self):
for link in self:
record = self.env[link.res_model].browse(link.res_id)
link.company_id = record.company_id if 'company_id' in record else False
def _generate_link(self):
for payment_link in self:
record = self.env[payment_link.res_model].browse(payment_link.res_id)
link = ('%s/website_payment/pay?reference=%s&amount=%s¤cy_id=%s'
'&partner_id=%s&access_token=%s') % (
record.get_base_url(),
urls.url_quote_plus(payment_link.description),
payment_link.amount,
payment_link.currency_id.id,
payment_link.partner_id.id,
payment_link.access_token
)
if payment_link.company_id:
link += '&company_id=%s' % payment_link.company_id.id
if payment_link.res_model == 'account.move':
link += '&invoice_id=%s' % payment_link.res_id
payment_link.link = link
@api.model
def check_token(self, access_token, partner_id, amount, currency_id):
secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
token_str = '%s%s%s' % (partner_id, amount, currency_id)
correct_token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest()
if consteq(ustr(access_token), correct_token):
return True
return False
|