@ -0,0 +1,48 @@ | 
				
			|||||
 | 
					.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg | 
				
			||||
 | 
					    :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html | 
				
			||||
 | 
					    :alt: License: AGPL-3 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Customer Credit Payment In Website | 
				
			||||
 | 
					================================== | 
				
			||||
 | 
					* Assign the credit amount from the website and the sales | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Configuration | 
				
			||||
 | 
					============ | 
				
			||||
 | 
					    - www.odoo.com/documentation/18.0/setup/install.html | 
				
			||||
 | 
					    - Install our custom addon | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Company | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					License | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					Affero General Public License v3.0 (AGPL v3) | 
				
			||||
 | 
					(https://www.gnu.org/licenses/agpl-3.0-standalone.html) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Credits | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					* Developer: (V18) NIHALA KP, Contact: odoo@cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Contacts | 
				
			||||
 | 
					-------- | 
				
			||||
 | 
					* Mail Contact : odoo@cybrosys.com | 
				
			||||
 | 
					* Website : https://cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Bug Tracker | 
				
			||||
 | 
					----------- | 
				
			||||
 | 
					Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Maintainer | 
				
			||||
 | 
					-------- | 
				
			||||
 | 
					This module is maintained by Cybrosys Technologies. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					For support and more information, please visit https://www.cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.. image:: https://cybrosys.com/images/logo.png | 
				
			||||
 | 
					   :target: https://cybrosys.com" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Further Information | 
				
			||||
 | 
					----------- | 
				
			||||
 | 
					HTML Description: `<static/description/index.html>`__ | 
				
			||||
@ -0,0 +1,33 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from . import controllers | 
				
			||||
 | 
					from . import models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					from odoo.addons.payment import setup_provider, reset_payment_provider | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					def post_init_hook(env): | 
				
			||||
 | 
					    setup_provider(env, 'credit_pay') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					def uninstall_hook(env): | 
				
			||||
 | 
					    reset_payment_provider(env, 'credit_pay') | 
				
			||||
@ -0,0 +1,69 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					    'name': 'Customer Credit Payment In Website', | 
				
			||||
 | 
					    'version': '18.0.1.0.0', | 
				
			||||
 | 
					    'category': 'Website', | 
				
			||||
 | 
					    'summary': """Assign the credit amount from the website and the sales""", | 
				
			||||
 | 
					    'description': 'This is a module used to assign the credit to the customer' | 
				
			||||
 | 
					                   ' in the website and also from the sales.', | 
				
			||||
 | 
					    'author': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'company': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'maintainer': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'website': "https://www.cybrosys.com", | 
				
			||||
 | 
					    'depends': ['sale_management', 'purchase', | 
				
			||||
 | 
					                'product', 'website_sale', 'payment', 'payment_demo' | 
				
			||||
 | 
					                ], | 
				
			||||
 | 
					    'data': [ | 
				
			||||
 | 
					        'security/ir.model.access.csv', | 
				
			||||
 | 
					        'security/website_credit_payment_security.xml', | 
				
			||||
 | 
					        'data/website_data.xml', | 
				
			||||
 | 
					        'data/product_data.xml', | 
				
			||||
 | 
					        'views/credit_amount_views.xml', | 
				
			||||
 | 
					        'views/credit_details_views.xml', | 
				
			||||
 | 
					        'views/credit_payment_views.xml', | 
				
			||||
 | 
					        'views/sale_views.xml', | 
				
			||||
 | 
					        'views/sale_order_views.xml', | 
				
			||||
 | 
					        'views/res_partner_views.xml', | 
				
			||||
 | 
					        'views/customer_credit_payment_website_templates.xml', | 
				
			||||
 | 
					        'views/restrict_message_template.xml', | 
				
			||||
 | 
					        'views/payment_demo_templates.xml', | 
				
			||||
 | 
					        'views/payment_token_views.xml', | 
				
			||||
 | 
					        'views/payment_transaction_views.xml', | 
				
			||||
 | 
					        'data/payment_method_data.xml', | 
				
			||||
 | 
					        'data/payment_provider_data.xml', | 
				
			||||
 | 
					    ], | 
				
			||||
 | 
					    'post_init_hook': 'post_init_hook', | 
				
			||||
 | 
					    'uninstall_hook': 'uninstall_hook', | 
				
			||||
 | 
					    'assets': { | 
				
			||||
 | 
					        'web.assets_frontend': [ | 
				
			||||
 | 
					            'customer_credit_payment_website/static/src/js/**/*', | 
				
			||||
 | 
					        ], | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    'images': [ | 
				
			||||
 | 
					        'static/description/banner.jpg', | 
				
			||||
 | 
					    ], | 
				
			||||
 | 
					    'license': 'AGPL-3', | 
				
			||||
 | 
					    'installable': True, | 
				
			||||
 | 
					    'auto_install': False, | 
				
			||||
 | 
					    'application': True, | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,23 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from . import customer_credit_payment_website | 
				
			||||
 | 
					from . import website_sale | 
				
			||||
@ -0,0 +1,61 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from odoo import http | 
				
			||||
 | 
					from odoo.http import request | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CreditDetails(http.Controller): | 
				
			||||
 | 
					    """ Controllers to get the credit details and the credit amount of each | 
				
			||||
 | 
					    partner.""" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/credit/details', type='http', auth='public', website=True, | 
				
			||||
 | 
					                csrf=False) | 
				
			||||
 | 
					    def credit_details(self, **post): | 
				
			||||
 | 
					        """ Get the credit amount for each user and return the credit payment | 
				
			||||
 | 
					        page.""" | 
				
			||||
 | 
					        credit_amount = request.env.user.credit_amount | 
				
			||||
 | 
					        return request.render( | 
				
			||||
 | 
					            'customer_credit_payment_website.credit_payment_page', | 
				
			||||
 | 
					            {'credit_amount': credit_amount}) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/add/credit/balance', type='http', auth='public', website=True, | 
				
			||||
 | 
					                csrf=False) | 
				
			||||
 | 
					    def add_credit_balance(self, **post): | 
				
			||||
 | 
					        """ Add the credit amount from the website.""" | 
				
			||||
 | 
					        return request.render( | 
				
			||||
 | 
					            'customer_credit_payment_website.add_credit_payment_page') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class PaymentCreditPayController(http.Controller): | 
				
			||||
 | 
					    _simulation_url = '/payment/credit_pay/simulate_payment' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/payment/credit_pay/simulate_payment', type='json', | 
				
			||||
 | 
					                auth='public') | 
				
			||||
 | 
					    def credit_pay_simulate_payment(self, **data): | 
				
			||||
 | 
					        """ Simulate the response of a payment request. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :param dict data: The simulated notification data. | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        return request.env[ | 
				
			||||
 | 
					            'payment.transaction'].sudo()._handle_notification_data( | 
				
			||||
 | 
					            'credit_pay', data.get('args')) | 
				
			||||
@ -0,0 +1,146 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from datetime import datetime | 
				
			||||
 | 
					from odoo import http | 
				
			||||
 | 
					from odoo.http import request | 
				
			||||
 | 
					from odoo.addons.website_sale.controllers.main import WebsiteSale | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class WebsiteSaleInherit(WebsiteSale): | 
				
			||||
 | 
					    """Custom class inheriting from WebsiteSale to implement additional | 
				
			||||
 | 
					    features.""" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route(['/shop/cart'], type='http', auth="public", website=True, | 
				
			||||
 | 
					                sitemap=False) | 
				
			||||
 | 
					    def cart(self, **post): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        Override of the controller for updating the product amount in the | 
				
			||||
 | 
					        shopping cart. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        order = request.website.sale_get_order(force_create=True) | 
				
			||||
 | 
					        res_super = super(WebsiteSaleInherit, self).cart(**post) | 
				
			||||
 | 
					        amount = post.get('amount') | 
				
			||||
 | 
					        if amount: | 
				
			||||
 | 
					            product_id = request.env.ref( | 
				
			||||
 | 
					                'customer_credit_payment_website.credit_product_0').id | 
				
			||||
 | 
					            order.update({ | 
				
			||||
 | 
					                'credit_amount_sale': amount, | 
				
			||||
 | 
					                'order_line': [(5, 0, 0), (0, 0, { | 
				
			||||
 | 
					                    'product_id': product_id, | 
				
			||||
 | 
					                    'price_unit': amount, | 
				
			||||
 | 
					                    'tax_id': False, | 
				
			||||
 | 
					                })] | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        res_super.qcontext.update({ | 
				
			||||
 | 
					            'website_sale_order': order, | 
				
			||||
 | 
					            'amount': amount, | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        return res_super | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route(['/shop/confirm_order'], type='http', auth="public", | 
				
			||||
 | 
					                website=True, sitemap=False) | 
				
			||||
 | 
					    def confirm_order(self, **post): | 
				
			||||
 | 
					        """ Override the function to update the amount for the credit amount | 
				
			||||
 | 
					        that purchase from the website.""" | 
				
			||||
 | 
					        order = request.website.sale_get_order() | 
				
			||||
 | 
					        if not order: | 
				
			||||
 | 
					            return request.redirect('/shop') | 
				
			||||
 | 
					        product_id = request.env.ref( | 
				
			||||
 | 
					            'customer_credit_payment_website.credit_product_0').id | 
				
			||||
 | 
					        if redirection := self._check_cart_and_addresses(order): | 
				
			||||
 | 
					            return redirection | 
				
			||||
 | 
					        order.order_line._compute_tax_id() | 
				
			||||
 | 
					        request.session['sale_last_order_id'] = order.id | 
				
			||||
 | 
					        request.website.sale_get_order() | 
				
			||||
 | 
					        extra_step = request.website.viewref('website_sale.extra_info') | 
				
			||||
 | 
					        if extra_step.active: | 
				
			||||
 | 
					            return request.redirect("/shop/extra_info") | 
				
			||||
 | 
					        if order.credit_amount_sale: | 
				
			||||
 | 
					            order.update({ | 
				
			||||
 | 
					                'order_line': [(5, 0, 0), (0, 0, { | 
				
			||||
 | 
					                    'product_id': product_id, | 
				
			||||
 | 
					                    'price_unit': order.credit_amount_sale, | 
				
			||||
 | 
					                })] | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        return request.redirect("/shop/payment") | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route(['/shop/confirmation'], type='http', auth="public", | 
				
			||||
 | 
					                website=True, sitemap=False) | 
				
			||||
 | 
					    def shop_payment_confirmation(self, **post): | 
				
			||||
 | 
					        """ End of checkout process controller. Confirmation is basically seeing | 
				
			||||
 | 
					        the status of a sale.order. """ | 
				
			||||
 | 
					        sale_order_id = request.session.get('sale_last_order_id') | 
				
			||||
 | 
					        if not sale_order_id: | 
				
			||||
 | 
					            return request.redirect('/shop') | 
				
			||||
 | 
					        order = request.env['sale.order'].sudo().browse(sale_order_id) | 
				
			||||
 | 
					        user_id = request.env.user | 
				
			||||
 | 
					        partner = user_id.partner_id | 
				
			||||
 | 
					        order_amount_total = order.amount_total | 
				
			||||
 | 
					        payment_transaction = request.env['payment.transaction'].search( | 
				
			||||
 | 
					            [('reference', '=', order.name)]) | 
				
			||||
 | 
					        payment_transaction_id = payment_transaction.provider_id | 
				
			||||
 | 
					        credit_product_id = request.env.ref( | 
				
			||||
 | 
					            'customer_credit_payment_website.credit_product_0').id | 
				
			||||
 | 
					        credit_payment_provider_id = request.env.ref( | 
				
			||||
 | 
					            'customer_credit_payment_website.payment_provider_credit').id | 
				
			||||
 | 
					        has_credit_product = any( | 
				
			||||
 | 
					            line.product_id.id == credit_product_id for line in | 
				
			||||
 | 
					            order.order_line) | 
				
			||||
 | 
					        if (has_credit_product and | 
				
			||||
 | 
					                payment_transaction_id.id != credit_payment_provider_id): | 
				
			||||
 | 
					            request.env['credit.amount'].create({ | 
				
			||||
 | 
					                'customer_id': partner.id, | 
				
			||||
 | 
					                'amount': order_amount_total | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        elif (not has_credit_product and | 
				
			||||
 | 
					              payment_transaction_id.id == credit_payment_provider_id): | 
				
			||||
 | 
					            if order.amount_total < partner.credit_amount: | 
				
			||||
 | 
					                credit_detail = request.env['credit.details'].search( | 
				
			||||
 | 
					                    [('customer_id', '=', partner.id)]) | 
				
			||||
 | 
					                credit_detail.write({ | 
				
			||||
 | 
					                    'debit_details_ids': [(0, 0, { | 
				
			||||
 | 
					                        'debit_amount': -order_amount_total, | 
				
			||||
 | 
					                        'approve_date': datetime.now(), | 
				
			||||
 | 
					                        'updated_amount': | 
				
			||||
 | 
					                            -order_amount_total + credit_detail.debit_amount, | 
				
			||||
 | 
					                        'previous_debit_amount': credit_detail.debit_amount, | 
				
			||||
 | 
					                    })] | 
				
			||||
 | 
					                }) | 
				
			||||
 | 
					            elif order.amount_total > partner.credit_amount: | 
				
			||||
 | 
					                if not partner.allow_credit_amount: | 
				
			||||
 | 
					                    return request.render( | 
				
			||||
 | 
					                        'customer_credit_payment_website.credit_error_details', | 
				
			||||
 | 
					                        {'name': order.name}) | 
				
			||||
 | 
					                else: | 
				
			||||
 | 
					                    credit_detail = request.env['credit.details'].search( | 
				
			||||
 | 
					                        [('customer_id', '=', partner.id)]) | 
				
			||||
 | 
					                    credit_detail.write({ | 
				
			||||
 | 
					                        'debit_details_ids': [(0, 0, { | 
				
			||||
 | 
					                            'debit_amount': -order_amount_total, | 
				
			||||
 | 
					                            'approve_date': datetime.now(), | 
				
			||||
 | 
					                            'previous_debit_amount': credit_detail.debit_amount, | 
				
			||||
 | 
					                            'updated_amount': | 
				
			||||
 | 
					                            -order_amount_total + credit_detail.debit_amount, | 
				
			||||
 | 
					                        })] | 
				
			||||
 | 
					                    }) | 
				
			||||
 | 
					        values = self._prepare_shop_payment_confirmation_values(order) | 
				
			||||
 | 
					        return request.render("website_sale.confirmation", values) | 
				
			||||
@ -0,0 +1,13 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<odoo noupdate="1"> | 
				
			||||
 | 
					    <!-- Created a payment method for newly configured payment provider--> | 
				
			||||
 | 
					    <record id="payment_method_credit_pay" model="payment.method"> | 
				
			||||
 | 
					        <field name="name">credit pay</field> | 
				
			||||
 | 
					        <field name="code">credit_pay</field> | 
				
			||||
 | 
					        <field name="active">True</field> | 
				
			||||
 | 
					        <field name="sequence">200</field> | 
				
			||||
 | 
					        <field name="image" type="base64" file="customer_credit_payment_website/static/description/credit.png"/> | 
				
			||||
 | 
					        <field name="support_tokenization">False</field> | 
				
			||||
 | 
					        <field name="support_express_checkout">False</field> | 
				
			||||
 | 
					    </record> | 
				
			||||
 | 
					</odoo> | 
				
			||||
@ -0,0 +1,21 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<odoo noupdate="1"> | 
				
			||||
 | 
					    <!--    Credit Payment Provider    --> | 
				
			||||
 | 
					    <record id="payment_provider_credit" model="payment.provider"> | 
				
			||||
 | 
					        <field name="name">Credit payment</field> | 
				
			||||
 | 
					        <field name="sequence">45</field> | 
				
			||||
 | 
					        <field name="image_128" type="base64" | 
				
			||||
 | 
					               file="customer_credit_payment_website/static/description/credit.png"/> | 
				
			||||
 | 
					        <field name="code">credit_pay</field> | 
				
			||||
 | 
					        <field name="inline_form_view_id" ref="inline_form"/> | 
				
			||||
 | 
					        <field name="token_inline_form_view_id" ref="token_inline_form"/> | 
				
			||||
 | 
					        <field name="allow_tokenization">True</field> | 
				
			||||
 | 
					        <field name="module_id" | 
				
			||||
 | 
					               ref="base.module_customer_credit_payment_website"/> | 
				
			||||
 | 
					        <field name="payment_method_ids" | 
				
			||||
 | 
					               eval="[Command.set([ | 
				
			||||
 | 
					                         ref('customer_credit_payment_website.payment_method_credit_pay'), | 
				
			||||
 | 
					                     ])]" | 
				
			||||
 | 
					        /> | 
				
			||||
 | 
					    </record> | 
				
			||||
 | 
					</odoo> | 
				
			||||
@ -0,0 +1,19 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<odoo> | 
				
			||||
 | 
					    <data noupdate="1"> | 
				
			||||
 | 
					        <!--    Data for the credit product  --> | 
				
			||||
 | 
					        <record id="credit_product_0" model="product.product"> | 
				
			||||
 | 
					            <field name="name">Credit Product</field> | 
				
			||||
 | 
					            <field name="categ_id" ref="product.product_category_3"/> | 
				
			||||
 | 
					            <field name="type">service</field> | 
				
			||||
 | 
					            <field name="list_price">1.0</field> | 
				
			||||
 | 
					            <field name="invoice_policy">order</field> | 
				
			||||
 | 
					            <field name="standard_price">1.0</field> | 
				
			||||
 | 
					            <field name="uom_id" ref="uom.product_uom_unit"/> | 
				
			||||
 | 
					            <field name="uom_po_id" ref="uom.product_uom_unit"/> | 
				
			||||
 | 
					            <field name="company_id" eval="[]"/> | 
				
			||||
 | 
					            <field name="taxes_id" eval="[]"/> | 
				
			||||
 | 
					            <field name="supplier_taxes_id" eval="[]"/> | 
				
			||||
 | 
					        </record> | 
				
			||||
 | 
					    </data> | 
				
			||||
 | 
					</odoo> | 
				
			||||
@ -0,0 +1,12 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<odoo> | 
				
			||||
 | 
					    <data> | 
				
			||||
 | 
					        <!--       Credit menu in the website     --> | 
				
			||||
 | 
					        <record id="credit_menu" model="website.menu"> | 
				
			||||
 | 
					            <field name="name">Credit</field> | 
				
			||||
 | 
					            <field name="url">/credit/details</field> | 
				
			||||
 | 
					            <field name="parent_id" ref="website.main_menu"/> | 
				
			||||
 | 
					            <field name="sequence" type="int">80</field> | 
				
			||||
 | 
					        </record> | 
				
			||||
 | 
					    </data> | 
				
			||||
 | 
					</odoo> | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			|||||
 | 
					## Module <customer_credit_payment_website> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#### 18.02.2025 | 
				
			||||
 | 
					#### Version 18.0.1.0.0 | 
				
			||||
 | 
					#### ADD | 
				
			||||
 | 
					- Initial commit for Customer Credit Payment In Website | 
				
			||||
@ -0,0 +1,29 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from . import credit_amount | 
				
			||||
 | 
					from . import credit_details | 
				
			||||
 | 
					from . import credit_payment | 
				
			||||
 | 
					from . import payment_provider | 
				
			||||
 | 
					from . import payment_token | 
				
			||||
 | 
					from . import payment_transaction | 
				
			||||
 | 
					from . import res_partner | 
				
			||||
 | 
					from . import sale_order_line | 
				
			||||
@ -0,0 +1,89 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from datetime import datetime | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CreditAmount(models.Model): | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					        Model for managing credit amounts associated with customers. | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					    _name = "credit.amount" | 
				
			||||
 | 
					    _description = "Credit Amount" | 
				
			||||
 | 
					    _rec_name = 'customer_id' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    customer_id = fields.Many2one( | 
				
			||||
 | 
					        'res.partner', string='Customer', required=1, | 
				
			||||
 | 
					        help='Reference to the associated customer/partner.') | 
				
			||||
 | 
					    amount = fields.Float(string="Amount", | 
				
			||||
 | 
					                          help='The monetary amount associated with this ' | 
				
			||||
 | 
					                               'record.') | 
				
			||||
 | 
					    approve_date = fields.Datetime( | 
				
			||||
 | 
					        'Approve Date', default=datetime.today(), | 
				
			||||
 | 
					        help='Date and time when the record was approved.') | 
				
			||||
 | 
					    state = fields.Selection( | 
				
			||||
 | 
					        [('to_approve', 'Waiting for approve'), ('approved', 'Approved'), ], | 
				
			||||
 | 
					        string='Stage', readonly=True, copy=False, | 
				
			||||
 | 
					        index=True, tracking=3, default='to_approve', | 
				
			||||
 | 
					        help='Current stage of the record, indicating whether it is waiting ' | 
				
			||||
 | 
					             'for approval or already approved.') | 
				
			||||
 | 
					    hide_approve = fields.Boolean( | 
				
			||||
 | 
					        'Approve', default=False, invisible="1", | 
				
			||||
 | 
					        help='Boolean field indicating whether the approval action should be ' | 
				
			||||
 | 
					             'hidden or visible.') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_approve(self): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					            Approves the credit amount and updates associated credit details. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            :return: None | 
				
			||||
 | 
					            """ | 
				
			||||
 | 
					        self.state = 'approved' | 
				
			||||
 | 
					        self.hide_approve = True | 
				
			||||
 | 
					        credit_details = self.env['credit.details'].search( | 
				
			||||
 | 
					            [('customer_id', '=', self.customer_id.id)]) | 
				
			||||
 | 
					        if credit_details: | 
				
			||||
 | 
					            previous_amt = credit_details.credit_amount | 
				
			||||
 | 
					            credit_details.write({ | 
				
			||||
 | 
					                'updated_amount':self.amount, | 
				
			||||
 | 
					                '_is_amount_updated': False, | 
				
			||||
 | 
					                'credit_details_ids': [(0, 0, { | 
				
			||||
 | 
					                    'amount': self.amount, | 
				
			||||
 | 
					                    'customer_id': credit_details.customer_id.id, | 
				
			||||
 | 
					                    'previous_credit_amount': previous_amt, | 
				
			||||
 | 
					                    'approve_date': self.approve_date, | 
				
			||||
 | 
					                    'updated_amount': self.amount + previous_amt, | 
				
			||||
 | 
					                    'credit_id': credit_details.id, | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                })] | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        else: | 
				
			||||
 | 
					            self.env['credit.details'].create({ | 
				
			||||
 | 
					                'customer_id': self.customer_id.id, | 
				
			||||
 | 
					                'updated_amount': self.amount, | 
				
			||||
 | 
					                'credit_details_ids': [(0, 0, { | 
				
			||||
 | 
					                    'customer_id': self.customer_id.id, | 
				
			||||
 | 
					                    'amount': self.amount, | 
				
			||||
 | 
					                    'previous_credit_amount': 0.0, | 
				
			||||
 | 
					                    'approve_date': self.approve_date, | 
				
			||||
 | 
					                    'updated_amount': self.amount, })] | 
				
			||||
 | 
					            }) | 
				
			||||
@ -0,0 +1,149 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from datetime import datetime | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CreditDetails(models.Model): | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					        Model for managing credit details associated with customers. | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					    _name = "credit.details" | 
				
			||||
 | 
					    _description = "Credit Details" | 
				
			||||
 | 
					    _rec_name = 'customer_id' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    credit_id = fields.Many2one( | 
				
			||||
 | 
					        'credit.amount', | 
				
			||||
 | 
					        help='Reference to the associated credit amount record.') | 
				
			||||
 | 
					    customer_id = fields.Many2one( | 
				
			||||
 | 
					        'res.partner', string='Customer', | 
				
			||||
 | 
					        help='Reference to the associated customer/partner.') | 
				
			||||
 | 
					    credit_amount = fields.Float( | 
				
			||||
 | 
					        "Credit", compute='_compute_credit_amount', | 
				
			||||
 | 
					        help='Representing the total credit amount associated with this ' | 
				
			||||
 | 
					             'record.') | 
				
			||||
 | 
					    debit_amount = fields.Float( | 
				
			||||
 | 
					        "Debit", compute='_compute_debit_amount', | 
				
			||||
 | 
					        help='Representing the total debit amount associated with this record.') | 
				
			||||
 | 
					    credit_details_amount = fields.Float( | 
				
			||||
 | 
					        "Credit Details", compute='_compute_credit_details_amount', | 
				
			||||
 | 
					        help='Representing the total credit details amount associated with ' | 
				
			||||
 | 
					             'this record.') | 
				
			||||
 | 
					    updated_amount = fields.Float( | 
				
			||||
 | 
					        "Update", help='Field used for updating the credit amount.') | 
				
			||||
 | 
					    credit_details_ids = fields.One2many( | 
				
			||||
 | 
					        'credit.detail.lines', 'credit_id', | 
				
			||||
 | 
					        help='Credit detail lines associated with this record.') | 
				
			||||
 | 
					    debit_details_ids = fields.One2many( | 
				
			||||
 | 
					        'debit.detail.lines', 'debit_id', | 
				
			||||
 | 
					        help='Debit detail lines associated with this record.') | 
				
			||||
 | 
					    _is_amount_updated = fields.Boolean( | 
				
			||||
 | 
					        string='to check whether the credit is updated with accounts') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_credit_amount(self): | 
				
			||||
 | 
					        """ Function to compute the credit amount """ | 
				
			||||
 | 
					        for rec in self: | 
				
			||||
 | 
					            rec.credit_amount = 0.0 | 
				
			||||
 | 
					            if rec.credit_details_ids: | 
				
			||||
 | 
					                rec.credit_amount = sum( | 
				
			||||
 | 
					                    rec.credit_details_ids.mapped('amount')) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_debit_amount(self): | 
				
			||||
 | 
					        """"" Function to compute the debit amount """ | 
				
			||||
 | 
					        for rec in self: | 
				
			||||
 | 
					            rec.debit_amount = 0.0 | 
				
			||||
 | 
					            if rec.debit_details_ids: | 
				
			||||
 | 
					                rec.debit_amount = sum( | 
				
			||||
 | 
					                    rec.debit_details_ids.mapped('debit_amount')) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_credit_details_amount(self): | 
				
			||||
 | 
					        """ Function to compute the credit details amount """ | 
				
			||||
 | 
					        for rec in self: | 
				
			||||
 | 
					            rec.credit_details_amount = 0.0 | 
				
			||||
 | 
					            rec.credit_details_amount = rec.credit_amount + rec.debit_amount | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_amount_updated(self): | 
				
			||||
 | 
					        for rec in self: | 
				
			||||
 | 
					            if rec.credit_details_ids.mapped( | 
				
			||||
 | 
					                    'previous_credit_amount').pop() < rec.credit_details_amount: | 
				
			||||
 | 
					                rec._is_amount_updated = True | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_update_account(self): | 
				
			||||
 | 
					        """ Function to update the amount in the account payment""" | 
				
			||||
 | 
					        self._is_amount_updated = True | 
				
			||||
 | 
					        return { | 
				
			||||
 | 
					            'name': 'Credit Payment', | 
				
			||||
 | 
					            'view_mode': 'form', | 
				
			||||
 | 
					            'res_model': 'credit.payment', | 
				
			||||
 | 
					            'type': 'ir.actions.act_window', | 
				
			||||
 | 
					            'context': {'default_partner_id': self.customer_id.id, | 
				
			||||
 | 
					                        'default_credit_amount': self.credit_details_ids.mapped( | 
				
			||||
 | 
					                            'amount').pop(), | 
				
			||||
 | 
					                        'default_payment_journal': self.env[ | 
				
			||||
 | 
					                            'account.journal'].search([('type', '=', 'bank')], | 
				
			||||
 | 
					                                                      limit=1).id, | 
				
			||||
 | 
					                        'default_credit_detail_id': self.id, | 
				
			||||
 | 
					                        }, | 
				
			||||
 | 
					            'target': 'new' | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CreditDetailsLines(models.Model): | 
				
			||||
 | 
					    """ Model for managing credit detail lines associated with credit details""" | 
				
			||||
 | 
					    _name = "credit.detail.lines" | 
				
			||||
 | 
					    _description = "Credit Detail Lines" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    credit_id = fields.Many2one('credit.details', string=" Credit Id", | 
				
			||||
 | 
					                                help="Credit detail associate with this " | 
				
			||||
 | 
					                                     "record.") | 
				
			||||
 | 
					    customer_id = fields.Many2one('res.partner', string="Customer details", | 
				
			||||
 | 
					                                  help="Customer details") | 
				
			||||
 | 
					    amount = fields.Float(string='Amount', | 
				
			||||
 | 
					                          help="Total credit amount associated with the " | 
				
			||||
 | 
					                               "partner.") | 
				
			||||
 | 
					    previous_credit_amount = fields.Float(string='Previous Credit Amount', | 
				
			||||
 | 
					                                          help='The previous credit amount') | 
				
			||||
 | 
					    approve_date = fields.Datetime(string='Approve Date', | 
				
			||||
 | 
					                                   default=datetime.today(), | 
				
			||||
 | 
					                                   help='Approved date of the credit amount') | 
				
			||||
 | 
					    updated_amount = fields.Float(string='Updated Amount', | 
				
			||||
 | 
					                                  help='Updated amount') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class DebitDetailsLines(models.Model): | 
				
			||||
 | 
					    """ Model for managing debit detail lines associated with credit details """ | 
				
			||||
 | 
					    _name = "debit.detail.lines" | 
				
			||||
 | 
					    _description = "Debit Detail lines" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    debit_id = fields.Many2one('credit.details', string=" Credit Id", | 
				
			||||
 | 
					                               help="Credit detail associate with this record.") | 
				
			||||
 | 
					    customer_id = fields.Many2one('res.partner', string="Customer details", | 
				
			||||
 | 
					                                  help="Customer details") | 
				
			||||
 | 
					    debit_amount = fields.Float(string='Amount', | 
				
			||||
 | 
					                                help="Total credit amount associated with the " | 
				
			||||
 | 
					                                     "partner.") | 
				
			||||
 | 
					    previous_debit_amount = fields.Float(string='Previous Debit Amount', | 
				
			||||
 | 
					                                         help='The previous credit amount') | 
				
			||||
 | 
					    approve_date = fields.Datetime('Approve Date', default=datetime.today(), | 
				
			||||
 | 
					                                   help='Approved date of the credit amount') | 
				
			||||
 | 
					    updated_amount = fields.Float(string='Updated Amount', | 
				
			||||
 | 
					                                  help='Updated amount') | 
				
			||||
@ -0,0 +1,59 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					from datetime import date | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CreditPayment(models.TransientModel): | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					        Transient Model for managing credit payments in the payment journal. | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					    _name = "credit.payment" | 
				
			||||
 | 
					    _description = "Credit Payment" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    payment_journal = fields.Many2one('account.journal', | 
				
			||||
 | 
					                                      string='Payment Journal', readonly=1, | 
				
			||||
 | 
					                                      help='Represents the payment journal ' | 
				
			||||
 | 
					                                           'associated with the record.') | 
				
			||||
 | 
					    credit_amount = fields.Float('Credit Amount', | 
				
			||||
 | 
					                                 help='Credit amount to update the journal') | 
				
			||||
 | 
					    partner_id = fields.Many2one('res.partner', help="customer value") | 
				
			||||
 | 
					    credit_detail_id = fields.Many2one('credit.details', help="credit details here") | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_submit(self): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					            Create and submit an inbound payment for the current record. | 
				
			||||
 | 
					            Returns: account.payment: The newly created payment record. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        payment_id = self.env['account.payment'].sudo().create({ | 
				
			||||
 | 
					            'payment_type': 'inbound', | 
				
			||||
 | 
					            'payment_method_id': self.env.ref( | 
				
			||||
 | 
					                'account.account_payment_method_manual_in').id, | 
				
			||||
 | 
					            'payment_method_line_id': self.env.ref( | 
				
			||||
 | 
					                'account.account_payment_method_manual_in').id, | 
				
			||||
 | 
					            'partner_type': 'customer', | 
				
			||||
 | 
					            'partner_id': self.partner_id.id, | 
				
			||||
 | 
					            'amount': self.credit_amount, | 
				
			||||
 | 
					            'date': date.today(), | 
				
			||||
 | 
					            'journal_id': self.payment_journal.id, | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        payment_id.action_post() | 
				
			||||
@ -0,0 +1,60 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from odoo import _, api, fields, models | 
				
			||||
 | 
					from odoo.exceptions import UserError | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class PaymentProvider(models.Model): | 
				
			||||
 | 
					    """ Inherits the payment provider to add the credit payment """ | 
				
			||||
 | 
					    _inherit = 'payment.provider' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    code = fields.Selection(selection_add=[('credit_pay', 'Credit Payment')], | 
				
			||||
 | 
					                            ondelete={'credit_pay': 'set default'}) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    # === COMPUTE METHODS ===# | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @api.depends('code') | 
				
			||||
 | 
					    def _compute_view_configuration_fields(self): | 
				
			||||
 | 
					        """ Override of payment to hide the credentials page. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        super()._compute_view_configuration_fields() | 
				
			||||
 | 
					        self.filtered( | 
				
			||||
 | 
					            lambda p: p.code == 'credit_pay').show_credentials_page = False | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_feature_support_fields(self): | 
				
			||||
 | 
					        """ Override of `payment` to enable additional features. """ | 
				
			||||
 | 
					        super()._compute_feature_support_fields() | 
				
			||||
 | 
					        self.filtered(lambda p: p.code == 'credit_pay').update({ | 
				
			||||
 | 
					            'support_manual_capture': 'partial', | 
				
			||||
 | 
					            'support_refund': 'partial', | 
				
			||||
 | 
					            'support_tokenization': True, | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    # === CONSTRAINT METHODS ===# | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @api.constrains('state', 'code') | 
				
			||||
 | 
					    def _check_provider_state(self): | 
				
			||||
 | 
					        if self.filtered(lambda p: p.code == 'credit_pay' and p.state not in ( | 
				
			||||
 | 
					                'test', 'disabled')): | 
				
			||||
 | 
					            raise UserError(_("Demo providers should never be enabled.")) | 
				
			||||
@ -0,0 +1,56 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class PaymentToken(models.Model): | 
				
			||||
 | 
					    """ Inherits the 'payment.token' """ | 
				
			||||
 | 
					    _inherit = 'payment.token' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    credit_pay_simulated_state = fields.Selection( | 
				
			||||
 | 
					        string="Simulated State", | 
				
			||||
 | 
					        help="The state in which transactions created from this token should " | 
				
			||||
 | 
					             "be set.", | 
				
			||||
 | 
					        selection=[ | 
				
			||||
 | 
					            ('pending', "Pending"), | 
				
			||||
 | 
					            ('done', "Confirmed"), | 
				
			||||
 | 
					            ('cancel', "Canceled"), | 
				
			||||
 | 
					            ('error', "Error"), | 
				
			||||
 | 
					        ], | 
				
			||||
 | 
					    ) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _build_display_name(self, *args, should_pad=True, **kwargs): | 
				
			||||
 | 
					        """ Override of `payment` to build the display name without padding. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :param list args: The arguments passed by QWeb when calling this method. | 
				
			||||
 | 
					        :param bool should_pad: Whether the token should be padded or not. | 
				
			||||
 | 
					        :param dict kwargs: Optional data. | 
				
			||||
 | 
					        :return: The demo token name. | 
				
			||||
 | 
					        :rtype: str | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return super()._build_display_name(*args, should_pad=should_pad, | 
				
			||||
 | 
					                                               **kwargs) | 
				
			||||
 | 
					        return super()._build_display_name(*args, should_pad=False, **kwargs) | 
				
			||||
@ -0,0 +1,254 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					import logging | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					from odoo import _, fields, models | 
				
			||||
 | 
					from odoo.exceptions import UserError, ValidationError | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					_logger = logging.getLogger(__name__) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class PaymentTransaction(models.Model): | 
				
			||||
 | 
					    _inherit = 'payment.transaction' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    capture_manually = fields.Boolean(related='provider_id.capture_manually') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    # === ACTION METHODS ===# | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_credit_pay_set_done(self): | 
				
			||||
 | 
					        """ Set the state of the credit_pay transaction to 'done'. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        self.ensure_one() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = {'reference': self.reference, | 
				
			||||
 | 
					                             'simulated_state': 'done'} | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_credit_pay_set_canceled(self): | 
				
			||||
 | 
					        """ Set the state of the credit_pay transaction to 'cancel'. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        self.ensure_one() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = {'reference': self.reference, | 
				
			||||
 | 
					                             'simulated_state': 'cancel'} | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_credit_pay_set_error(self): | 
				
			||||
 | 
					        """ Set the state of the credit_pay transaction to 'error'. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        self.ensure_one() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = {'reference': self.reference, | 
				
			||||
 | 
					                             'simulated_state': 'error'} | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    # === BUSINESS METHODS ===# | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _send_payment_request(self): | 
				
			||||
 | 
					        """ Override of payment to simulate a payment request. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        super()._send_payment_request() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if not self.token_id: | 
				
			||||
 | 
					            raise UserError( | 
				
			||||
 | 
					                "Demo: " + _("The transaction is not linked to a token.")) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        simulated_state = self.token_id.credit_pay_simulated_state | 
				
			||||
 | 
					        notification_data = {'reference': self.reference, | 
				
			||||
 | 
					                             'simulated_state': simulated_state} | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _send_refund_request(self, **kwargs): | 
				
			||||
 | 
					        """ Override of payment to simulate a refund. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :param dict kwargs: The keyword arguments. | 
				
			||||
 | 
					        :return: The refund transaction created to process the refund request. | 
				
			||||
 | 
					        :rtype: recordset of `payment.transaction` | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        refund_tx = super()._send_refund_request(**kwargs) | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return refund_tx | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = {'reference': refund_tx.reference, | 
				
			||||
 | 
					                             'simulated_state': 'done'} | 
				
			||||
 | 
					        refund_tx._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        return refund_tx | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _send_capture_request(self): | 
				
			||||
 | 
					        """ Override of payment to simulate a capture request. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        super()._send_capture_request() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = { | 
				
			||||
 | 
					            'reference': self.reference, | 
				
			||||
 | 
					            'simulated_state': 'done', | 
				
			||||
 | 
					            'manual_capture': True, | 
				
			||||
 | 
					            # Distinguish manual captures from regular one-step captures. | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _send_void_request(self): | 
				
			||||
 | 
					        """ Override of payment to simulate a void request. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        super()._send_void_request() | 
				
			||||
 | 
					        if self.provider_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        notification_data = {'reference': self.reference, | 
				
			||||
 | 
					                             'simulated_state': 'cancel'} | 
				
			||||
 | 
					        self._handle_notification_data('credit_pay', notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    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 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 != 'credit_pay' or len(tx) == 1: | 
				
			||||
 | 
					            return tx | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        reference = notification_data.get('reference') | 
				
			||||
 | 
					        tx = self.search([('reference', '=', reference), | 
				
			||||
 | 
					                          ('provider_code', '=', 'credit_pay')]) | 
				
			||||
 | 
					        if not tx: | 
				
			||||
 | 
					            raise ValidationError( | 
				
			||||
 | 
					                "Demo: " + _("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_code != 'credit_pay': | 
				
			||||
 | 
					            return | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        self.provider_reference = f'credit_pay-{self.reference}' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if self.tokenize: | 
				
			||||
 | 
					            # The reasons why we immediately tokenize the transaction | 
				
			||||
 | 
					            # regardless of the state rather than waiting for the payment | 
				
			||||
 | 
					            # method to be validated ('authorized' or 'done') like the other | 
				
			||||
 | 
					            # payment providers do are: - To save the simulated state and | 
				
			||||
 | 
					            # payment details on the token while we have them. - To allow | 
				
			||||
 | 
					            # customers to create tokens whose transactions will always end | 
				
			||||
 | 
					            # up in the said simulated state. | 
				
			||||
 | 
					            self._credit_pay_tokenize_from_notification_data(notification_data) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        state = notification_data['simulated_state'] | 
				
			||||
 | 
					        if state == 'pending': | 
				
			||||
 | 
					            self._set_pending() | 
				
			||||
 | 
					        elif state == 'done': | 
				
			||||
 | 
					            if self.capture_manually and not notification_data.get( | 
				
			||||
 | 
					                    'manual_capture'): | 
				
			||||
 | 
					                self._set_authorized() | 
				
			||||
 | 
					            else: | 
				
			||||
 | 
					                self._set_done() | 
				
			||||
 | 
					                # Immediately post-process the transaction if it is a refund, | 
				
			||||
 | 
					                # as the post-processing will not be triggered by a customer | 
				
			||||
 | 
					                # browsing the transaction from the portal. | 
				
			||||
 | 
					                if self.operation == 'refund': | 
				
			||||
 | 
					                    self.env.ref( | 
				
			||||
 | 
					                        'payment.cron_post_process_payment_tx')._trigger() | 
				
			||||
 | 
					        elif state == 'cancel': | 
				
			||||
 | 
					            self._set_canceled() | 
				
			||||
 | 
					        else:  # Simulate an error state. | 
				
			||||
 | 
					            self._set_error( | 
				
			||||
 | 
					                _("You selected the following credit_pay payment status: %s", | 
				
			||||
 | 
					                  state)) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _credit_pay_tokenize_from_notification_data(self, notification_data): | 
				
			||||
 | 
					        """ Create a new token based on the notification data. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        Note: self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        :param dict notification_data: The fake notification data to tokenize | 
				
			||||
 | 
					        from. :return: None | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        self.ensure_one() | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        state = notification_data['simulated_state'] | 
				
			||||
 | 
					        token = self.env['payment.token'].create({ | 
				
			||||
 | 
					            'provider_id': self.provider_id.id, | 
				
			||||
 | 
					            'payment_details': notification_data['payment_details'], | 
				
			||||
 | 
					            'partner_id': self.partner_id.id, | 
				
			||||
 | 
					            'provider_ref': 'fake provider reference', | 
				
			||||
 | 
					            'verified': True, | 
				
			||||
 | 
					            'credit_pay_simulated_state': state, | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        self.write({ | 
				
			||||
 | 
					            'token_id': token, | 
				
			||||
 | 
					            'tokenize': False, | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        _logger.info( | 
				
			||||
 | 
					            "Created token with id %s for partner with id %s.", token.id, | 
				
			||||
 | 
					            self.partner_id.id | 
				
			||||
 | 
					        ) | 
				
			||||
@ -0,0 +1,101 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class ResPartner(models.Model): | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					        Inherited Model res partner adding the credit details. | 
				
			||||
 | 
					    """ | 
				
			||||
 | 
					    _inherit = "res.partner" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    credit_amount = fields.Float(compute='_compute_credit_amount', | 
				
			||||
 | 
					                                 string='Credit Amount', | 
				
			||||
 | 
					                                 help='Here the credit amount for the ' | 
				
			||||
 | 
					                                      'associated customer.') | 
				
			||||
 | 
					    allow_credit_amount = fields.Boolean( | 
				
			||||
 | 
					        string='Allow credit payment when Order Amount is More Than Credit ' | 
				
			||||
 | 
					               'Balance', | 
				
			||||
 | 
					        help='Field allows the customer to purchase if the credit amount is ' | 
				
			||||
 | 
					             'insufficient.') | 
				
			||||
 | 
					    cust_credit_line_ids = fields.One2many('credit.detail.lines', 'customer_id', | 
				
			||||
 | 
					                                           string='Credit Details', | 
				
			||||
 | 
					                                           help='Credit details associated ' | 
				
			||||
 | 
					                                                'with the customer') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def _compute_credit_amount(self): | 
				
			||||
 | 
					        """ Compute function to get the credit amount of the associated | 
				
			||||
 | 
					        customer""" | 
				
			||||
 | 
					        for record in self: | 
				
			||||
 | 
					            credit_count = self.env['credit.details'].search( | 
				
			||||
 | 
					                [('customer_id', '=', record.id)]) | 
				
			||||
 | 
					            record.credit_amount = credit_count.credit_details_amount | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def credit_details(self): | 
				
			||||
 | 
					        """ Function to return the credit details associated with the | 
				
			||||
 | 
					        customer.""" | 
				
			||||
 | 
					        return { | 
				
			||||
 | 
					            'name': 'Credits', | 
				
			||||
 | 
					            'view_type': 'form', | 
				
			||||
 | 
					            'view_mode': 'list,form', | 
				
			||||
 | 
					            'res_model': 'credit.details', | 
				
			||||
 | 
					            'type': 'ir.actions.act_window', | 
				
			||||
 | 
					            'domain': [('customer_id', '=', self.id)] | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class CustomerCreditDetails(models.Model): | 
				
			||||
 | 
					    """ Model to get the customer credit details """ | 
				
			||||
 | 
					    _name = 'customer.credit.details' | 
				
			||||
 | 
					    _description = "Customer Credit Details" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    customer_credit_id = fields.Many2one('res.partner', string='Customer Id', | 
				
			||||
 | 
					                                         help='To attach with the customer ' | 
				
			||||
 | 
					                                              'model') | 
				
			||||
 | 
					    customer_credit_details_id = fields.Many2one('credit.detail.lines', | 
				
			||||
 | 
					                                                 string='Customer Credit ' | 
				
			||||
 | 
					                                                        'Details', | 
				
			||||
 | 
					                                                 help='The field to get the ' | 
				
			||||
 | 
					                                                      'customer credit details') | 
				
			||||
 | 
					    date = fields.Date(string='Date', | 
				
			||||
 | 
					                       help='The date field for the associated credit detail ' | 
				
			||||
 | 
					                            'lines.') | 
				
			||||
 | 
					    amount = fields.Float(string='Amount', | 
				
			||||
 | 
					                          help='To get the credit amount for the partner') | 
				
			||||
 | 
					    previous_credit_amount = fields.Float(string='Previous Credit Amount', | 
				
			||||
 | 
					                                          help='The previous credit amount ' | 
				
			||||
 | 
					                                               'associated with the partner.') | 
				
			||||
 | 
					    updated_amount = fields.Float('Updated Amount', | 
				
			||||
 | 
					                                  help='The Updated amount associated with ' | 
				
			||||
 | 
					                                       'the partner.') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class AccountPayment(models.Model): | 
				
			||||
 | 
					    """ Inherited the Model "account.payment" to add the customer details """ | 
				
			||||
 | 
					    _inherit = "account.payment" | 
				
			||||
 | 
					    _description = "Account Payment" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    customer_credit_payment_id = fields.Many2one('res.partner', | 
				
			||||
 | 
					                                                 string='Customer', | 
				
			||||
 | 
					                                                 help='The customer details ' | 
				
			||||
 | 
					                                                      'add to the account ' | 
				
			||||
 | 
					                                                      'payment.') | 
				
			||||
@ -0,0 +1,31 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			||||
 | 
					#    Author: Afra K (odoo@cybrosys.com) | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You can modify it under the terms of the GNU AFFERO | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    This program is distributed in the hope that it will be useful, | 
				
			||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			||||
 | 
					#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (AGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################### | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class SaleOrder(models.Model): | 
				
			||||
 | 
					    """ Inherited SaleOrder to add the field""" | 
				
			||||
 | 
					    _inherit = 'sale.order' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    credit_amount_sale = fields.Float(string='Credit amount website', | 
				
			||||
 | 
					                                      help='The credit amount used in the ' | 
				
			||||
 | 
					                                           'website') | 
				
			||||
		
		
			
  | 
@ -0,0 +1,7 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<odoo> | 
				
			||||
 | 
					    <!--        Access group for Credit approval        --> | 
				
			||||
 | 
					    <record id="credit_approval_access" model="res.groups"> | 
				
			||||
 | 
					        <field name="name">Credit Payment Approval</field> | 
				
			||||
 | 
					    </record> | 
				
			||||
 | 
					</odoo> | 
				
			||||
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 210 KiB  | 
| 
		 After Width: | Height: | Size: 209 KiB  | 
| 
		 After Width: | Height: | Size: 109 KiB  | 
| 
		 After Width: | Height: | Size: 495 B  | 
| 
		 After Width: | Height: | Size: 1.0 KiB  | 
| 
		 After Width: | Height: | Size: 624 B  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 214 KiB  | 
| 
		 After Width: | Height: | Size: 36 KiB  | 
| 
		 After Width: | Height: | Size: 3.6 KiB  | 
| 
		 After Width: | Height: | Size: 310 B  | 
| 
		 After Width: | Height: | Size: 929 B  | 
| 
		 After Width: | Height: | Size: 1.3 KiB  | 
| 
		 After Width: | Height: | Size: 3.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.4 KiB  | 
| 
		 After Width: | Height: | Size: 17 KiB  | 
| 
		 After Width: | Height: | Size: 542 B  | 
| 
		 After Width: | Height: | Size: 576 B  | 
| 
		 After Width: | Height: | Size: 733 B  | 
| 
		 After Width: | Height: | Size: 4.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 4.0 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 738 KiB  | 
| 
		 After Width: | Height: | Size: 2.2 KiB  | 
| 
		 After Width: | Height: | Size: 911 B  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 600 B  | 
| 
		 After Width: | Height: | Size: 673 B  | 
| 
		 After Width: | Height: | Size: 2.0 KiB  | 
| 
		 After Width: | Height: | Size: 462 B  | 
| 
		 After Width: | Height: | Size: 2.1 KiB  | 
| 
		 After Width: | Height: | Size: 926 B  | 
| 
		 After Width: | Height: | Size: 9.0 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 7.0 KiB  | 
| 
		 After Width: | Height: | Size: 878 B  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 653 B  | 
| 
		 After Width: | Height: | Size: 800 B  | 
| 
		 After Width: | Height: | Size: 905 B  | 
| 
		 After Width: | Height: | Size: 189 KiB  | 
| 
		 After Width: | Height: | Size: 4.3 KiB  | 
| 
		 After Width: | Height: | Size: 839 B  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 5.9 KiB  | 
| 
		 After Width: | Height: | Size: 1.6 KiB  | 
| 
		 After Width: | Height: | Size: 34 KiB  | 
| 
		 After Width: | Height: | Size: 26 KiB  | 
| 
		 After Width: | Height: | Size: 3.8 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 After Width: | Height: | Size: 427 B  | 
| 
		 After Width: | Height: | Size: 627 B  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 988 B  | 
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
| 
		 After Width: | Height: | Size: 5.0 KiB  | 
| 
		 After Width: | Height: | Size: 875 B  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 767 KiB  | 
| 
		 After Width: | Height: | Size: 138 KiB  | 
| 
		 After Width: | Height: | Size: 697 KiB  | 
| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 After Width: | Height: | Size: 126 KiB  | 
| 
		 After Width: | Height: | Size: 776 KiB  | 
| 
		 After Width: | Height: | Size: 105 KiB  | 
| 
		 After Width: | Height: | Size: 101 KiB  | 
| 
		 After Width: | Height: | Size: 58 KiB  | 
| 
		 After Width: | Height: | Size: 70 KiB  | 
| 
		 After Width: | Height: | Size: 114 KiB  | 
| 
		 After Width: | Height: | Size: 131 KiB  |