diff --git a/setup/website_payment_acquirer_bank_account/odoo/addons/website_payment_acquirer_bank_account b/setup/website_payment_acquirer_bank_account/odoo/addons/website_payment_acquirer_bank_account new file mode 120000 index 0000000000..781efd05bb --- /dev/null +++ b/setup/website_payment_acquirer_bank_account/odoo/addons/website_payment_acquirer_bank_account @@ -0,0 +1 @@ +../../../../website_payment_acquirer_bank_account \ No newline at end of file diff --git a/setup/website_payment_acquirer_bank_account/setup.py b/setup/website_payment_acquirer_bank_account/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/website_payment_acquirer_bank_account/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/website_payment_acquirer_bank_account/README.rst b/website_payment_acquirer_bank_account/README.rst new file mode 100644 index 0000000000..7ad318ca9b --- /dev/null +++ b/website_payment_acquirer_bank_account/README.rst @@ -0,0 +1,73 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg + :target: https://opensource.org/licenses/LGPL-3.0 + :alt: License: LGPL-3 + +================================= +Account Payment Mode and Acquirer +================================= + +Overview +======== + +The **Account Payment Mode and Acquirer** module integrates payment modes with bank accounts in sales. It allows users to select a bank account for payments directly from the sales order, enhancing the payment processing workflow. + +Features +======== + +- **Bank Account Selection**: Users can select a bank account for payments directly from the sales order. + +- **Automatic Payment Mode Assignment**: When confirming an order, the payment mode is automatically set based on the selected bank account. + +- **Bank Account Management**: Users can create new bank accounts linked to partners seamlessly. + +Usage +===== + +1. **Install the Module**: + + - Install the module via Odoo's Apps interface. + +2. **Using Bank Accounts**: + + - When creating or editing a sales order, select a bank account from the dropdown. + - Confirm the order, and the payment mode will automatically be assigned based on the selected bank account. + +Configuration +============= + +No additional configuration is required. The module is ready to use once installed. + +Testing +======= + +Test the following scenarios: + +- **Bank Account Selection**: + + - Create or edit a sales order and select a bank account. + - Confirm the order and verify that the payment mode is set correctly. + +- **Bank Account Creation**: + + - Create a new bank account from the sales order and ensure it links correctly to the partner. + +Bug Tracker +=========== + +If you encounter any issues, please report them on the GitHub repository at `GitHub Issues `_. + +Credits +======= + +Contributors +------------ + +* Unai Beristain +* Ana Juaristi + +For module-specific questions, please contact the contributors directly. Support requests should be made through the official channels. + +License +======= + +This project is licensed under the LGPL-3 License. For more details, please refer to the LICENSE file or visit . diff --git a/website_payment_acquirer_bank_account/__init__.py b/website_payment_acquirer_bank_account/__init__.py new file mode 100644 index 0000000000..91c5580fed --- /dev/null +++ b/website_payment_acquirer_bank_account/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/website_payment_acquirer_bank_account/__manifest__.py b/website_payment_acquirer_bank_account/__manifest__.py new file mode 100644 index 0000000000..25f5354df1 --- /dev/null +++ b/website_payment_acquirer_bank_account/__manifest__.py @@ -0,0 +1,17 @@ +{ + "name": "Account Payment Mode and Acquirer", + "version": "14.0.1.0.0", + "author": "Avanzosc", + "summary": "Integrates payment modes with bank accounts in sales.", + "website": "https://github.com/avanzosc/odoo-addons", + "license": "LGPL-3", + "depends": [ + "web", + "sale", + "account", + "payment_acquirer_payment_mode", # trey + ], + "data": ["views/payment_view.xml"], + "installable": True, + "application": False, +} diff --git a/website_payment_acquirer_bank_account/controllers/__init__.py b/website_payment_acquirer_bank_account/controllers/__init__.py new file mode 100644 index 0000000000..12a7e529b6 --- /dev/null +++ b/website_payment_acquirer_bank_account/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/website_payment_acquirer_bank_account/controllers/main.py b/website_payment_acquirer_bank_account/controllers/main.py new file mode 100644 index 0000000000..b8e1b72701 --- /dev/null +++ b/website_payment_acquirer_bank_account/controllers/main.py @@ -0,0 +1,129 @@ +import logging + +from odoo import _, http + +_logger = logging.getLogger(__name__) + + +class PaymentController(http.Controller): + @http.route( + "/create_new_bank_account", + type="http", + auth="user", + methods=["POST"], + csrf=False, + website=True, + ) + def create_new_bank_account(self, **kwargs): + new_bank_account = kwargs.get("new_bank_account") + payment_mode_id = kwargs.get("payment_mode_id") + + msg_payment_mode_missing = _("Payment mode ID is missing") + msg_invalid_bank_account = _( + "The bank account number must have exactly 20 digits." + ) + msg_bank_account_exists = _("The bank account already exists") + msg_success = _("Bank account saved successfully") + + if not payment_mode_id: + _logger.warning("Payment mode ID was not provided.") + return http.request.redirect( + f"/shop/payment?message={msg_payment_mode_missing}&status=400" + ) + + payment_mode_id = int(payment_mode_id) + sale_order_id = http.request.session.get("sale_order_id") + + if len(new_bank_account) != 20 or not new_bank_account.isdigit(): + _logger.warning("The bank account number must have exactly 20 digits.") + return http.request.redirect( + f"/shop/payment?message={msg_invalid_bank_account}&status=400" + ) + + existing_bank = ( + http.request.env["res.partner.bank"] + .sudo() + .search([("acc_number", "=", new_bank_account)], limit=1) + ) + + if existing_bank: + _logger.warning("The bank account already exists: %s", new_bank_account) + return http.request.redirect( + f"/shop/payment?message={msg_bank_account_exists}&status=400" + ) + + partner_id = http.request.env.user.partner_id.id + + http.request.env["res.partner.bank"].sudo().create( + { + "acc_number": new_bank_account, + "partner_id": partner_id, + } + ) + + sale_order = http.request.env["sale.order"].sudo().browse(sale_order_id) + sale_order.write( + { + "payment_mode_id": payment_mode_id, + # "bank_account_id": new_bank_account_record.id, + } + ) + + _logger.info( + "Bank account created and successfully assigned to order ID: %s", + sale_order_id, + ) + + return http.request.redirect(f"/shop/payment?message={msg_success}&status=200") + + @http.route( + "/choose_bank_account", + type="json", + auth="user", + methods=["POST"], + csrf=False, + website=True, + ) + def choose_bank_account(self, bank_id=None, **kwargs): + if not bank_id: + _logger.warning("Bank account ID was not provided.") + return { + "status": "error", + "message": "Bank account ID was not provided.", + } + + try: + bank_id = int(bank_id) + except ValueError: + _logger.error("The bank account ID is not a valid number: %s", bank_id) + return { + "status": "error", + "message": "The bank account ID is not a valid number.", + } + + sale_order_id = http.request.session.get("sale_order_id") + if not sale_order_id: + _logger.warning("No sale order ID found in the session.") + return { + "status": "error", + "message": "No sale order ID found in the session.", + } + + sale_order = http.request.env["sale.order"].sudo().browse(sale_order_id) + if not sale_order.exists(): + _logger.warning("No sale order found with ID: %s", sale_order_id) + return { + "status": "error", + "message": "No sale order found with the provided ID.", + } + + # sale_order.write({"bank_account_id": bank_id}) + _logger.info( + "Bank account selected and successfully assigned to order ID: %s", + sale_order_id, + ) + + return { + "status": "success", + "message": "Bank account selected and successfully assigned to the order.", + } diff --git a/website_payment_acquirer_bank_account/models/__init__.py b/website_payment_acquirer_bank_account/models/__init__.py new file mode 100644 index 0000000000..ad77877f42 --- /dev/null +++ b/website_payment_acquirer_bank_account/models/__init__.py @@ -0,0 +1,3 @@ +from . import res_bank_account +from . import res_partner +from . import sale_order diff --git a/website_payment_acquirer_bank_account/models/res_bank_account.py b/website_payment_acquirer_bank_account/models/res_bank_account.py new file mode 100644 index 0000000000..0de065f836 --- /dev/null +++ b/website_payment_acquirer_bank_account/models/res_bank_account.py @@ -0,0 +1,10 @@ +from odoo import fields, models + + +class ResBankAccount(models.Model): + _name = "res.bank.account" + _description = "Bank Account" + + name = fields.Char(string="Account Name", required=True) + bank_account = fields.Char(string="Bank Account", required=True) + partner_id = fields.Many2one("res.partner", string="Partner", required=True) diff --git a/website_payment_acquirer_bank_account/models/res_partner.py b/website_payment_acquirer_bank_account/models/res_partner.py new file mode 100644 index 0000000000..e3e84ae644 --- /dev/null +++ b/website_payment_acquirer_bank_account/models/res_partner.py @@ -0,0 +1,11 @@ +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + bank_account_ids = fields.One2many( + "res.bank.account", + "partner_id", + string="Bank Accounts", + ) diff --git a/website_payment_acquirer_bank_account/models/sale_order.py b/website_payment_acquirer_bank_account/models/sale_order.py new file mode 100644 index 0000000000..59cf8dff6b --- /dev/null +++ b/website_payment_acquirer_bank_account/models/sale_order.py @@ -0,0 +1,29 @@ +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + bank_account_id = fields.Many2one( + "res.bank.account", + string="Bank Account", + help="Bank account selected for the payment.", + ) + + def confirm_order(self): + self.ensure_one() + if self.bank_account_id: + # Si hay una cuenta bancaria seleccionada + self.payment_mode_id = self.bank_account_id.payment_method_id + # Crear la cuenta bancaria si es nueva + if not self.bank_account_id.exists(): + self.env["res.bank.account"].create( + { + "name": self.bank_account_id.name, + "bank_account": self.bank_account_id.bank_account, + "partner_id": self.partner_id.id, + } + ) + else: + raise ValidationError(_("Please select a bank account.")) diff --git a/website_payment_acquirer_bank_account/static/src/js/choose_bank_account.js b/website_payment_acquirer_bank_account/static/src/js/choose_bank_account.js new file mode 100644 index 0000000000..f990560f4c --- /dev/null +++ b/website_payment_acquirer_bank_account/static/src/js/choose_bank_account.js @@ -0,0 +1,117 @@ +odoo.define("website_payment_acquirer_bank_account.choose_bank_account", function ( + require +) { + "use strict"; + + const rpc = require("web.rpc"); + + function getUrlParameter(name) { + const url = new URL(window.location.href); + return url.searchParams.get(name); + } + + function removeUrlParameter(name) { + const url = new URL(window.location.href); + url.searchParams.delete(name); + window.history.replaceState({}, document.title, url); + } + + function displayUrlMessage() { + const message = getUrlParameter("message"); + const status = getUrlParameter("status"); + const messageContainer = document.querySelector("#bank-account-message"); + + if (!messageContainer) { + console.warn("Element with ID 'bank-account-message' not found."); + return; + } + + if (message) { + messageContainer.innerHTML = `
${message}
`; + if (status === "200") { + messageContainer.style.backgroundColor = "#d4edda"; + messageContainer.style.color = "#155724"; + } else if (status === "400") { + messageContainer.style.backgroundColor = "#f8d7da"; + messageContainer.style.color = "#721c24"; + } else { + messageContainer.style.backgroundColor = "#fff3cd"; + messageContainer.style.color = "#856404"; + } + + removeUrlParameter("message"); + removeUrlParameter("status"); + } + } + + function onDOMReady() { + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", function () { + displayUrlMessage(); + }); + } else { + displayUrlMessage(); + } + } + + onDOMReady(); + + function chooseBankAccount(radio) { + if (!radio || !radio.value) { + alert("Please select a bank account."); + return; + } + + const BankID = radio.value; + + const requestData = { + bank_id: BankID, + }; + + const messageContainer = document.querySelector("#bank-account-message"); + if (messageContainer) { + messageContainer.innerHTML = ""; + messageContainer.style.backgroundColor = ""; + } + + rpc + .query({ + route: "/choose_bank_account", + params: requestData, + }) + .then(function (data) { + const messageContainer = document.querySelector("#bank-account-message"); + if (data.status === "success") { + messageContainer.innerHTML = `
${ + data.message || "Bank account selected successfully." + }
`; + messageContainer.style.backgroundColor = "#dff0d8"; + + removeUrlParameter("status"); + } else if (data.status === "error") { + messageContainer.innerHTML = `
${ + data.message || "An error occurred while selecting the bank account." + }
`; + messageContainer.style.backgroundColor = "#f2dede"; + + removeUrlParameter("status"); + } + }) + .catch(function (error) { + console.error("Error:", error); + const messageContainer = document.querySelector("#bank-account-message"); + if (messageContainer) { + messageContainer.innerHTML = `
An error occurred while processing your request.
`; + messageContainer.style.backgroundColor = "#f2dede"; + + removeUrlParameter("status"); + } + }); + } + + window.chooseBankAccount = chooseBankAccount; + + return { + chooseBankAccount: chooseBankAccount, + }; +}); diff --git a/website_payment_acquirer_bank_account/views/payment_view.xml b/website_payment_acquirer_bank_account/views/payment_view.xml new file mode 100644 index 0000000000..33f6604bad --- /dev/null +++ b/website_payment_acquirer_bank_account/views/payment_view.xml @@ -0,0 +1,80 @@ + + +