Skip to content

Commit ee14089

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 ee14089

11 files changed

Lines changed: 213 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: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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+
)
19+
if not rental_lines:
20+
return lines
21+
company_map = {}
22+
for line in rental_lines:
23+
company = line.company_id
24+
if company not in company_map:
25+
if not company.deposit_product:
26+
raise UserError(_("Please set deposit product in settings."))
27+
company_map[company] = company.deposit_product
28+
deposit_vals = []
29+
for line in rental_lines:
30+
deposit_product = company_map[line.company_id]
31+
deposit_vals.append({
32+
'order_id': line.order_id.id,
33+
'product_id': deposit_product.id,
34+
'product_uom_qty': line.product_uom_qty,
35+
'price_unit': line.product_id.deposit_amount,
36+
'name': f"This amount is deposit for {line.product_id.name} product",
37+
'is_deposit_line': True,
38+
})
39+
self.create(deposit_vals)
40+
return lines
41+
42+
@api.ondelete(at_uninstall=False)
43+
def _unlink_deposit_fee(self):
44+
if not self.env.context.get("bypass_deposit_protection_for_delete"):
45+
for record in self:
46+
if record.is_deposit_line:
47+
raise UserError(_("You can't delete a Deposit Product line directly."))
48+
rental_lines = self.filtered(
49+
lambda l: l.product_id.rent_ok
50+
and l.product_id.requires_deposit
51+
and l.product_id.deposit_amount > 0
52+
and not l.is_deposit_line
53+
)
54+
if not rental_lines:
55+
return
56+
deposit_lines = self.search([
57+
('order_id', 'in', rental_lines.mapped('order_id').ids),
58+
('is_deposit_line', '=', True),
59+
])
60+
deposit_map = {}
61+
for line in deposit_lines:
62+
deposit_map[line.name] = line
63+
for line in rental_lines:
64+
deposit_line = deposit_map.get(
65+
f"This amount is deposit for {line.product_id.name} product"
66+
)
67+
if not deposit_line:
68+
raise MissingError(_("Deposit fee is not present."))
69+
deposit_line.with_context(bypass_deposit_protection_for_delete=True).unlink()
70+
71+
def write(self, vals):
72+
if not self.env.context.get("bypass_deposit_protection_for_write"):
73+
for record in self:
74+
if record.is_deposit_line:
75+
raise UserError(_("You can't edit Deposit Product line directly."))
76+
res = super().write(vals)
77+
if 'product_uom_qty' not in vals:
78+
return res
79+
rental_lines = self.filtered(
80+
lambda l: l.product_id.rent_ok
81+
and l.product_id.requires_deposit
82+
and l.product_id.deposit_amount > 0
83+
)
84+
if not rental_lines:
85+
return res
86+
deposit_lines = self.search([
87+
('order_id', 'in', rental_lines.mapped('order_id').ids),
88+
('is_deposit_line', '=', True),
89+
])
90+
deposit_map = {}
91+
for line in deposit_lines:
92+
deposit_map[line.name] = line
93+
for line in rental_lines:
94+
deposit_line = deposit_map.get(
95+
f"This amount is deposit for {line.product_id.name} product"
96+
)
97+
if not deposit_line:
98+
raise MissingError(_("Deposit product line not found."))
99+
deposit_line.with_context(bypass_deposit_protection_for_write=True).write({
100+
'product_uom_qty': line.product_uom_qty,
101+
'price_unit': line.product_id.deposit_amount,
102+
})
103+
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)