Skip to content

Commit 7a4879a

Browse files
committed
[IMP] real_estate: Enforce business logic and modular invoicing integration
- Enforced business rules for property deletion and offer validation - Linked available properties to users via domain and UI integration - Introduced estate_account as a modular extension for invoicing with commission and fixed administrative charges
1 parent 2e3d703 commit 7a4879a

File tree

11 files changed

+125
-6
lines changed

11 files changed

+125
-6
lines changed

estate_account/__init__.py

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

estate_account/__manifest__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "Estate Account",
3+
"version": "1.0",
4+
"depends": ["real_estate", "account"],
5+
"author": "",
6+
"category": "Accounts for Estate",
7+
"data": [],
8+
"license": "LGPL-3",
9+
"installable": True,
10+
"application": True,
11+
}

estate_account/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import estate_property
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from odoo import Command, models
2+
3+
4+
class Property(models.Model):
5+
_inherit = "estate.property"
6+
7+
def action_sold(self):
8+
for property in self:
9+
journal = self.env["account.journal"].search(
10+
[("type", "=", "sale")], limit=1
11+
)
12+
13+
commission = property.selling_price * 0.06
14+
discount = property.selling_price * 0.05
15+
invoice_lines = [
16+
Command.create(
17+
{
18+
"name": "6% Commission",
19+
"quantity": 1,
20+
"price_unit": commission,
21+
}
22+
),
23+
Command.create(
24+
{
25+
"name": "Administrative Fees",
26+
"quantity": 1,
27+
"price_unit": 100.00,
28+
}
29+
),
30+
Command.create(
31+
{
32+
"name": "Discount",
33+
"quantity": 1,
34+
"price_unit": -discount,
35+
}
36+
),
37+
]
38+
39+
invoice_vals = {
40+
"partner_id": property.buyer_id.id,
41+
"move_type": "out_invoice",
42+
"journal_id": journal.id,
43+
"invoice_line_ids": invoice_lines,
44+
}
45+
46+
self.env["account.move"].create(invoice_vals)
47+
48+
return super().action_sold()

real_estate/__manifest__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"views/estate_property_type_views.xml",
1212
"views/estate_property_tag_views.xml",
1313
"views/estate_property_menus.xml",
14+
"views/res_users_views.xml",
1415
],
1516
"license": "LGPL-3",
1617
"installable": True,

real_estate/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
from . import estate_property_offers
33
from . import estate_property_tags
44
from . import estate_property_types
5+
from . import res_users

real_estate/models/estate_property.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ def _onchange_garden(self):
8888

8989
def action_sold(self):
9090
for record in self:
91+
if not record.state == "offer_accepted":
92+
raise UserError("Accept an offer first")
93+
9194
if record.state == "cancelled":
9295
raise UserError("You cannot mark a cancelled property as sold.")
9396
record.state = "sold"
@@ -117,3 +120,11 @@ def _check_selling_price(self):
117120
raise ValidationError(
118121
"Selling price must be at least 90% of the expected price."
119122
)
123+
124+
@api.ondelete(at_uninstall=False)
125+
def _check_deletion_state(self):
126+
for rec in self:
127+
if rec.state not in ["new", "cancelled"]:
128+
raise UserError(
129+
"Only properties in 'New' or 'Cancelled' state can be deleted."
130+
)

real_estate/models/estate_property_offers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,18 @@ def action_refuse_offer(self):
6767
"Offer price must be strictly positive.",
6868
)
6969
]
70+
71+
@api.model_create_multi
72+
def create(self, vals):
73+
for val in vals:
74+
property_id = self.env["estate.property"].browse(val["property_id"])
75+
76+
if property_id.state == "new":
77+
property_id.state = "offer_received"
78+
79+
if val["price"] <= property_id.best_offer:
80+
raise UserError(
81+
f"The offer must be higher than {property_id.best_offer}"
82+
)
83+
84+
return super().create(vals)

real_estate/models/res_users.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from odoo import fields, models
2+
3+
4+
class ResUsers(models.Model):
5+
_inherit = "res.users"
6+
7+
property_ids = fields.One2many(
8+
comodel_name="estate.property",
9+
inverse_name="seller_id",
10+
domain="[('state', 'in', ('new','offer_received'))]",
11+
)
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<odoo>
33
<!-- Root menu -->
4-
<menuitem id="estate_menu_root" name="Real Estate"/>
4+
<menuitem id="estate_menu_root" name="Real Estate" />
55

66
<!-- First level submenu under root -->
7-
<menuitem id="estate_menu_advertisements" name="Advertisements" parent="estate_menu_root"/>
8-
<menuitem id="estate_menu_settings" name="Settings" parent="estate_menu_root"/>
7+
<menuitem id="estate_menu_advertisements" name="Advertisements" parent="estate_menu_root" />
8+
<menuitem id="estate_menu_settings" name="Settings" parent="estate_menu_root" />
99

1010
<!-- Action menu under first level -->
11-
<menuitem id="estate_property_menu_action" parent="estate_menu_advertisements" action="real_estate_main_action"/>
12-
<menuitem id="estate_property_type_menu_action" parent="estate_menu_settings" action="estate_property_type_action"/>
13-
<menuitem id="estate_property_tag_menu_action" parent="estate_menu_settings" action="estate_property_tag_action"/>
11+
<menuitem id="estate_property_menu_action" parent="estate_menu_advertisements"
12+
action="real_estate_main_action" />
13+
<menuitem id="estate_property_type_menu_action" parent="estate_menu_settings"
14+
action="estate_property_type_action" />
15+
<menuitem id="estate_property_tag_menu_action" parent="estate_menu_settings"
16+
action="estate_property_tag_action" />
1417

1518
</odoo>

0 commit comments

Comments
 (0)