-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IMP] website_sale_sepa_dd_payment: payment provider for sepa dd
- Loading branch information
Showing
9 changed files
with
279 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
website_sale_sepa_dd_payment/data/payment_provider_data.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo noupdate="1"> | ||
|
||
<record id="payment_provider_sepa_dd" model="payment.provider"> | ||
<field name="name">SEPA Direct Debit</field> | ||
<field name="module_id" ref="base.module_website_sale_sepa_dd_payment" /> | ||
<field name="code">custom</field> | ||
<field name="custom_mode">sepa_dd</field> | ||
<field name="state">enabled</field> | ||
<field name="inline_form_view_id" ref="inline_form" /> | ||
<field name="pending_msg" type="html"> | ||
<p> | ||
<i>Your order has been saved.</i> | ||
Your payment by SEPA Dierct Debit will be processed soon. | ||
</p> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC | ||
# | ||
# SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
from odoo import api, fields, models | ||
|
||
|
||
class PaymentProvider(models.Model): | ||
_inherit = "payment.provider" | ||
|
||
custom_mode = fields.Selection(selection_add=[("sepa_dd", "SEPA Direct Debit")]) | ||
|
||
@api.model | ||
def _get_compatible_providers( | ||
self, *args, sale_order_id=None, website_id=None, **kwargs | ||
): | ||
"""Override of payment to exclude onsite providers if the delivery doesn't match. | ||
:param int sale_order_id: The sale order to be paid, if any, as a `sale.order` id | ||
:param int website_id: The provided website, as a `website` id | ||
:return: The compatible providers | ||
:rtype: recordset of `payment.provider` | ||
""" | ||
compatible_providers = super()._get_compatible_providers( | ||
*args, sale_order_id=sale_order_id, website_id=website_id, **kwargs | ||
) | ||
order = self.env["sale.order"].browse(sale_order_id).exists() | ||
# Allow SEPA Direct Debit only if all products allow SEPA DD payment | ||
allow_sepa_dd_payment = all( | ||
order.order_line.mapped("product_id").mapped("allow_sepa_dd_payment") | ||
) | ||
if not allow_sepa_dd_payment: | ||
compatible_providers = compatible_providers.filtered( | ||
lambda p: p.code != "custom" or p.custom_mode != "sepa_dd" | ||
) | ||
|
||
return compatible_providers |
82 changes: 82 additions & 0 deletions
82
website_sale_sepa_dd_payment/models/payment_transaction.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC | ||
# | ||
# SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
import datetime | ||
|
||
from odoo import api, fields, models | ||
from odoo.exceptions import ValidationError | ||
|
||
from odoo.addons.base.models.res_bank import sanitize_account_number | ||
from odoo.addons.base_iban.models.res_partner_bank import validate_iban | ||
|
||
|
||
class PaymentTransaction(models.Model): | ||
_inherit = "payment.transaction" | ||
|
||
sepa_dd_iban = fields.Char(string="IBAN (for SEPA Direct Debit)") | ||
|
||
@api.constrains("sepa_dd_iban", "partner_id") | ||
def _check_sepa_dd_iban(self): | ||
"""Raise ValidationError if sepa_dd_iban is not correct""" | ||
if self.sepa_dd_iban: | ||
validate_iban(self.sepa_dd_iban) | ||
sanitized_sepa_dd_iban = sanitize_account_number(self.sepa_dd_iban) | ||
res_partner_bank = self.env["res.partner.bank"].search( | ||
[("sanitized_acc_number", "=", sanitized_sepa_dd_iban)], | ||
limit=1, | ||
) | ||
if res_partner_bank and res_partner_bank.partner_id != self.partner_id: | ||
raise ValidationError( | ||
f"The account number {sanitized_sepa_dd_iban} does not belongs " | ||
f"to {self.partner_id.name}." | ||
) | ||
return res_partner_bank | ||
|
||
def _set_pending(self, state_message=None): | ||
txs_to_process = super()._set_pending(state_message=state_message) | ||
txs_to_process.create_sepa_dd_mandate() | ||
return txs_to_process | ||
|
||
def get_res_partner_bank(self): | ||
"""Return res.partner.bank that match the sepa_dd_iban | ||
account. | ||
""" | ||
self.ensure_one() | ||
res_partner_bank = self.env["res.partner.bank"] | ||
if self.sepa_dd_iban: | ||
sanitized_sepa_dd_iban = sanitize_account_number(self.sepa_dd_iban) | ||
res_partner_bank = self.env["res.partner.bank"].search( | ||
[("sanitized_acc_number", "=", sanitized_sepa_dd_iban)], | ||
limit=1, | ||
) | ||
return res_partner_bank | ||
|
||
def sepa_dd_mandate_vals(self): | ||
self.ensure_one() | ||
return { | ||
"format": "sepa", | ||
"type": "recurrent", | ||
"scheme": "CORE", | ||
"recurrent_sequence_type": "recurring", | ||
"signature_date": datetime.datetime.now(), | ||
"state": "valid", | ||
} | ||
|
||
def create_sepa_dd_mandate(self): | ||
for tx in self: | ||
res_partner_bank = tx.get_res_partner_bank() | ||
if not res_partner_bank: | ||
res_partner_bank = self.env["res.partner.bank"].create( | ||
{ | ||
"partner_id": tx.partner_id.id, | ||
"acc_number": tx.sepa_dd_iban, | ||
} | ||
) | ||
res_partner_bank.write( | ||
{ | ||
"mandate_ids": [ | ||
(0, 0, tx.sepa_dd_mandate_vals()), | ||
], | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
website_sale_sepa_dd_payment/static/src/js/payment_form.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
odoo.define("website_sale_sepa_dd_payment.payment_form", (require) => { | ||
"use strict"; | ||
|
||
const checkoutForm = require("payment.checkout_form"); | ||
const manageForm = require("payment.manage_form"); | ||
|
||
const sepaDDMixin = { | ||
/** | ||
* Return all relevant inline form inputs | ||
* | ||
* @private | ||
* @param {Number} providerId - The id of the selected provider | ||
* @returns {Object} - An object mapping the name of inline form inputs | ||
* to their DOM element | ||
*/ | ||
_getInlineFormInputs: function (providerId) { | ||
return { | ||
sepa_dd_iban: document.getElementById(`o_sepa_dd_iban_${providerId}`), | ||
sepa_dd_accept: document.getElementById( | ||
`o_sepa_dd_accept_${providerId}` | ||
), | ||
}; | ||
}, | ||
|
||
/** | ||
* Return values to pass to the default transaction validation | ||
* route | ||
* | ||
* @private | ||
* @param {String} code - The code of the payment option's provider | ||
* @param {Number} paymentOptionId - The id of the selected provider | ||
* @param {String} flow - The online payment flow of the transaction | ||
* @returns {Object} - The params for the default transaction route | ||
*/ | ||
_prepareTransactionRouteParams: function (code, paymentOptionId, flow) { | ||
const values = this._super(code, paymentOptionId, flow); | ||
const inputs = this._getInlineFormInputs(paymentOptionId); | ||
values.sepa_dd_iban = inputs.sepa_dd_iban.value; | ||
values.sepa_dd_accept = inputs.sepa_dd_accept.value; | ||
return values; | ||
}, | ||
|
||
/** | ||
* Ensure that inputs for the form are valid (more validation | ||
* are done in python by the backend). | ||
* | ||
* @override method from payment.payment_form_mixin | ||
* @private | ||
* @param {String} code - The code of the payment option's provider | ||
* @param {Number} paymentOptionId - The id of the payment option handling the transaction | ||
* @param {String} flow - The online payment flow of the transaction | ||
* @returns {Promise} | ||
*/ | ||
_processPayment: function (code, paymentOptionId, flow) { | ||
if (code !== "custom" || flow === "token") { | ||
return this._super(...arguments); | ||
} | ||
|
||
if (!this._validateFormInputs(paymentOptionId)) { | ||
this._enableButton(); | ||
$("body").unblock(); | ||
return Promise.resolve(); | ||
} | ||
|
||
return this._super(...arguments); | ||
}, | ||
|
||
/** | ||
* Checks that all payment inputs adhere to the DOM validation constraints. | ||
* | ||
* @private | ||
* @param {Number} providerId - The id of the selected provider | ||
* @returns {Boolean} - Whether all elements pass the validation constraints | ||
*/ | ||
_validateFormInputs: function (providerId) { | ||
const inputs = Object.values(this._getInlineFormInputs(providerId)); | ||
return inputs.every((element) => element.reportValidity()); | ||
}, | ||
}; | ||
|
||
checkoutForm.include(sepaDDMixin); | ||
manageForm.include(sepaDDMixin); | ||
}); |
Oops, something went wrong.