Skip to content

Commit b3753a6

Browse files
committed
[ADD] rental_deposit: adding deposit to rental products.
- Added and fields on to allow per-product deposit configuration - Added on , exposed via config settings - Auto-add/update/delete deposit line on sale order via CRUD overrides - Blocked direct editing or deletion of deposit lines using context guards - Added deposit display on webshop product page with dynamic qty update
1 parent 781b590 commit b3753a6

11 files changed

Lines changed: 214 additions & 0 deletions

rental_deposit/__init__.py

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

rental_deposit/__manifest__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
'author': 'Aditi (adpaw)',
3+
'name': 'Deposit Rental App',
4+
'license': 'LGPL-3',
5+
'depends': ['sale_renting', 'website_sale'],
6+
'data': [
7+
'views/res_config_settings_view.xml',
8+
'views/product_template_view.xml',
9+
'views/template_view.xml'
10+
],
11+
'assets': {
12+
'web.assets_frontend': [
13+
'rental_deposit/static/src/deposit_amount.js',
14+
],
15+
},
16+
'installable': True,
17+
'auto_install': True,
18+
}

rental_deposit/models/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from . import res_config_settings
2+
from . import product_template
3+
from . import sale_order_line
4+
from . import res_company
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+
requires_deposit = fields.Boolean(string="Requires Deposit")
8+
deposit_amount = fields.Float()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from odoo import fields, models
2+
3+
4+
class ResCompany(models.Model):
5+
_inherit = "res.company"
6+
7+
deposit_product = fields.Many2one("product.product")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from odoo import fields, models
2+
3+
4+
class ResConfigSettings(models.TransientModel):
5+
_inherit = 'res.config.settings'
6+
7+
deposit_product = fields.Many2one(
8+
"product.product",
9+
related="company_id.deposit_product",
10+
string="Deposit",
11+
readonly=False
12+
)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from odoo import api, fields, models
2+
from odoo.exceptions import UserError, MissingError
3+
from odoo.tools import _
4+
5+
6+
class SaleOrderLine(models.Model):
7+
_inherit = 'sale.order.line'
8+
9+
is_deposit_line = fields.Boolean(default=False)
10+
11+
@api.model_create_multi
12+
def create(self, vals_list):
13+
lines = super().create(vals_list)
14+
rental_lines = lines.filtered(
15+
lambda l: l.product_id.rent_ok
16+
and l.product_id.requires_deposit
17+
and l.product_id.deposit_amount > 0
18+
and not l.is_deposit_line
19+
)
20+
if not rental_lines:
21+
return lines
22+
company_map = {}
23+
for line in rental_lines:
24+
company = line.company_id
25+
if company not in company_map:
26+
if not company.deposit_product:
27+
raise UserError(_("Please set deposit product in settings."))
28+
company_map[company] = company.deposit_product
29+
deposit_vals = []
30+
for line in rental_lines:
31+
deposit_product = company_map[line.company_id]
32+
deposit_vals.append({
33+
'order_id': line.order_id.id,
34+
'product_id': deposit_product.id,
35+
'product_uom_qty': line.product_uom_qty,
36+
'price_unit': line.product_id.deposit_amount,
37+
'name': f"This amount is deposit for {line.product_id.name} product",
38+
'is_deposit_line': True,
39+
})
40+
self.create(deposit_vals)
41+
return lines
42+
43+
@api.ondelete(at_uninstall=False)
44+
def _unlink_deposit_fee(self):
45+
if not self.env.context.get("bypass_deposit_protection_for_delete"):
46+
for record in self:
47+
if record.is_deposit_line:
48+
raise UserError(_("You can't delete a Deposit Product line directly."))
49+
rental_lines = self.filtered(
50+
lambda l: l.product_id.rent_ok
51+
and l.product_id.requires_deposit
52+
and l.product_id.deposit_amount > 0
53+
and not l.is_deposit_line
54+
)
55+
if not rental_lines:
56+
return
57+
deposit_lines = self.search([
58+
('order_id', 'in', rental_lines.mapped('order_id').ids),
59+
('is_deposit_line', '=', True),
60+
])
61+
deposit_map = {}
62+
for line in deposit_lines:
63+
deposit_map[line.name] = line
64+
for line in rental_lines:
65+
deposit_line = deposit_map.get(
66+
f"This amount is deposit for {line.product_id.name} product"
67+
)
68+
if not deposit_line:
69+
raise MissingError(_("Deposit fee is not present."))
70+
deposit_line.with_context(bypass_deposit_protection_for_delete=True).unlink()
71+
72+
def write(self, vals):
73+
if not self.env.context.get("bypass_deposit_protection_for_write"):
74+
for record in self:
75+
if record.is_deposit_line:
76+
raise UserError(_("You can't edit Deposit Product line directly."))
77+
res = super().write(vals)
78+
if 'product_uom_qty' not in vals:
79+
return res
80+
rental_lines = self.filtered(
81+
lambda l: l.product_id.rent_ok
82+
and l.product_id.requires_deposit
83+
and l.product_id.deposit_amount > 0
84+
)
85+
if not rental_lines:
86+
return res
87+
deposit_lines = self.search([
88+
('order_id', 'in', rental_lines.mapped('order_id').ids),
89+
('is_deposit_line', '=', True),
90+
])
91+
deposit_map = {}
92+
for line in deposit_lines:
93+
deposit_map[line.name] = line
94+
for line in rental_lines:
95+
deposit_line = deposit_map.get(
96+
f"This amount is deposit for {line.product_id.name} product"
97+
)
98+
if not deposit_line:
99+
raise MissingError(_("Deposit product line not found."))
100+
deposit_line.with_context(bypass_deposit_protection_for_write=True).write({
101+
'product_uom_qty': line.product_uom_qty,
102+
'price_unit': line.product_id.deposit_amount,
103+
})
104+
return res
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import publicWidget from "@web/legacy/js/public/public_widget";
2+
3+
publicWidget.registry.DepositRental = publicWidget.Widget.extend({
4+
selector: "#product_detail",
5+
events: {
6+
'change input[name="add_qty"]': '_updateDepositAmount',
7+
},
8+
start: function () {
9+
this._super.apply(this, arguments);
10+
if ($("#deposit_amount").length) {
11+
this._updateDepositAmount();
12+
}
13+
else {
14+
this.$el.off('change input[name="add_qty"]');
15+
}
16+
},
17+
_updateDepositAmount: function () {
18+
var qty = parseFloat($("#o_wsale_cta_wrapper").find("input[name='add_qty']").val());
19+
var depositAmount = parseFloat($("#deposit_amount").attr("data-base-amount")) || 0;
20+
$("#deposit_amount").text(depositAmount * qty);
21+
}
22+
})
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_rental_deposit" model="ir.ui.view">
3+
<field name="name">product.template.view.form.inherit.rental.deposit</field>
4+
<field name="model">product.template</field>
5+
<field name="inherit_id" ref="product.product_template_only_form_view"/>
6+
<field name="arch" type="xml">
7+
<xpath expr="//group[@name='extra_rental']" position="inside">
8+
<field name="requires_deposit"/>
9+
<field name="deposit_amount" invisible="not requires_deposit" widget="monetary"/>
10+
</xpath>
11+
</field>
12+
</record>
13+
</odoo>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<odoo>
2+
<record id="res_config_settings_view_form_deposit_inherit" model="ir.ui.view">
3+
<field name="name">res.config.settings.view.form.inherit.deposit</field>
4+
<field name="model">res.config.settings</field>
5+
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
6+
<field name="arch" type="xml">
7+
<xpath expr="//field[@name='extra_product']" position="after">
8+
<label for="deposit_product"/>
9+
<field name="deposit_product"/>
10+
</xpath>
11+
</field>
12+
</record>
13+
</odoo>

0 commit comments

Comments
 (0)