@ -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 |