-
Notifications
You must be signed in to change notification settings - Fork 2k
[ADD] estate: implement core real estate property management module #758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Conversation
Core Functionality: - Created base models for property listings with fields for pricing, descriptions , and status tracking - Implemented property type categorization (House, Apartment etc.) - Added tagging system for property characteristics (Cozy, Renovated etc.) - Developed offer management system to track buyer proposals Technical Implementation: 1. Models: - estate.property (main listing model) - estate.property.type (categorization) - estate.property.tag (characteristics) - estate.property.offer (purchase offers) 2. Relationships: - Many2one: Property → Type, Buyer, Salesperson - Many2many: Property ↔ Tags - One2many: Property → Offers 3. Security: - Configured access rights for all models - Set appropriate permissions for CRUD operations 4. UI/UX: - Custom list view with key property attributes - Detailed form view with tabbed interface - Advanced search with filters and grouping - Intuitive menu structure 5. Business Logic: - Default values (salesperson = current user) - Field constraints (read-only selling price) - Non-copyable fields (availability date) task-001 (Chapter 1–7 Odoo 18 Developer Tutorial)
…arameter SQL Constraints: - Add CHECK(expected_price > 0) to ensure strictly positive expected prices. - Add CHECK(selling_price >= 0) for non-negative selling prices. - Ensure price > 0 for offers via SQL constraint. - Enforce unique names for property tags and types with UNIQUE(name). Python Constraint: - Add @api.constrains to validate selling price ≥ 90% of expected price. Fixes: - Correct typo in selling_price field parameter (readOnly → readonly). - Cleanup existing invalid data (e.g., non-positive prices) to apply constraints.
- Fix: Replace active_id with id in estate.property.type stat button context to resolve access rights error. - Add: Inline list view for properties linked to types in estate.property.type form. - Add: Stat button on property type form to view linked offers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @shib-odoo
Some comments/questions
Thanks!!
estate/__init__.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line EOF needs to check other occurrences also
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added blank line EOF in all the respective files.
estate/__manifest__.py
Outdated
'security/ir.model.access.csv', | ||
'views/estate_property_views.xml', | ||
'views/estate_menus.xml', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
estate/models/estate_property.py
Outdated
from odoo import api,models, fields | ||
from dateutil.relativedelta import relativedelta | ||
from odoo.exceptions import UserError | ||
from odoo.exceptions import ValidationError | ||
from odoo.tools import float_compare, float_is_zero |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from odoo import api,models, fields | |
from dateutil.relativedelta import relativedelta | |
from odoo.exceptions import UserError | |
from odoo.exceptions import ValidationError | |
from odoo.tools import float_compare, float_is_zero | |
from dateutil.relativedelta import relativedelta | |
from odoo import api, fields, models | |
from odoo.exceptions import UserError, ValidationError | |
from odoo.tools import float_compare, float_is_zero |
Generally we follow a convention where we imports the external libraries first and then we make the imports from odoo.
https://www.odoo.com/documentation/18.0/contributing/development/coding_guidelines.html#imports
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the imports where all the external libraries are on the top followed by the imports from odoo in all the files.
estate/models/estate_property.py
Outdated
name = fields.Char(required=True) # Required field | ||
description = fields.Text() | ||
postcode = fields.Char() | ||
date_availability = fields.Date( default=lambda self: fields.Date.today() + relativedelta(months=3),copy=False) | ||
expected_price = fields.Float(required=True) # Required field | ||
selling_price = fields.Float(readonly=True,copy=False) | ||
bedrooms = fields.Integer(default=2) | ||
living_area = fields.Integer() | ||
facades = fields.Integer() | ||
garage = fields.Boolean() | ||
garden = fields.Boolean() | ||
garden_area = fields.Integer() | ||
garden_orientation = fields.Selection( | ||
selection=[ | ||
('North', 'North'), | ||
('South', 'South'), | ||
('East', 'East'), | ||
('West', 'West'), | ||
], | ||
) | ||
active = fields.Boolean(default=True), | ||
state = fields.Selection( | ||
selection=[ | ||
('new', 'New'), | ||
('offer_received', 'Offer Received'), | ||
('offer_accepted', 'Offer Accepted'), | ||
('sold', 'Sold'), | ||
('cancelled', 'Cancelled'), | ||
], | ||
required=True, | ||
default='new', | ||
copy=False | ||
) | ||
property_type_id = fields.Many2one("estate.property.type", string="Property Type") | ||
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") | ||
buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) | ||
salesperson_id = fields.Many2one( | ||
"res.users", | ||
string="Salesperson", | ||
default=lambda self: self.env.user, # Default to current user | ||
) | ||
tag_ids = fields.Many2many("estate.property.tag", string="Tags") | ||
|
||
# Add to EstateProperty class | ||
total_area = fields.Float(compute="_compute_total_area", string="Total Area") | ||
best_price = fields.Float(compute="_compute_best_price", string="Best Offer") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Field definition should be above followed by the business logic as per our coding guidelines. it may change in certain cases for special methods. Hint: refer codebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change file structure by moving field definitions on top then compute methods and last is the business logic.
from odoo.exceptions import UserError | ||
from odoo.exceptions import ValidationError | ||
from odoo.tools import float_compare, float_is_zero | ||
class EstateProperty(models.Model): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need 2 blank lines before defining the class.
estate/models/estate_property.py
Outdated
|
||
|
||
def action_cancel(self): | ||
for prop in self: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, we write `` `for record self``` because here self refers to a recordset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_sql_constraints = [ | ||
('check_offer_price_positive', 'CHECK(price > 0)', 'The offer price must be strictly positive.'), | ||
] | ||
@api.depends('create_date', 'validity') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove create_date
from depends as it will never change after record creation, and at the time of record default value for validity is there, so it will serve our purpose. Can you give it a try?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_sql_constraints = [ | ||
("unique_name", "UNIQUE(name)", "Property type name must be unique."), | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be after the field definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move ' _sql_constraints' after all field definitions in all the model files
<list string="Estate offer list" | ||
editable="top" | ||
decoration-danger="status == 'refused'" | ||
< 628C span class="blob-code-inner blob-code-marker-addition"> decoration-success="status == 'accepted'"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<list string="Estate offer list" | |
editable="top" | |
decoration-danger="status == 'refused'" | |
decoration-success="status == 'accepted'"> | |
<list string="Estate offer list" | |
editable="top" | |
decoration-danger="status == 'refused'" | |
decoration-success="status == 'accepted'"> |
Need to check the indenation in other places also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed indentation issue in all the xml files.
<group> | ||
<field name="name"/> | ||
<field name="tag_ids" | ||
widget="many2many_tags" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation issue.
…ency - Replaced `for prop in self` with `for record in self` across methods for clarity, since `self` is a recordset. - Moved `_sql_constraints` definitions below field declarations in all models, per community conventions. - Removed `create_date` from @api.depends in `_compute_date_deadline` since it doesn't change after record creation. - Fixed indentation issues in all the xml files for better readability of codebase.
- Fixed the suggested whitespace and newline style issues in all the files suggested by Github checklist
- Fix minor issues related to github style checklist
- Fix minor issues related to github style checklist
…with offers - Added two demo properties: 'Big Villa' and 'Trailer home', including full field population. - Created associated property offers for these demo properties using existing partners. - Demonstrated inline offer creation using Command.create for a new property. - Ensured property type is set to 'Residential' for all demo properties. - Set offer statuses explicitly (accepted/refused) for demo evaluation.
- Created controllers with /properties and /properties/<int:property_id> routes to render the properties - Added wizard in my module making it compatible with selecting one or more properties at a time and making an offer on it. - Build report pdf to download the report of the offers for perticular property \
Core Functionality:
Technical Implementation:
Models:
Relationships:
Security:
UI/UX:
Business Logic:
task-001 (Chapter 1–7 Odoo 18 Developer Tutorial)