Real Estate Tutorial (raame)#1248
Conversation
9f184e7 to
7371099
Compare
…nd access rights A new estate module was created. Property model was created as well and contains some fields. Access rights were added.
7371099 to
6a48a78
Compare
vandroogenbd
left a comment
There was a problem hiding this comment.
Not much to say, runbot is green... Keep going! 🚀
| _description = "Properties of the estate" | ||
|
|
||
| name = fields.Char(required=True) |
There was a problem hiding this comment.
Good practice to separate attributes from fields 👍
| @@ -0,0 +1,2 @@ | |||
| id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink | |||
| access_property_model,access_property_model,model_estate_property,base.group_user,1,1,1,1 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
| { | ||
| 'name': 'Real Estate', | ||
| 'depends': [ | ||
| 'base' |
There was a problem hiding this comment.
It is good practice to end such 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!
| 'security/ir.model.access.csv' | ||
| ], | ||
| 'application': True, | ||
| 'license': 'AGPL-3' |
|
Forgot to say, please add a description to the PR |
Base users were able to unlink records although they're just plebs.
Added an xml file for actions. Also added the 3 levels of menu items and linked them to actions. Finally, some new fields were added like active and state. Some new attributes were added to new and existing fields.
0acc010 to
9d4d467
Compare
List view, form view, and search with filter were added in this Chapter
Many2one fields and One2many fields were added to represent types, tags, and offers
8570dc0 to
7876339
Compare
Added computed fields, inverse methods, and onchange methods
577213f to
23e6402
Compare
Added action buttons
23e6402 to
88c7d39
Compare
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.
Added constraint and changed behaviour to pass the tests
53100c5 to
d1ca42c
Compare
vandroogenbd
left a comment
There was a problem hiding this comment.
Don't hesitate to ask me if you have questions and if you don't, keep it up! 💪
| garage = fields.Boolean() | ||
| garden = fields.Boolean() | ||
| garden_area = fields.Integer() | ||
| garden_orientation = fields.Selection(selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')]) |
There was a problem hiding this comment.
I know we're not paid by line count, but it is sometimes worth using linebreaks for readability
| garden_orientation = fields.Selection(selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')]) | |
| garden_orientation = fields.Selection( | |
| selection=[ | |
| ('north', 'North'), | |
| ('south', 'South'), | |
| ('east', 'East'), | |
| ('west', 'West'), | |
| ], | |
| ) |
| 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, copy=False, default='new') |
There was a problem hiding this comment.
Same here
| state = fields.Selection(selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], required=True, copy=False, default='new') | |
| state = fields.Selection( | |
| selection=[ | |
| ('new', 'New'), | |
| ('offer_received', 'Offer Received'), | |
| ('offer_accepted', 'Offer Accepted'), | |
| ('sold', 'Sold'), | |
| ('cancelled', 'Cancelled'), | |
| ], | |
| required=True, | |
| copy=False, | |
| default='new', | |
| ) |
| 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, copy=False, default='new') | ||
| property_type_id = fields.Many2one("estate.property.type", string="property Type") |
There was a problem hiding this comment.
When the variable name is that explicit, you don't have to specify a string 😉
| _check_expected_price = models.Constraint( | ||
| 'CHECK(expected_price > 0)', | ||
| 'A property expected price must be strictly positive', | ||
| ) |
There was a problem hiding this comment.
Indentation is off here
| _check_expected_price = models.Constraint( | |
| 'CHECK(expected_price > 0)', | |
| 'A property expected price must be strictly positive', | |
| ) | |
| _check_expected_price = models.Constraint( | |
| 'CHECK(expected_price > 0)', | |
| 'A property expected price must be strictly positive', | |
| ) |
| _check_expected_price = models.Constraint( | ||
| 'CHECK(expected_price > 0)', | ||
| 'A property expected price must be strictly positive', | ||
| ) | ||
|
|
||
| _check_selling_price = models.Constraint( | ||
| 'CHECK(selling_price >= 0)', | ||
| 'A property selling price must be positive', | ||
| ) |
There was a problem hiding this comment.
Constraints should be after computes (see doc)
| <menuitem id="property_menu_root" name="Real Estate"> | ||
| <menuitem id="property_first_level_menu" name="Advertisements"> | ||
| <menuitem id="property_model_menu_action" action="property_model_action"/> | ||
| </menuitem> | ||
| <menuitem id="settings_first_level_menu" name="Settings"> | ||
| <menuitem id="property_type_model_menu_action" action="property_type_model_action"/> | ||
| <menuitem id="property_tag_model_menu_action" action="property_tag_model_action"/> | ||
| </menuitem> | ||
| </menuitem> |
There was a problem hiding this comment.
There are specific guidelines for xml (see doc)
| <menuitem id="property_menu_root" name="Real Estate"> | |
| <menuitem id="property_first_level_menu" name="Advertisements"> | |
| <menuitem id="property_model_menu_action" action="property_model_action"/> | |
| </menuitem> | |
| <menuitem id="settings_first_level_menu" name="Settings"> | |
| <menuitem id="property_type_model_menu_action" action="property_type_model_action"/> | |
| <menuitem id="property_tag_model_menu_action" action="property_tag_model_action"/> | |
| </menuitem> | |
| </menuitem> | |
| <menuitem id="estate_menu_root" name="Real Estate"> | |
| <menuitem id="estate_property_menu" name="Advertisements"> | |
| <menuitem id="estate_property_menu_action" action="estate_property_action"/> | |
| </menuitem> | |
| <menuitem id="estate_settings_menu" name="Settings"> | |
| <menuitem id="estate_property_type_menu_action" action="estate_property_type_action"/> | |
| <menuitem id="estate_property_tag_menu_action" action="estate_property_tag_action"/> | |
| </menuitem> | |
| </menuitem> |
The idea is to match model names.
| <record id="property_model_action" model="ir.actions.act_window"> | ||
| <field name="name">Properties</field> | ||
| <field name="res_model">estate.property</field> | ||
| <field name="view_mode">list,form</field> | ||
| </record> | ||
|
|
||
| <record id="property_type_model_action" model="ir.actions.act_window"> | ||
| <field name="name">Property Types</field> | ||
| <field name="res_model">estate.property.type</field> | ||
| <field name="view_mode">list,form</field> | ||
| </record> | ||
|
|
||
| <record id="property_tag_model_action" model="ir.actions.act_window"> | ||
| <field name="name">Property Tags</field> | ||
| <field name="res_model">estate.property.tag</field> | ||
| <field name="view_mode">list,form</field> | ||
| </record> |
There was a problem hiding this comment.
You will need to do some renaming here to match the changes from above
| <field name="view_mode">list,form</field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_view_list" model="ir.ui.view"> |
There was a problem hiding this comment.
Naming for the model views is great! 👍
| <record id="estate_property_offer_view_list" model="ir.ui.view"> | ||
| <field name="name">estate.property.offer.list</field> | ||
| <field name="model">estate.property.offer</field> | ||
| <field name="arch" type="xml"> | ||
| <list string="Offers"> | ||
| <field name="price" width="400px"/> | ||
| <field name="partner_id" string="Buyer" width="100px"/> | ||
| <field name="validity" string="Validity (days)" width="100px"/> | ||
| <field name="date_deadline" string="Deadline" width="100px"/> | ||
| <button name="accept_offer" type="object" icon="fa-check"/> | ||
| <button name="action_refuse" type="object" icon="fa-times"/> | ||
| <field name="status" width="100px"/> | ||
| </list> | ||
| </field> | ||
| </record> |
There was a problem hiding this comment.
It would make more sense to group the views by model, eg all of the estate_property views first, then all of the estate_property_offer views.
You don't have to, but you could also split them into 2 separate files to make it even cleaner (although here it is okay to keep them in the same file as it isn't too long).

PR for the Real Estate Module Tutorial