Technical Training (Ahnae)#1247
Conversation
ahmedamein100
commented
Apr 22, 2026
- created empty Estate module
- update it's manifest to make it an app
- created model files and write down the required fields
- fix PR errors
Some imports are missing in the manifest causing some warnings and the css doesn't load properly. Fix was fixed in the master branch, backporting it in 19.0 for the onboarding classes that always happen in the lastest stable. task-none Part-of: odoo#1037 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
`json` routes were deprecated to `jsonrpc` in 19.0, let's get rid of the warning to avoid confusion for the newdoos. task-none closes odoo#1037 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
a9d6923 to
2666fbd
Compare
The goal of this commit is to provide the initial user interface and core field behaviors for the Real Estate module. - UI: Added window action and a three-level menu hierarchy to allow users to navigate to property records. - Data Integrity: Set 'selling_price' to read-only and prevented copying of 'date_availability' to ensure fresh data on duplication. - Automation: Implemented a 3-month default for 'date_availability' using a dynamic lambda to handle the 'today' calculation at runtime. - Management: Added 'active' (archiving) and 'state' (workflow) fields to support record lifecycle management.
Base users were able to unlink records although they're just plebs.
vandroogenbd
left a comment
There was a problem hiding this comment.
Just some small comments 🙂
Be careful that I might have made a contribution to your PR 🫣
| _description = "Estate Property Model" | ||
|
|
||
| name = fields.Char(required=True) |
There was a problem hiding this comment.
Good practice to separate attributes from fields 👍
There was a problem hiding this comment.
I am sorry but isn't it separated with line number 7?
| garden_orientation = fields.Selection( | ||
| string='Type', | ||
| selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')] | ||
| ) |
| garden_area = fields.Integer() | ||
| garden_orientation = fields.Selection( | ||
| string='Type', | ||
| selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')] |
There was a problem hiding this comment.
It is good practice to end argument lines with a ,. This way, if someone later adds a line, they don't have to add the coma so the line stays unchanged, this keeps the git history cleaner!
| state = fields.Selection( | ||
| selection=[ | ||
| ('new', 'New'), | ||
| ('offer_received', 'Offer Received'), | ||
| ('offer_accepted', 'Offer Accepted'), | ||
| ('sold', 'Sold'), | ||
| ('canceled', 'Cancelled'), | ||
| ], | ||
| required=True, | ||
| copy=False, | ||
| default='new', | ||
| ) |
There was a problem hiding this comment.
You might want to re-indent this block
| @@ -0,0 +1,2 @@ | |||
| id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | |||
| estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,0 No newline at end of file | |||
There was a problem hiding this comment.
It is good practice to add a trailing empty line to your files
|
|
||
|
|
||
| class EstatePropertytModel(models.Model): | ||
| _name = "estate_property" |
There was a problem hiding this comment.
By convention, we separate words with . in model names
word.word => model name
word_word => python variable (snake case)
wordWord => js variable (camel case)
| 'depends': ['base'], | ||
| 'category': 'Tutorials', | ||
| 'application': True, | ||
| 'data': ['security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menus.xml'], |
There was a problem hiding this comment.
Same idea as the comment about the ,, if you break this into multiple lines it makes it so later commits don't mess with git-blaming when adding dependencies
Implement the property list, form, and search views, while correcting technical naming and styling issues. - Add list view for property overview - Add form view with sheet layout, groups, and notebook - Add search view with 'Available' filter and 'Postcode' grouping - Correct model name to 'estate.property' and fix field indentation
- Create estate.property.type, estate.property.tag, and estate.property.offer models. - Add Many2one relationships for property type, salesperson (res.users), and buyer (res.partner). - Add Many2many relationship for property tags with many2many_tags widget. - Add One2many relationship for property offers. - Update views to include new relational fields and notebook pages. - Add security access rights for all new models.
- Add 'total_area' as a sum of living and garden area. - Add 'best_price' to track the highest offer using mapped(). - Add 'date_deadline' and 'validity' to offers with an inverse function to allow bi-directional updates. - Implement an onchange to automatically set garden area and orientation when the garden checkbox is toggled.
- Add 'Sold' and 'Cancel' buttons to property form with UserError constraints to prevent invalid state transitions. - Add 'Accept' and 'Refuse' buttons to property offers with icons. - Implement logic to automatically set the property buyer and selling price when an offer is accepted. - Add validation to ensure only one offer can be accepted per property.
- Add SQL constraints to ensure expected_price and offer price are strictly positive, and selling_price is positive. - Add unique SQL constraints on property tag and type names. - Add Python @api.constrains on the property model to ensure the selling price is at least 90% of the expected price. - Use float_is_zero and float_compare to handle decimal precision safely in price validation.
- Add list view decorations based on property and offer states. - Implement 'editable="bottom"' for offer and tag list views. - Make 'date_availability' an optional hidden field in list view. - Add 'filter_domain' to living area search for >= filtering. - Implement 'search_default_available' in the window action. - Add a stat button on property types to view related offers. - Define 'property_type_id' as a stored related field on offers.
- Remove trailing whitespaces in property and offer models. - Remove 'print' statement in property type compute method. - Fix blank lines containing whitespace. - Clean up formatting in ValidationErrors and related fields.
- Prevent deletion of properties unless state is 'New' or 'Cancelled' using '@api.ondelete'. - Override 'create' in estate.property.offer to validate offer price against 'best_price' and update property state to 'Offer Received'. - Extend 'res.users' model with a 'property_ids' One2many field. - Add a filtered notebook page to the Users form view to display assigned available properties.
This commit is here to introduce the testing framework of Odoo. Try running the tests using `--test-tags :TestEstateProperty`. Doc: https://www.odoo.com/documentation/18.0/developer/reference/backend/testing.html?highlight=tests#invocation The tests were made such that the first one should work but the second one should fail. Your job is to ensure both tests pass in the end. You should update the behaviour of the appropriate models. If you want, you can also add a small test of your own to get a feel for it.
- Inherit estate.property in a new estate_account module.
- Override 'action_sold' to automate invoice creation.
- Implement 'account.move' generation with specific lines:
- 6% commission on property selling price.
- 100.00 fixed administrative fees.
- Use 'Command.create' for One2many invoice line handling.
- Update 'action_accept_offer' to prevent accepting offers below expected price for south-facing properties with gardens.
- Remove unused imports (float_compare, float_is_zero, fields). - Fix 'Too many blank lines' (E303) in res_users and estate_property. - Add missing newlines at end of files (W292) in multiple __init__ files. - Clean up estate_account model imports.
- Create property kanban view with 'default_group_by' on state.
- Disable manual record relocation using 'records_draggable="0"'.
- Add conditional display logic using 't-if' for:
- 'best_price' (shown only when offers are received).
- 'selling_price' (shown only when an offer is accepted).
- Include 'expected_price' and 'tag_ids' in the card template.
vandroogenbd
left a comment
There was a problem hiding this comment.
Make sure to remove the extra files you pushed. Also, you pushed changes to modules outside of estate and estate_account, can you remove those as well?
Once you're done with that you can squash your commits for estate 🙂
| @@ -0,0 +1,56 @@ | |||
| { | |||
There was a problem hiding this comment.
You should configure your global .gitignore to make sure such files don't get pushed to your PRs 😉
| from odoo import api, fields, models, exceptions | ||
| from odoo.exceptions import ValidationError, UserError |
There was a problem hiding this comment.
Please respect alphabetical order for imports
| garden_orientation = fields.Selection( | ||
| string='Type', | ||
| selection=[ | ||
| ('north', 'North'), | ||
| ('south', 'South'), | ||
| ('east', 'East'), | ||
| ('west', 'West'), | ||
| ] | ||
| ) |
There was a problem hiding this comment.
Indentation
| garden_orientation = fields.Selection( | |
| string='Type', | |
| selection=[ | |
| ('north', 'North'), | |
| ('south', 'South'), | |
| ('east', 'East'), | |
| ('west', 'West'), | |
| ] | |
| ) | |
| garden_orientation = fields.Selection( | |
| string='Type', | |
| selection=[ | |
| ('north', 'North'), | |
| ('south', 'South'), | |
| ('east', 'East'), | |
| ('west', 'West'), | |
| ], | |
| ) |
| ] | ||
| ) | ||
| active = fields.Boolean(default=True) | ||
| state = fields.Selection( |
| "estate.property.type", | ||
| string="Tag", | ||
| ) | ||
| salesperson_id = fields.Many2one( |
| </list> | ||
| </field> | ||
| </record> | ||
| </odoo> No newline at end of file |
There was a problem hiding this comment.
Missing empty line at end of file 😉
| @@ -0,0 +1,51 @@ | |||
| <odoo> | |||
There was a problem hiding this comment.
Overall indentation of the file is off + missing empty line at end
| <field name="view_mode">list,form,kanban</field> | ||
| <field name="context">{'search_default_available': True}</field> | ||
| </record> | ||
| <record id="estate_property_view_list" model="ir.ui.view"> |
There was a problem hiding this comment.
Separate <record> blocks with empty lines to make it easier to read please.
| @@ -0,0 +1,20 @@ | |||
| { | |||
| 'name': "Estate", | |||
| 'version': '1.0', | |||
There was a problem hiding this comment.
Version should match the Odoo version, this way Odoo will not allow the module to be installed in other versions.
| 'version': '1.0', | |
| 'version': '19.0.0.1.0', |
| @@ -0,0 +1,13 @@ | |||
| { | |||
| 'name': "Estate Account", | |||
| 'version': '1.0', | |||
