Before this commit, zombie payment tokens (= tokens linked to disabled acquirers) could still 1) be used by internal users and 2) reactivated when the acquirer’s state changed to ‘test’ or ‘enabled’. This is not desirable because zombie tokens should neither be used, nor reactivated. After this commit, all tokens related to an acquirer are unassigned from linked documents and archived as soon as the acquirer’s state is changed to ‘disabled’. Creating a payment with an archived token is prohibited. In addition, archived tokens cannot be un-archived anymore. task-2649806 closes odoo/odoo#93774 Related: odoo/enterprise#28661 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import logging
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PaymentToken(models.Model):
|
|
_name = 'payment.token'
|
|
_order = 'partner_id, id desc'
|
|
_description = 'Payment Token'
|
|
|
|
acquirer_id = fields.Many2one(
|
|
string="Acquirer Account", comodel_name='payment.acquirer', required=True)
|
|
provider = fields.Selection(related='acquirer_id.provider')
|
|
name = fields.Char(
|
|
string="Name", help="The anonymized acquirer reference of the payment method",
|
|
required=True)
|
|
partner_id = fields.Many2one(string="Partner", comodel_name='res.partner', required=True)
|
|
company_id = fields.Many2one( # Indexed to speed-up ORM searches (from ir_rule or others)
|
|
related='acquirer_id.company_id', store=True, index=True)
|
|
acquirer_ref = fields.Char(
|
|
string="Acquirer Reference", help="The acquirer reference of the token of the transaction",
|
|
required=True) # This is not the same thing as the acquirer reference of the transaction
|
|
transaction_ids = fields.One2many(
|
|
string="Payment Transactions", comodel_name='payment.transaction', inverse_name='token_id')
|
|
verified = fields.Boolean(string="Verified")
|
|
active = fields.Boolean(string="Active", default=True)
|
|
|
|
#=== CRUD METHODS ===#
|
|
|
|
@api.model_create_multi
|
|
def create(self, values_list):
|
|
for values in values_list:
|
|
if 'acquirer_id' in values:
|
|
acquirer = self.env['payment.acquirer'].browse(values['acquirer_id'])
|
|
|
|
# Include acquirer-specific create values
|
|
values.update(self._get_specific_create_values(acquirer.provider, values))
|
|
else:
|
|
pass # Let psycopg warn about the missing required field
|
|
|
|
return super().create(values_list)
|
|
|
|
@api.model
|
|
def _get_specific_create_values(self, provider, values):
|
|
""" Complete the values of the `create` method with acquirer-specific values.
|
|
|
|
For an acquirer to add its own create values, it must overwrite this method and return a
|
|
dict of values. Acquirer-specific values take precedence over those of the dict of generic
|
|
create values.
|
|
|
|
:param str provider: The provider of the acquirer managing the token
|
|
:param dict values: The original create values
|
|
:return: The dict of acquirer-specific create values
|
|
:rtype: dict
|
|
"""
|
|
return dict()
|
|
|
|
def write(self, values):
|
|
""" Prevent unarchiving tokens and handle their archiving.
|
|
|
|
:return: The result of the call to the parent method.
|
|
:rtype: bool
|
|
:raise UserError: If at least one token is being unarchived.
|
|
"""
|
|
if 'active' in values:
|
|
if values['active']:
|
|
if any(not token.active for token in self):
|
|
raise UserError(_("A token cannot be unarchived once it has been archived."))
|
|
else:
|
|
# Call the handlers in sudo mode because this method might have been called by RPC.
|
|
self.filtered('active').sudo()._handle_archiving()
|
|
|
|
return super().write(values)
|
|
|
|
#=== BUSINESS METHODS ===#
|
|
|
|
def _handle_archiving(self):
|
|
""" Handle the archiving of the current tokens.
|
|
|
|
For a module to perform additional operations when a token is archived, it must override
|
|
this method.
|
|
|
|
:return: None
|
|
"""
|
|
return None
|
|
|
|
def get_linked_records_info(self):
|
|
""" Return a list of information about records linked to the current token.
|
|
|
|
For a module to implement payments and link documents to a token, it must override this
|
|
method and add information about linked records to the returned list.
|
|
|
|
The information must be structured as a dict with the following keys:
|
|
- description: The description of the record's model (e.g. "Subscription")
|
|
- id: The id of the record
|
|
- name: The name of the record
|
|
- url: The url to access the record.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: The list of information about linked documents
|
|
:rtype: list
|
|
"""
|
|
self.ensure_one()
|
|
return []
|