-
Notifications
You must be signed in to change notification settings - Fork 2.9k
19.0 real estate tutorial jakan #1109
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: 19.0
Are you sure you want to change the base?
Conversation
- Real Estate module created - Basic structure and required fields added - CHAPTER 1, 2, and 3
- Added basic security access for estate records - Fixed missing whitespace and formatting issues - Covers CHAPTER 4
- Added form and list views for estate records - Added menu and action to access the module - Covers CHAPTER 5
- Added list, form, and search views - Added domains and group by options - Covers CHAPTER 6
mash-odoo
left a comment
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 @jakan-odoo,
Good start on the PR,
Please view the comments and apply the needed changes.
estate/models/estate_property.py
Outdated
| from odoo import fields, models | ||
| from dateutil.relativedelta import relativedelta |
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.
For ordering of imports, refer this: https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#imports
| <record id="estate_property_list_view" model="ir.ui.view"> | ||
| <field name="name">estate.property.list</field> |
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.
For naming a view: <model_name>_view_<view_type>, where view_type is kanban, form, list, search, …
You can refer this guideline: https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#xml-ids-and-naming
| <record id="estate_property_form_view" model="ir.ui.view"> | ||
| <field name="name">estate.property.form</field> |
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.
Do same as suggested above
- Added Many2one relation between models - Improves data linking between records - Covers CHAPTER 7
- Added One2many and Many2many relations between models - Improves linking and management of related records - Covers CHAPTER 7
- Added computed fields for automatic values - Added onchange methods to update fields - Covers CHAPTER 8
- Created Sell, Cancel, Accept, and Refuse buttons - Buttons call related methods on the estate models - Buyer and selling price are set when an offer is accepted - Covers CHAPTER 9
mash-odoo
left a comment
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,
Good going on the task..
Here are some suggestions..
| <field name="bedrooms"/> | ||
| <field name="living_area"/> | ||
| <field name="selling_price"/> | ||
| <filter string="Available Properties" name="available properties" domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]"/> |
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.
Can we write this filter in any other way?
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.
Yes ma'am,
We can write filter like this
<filter string="Available Properties" name="available_properties" domain="[('state', 'in', ('new', 'offer_received'))]"/>
| </form> | ||
| </field> | ||
| </record> | ||
| </odoo> No newline at end of file |
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.
Leave a line at the end of file
estate/models/estate_property.py
Outdated
| ("north", "North"), | ||
| ("south", "South"), | ||
| ("east", "East"), | ||
| ("west", "West")]) |
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.
| ("north", "North"), | |
| ("south", "South"), | |
| ("east", "East"), | |
| ("west", "West")]) | |
| ('north', "North"), | |
| ('south', "South"), | |
| ('east', "East"), | |
| ('west', "West")]) |
estate/models/estate_property.py
Outdated
| ('new', 'New'), | ||
| ('offer_received', 'Offer Received'), | ||
| ('offer_accepted', 'Offer Accepted'), | ||
| ('sold', 'Sold'), | ||
| ('cancelled', 'Cancelled'), |
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.
| ('new', 'New'), | |
| ('offer_received', 'Offer Received'), | |
| ('offer_accepted', 'Offer Accepted'), | |
| ('sold', 'Sold'), | |
| ('cancelled', 'Cancelled'), | |
| ('new', "New"), | |
| ('offer_received', "Offer Received"), | |
| ('offer_accepted', "Offer Accepted"), | |
| ('sold', "Sold"), | |
| ('cancelled', '"Cancelled"), |
estate/__manifest__.py
Outdated
| @@ -0,0 +1,20 @@ | |||
| { | |||
| 'name': 'Real Estate', | |||
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.
| 'name': 'Real Estate', | |
| 'name': "Real Estate", |
estate/__manifest__.py
Outdated
| 'version': '1.0', | ||
| 'category': 'Real Estate', | ||
| 'summary': 'Manage real estate properties', | ||
| 'description': 'This module allows managing properties.', |
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.
| 'description': 'This module allows managing properties.', | |
| 'description': "This module allows managing properties.", |
estate/models/estate_property.py
Outdated
| from dateutil.relativedelta import relativedelta | ||
| from odoo import fields, models, api |
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.
For ordering of imports, refer this: https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#imports
- Added SQL constraints to ensure data validity - Added Python constraints for business rules - Covers CHAPTER 10
- Added inline views for related records - Applied widgets to improve user interface - Set default ordering using _order - CHAPTER 11
- Added maintenance request model with title, cost, and status - Ensured approved requests have a positive cost - Displayed total maintenance cost on the property - Prevented property sale when maintenance is not completed
- Replaced direct cost check with float_is_zero - Ensures correct validation for decimal precision
- Added manual ordering and widget options - Applied conditional button visibility using invisible - Made list views editable and some fields optional - Added decorations, default filters, and stat buttons - Covers CHAPTER 11
mash-odoo
left a comment
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!
Thank you for your work..
Here are some suggestions and questions..
| def action_accept(self): | ||
| for offer in self: | ||
| if offer.property_id.buyer_id: | ||
| raise UserError("Property already accepted") | ||
|
|
||
| other_offer = offer.property_id.offer_ids - offer | ||
| other_offer.write({'status': 'refused'}) | ||
|
|
||
| offer.status = "accepted" | ||
| offer.property_id.buyer_id = offer.partner_id | ||
| offer.property_id.selling_price = offer.price | ||
| return True |
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.
Can you optimize this?
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.
Yes ma'am I can optimize using write,
def action_accept(self):
for offer in self:
property_rec = offer.property_id
if property_rec.buyer_id:
raise UserError("Property already accepted")
other_offer = property_rec.offer_ids - offer
other_offer.write({'status': 'refused'})
offer.status = "accepted"
property_rec.write({
'buyer_id': offer.partner_id.id,
'selling_price': offer.price,
'state': 'sold',
'active': False,
})
return True
| offer.status = "refused" | ||
| return True | ||
|
|
||
| _check_offer_price_positive = models.Constraint( |
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.
Follow this conventions while declaring fields, constraints, methods or CRUD operations.
| _order = 'name' | ||
|
|
||
| name = fields.Char(required=True) | ||
|
|
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.
| <notebook> | ||
| <page string="Properties"> | ||
| <field name="property_ids"> | ||
| <list> |
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.
What is the purpose of explicitly defining a list (tree) view here, even though the field is a One2many?
Won't it work just fine even if you write just this <field name="property_ids">?
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.
Yes, it works without defining a list view, Odoo auto generates a list view.
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.
What do you mean by auto generates?
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.
Auto generates means odoo take by default all field of property we need only 3 field that's why we write list view add field in this list view.
estate/models/estate_property.py
Outdated
| property.state = 'cancelled' | ||
| return True | ||
|
|
||
| _check_expected_price_positive = models.Constraint( |
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.
Follow this conventions while declaring fields, constraints, methods or CRUD operations.
| <header> | ||
| <field name="state" widget="statusbar" statusbar_visible="new,offer_received,offer_accepted,sold"/> | ||
| </header> | ||
| <sheet> | ||
| <header> | ||
| <button name="action_sold" type="object" string="Sold" class="btn-primary" invisible="state in ('sold', 'cancelled')"/> | ||
| <button name="action_cancel" type="object" string="Cancel" class="btn-secondary" invisible="state in ('sold', 'cancelled')"/> | ||
| </header> |
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.
| <header> | |
| <field name="state" widget="statusbar" statusbar_visible="new,offer_received,offer_accepted,sold"/> | |
| </header> | |
| <sheet> | |
| <header> | |
| <button name="action_sold" type="object" string="Sold" class="btn-primary" invisible="state in ('sold', 'cancelled')"/> | |
| <button name="action_cancel" type="object" string="Cancel" class="btn-secondary" invisible="state in ('sold', 'cancelled')"/> | |
| </header> | |
| <header> | |
| <field name="state" widget="statusbar" statusbar_visible="new,offer_received,offer_accepted,sold"/> | |
| <button name="action_sold" type="object" string="Sold" class="btn-primary" invisible="state in ('sold', 'cancelled')"/> | |
| <button name="action_cancel" type="object" string="Cancel" class="btn-secondary" invisible="state in ('sold', 'cancelled')"/> | |
| </header> | |
| <sheet> |
You can add these buttons directly in the header.
- Used Python inheritance to extend existing logic - Applied model inheritance to add fields and behavior - Used view inheritance to update and extend UI - Covers CHAPTER 12
- Added translatable strings for the module - Updated constraint names for clarity - Applied small user interface changes - Added archived filter for records
- Created new estate_account module - Linked estate module with account module - Added invoice creation for sold properties - Covers CHAPTER 13
- Added investor profile linked to partner data - Deleting partner removes investor, investor delete keeps partner - Computed total unsold property value on res.partner - Sum based on expected price of non-sold properties
- Added a Kanban view for estate properties - Grouped properties by type by default - Covers CHAPTER 14

Chapter 4 is completed in this update.
Basic security access rules are added for the Estate module so users can access records correctly. Code style issues like missing white space and formatting problems are also fixed.