Skip to content

Commit 871bd93

Browse files
committed
[ADD] estate_account: extend model via inheritance and integrate external module
Extended the model in the module using model inheritance. This extension adds new accounting-related fields and functionality that align with the tutorial’s objective of building on top of existing models. Additionally, reused features from another module (), demonstrating how to extend and interact with models defined externally. This helps in separating concerns and encourages modular design by keeping accounting logic in a separate module. Reasons for the change: - To demonstrate how to extend existing models via , promoting reuse of logic. - To maintain separation of concerns by creating a dedicated accounting module for estate management. - To align with Odoo framework best practices, particularly regarding modularization and cross-module integration. - To enhance maintainability and scalability of the estate management application.
1 parent e12ec45 commit 871bd93

16 files changed

+177
-58
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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
'name': 'Estate Account',
3+
'version': '1.0',
4+
'sequence': 2,
5+
'depends': ['base', 'real_estate', 'account'],
6+
'category': 'Real Estate',
7+
'author': 'prbo',
8+
'summary': 'Invoice integration with Real Estate',
9+
'description': 'Creates an invoice when a property is sold.',
10+
'data': [],
11+
'installable': True,
12+
'application': False,
13+
'auto_install': False,
14+
}

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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from odoo import models, Command
2+
3+
4+
class EstateProperty(models.Model):
5+
_inherit = "estate.property"
6+
7+
def action_sold(self):
8+
journal = self.env['account.journal'].search([
9+
('type', '=', 'sale'),
10+
], limit=1)
11+
12+
if not journal:
13+
raise ValueError("No sales journal found!")
14+
15+
for property in self:
16+
if not property.buyer:
17+
raise ValueError("Buyer is required to create invoice.")
18+
19+
selling_price = property.selling_price
20+
service_fee = selling_price * 0.06
21+
22+
invoice_vals = {
23+
'partner_id': property.buyer.id,
24+
'move_type': 'out_invoice',
25+
'journal_id': journal.id,
26+
'invoice_line_ids': [
27+
Command.create({
28+
'name': "Service Fees (6%)",
29+
'quantity': 1,
30+
'price_unit': service_fee,
31+
}),
32+
Command.create({
33+
'name': "Administrative Fees",
34+
'quantity': 1,
35+
'price_unit': 100.00,
36+
}),
37+
],
38+
}
39+
40+
self.env['account.move'].create(invoice_vals)
41+
42+
return super().action_sold()

real_estate/__manifest__.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
{
22
'name': "RealEstate",
3-
'depends': ['base'],
4-
'sequence': 1,
5-
'license': 'LGPL-3',
6-
'application': True,
7-
'category': 'Real Estate',
83
'version': '1.0',
94
'author': "prbo",
5+
'license': 'LGPL-3',
6+
'category': 'Real Estate',
7+
'sequence': 1,
8+
'application': True,
9+
'depends': ['base'],
1010
'data': [
11-
'security/ir.model.access.csv',
12-
'views/estate_property_offer_view.xml',
13-
'views/estate_property_type_view.xml',
14-
'views/estate_property_views.xml',
15-
'views/estate_property_tag_view.xml',
16-
'views/estate_menus.xml'
17-
]
11+
'security/ir.model.access.csv',
12+
'views/estate_property_offer_view.xml',
13+
'views/estate_property_type_view.xml',
14+
'views/estate_property_views.xml',
15+
'views/estate_property_tag_view.xml',
16+
'views/estate_menus.xml',
17+
'views/res_users_views.xml',
18+
],
1819
}

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_type
33
from . import estate_property_tag
44
from . import estate_property_offer
5+
from . import res_users

real_estate/models/estate_property.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ class EstateProperty(models.Model):
5656

5757
property_type = fields.Many2one("estate.property.type", string="Property Type")
5858
buyer = fields.Many2one("res.partner", string="Buyer", copy=False)
59-
seller = fields.Many2one("res.partner", string="Salesperson", default=lambda self: self.env.user)
60-
tag_ids = fields.Many2many("estate.property.tag", string="Tags", default=None)
59+
seller = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user)
60+
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
6161
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
6262

6363
_sql_constraints = [
@@ -73,10 +73,7 @@ def _compute_total_area(self):
7373
@api.depends("offer_ids.price")
7474
def _compute_best_price(self):
7575
for record in self:
76-
if record.offer_ids:
77-
record.best_price = max(record.offer_ids.mapped("price"))
78-
else:
79-
record.best_price = 0.0
76+
record.best_price = max(record.offer_ids.mapped("price"), default=0.0)
8077

8178
@api.onchange('garden')
8279
def _onchange_garden(self):
@@ -108,3 +105,9 @@ def _check_selling_price_margin(self):
108105
min_acceptable_price = 0.9 * record.expected_price
109106
if float_compare(record.selling_price, min_acceptable_price, precision_digits=2) < 0:
110107
raise ValidationError("Selling price cannot be lower than 90% of the expected price.")
108+
109+
@api.ondelete(at_uninstall=False)
110+
def _check_property_state_on_delete(self):
111+
for record in self:
112+
if record.state not in ['new', 'cancelled']:
113+
raise UserError("Only properties with state 'New' or 'Cancelled' can be deleted.")

real_estate/models/estate_property_offer.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from odoo import models, fields, api
22
from datetime import timedelta
3-
from odoo.exceptions import UserError
3+
from odoo.exceptions import UserError, ValidationError
44

55

66
class EstatePropertyOffer(models.Model):
@@ -14,7 +14,11 @@ class EstatePropertyOffer(models.Model):
1414
('refused', 'Refused')
1515
])
1616
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
17-
property_id = fields.Many2one("estate.property", string="Property", required=True)
17+
property_id = fields.Many2one(
18+
"estate.property",
19+
required=True,
20+
ondelete='cascade'
21+
)
1822
property_type_id = fields.Many2one(
1923
related="property_id.property_type",
2024
store=True,
@@ -52,7 +56,6 @@ def action_accept(self):
5256
record.property_id.buyer = record.partner_id
5357
record.property_id.state = 'offer_accepted'
5458

55-
# Refuse all other offers
5659
other_offers = self.search([
5760
('property_id', '=', record.property_id.id),
5861
('id', '!=', record.id)
@@ -63,3 +66,16 @@ def action_refuse(self):
6366
for offer in self:
6467
offer.status = 'refused'
6568
return True
69+
70+
@api.model
71+
def create(self, vals):
72+
property_id = vals.get('property_id')
73+
if property_id:
74+
property_rec = self.env['estate.property'].browse(property_id)
75+
existing_offers = property_rec.offer_ids.filtered(
76+
lambda o: o.price >= vals.get('price', 0)
77+
)
78+
if existing_offers:
79+
raise ValidationError("You cannot create an offer lower than or equal to an existing one.")
80+
property_rec.state = 'offer_received'
81+
return super().create(vals)

real_estate/models/estate_property_tag.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class EstatePropertyTag(models.Model):
88

99
name = fields.Char(required=True)
1010
color = fields.Integer(string="Color")
11+
sequence = fields.Integer(string="10")
1112

1213
_sql_constraints = [
1314
('unique_tag_name', 'UNIQUE(name)', 'Tag name must be unique.')

real_estate/models/res_users.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from odoo import models, fields
2+
3+
4+
class ResUsers(models.Model):
5+
_inherit = 'res.users'
6+
7+
property_ids = fields.One2many(
8+
'estate.property',
9+
'seller',
10+
string='Properties',
11+
domain=[('state', '=', 'available')]
12+
)

0 commit comments

Comments
 (0)