-
Notifications
You must be signed in to change notification settings - Fork 2.9k
[ADD] estate: create a new module for Real Estate Advertisement #1127
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
Creation of a new module estate that covers Real Estate Advertisement. There is no module that answer this business case by default.
This adds property model to the estate module with the objective to store the informations related to the property.
This adds fields to store information related to the property (name, description, price, living area…)
artn-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.
Nice job so far !
We always try to add a new line at the end of every file, for it to be easier to read.
This can be done automatically if you are using vscode by turning on the Insert Final Newline option in the settings.
estate/models/property.py
Outdated
| _name = "estate_property" | ||
| _description = "estate property" |
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.
You don't have to change it all, but we prefer using single quotes in Python files unless using double is required for some semantic reasons.
|
|
||
| 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.
We prefer adding 2 blank lines before declaring a class.
| class EstateProperty(models.Model): | |
| class EstateProperty(models.Model): |
This add a new line at the end of every file to be easier to read. This changes strings defined by double quotes to strings with single quotes. This also uses two blank lines instead of one before declaring a class
This gives access rights to the group base.group_user. This is needed because no access rights was defined so no users can access the data.
This creates a 3 levels architecture with an action to interact with property model.
This changes attributes of selling price to read-only and prevents the copy of availability date and selling price fields.
This adds a default value for the bedrooms and the availability date. This also add an active and a state field.
This cleans the code based on robodoo recommendations by removing some lines and correcting wrong indentations.
This adds new column names to the list view and a new form view according to the required specifications.
This creates new search fields, a filter for available properties and the possibility to group the properties by postcode.
This creates a new module for the type of a property. The type of a property record can be observerd in list and form views.
This adds add salesperson and buyer as field of the property module. This also adds salesperson and buyer in the property form.
This creates a new model for tags and adds a many2many field to property model. This new field is visible in list and form views.
This creates an offer model and adds it as a one2many field for the property model.
This creates computed fields (total_area and best_offer) that are visible in the form view of the estate_property model.
This creates two new fields to compute deadline from validity and the inverse way.
artn-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.
Looking good ! Just a few nitpicks
estate/models/property.py
Outdated
| garden_area = fields.Integer(string='Garden Area (sqm)') | ||
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be broken down into multiple lines as it's quite long
| 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' | |
| ) |
estate/models/property.py
Outdated
|
|
||
| property_type_id = fields.Many2one('estate_property_type', string='Property Type') | ||
|
|
||
| salesperson = fields.Many2one('res.users', string='Salesman', default=lambda self: self.env.user) | ||
| buyer = fields.Many2one('res.partner', copy=False) | ||
|
|
||
| property_tag_id = fields.Many2many('estate_property_tag', string='Property Tag') | ||
|
|
||
| property_offer_id = fields.One2many('estate_property_offer', 'property_id', string='Property Offer') | ||
|
|
||
| total_area = fields.Float(string="Total Area (sqm)", compute='_compute_area') |
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.
The newlines seem to be written kind of randomly, I think you can delete them
| property_type_id = fields.Many2one('estate_property_type', string='Property Type') | |
| salesperson = fields.Many2one('res.users', string='Salesman', default=lambda self: self.env.user) | |
| buyer = fields.Many2one('res.partner', copy=False) | |
| property_tag_id = fields.Many2many('estate_property_tag', string='Property Tag') | |
| property_offer_id = fields.One2many('estate_property_offer', 'property_id', string='Property Offer') | |
| total_area = fields.Float(string="Total Area (sqm)", compute='_compute_area') | |
| property_type_id = fields.Many2one('estate_property_type', string='Property Type') | |
| salesperson = fields.Many2one('res.users', string='Salesman', default=lambda self: self.env.user) | |
| buyer = fields.Many2one('res.partner', copy=False) | |
| property_tag_id = fields.Many2many('estate_property_tag', string='Property Tag') | |
| property_offer_id = fields.One2many('estate_property_offer', 'property_id', string='Property Offer') | |
| total_area = fields.Float(string="Total Area (sqm)", compute='_compute_area') |
estate/models/property.py
Outdated
| for record in self: | ||
| record.total_area = record.living_area + record.garden_area | ||
|
|
||
| best_price = fields.Float(string="Best offer", compute='_compute_best_price') |
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.
Could be defined in the same place as the other fields
estate/models/property_tag.py
Outdated
| from odoo import fields, models | ||
|
|
||
|
|
||
| class EstatePropertyType(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.
| class EstatePropertyType(models.Model): | |
| class EstatePropertyTag(models.Model): |
Looks like it should be tag
estate/security/ir.model.access.csv
Outdated
| access_ir_group_user,ir_group_user,model_estate_property,base.group_user,1,1,1,1 | ||
| access_ir_group_user_type,ir_group_user_type,model_estate_property_type,base.group_user,1,1,1,1 | ||
| access_ir_group_user_tag,ir_group_user_tag,model_estate_property_tag,base.group_user,1,1,1,1 | ||
| access_ir_group_user_offer,ir_group_user_offer,model_estate_property_offer,base.group_user,1,1,1,1 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.
Don't forget the empty line at the end of a file
This cleans the fields declaration based on the review.
This add sold and cancel button on the property form view to change the status. This also add accept/refuse button on the offer list view to change the status of an offer (we can accept only if no other offers are accepted).
This solves the problem that the selling price was the same for every property.
artn-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.
Looking good, nice one !
This adds constraints to expected price, selling price offer price, tag name and price name. This also adds the constraint selling_price <= expected_price.
This adds an inline list views in the type form.
This cleans the code to respect conventions.
This adds a new view of the state in the property form view. This also adds automatic ordering to each model. This also adds manual ordering of property based on property type.
This changes the statusbar widget for the state depending on the offers. If there is not offer, then new state. If there are not offers, then offer received and if an offer is accepted then offer accepted.
This adds a widget option to prevent "create and edit" for the type in the property form. This also add color to tags and a color picker in the form of a tag.
This adds new invisible and readonly fields based on some conditions.
This adds a editable list views for the offers and the tags. The field date_availability becomes optional in the offer list view and is hidden by default.
This adds decorations in property and offer list views.
This adds the filter for available properties by default and allows the search of properties with a living area of at least a value.
artn-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.
Small nitpick as always, otherwise it looks good to me !
estate/models/property.py
Outdated
| _check_expected_price = models.Constraint( | ||
| 'CHECK(0 < expected_price)', | ||
| 'A property expected price must be strictly positive') | ||
|
|
||
| _check_selling_price = models.Constraint( | ||
| 'CHECK(0 <= selling_price)', | ||
| 'A property selling price must be positive') |
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 constrains are usually declared right after the fields and before the function definition
| _check_offer_price = models.Constraint( | ||
| 'CHECK(0 < price)', | ||
| 'An offer price must be strictly positive') |
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.
Same here
This adds a stat button from the form view of a property type to see the active offers linked to this type.
This prevents the deletion of a property if its state is 'New' or 'Cancelled'. This also adds a raise when we try to create an offer with a lower amount than another offer.
This adds a 'Real Estate Properties' page to the user form. This shows the properties for which the user is the salesman.
This creates an invoice for the buyer when clicking on the button 'Sold'.
This cleans a lost white space.
This adds Kanban view to the property views. The properties are grouped by type by default and cannot be drag and drop.
This adds a Counter class as a sub component to call multiple counters in the playground.

Creation of a new module estate that covers Real Estate Advertisement. There is no module that answer this business case by default.