19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -1,37 +1,53 @@
# 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
from odoo.exceptions import UserError, ValidationError
class PaymentToken(models.Model):
_name = 'payment.token'
_order = 'partner_id, id desc'
_description = 'Payment Token'
_check_company_auto = True
_rec_names_search = ['payment_details', 'partner_id', 'provider_id']
provider_id = fields.Many2one(string="Provider", comodel_name='payment.provider', required=True)
provider_code = fields.Selection(related='provider_id.code')
provider_code = fields.Selection(string="Provider Code", related='provider_id.code')
company_id = fields.Many2one(
related='provider_id.company_id', store=True, index=True
) # Indexed to speed-up ORM searches (from ir_rule or others).
payment_method_id = fields.Many2one(
string="Payment Method", comodel_name='payment.method', readonly=True, required=True
)
payment_method_code = fields.Char(
string="Payment Method Code", related='payment_method_id.code'
)
payment_details = fields.Char(
string="Payment Details", help="The clear part of the payment method's payment details.",
)
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='provider_id.company_id', store=True, index=True)
partner_id = fields.Many2one(string="Partner", comodel_name='res.partner', required=True, index=True)
provider_ref = fields.Char(
string="Provider Reference", help="The provider reference of the token of the transaction",
required=True) # This is not the same thing as the provider reference of the transaction.
string="Provider Reference",
help="The provider reference of the token of the transaction.",
required=True,
) # This is not the same thing as the provider reference of the transaction.
transaction_ids = fields.One2many(
string="Payment Transactions", comodel_name='payment.transaction', inverse_name='token_id')
verified = fields.Boolean(string="Verified")
string="Payment Transactions", comodel_name='payment.transaction', inverse_name='token_id'
)
active = fields.Boolean(string="Active", default=True)
#=== CRUD METHODS ===#
# === COMPUTE METHODS === #
@api.depends('payment_details', 'create_date')
def _compute_display_name(self):
for token in self:
token.display_name = token._build_display_name()
# === CRUD METHODS === #
@api.model_create_multi
def create(self, values_list):
for values in values_list:
def create(self, vals_list):
for values in vals_list:
if 'provider_id' in values:
provider = self.env['payment.provider'].browse(values['provider_id'])
@ -40,7 +56,7 @@ class PaymentToken(models.Model):
else:
pass # Let psycopg warn about the missing required field.
return super().create(values_list)
return super().create(vals_list)
@api.model
def _get_specific_create_values(self, provider_code, values):
@ -57,22 +73,36 @@ class PaymentToken(models.Model):
"""
return dict()
def write(self, values):
def write(self, vals):
""" 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."))
if 'active' in vals:
if vals['active']:
if any(
not token.payment_method_id.active
or token.provider_id.state == 'disabled'
for token in self
):
raise UserError(_(
"You can't unarchive tokens linked to inactive payment methods or disabled"
" providers."
))
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)
return super().write(vals)
@api.constrains('partner_id')
def _check_partner_is_never_public(self):
""" Check that the partner associated with the token is never public. """
for token in self:
if token.partner_id.is_public:
raise ValidationError(_("No token can be assigned to the public partner."))
def _handle_archiving(self):
""" Handle the archiving of tokens.
@ -84,10 +114,32 @@ class PaymentToken(models.Model):
"""
return
def name_get(self):
return [(token.id, token._build_display_name()) for token in self]
# === BUSINESS METHODS === #
#=== BUSINESS METHODS ===#
def _get_available_tokens(self, providers_ids, partner_id, is_validation=False, **kwargs):
""" Return the available tokens linked to the given providers and partner.
For a module to retrieve the available tokens, it must override this method and add
information in the kwargs to define the context of the request.
:param list providers_ids: The ids of the providers available for the transaction.
:param int partner_id: The id of the partner.
:param bool is_validation: Whether the transaction is a validation operation.
:param dict kwargs: Locally unused keywords arguments.
:return: The available tokens.
:rtype: payment.token
"""
if not is_validation:
return self.env['payment.token'].search(
[('provider_id', 'in', providers_ids), ('partner_id', '=', partner_id)]
)
else:
# Get all the tokens of the partner and of their commercial partner, regardless of
# whether the providers are available.
partner = self.env['res.partner'].browse(partner_id)
return self.env['payment.token'].search(
[('partner_id', 'in', [partner.id, partner.commercial_partner_id.id])]
)
def _build_display_name(self, *args, max_length=34, should_pad=True, **kwargs):
""" Build a token name of the desired maximum length with the format `•••• 1234`.
@ -112,6 +164,9 @@ class PaymentToken(models.Model):
"""
self.ensure_one()
if not self.create_date:
return ''
padding_length = max_length - len(self.payment_details or '')
if not self.payment_details:
create_date_str = self.create_date.strftime('%Y/%m/%d')