1# coding: utf-8 2 3import datetime 4 5from odoo import _, api, fields, models 6from odoo.exceptions import ValidationError 7 8 9class AccountPayment(models.Model): 10 _inherit = 'account.payment' 11 12 payment_transaction_id = fields.Many2one('payment.transaction', string='Payment Transaction', readonly=True) 13 payment_token_id = fields.Many2one( 14 'payment.token', string="Saved payment token", 15 domain="""[ 16 (payment_method_code == 'electronic', '=', 1), 17 ('company_id', '=', company_id), 18 ('acquirer_id.capture_manually', '=', False), 19 ('acquirer_id.journal_id', '=', journal_id), 20 ('partner_id', 'in', related_partner_ids), 21 ]""", 22 help="Note that tokens from acquirers set to only authorize transactions (instead of capturing the amount) are not available.") 23 related_partner_ids = fields.Many2many('res.partner', compute='_compute_related_partners') 24 25 def _get_payment_chatter_link(self): 26 self.ensure_one() 27 return '<a href=# data-oe-model=account.payment data-oe-id=%d>%s</a>' % (self.id, self.name) 28 29 @api.depends('partner_id.commercial_partner_id.child_ids') 30 def _compute_related_partners(self): 31 for p in self: 32 p.related_partner_ids = ( 33 p.partner_id 34 | p.partner_id.commercial_partner_id 35 | p.partner_id.commercial_partner_id.child_ids 36 )._origin 37 38 @api.onchange('partner_id', 'payment_method_id', 'journal_id') 39 def _onchange_set_payment_token_id(self): 40 if not (self.payment_method_code == 'electronic' and self.partner_id and self.journal_id): 41 self.payment_token_id = False 42 return 43 44 self.payment_token_id = self.env['payment.token'].search([ 45 ('partner_id', 'in', self.related_partner_ids.ids), 46 ('acquirer_id.capture_manually', '=', False), 47 ('acquirer_id.journal_id', '=', self.journal_id.id), 48 ], limit=1) 49 50 def _prepare_payment_transaction_vals(self): 51 self.ensure_one() 52 return { 53 'amount': self.amount, 54 'reference': self.ref, 55 'currency_id': self.currency_id.id, 56 'partner_id': self.partner_id.id, 57 'partner_country_id': self.partner_id.country_id.id, 58 'payment_token_id': self.payment_token_id.id, 59 'acquirer_id': self.payment_token_id.acquirer_id.id, 60 'payment_id': self.id, 61 'type': 'server2server', 62 } 63 64 def _create_payment_transaction(self, vals=None): 65 for pay in self: 66 if pay.payment_transaction_id: 67 raise ValidationError(_('A payment transaction already exists.')) 68 elif not pay.payment_token_id: 69 raise ValidationError(_('A token is required to create a new payment transaction.')) 70 71 transactions = self.env['payment.transaction'] 72 for pay in self: 73 transaction_vals = pay._prepare_payment_transaction_vals() 74 75 if vals: 76 transaction_vals.update(vals) 77 78 transaction = self.env['payment.transaction'].create(transaction_vals) 79 transactions += transaction 80 81 # Link the transaction to the payment. 82 pay.payment_transaction_id = transaction 83 84 return transactions 85 86 def action_validate_invoice_payment(self): 87 res = super(AccountPayment, self).action_validate_invoice_payment() 88 self.mapped('payment_transaction_id').filtered(lambda x: x.state == 'done' and not x.is_processed)._post_process_after_done() 89 return res 90 91 def action_post(self): 92 # Post the payments "normally" if no transactions are needed. 93 # If not, let the acquirer updates the state. 94 # __________ ______________ 95 # | Payments | | Transactions | 96 # |__________| |______________| 97 # || | | 98 # || | | 99 # || | | 100 # __________ no s2s required __\/______ s2s required | | s2s_do_transaction() 101 # | Posted |<-----------------| post() |---------------- | 102 # |__________| |__________|<----- | 103 # | | 104 # OR--------------- 105 # __________ __________ | 106 # | Cancelled|<-----------------| cancel() |<----- 107 # |__________| |__________| 108 109 payments_need_trans = self.filtered(lambda pay: pay.payment_token_id and not pay.payment_transaction_id) 110 transactions = payments_need_trans._create_payment_transaction() 111 112 res = super(AccountPayment, self - payments_need_trans).action_post() 113 114 transactions.s2s_do_transaction() 115 116 # Post payments for issued transactions. 117 transactions._post_process_after_done() 118 payments_trans_done = payments_need_trans.filtered(lambda pay: pay.payment_transaction_id.state == 'done') 119 super(AccountPayment, payments_trans_done).action_post() 120 payments_trans_not_done = payments_need_trans.filtered(lambda pay: pay.payment_transaction_id.state != 'done') 121 payments_trans_not_done.action_cancel() 122 123 return res 124