Conversation
| @@ -0,0 +1 @@ | |||
| from . import estate_property No newline at end of file | |||
There was a problem hiding this comment.
Don't forget to have an empty line at the end of every file. This will be automatic if you use a formatter like Ruff
There was a problem hiding this comment.
You can check which files are missing the line on the PR
| @@ -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,1 No newline at end of file | |||
There was a problem hiding this comment.
| estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1 | |
| access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 |
You don't need to start with the module name here as that will be done automatically.
There was a problem hiding this comment.
Important thing to notice: You need to keep 'base' in base.group_user because it's a different module. But if you just write model_estate_property odoo knows to look for that in the estate module.
|
|
||
|
|
||
| class EstateProperty(models.Model): | ||
| _name = 'estate_property' |
There was a problem hiding this comment.
For technical names we separate words with .
| _name = 'estate_property' | |
| _name = 'estate.property' |
| @@ -0,0 +1,9 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | |||
There was a problem hiding this comment.
No need to have this line for xml files
| <?xml version="1.0" encoding="utf-8" ?> |
| 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.
| selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')] | |
| [('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')] |
The first positional argument is already 'selection' so it's redundant to have it.
e291eec to
a2c494c
Compare
| _description = 'Estate Property' | ||
|
|
||
| name = fields.Char(required=True) | ||
| name = fields.Char('Title', required=True) |
There was a problem hiding this comment.
For strings, as far as I know in R&D they put user facing strings in double quotes and technical strings in single quotes. In PS-Tech we put everything in double quotes.
Again something that will easily be fixed with a formatter configuration
There was a problem hiding this comment.
Do you have a formatter configuration I can start from, because now I use the formatter of pycharm by default.
I forgot to enable it for the first couple of commits.
| description = fields.Text() | ||
| postcode = fields.Char() | ||
| date_availability = fields.Date() | ||
| date_availability = fields.Date('Available From', default=fields.Date.today() + relativedelta(months=3), copy=False) |
There was a problem hiding this comment.
Here you're passing a value as default. This value will be calculated once when you run the server.
However, what you want to do is to pass a function, so that the value is calculated every time the default value is needed.
| [('new', 'New'), ('offer', 'Offer Received'), ('accepted', 'Offer Accepted'), ('sold', 'Sold'), ('canceled', 'Cancelled')], | ||
| default='new' | ||
| ) | ||
| property_type_id = fields.Many2one('estate.property.type', 'Property Type') |
There was a problem hiding this comment.
No need to add the string here, the default string for property_type_id is already Property Type
| default='new' | ||
| ) | ||
| property_type_id = fields.Many2one('estate.property.type', 'Property Type') | ||
| sales_person_id = fields.Many2one('res.users', "Salesman", copy=False, default=lambda self: self.env.user) |
There was a problem hiding this comment.
| sales_person_id = fields.Many2one('res.users', "Salesman", copy=False, default=lambda self: self.env.user) | |
| salesperson_id = fields.Many2one('res.users', copy=False, default=lambda self: self.env.user) |
salesperson is one word i guess, not super sure
There was a problem hiding this comment.
indeed this is one word, is there a way to not loose data when renaming a field?
There was a problem hiding this comment.
Yes there is, you can check:
https://www.odoo.com/documentation/18.0/developer/reference/upgrades/upgrade_scripts.html
For this specific case:
https://www.odoo.com/documentation/18.0/developer/reference/upgrades/upgrade_utils.html#odoo.upgrade.util.fields.rename_field
No need for now, but do it if you find it interesting
| ) | ||
| property_type_id = fields.Many2one('estate.property.type', 'Property Type') | ||
| sales_person_id = fields.Many2one('res.users', "Salesman", copy=False, default=lambda self: self.env.user) | ||
| buyer_id = fields.Many2one('res.partner', 'Buyer', copy=False) |
There was a problem hiding this comment.
| buyer_id = fields.Many2one('res.partner', 'Buyer', copy=False) | |
| buyer_id = fields.Many2one('res.partner, copy=False) |
| <odoo> | ||
|
|
||
| <record id="estate_property_view_search_name" model="ir.ui.view"> | ||
| <field name="name">estate.property.list</field> |
There was a problem hiding this comment.
| <field name="name">estate.property.list</field> | |
| <field name="name">estate.property.view.search</field> |
| <field name="living_area"/> | ||
| <field name="facades"/> | ||
| <field name="property_type_id"/> | ||
| <filter name="available" domain="['|',('state','=','new'),('state','=','offer')]"/> |
There was a problem hiding this comment.
| <filter name="available" domain="['|',('state','=','new'),('state','=','offer')]"/> | |
| <filter name="available" domain="[('state', 'in', ['new', 'offer'])]"/> |
| </record> | ||
|
|
||
| <record id="estate_property_view_form" model="ir.ui.view"> | ||
| <field name="name">estate.property.list</field> |
There was a problem hiding this comment.
| <field name="name">estate.property.list</field> | |
| <field name="name">estate.property.view.form</field> |
| "views/estate_property_views.xml", | ||
| "views/estate_property_offer_views.xml", | ||
| "views/estate_menus.xml", | ||
| 'security/ir.model.access.csv', |
There was a problem hiding this comment.
We usually put the security files on the top, since what they define can be used in the views but not the opposite
|
|
||
| class EstatePropertyTag(models.Model): | ||
| _name = 'estate.property.tag' | ||
| _description = 'Tags for properties' |
There was a problem hiding this comment.
| _description = 'Tags for properties' | |
| _description = 'Estate Property Tag' |
cgun-odoo
left a comment
There was a problem hiding this comment.
Added some comments to align more with the conventions
| _check_expected_price = models.Constraint("CHECK(expected_price>0)", "The expected price needs to be bigger then 0") | ||
| _check_selling_price = models.Constraint("CHECK(selling_price>=0)", "The selling price needs to be positive") |
There was a problem hiding this comment.
sql Constraints should be above fields with other private properties.
Refer to this to check the order in a model:
https://www.odoo.com/documentation/18.0/contributing/development/coding_guidelines.html#symbols-and-conventions
There was a problem hiding this comment.
I was following the 19 guidelines where it was indicating that this is below the field declaration
https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#symbols-and-conventions
| def action_state_to_canceled(self): | ||
| self.ensure_one() | ||
| if self.state == "sold": | ||
| raise UserError("Canceled properties can not be sold") |
There was a problem hiding this comment.
The Error messages for action_state_to_sold and action_state_to_canceled felt like the opposite of what it should be
| not float_is_zero(estate_property.selling_price, 2) | ||
| and float_compare(estate_property.selling_price, estate_property.expected_price * 0.9, 2) < 0 | ||
| ): | ||
| raise UserError("The property can not be sold for a price lower than 90% of the expected price") |
There was a problem hiding this comment.
This one should be a ValidationError as it's thrown from an api.constrains
Check this for exceptions in Odoo
https://www.odoo.com/documentation/18.0/developer/reference/backend/orm.html?highlight=usererror#odoo.exceptions.UserError
| def accept_offer(self, price, buyer): | ||
| self.ensure_one() | ||
| if self.state not in ["new", "offer"]: | ||
| raise UserError("The offer can not be accepted") |
There was a problem hiding this comment.
You can explain more like with the message like you did for the other ones.
Why can't they accept it?
There was a problem hiding this comment.
would you go for 1 generic message, or for individual messages based on the different states?
There was a problem hiding this comment.
I would go for multiple messages to be more explanatory. If there are too many different states that require too many messages, I would think about creating a helper function that generates an error message.
| <record id="estate_property_tag_view_form" model="ir.ui.view"> | ||
| <field name="name">estate.property.tag.list</field> | ||
| <field name="model">estate.property.tag</field> | ||
| <field name="arch" type="xml"> | ||
| <form string="Tag"> | ||
| <sheet> | ||
| <group> | ||
| <field name="name"/> | ||
| </group> | ||
| </sheet> | ||
| </form> | ||
| </field> | ||
| </record> |
There was a problem hiding this comment.
If you don't want them to access the form view you should remove it from the action as well
| </page> | ||
| <page string="Offers"> | ||
| <field name="offer_ids"/> | ||
| <field name="offer_ids" readonly="state in ['accepted','sold','canceled']"/> |
There was a problem hiding this comment.
You can define the list view of offers here so that you don't need to have a file for it (i guess you don't access that view anywhere else)
Kind of like
<field name="one2many_field">
<list>
<field/>
<field/>
</list>
</field>
| self.ensure_one() | ||
| if self.state not in ["new", "offer"]: | ||
| raise UserError( | ||
| "An offer can can only be accepted when the building is still for sale and no other offer is already accepted" |
There was a problem hiding this comment.
"An offer can only be made" probably
| "An offer can can only be accepted when the building is still for sale and no other offer is already accepted" | ||
| ) | ||
| if float_compare(price, self.best_offer, 2) <= 0: | ||
| raise UserError("Only offers that are over the current best offer can be accepted") |
There was a problem hiding this comment.
Shouldn't this check be in accept_offer?
There was a problem hiding this comment.
question was to only allow offers that are higher than previous made offers
|
|
||
| @api.model | ||
| def create(self, vals_list): | ||
| for offer in vals_list: |
There was a problem hiding this comment.
Here we usually do
for vals in vals_list:
As they aren't offers yet
| @api.depends("offer_ids") | ||
| def _compute_offer_count(self): | ||
| for offer in self: | ||
| offer.offer_count = len(offer.offer_ids) |
There was a problem hiding this comment.
This should match the model
for property_type in self:
| @@ -0,0 +1,15 @@ | |||
| <odoo> | |||
| <!-- Update User form !--> | |||
| <record id="res_users_form_view_properties" model="ir.ui.view"> | |||
There was a problem hiding this comment.
ID of the inherited record should stay the same:
<record id="view_users_form" model="ir.ui.view">
I know that some people in the department actually don't like this and they try to give more explanatory id and names to view records.
IMO, naming them the same helps check where the record has been updated easily so I follow the convention.
There was a problem hiding this comment.
makes sense, did not get that from the tutorial
| <odoo> | ||
| <!-- Update User form !--> | ||
| <record id="res_users_form_view_properties" model="ir.ui.view"> | ||
| <field name="name">res.users.form.properties</field> |
There was a problem hiding this comment.
According to the same guideline this should be named:
res.users.view.form.inherit.estate
| property_id = fields.Many2one("estate.property", required=True) | ||
| validity = fields.Integer("Validity (days)", default=7) | ||
| date_deadline = fields.Date("Deadline", compute="_calculate_date_deadline", inverse="_inverse_date_deadline") | ||
| property_type_id = fields.Many2one(related="property_id.property_type_id", stored=True) |
There was a problem hiding this comment.
Why did you need to make this field stored?
There was a problem hiding this comment.
done to make it possible to have the inverse field in property_type as one2many, if not stored then these items could not be found from a property_type trough SQL queries
There was a problem hiding this comment.
There is one problem though: It should be store=True without the 'd'. Right now, the field is probably not stored.
It works because related fields are special, you can search on them even if they aren't stored.
|
|
||
| def action_state_to_sold(self): | ||
| if not self.buyer_id: | ||
| raise ValidationError("Properties can only be sold if the buyer is filled in") |
There was a problem hiding this comment.
This should be a UserError since it's not a constraint https://www.odoo.com/documentation/18.0/developer/reference/backend/orm.html?highlight=usererror#odoo.exceptions.UserError
| property_id = fields.Many2one("estate.property", required=True) | ||
| validity = fields.Integer("Validity (days)", default=7) | ||
| date_deadline = fields.Date("Deadline", compute="_calculate_date_deadline", inverse="_inverse_date_deadline") | ||
| property_type_id = fields.Many2one(related="property_id.property_type_id", stored=True) |
There was a problem hiding this comment.
There is one problem though: It should be store=True without the 'd'. Right now, the field is probably not stored.
It works because related fields are special, you can search on them even if they aren't stored.
cgun-odoo
left a comment
There was a problem hiding this comment.
You can try to make the runbot green now
make it possible to handle all requests for this [ADD] estate: create placeholder for Real Estate Advertisement make basic setup [IMP] estate: convert module in application convert module in application [IMP] estate: add property in database make it possible to store properties in the database [IMP] estate: add description to property database model make it easier to understand what the estate property means [IMP] estate: add fields in property model make sure the basic information can be stored in the estate property [FIX] estate: in property some fields are not optional some fields should not be required [IMP] estate: add access rights for properties make sure that data is only accessible for the predefined usergroup [IMP] estate: create view for properties making it possible to have a view the model of property [IMP] estate: make app visible in UI make it possible to see the properties in the userinterface [LINT] estate: fix end of file keep code inline with the python standard [FIX] estate: make UI labels in line with wireframe change the labels so the labes in the UI stay inline with the wireframe [CLN] estate: resolve problems with coding guidelines improve consistency with rest of the codebase [IMP] estate: make property more resilient during copy make sure property specific information is not copied [IMP] estate: default values for property reducing work by filling in fields op properties with sensible default values [IMP] estate: add option to archive a property reducing work by filling in fields op properties with sensible default values [FIX] estate: stop archiving new properties when creating new properties they should not be archived immediately [FIX] estate: add different states for property making sure the current state of a property can be properly represented [IMP] estate: add listview for property making it possible to view more information in the list view [IMP] estate: add formview for property make the detail view of a property more appealing [IMP] estate: add search options improve the possible options for searching [IMP] estate: default filter and grouping for property improve the options for searching properties by having defaults [IMP] estate: add type of properties make it possible to distinguish between multiple types of properties [IMP] estate: add buyer and salesperson on property keep track of who bought the property and the salesperson [IMP] estate: add tags for properties adding an option to some custom tag to buildings so you don't need to search for important information about the building [FIX] estate: wrong naming in records of tag and type make naming consistent [IMP] estate: add option to put offers in allow the system to store offers on a property, in preparation to be able to really sell [IMP] estate: add total area of property help the realtor, precalculate the total area [IMP] estate: show best offer help the realtor with showing the price of the best offer [IMP] estate: add validity and deadline to offer make sure an offer is not valid for an infinite amount of time [IMP] estate: defaults for garden attributes based on availability help users when garden is selected to fill in some details and remove them if no garden is there [CLN] estate: use blank end of line follow coding guidelines [CLN] estate: double quotes for language specific texts follow coding guidelines [FIX] estate: make default value based on moment of invocation default availability needs to be calculated when creating the property, not at startup [IMP] estate: rename field make field in line with naming standaard [IMP] estate: state changes make sure transitions are set to reduce users making impossible actions [CLN] estate: add missing fields in module manifest make sure the module is compliant with the testing tools [LINT] estate: blank line at end of file make sure the module is compliant with the coding style [CLN] estate: make _description technical term the _description is used in technical locations so keep it useful for that environment over an explanation [CLN] estate: code guidelines fix naming compute and inverse make sure to follow coding guidelines [FIX] estate: make it possible to delete offers for admins make sure offers can be deleted, but only if you know what you do [CLN] estate: change naming to match coding style for views follow coding rules [REF] estate: improve readability of search filter improve readability [REF] estate: move the security file to load before the views the content of the security can be used in the views but not the opposite [LINT] estate: use linter to fix codestyle follow style defined by team [FIX] estate: security duplicate entry make sure the id's are unique for security rules [IMP] estate: add database constraints on prices, tags and types make sure no invalid data or duplicate can be entered in the database [IMP] estate: add code constraint on selling price make sure the property can not be sold if it is not at least 90% of the expected price [IMP] estate: view property on type page make it possible to view a minimum of property information that is linked to one type of property [IMP] estate: add status bar on property details make the status visually appealing [IMP] estate: add default ordering making sure there is a logical default ordering for each model [IMP] estate: add manual sorting for properties make sure that it is possible to manually sort the properties [IMP] estate: add widget options making sure property tags can be easily distinguished from each-other based on color avoid accidentally creating new property types when creating or editing properties [IMP] estate: hide action buttons if not possible to use help user by not showing buttons they can not use op properties [IMP] estate: improve user workflow help user by disabling or hiding buttons or items they do not need [IMP] estate: list views editable there is no need for detailed form_view if the data is limited and can easily be changed in the listview [IMP] estate: hide field improve usability by making fields optional if they are not adding value all the time [IMP] estate: use decoration to indicate state make the state visually appealing so less space is wasted on the screen and have a quick overview [IMP] estate: improve property search and listview make sure search has some sensible defaults and make sure searching is not exact but at least add some missing information to the listview [IMP] estate: add offers to be shown by type when looking at a type of building see the amount of offers and also see the detailed list of the offers [IMP] estate: improve error handling and fix error message making sure to use the correct type of errors make output to the user more consistent [IMP] estate: add validation on CRUD operations limit creation offer to useful situations do not allow delete of properties that are currently active [IMP] estate: add properties to user page help the user to access properties by adding them to there userpage [IMP] estate: add kanban view for properties have a secondary way to show the different properties, imporve readablility and make sure values are stored correctly [IMP] estate: add kanban view for properties have a secondary way to show the different properties [IMP] estate: follow up on coding advice improve readability of code [IMP] estate: runbot message fix make sure value is stored
make life easy for the accounting by creating an invoice directly from the property when sold [IMP] estate_account: use the correct error the error that is needed is a usererror not validation error [IMP] estate_account: change type of error errors should be of correct type
4cc9d4c to
ac225f6
Compare


No description provided.