Skip to content

Commit 054ca6f

Browse files
committed
[ADD] deposit_renting: added deposit for rental products
With This Commit ======================================================== - Added deposit product configuration in settings. - Inherited product.template to add require_deposit & deposit_amount field. - Linked deposit product automatically to rental product in sale order line. - Synced deposit product quantity with main product in cart. - Disabled remove button and quantity changer for deposit products in cart view.
1 parent 4c650f3 commit 054ca6f

12 files changed

+198
-0
lines changed

deposit_renting/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

deposit_renting/__manifest__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
'name': "Deposit Rental Products",
3+
'depends': ['sale_renting', 'website_sale'],
4+
'application': False,
5+
'installable': True,
6+
'license': 'LGPL-3',
7+
'data': [
8+
'views/product_template_views.xml',
9+
'views/res_config_settings_views.xml',
10+
'views/templates.xml',
11+
'views/sale_order_view.xml',
12+
],
13+
'assets': {
14+
'web.assets_frontend': [
15+
'deposit_renting/static/src/js/product_deposit.js',
16+
],
17+
}
18+
}

deposit_renting/models/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from . import product_template
2+
from . import res_config_settings
3+
from . import sale_order
4+
from . import sale_order_line
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from odoo import fields, models
2+
3+
4+
class ProductTemplate(models.Model):
5+
_inherit = "product.template"
6+
7+
require_deposit = fields.Boolean(string='Require Deposit')
8+
deposit_amount = fields.Float(string='Deposit Amount', help="Deposit amount for single unit.")
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from odoo import fields, models
2+
3+
4+
class ResConfigSettings(models.TransientModel):
5+
_inherit = "res.config.settings"
6+
7+
deposit_product_id = fields.Many2one("product.product", string="Deposit Product", help="Product to be used for deposit on sale order.")
8+
9+
def set_values(self):
10+
super().set_values()
11+
self.env['ir.config_parameter'].sudo().set_param('deposit_product_id', self.deposit_product_id.id)
12+
13+
def get_values(self):
14+
res = super().get_values()
15+
product_id = int(self.env['ir.config_parameter'].sudo().get_param('deposit_product_id', default=False))
16+
res['deposit_product_id'] = self.env['product.product'].browse(product_id)
17+
return res
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from odoo import api, fields, models
2+
3+
4+
class SaleOrder(models.Model):
5+
_inherit = "sale.order"
6+
7+
require_deposit_config = fields.Boolean(string="Require Deposit Configuration", default=False, compute="_compute_has_deposit_line_without_config", help="Has line that require deposit, without configuring the deposit product in settings.")
8+
9+
@api.depends('order_line')
10+
def _compute_has_deposit_line_without_config(self):
11+
deposit_product_id = self.env['ir.config_parameter'].get_param('deposit_product_id')
12+
for sale_order in self:
13+
has_line_require_deposit_config = True if len(sale_order.order_line.filtered(lambda line: line.product_id.require_deposit)) > 0 else False
14+
if has_line_require_deposit_config and not deposit_product_id:
15+
sale_order.require_deposit_config = True
16+
else:
17+
sale_order.require_deposit_config = False
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from odoo import api, fields, models
2+
3+
4+
class SaleOrderLine(models.Model):
5+
_inherit = "sale.order.line"
6+
7+
is_deposit_line = fields.Boolean(string="Is Deposit Line", default=False)
8+
9+
def _add_deposit_line(self):
10+
deposit_product_id = int(self.env['ir.config_parameter'].get_param('deposit_product_id'))
11+
deposit_product = self.env['product.product'].browse(deposit_product_id)
12+
for line in self:
13+
if line.order_id and line.product_id.rent_ok and line.product_id.require_deposit:
14+
deposit_line = line.order_id.order_line.filtered(lambda line: line.linked_line_id == self.id)
15+
if deposit_line:
16+
deposit_line.product_uom_qty = line.product_uom_qty
17+
deposit_line.price_unit = line.product_id.deposit_amount
18+
else:
19+
self.env["sale.order.line"].create({
20+
'order_id': line.order_id.id,
21+
'product_id': deposit_product.id,
22+
'name': f"Deposit For {line.product_id.name}",
23+
'product_uom_qty': line.product_uom_qty,
24+
'price_unit': line.product_id.deposit_amount,
25+
'linked_line_id': line.id,
26+
'price_subtotal': line.product_uom_qty * line.product_id.deposit_amount,
27+
'is_deposit_line': True,
28+
})
29+
30+
@api.model_create_multi
31+
def create(self, vals_list):
32+
res = super().create(vals_list)
33+
res._add_deposit_line()
34+
return res
35+
36+
def write(self, vals):
37+
res = super().write(vals)
38+
if 'product_uom_qty' in vals:
39+
for line in self:
40+
linked_lines = self.search([('linked_line_id', '=', line.id)])
41+
for linked_line in linked_lines:
42+
linked_line.product_uom_qty = line.product_uom_qty
43+
linked_line.price_subtotal = line.product_uom_qty * line.product_id.deposit_amount
44+
45+
return res
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import publicWidget from "@web/legacy/js/public/public_widget";
2+
3+
publicWidget.registry.WebsiteSale.include({
4+
_onChangeAddQuantity: function (ev) {
5+
this._super.apply(this, arguments);
6+
this.changeDepositAmount(ev);
7+
},
8+
9+
changeDepositAmount: function(ev){
10+
const input = ev.target;
11+
const qty = parseFloat(input.value || 1);
12+
const depositSpan = document.getElementById('product_deposit_amount');
13+
if (!depositSpan) return;
14+
15+
const baseDeposit = parseFloat(depositSpan.dataset.baseAmount || 0);
16+
const currencySymbol = depositSpan.dataset.currencySymbol || '';
17+
const totalDeposit = (baseDeposit * qty).toFixed(2);
18+
depositSpan.textContent = `${currencySymbol} ${totalDeposit}`;
19+
}
20+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<odoo>
2+
<record id="product_template_form_view_deposit_renting" model="ir.ui.view">
3+
<field name="name">product.template.deposit.renting.form</field>
4+
<field name="model">product.template</field>
5+
<field name="inherit_id" ref="sale_renting.product_template_form_view_rental" />
6+
<field name="arch" type="xml">
7+
<group name="extra_rental" position="inside">
8+
<field name="require_deposit" />
9+
<field name="deposit_amount" invisible="not require_deposit" />
10+
</group>
11+
</field>
12+
</record>
13+
</odoo>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<odoo>
2+
<record id="res_config_settings_view_form_deposit_renting" model="ir.ui.view">
3+
<field name="name">res.config.settings.deposit.renting.form</field>
4+
<field name="model">res.config.settings</field>
5+
<field name="inherit_id" ref="sale_renting.res_config_settings_view_form" />
6+
<field name="arch" type="xml">
7+
<xpath expr="//setting[@name='rental_delay_costs']" position="after">
8+
<setting string="Deposit Product" help="Product to be used for deposit on sale order">
9+
<label string="Deposit" for="deposit_product_id" class="o_light_label me-3" />
10+
<field name="deposit_product_id" />
11+
</setting>
12+
</xpath>
13+
</field>
14+
</record>
15+
</odoo>

0 commit comments

Comments
 (0)