1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/payment_sepa_direct_debit/models/payment_transaction.py
2024-12-10 09:04:09 +07:00

162 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo import _, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.addons.payment import utils as payment_utils
class PaymentTransaction(models.Model):
_inherit = 'payment.transaction'
mandate_id = fields.Many2one(comodel_name='sdd.mandate')
#=== BUSINESS METHODS ===#
def _get_specific_processing_values(self, processing_values):
""" Override of `payment` to return SEPA-specific processing values. """
res = super()._get_specific_processing_values(processing_values)
if self.provider_id.custom_mode != 'sepa_direct_debit' or self.operation == 'online_token':
return res
return {
'access_token': payment_utils.generate_access_token(self.reference),
}
def _send_payment_request(self):
""" Override of payment to create the related `account.payment` and notify the customer.
Note: self.ensure_one()
:return: None
:raise: UserError if the transaction is not linked to a token
:raise: UserError if the transaction is not linked to a valid mandate
"""
super()._send_payment_request()
if self.provider_id.custom_mode != 'sepa_direct_debit':
return
if not self.token_id:
raise UserError("SEPA: " + _("The transaction is not linked to a token."))
mandate = self.token_id.sdd_mandate_id
if not mandate:
raise UserError("SEPA: " + _("The token is not linked to a mandate."))
if (
mandate.state != 'active'
or (mandate.end_date and mandate.end_date > fields.Datetime.now())
):
raise UserError("SEPA: " + _("The mandate is invalid."))
# There is no provider to send a payment request to, but we handle empty notification data
# to let the payment engine call the generic processing methods.
self._handle_notification_data('sepa_direct_debit', {'reference': self.reference})
def _get_tx_from_notification_data(self, provider_code, notification_data):
""" Override of `payment` to find the transaction based on dummy data.
:param str provider_code: The provider_code of the provider that handled the transaction.
:param dict notification_data: The dummy notification data.
:return: The transaction if found.
:rtype: recordset of `payment.transaction`
:raise ValidationError: If the data match no transaction.
"""
tx = super()._get_tx_from_notification_data(provider_code, notification_data)
if provider_code != 'sepa_direct_debit' or len(tx) == 1:
return tx
reference = notification_data.get('reference')
tx = self.search([
('reference', '=', reference),
('provider_code', '=', 'custom'),
('provider_id.custom_mode', '=', 'sepa_direct_debit'),
])
if not tx:
raise ValidationError(
"SEPA: " + _("No transaction found matching reference %s.", reference)
)
return tx
def _process_notification_data(self, notification_data):
""" Override of `payment` to process the transaction based on dummy data.
Note: self.ensure_one()
:param dict notification_data: The dummy notification data.
:return: None
:raise ValidationError: If inconsistent data were received.
"""
super()._process_notification_data(notification_data)
if self.provider_id.custom_mode != 'sepa_direct_debit':
return
if self.operation in ('online_token', 'offline'):
self._set_done() # SEPA transactions are confirmed as soon as the mandate is valid.
self._sdd_notify_debit(self.token_id)
def _set_done(self, *args, **kwargs):
confirmed_txs = super()._set_done(*args, **kwargs)
sepa_txs = confirmed_txs.filtered(
lambda t: t.provider_code == 'custom'
and t.provider_id.custom_mode == 'sepa_direct_debit'
and t.mandate_id
)
for tx in sepa_txs:
tx.token_id = tx.provider_id._sdd_create_token_for_mandate(tx.partner_id, tx.mandate_id)
tx.mandate_id._confirm()
return confirmed_txs
def _sdd_notify_debit(self, token):
""" Notify the customer that a debit has been made from his account.
This is required as per the SEPA Direct Debit rulebook.
The notice must include:
- the last 4 digits of the debtors bank account
- the mandate reference
- the amount to be debited
- your SEPA creditor identifier
- your contact information
Notifications should be sent at least 14 calendar days before the payment is created unless
specified otherwise.
:param recordset token: The token linked to the mandate from which the debit has been made,
as a `payment.token` record
:return: None
"""
ctx = self.env.context.copy()
ctx.update({
'iban_last_4': token.payment_details[:4],
'mandate_ref': token.sdd_mandate_id.name,
'creditor_identifier': self.env.company.sdd_creditor_identifier,
})
template = self.env.ref('payment_sepa_direct_debit.mail_template_sepa_notify_debit')
template.with_context(ctx).send_mail(self.id)
def _create_payment(self, **extra_create_values):
""" Override of `payment` to pass the correct payment method line id and the SDD mandate id
to the extra create values.
Note: self.ensure_one()
:param dict extra_create_values: The optional extra create values.
:return: The created payment.
:rtype: recordset of `account.payment`
"""
if self.provider_id.custom_mode != 'sepa_direct_debit':
return super()._create_payment(**extra_create_values)
if self.operation in ('online_token', 'offline'):
mandate = self.token_id.sdd_mandate_id
else:
mandate = self.mandate_id
payment_method_line = self.provider_id.journal_id.inbound_payment_method_line_ids.filtered(
lambda l: l.payment_provider_id == self.provider_id
)
return super()._create_payment(
payment_method_line_id=payment_method_line.id, sdd_mandate_id=mandate.id
)