-
Notifications
You must be signed in to change notification settings - Fork 2k
[ADD] estate: added a new estate module #734
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: 18.0
Are you sure you want to change the base?
Conversation
We have added a module as an application with a model a some basic properties like (name, description, expected price ...etc) We have added security rules for read, write, create and delete actions on this model We have added menu items and UI interaction to access a form view of the records we create and we also added attributes to some properties of the model like (copy, default, readonly, required)
Changed the individual definition of menuitems to nested menu items for better readability
Added linting with flake8 and fixed some linting warnings
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.
Some linting remarks. 👍
estate/security/ir.model.access.csv
Outdated
@@ -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 |
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.
Missing blank line at the end of the file.
</p> | ||
</field> | ||
</record> | ||
|
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.
Unnecessary blank line here
</field> | ||
</record> | ||
</data> | ||
</odoo> |
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.
Blank line missing
fixed review warnings
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.
Seems good :) Just a little remark
<field name="bedrooms"/> | ||
<field name="living_area"/> | ||
<field name="facades"/> | ||
<filter string="Available" name="state" 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.
Just a nitpick :)
<filter string="Available" name="state" domain="['|',('state', '=', 'new'),('state', '=', 'offer_received')]"/> | |
<filter string="Available" name="state" domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]"/> |
@@ -79,7 +79,7 @@ | |||
<field name="bedrooms"/> | |||
<field name="living_area"/> | |||
<field name="facades"/> | |||
<filter string="Available" name="state" domain="['|',('state', '=', 'new'),('state', '=', 'offer_received')]"/> | |||
<filter string="Available" name="state" domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]"/> | |||
<group expand="1" string="Group By"> |
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.
Try to squash this commit with the previous one. No need to have a separated commit for this.
doc: https://www.git-tower.com/learn/git/faq/git-squash
In this commit we added form view with a well formated view of the created properties We also added a search view for searching by name, by selling price, etc .., added a filter by availability and a group by postcode
0cc4cde
to
7f831ed
Compare
estate/security/ir.model.access.csv
Outdated
@@ -1,2 +1,5 @@ | |||
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 | |||
estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1 | |||
estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 | |||
estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1 |
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.
Missing a blank line EOF.
- Added Estate property type model and linked it with properties as a many2one field - Added buyer and salesperson fields to a property as many2one fields - Added tags to properties as many2many fields - Added offers model and linked it with properties as one2many field
3d88445
to
4c14c9b
Compare
@@ -0,0 +1,17 @@ | |||
from odoo import models, fields | |||
|
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.
Missing a blank line. We should have 2 blank lines between imports and class definition. Check the other files. Thanks 👍
{ | ||
'name': 'Estate', | ||
'depends': ['base'], | ||
'application': 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.
Don't forget to add the license
to avoid warnings in the log.
- Added total area as computed field, as the sum of living area and garden area - Added best price as computed field calculated from the linked offers - Added 2 fields in the offer model: date_deadline and validity and linked them with inverse updates - Added an onchange callback to the garden field to set/reset the values of garden_area and garden_orientation
@naja628 You can take over :) |
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 work :)
I left some nitpicks
@@ -0,0 +1,2 @@ | |||
from . import models | |||
assert models |
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.
nitpick: not really needed but ok
estate/models/__init__.py
Outdated
from . import estate_property | ||
from . import estate_property_type, estate_property_tag, estate_property_offer | ||
|
||
assert estate_property | ||
assert estate_property_type | ||
assert estate_property_tag | ||
assert estate_property_offer |
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.
from . import estate_property | |
from . import estate_property_type, estate_property_tag, estate_property_offer | |
assert estate_property | |
assert estate_property_type | |
assert estate_property_tag | |
assert estate_property_offer | |
from . import estate_property | |
from . import estate_property_type | |
... |
nitpick: this syntax is fine but in odoo code, __init__
files usually look like this
estate/models/estate_property.py
Outdated
|
||
name = fields.Char(required=True) | ||
description = fields.Text() | ||
property_tags_ids = fields.Many2many("estate.property.tag") |
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.
nitpick:
property_tags_ids = fields.Many2many("estate.property.tag") | |
property_tag_ids = fields.Many2many("estate.property.tag", string="Property Tags") |
for x2m the convention is usually to keep the base name in the singular (since _ids
is already plural)
<field name="bedrooms"/> | ||
<field name="living_area"/> | ||
<field name="facades"/> | ||
<filter string="Available" name="state" 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.
just for info this should be equivalent to
<filter string="Available" name="state" domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]"/> | |
<filter string="Available" name="state" domain="[('state', 'in', ['new', 'offer_received'])]"/> |
- Added 2 buttons: cancel and set a property as sold - Added 2 buttons for the offers, accept and refuse - Once an offer is accepted, the selling price and the Buyer are Set in the property info
- Added SQL constraints for : - property expected price must be strictly positive - property selling price must be positive - offer price must be strictly positive - property tag and type must be unique - Added python constraint for selling price must not be lower than 90% of expected price
- Added inline views to show properties of a type in a list (only shows title, expected price, status) - Added widget statusbar to have a better view of the status of the property - Added default list ordering and manual ordering with handle - Added conditional attributes like invisible and readonly to create dynamic forms that adapt to data context - Added aditable inline editing to the lists - Added default filters for search views with search_defaul_Availability and custom search logic for the surface with filter_domain - Added a stat button to quickly access all offers of a given property type
0fc52fe
to
8826e2b
Compare
Fixed views imports in the data field in the manifest file
- Overrided CRUD methods for property deletion and offer creation logic (don't allow deletion of ongoing properties, and don't create offers lower than the existing ones) - Add properties field to res.user model and add a view to see properties from the user list view
- Added a new link module estate_account responsible for creating an invoice when the sold button is created - Overriden the action_set_sold method to add the creation of the invoice in it
Added kanban view grouped by property type for properties
68304dd
to
d270336
Compare
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 work !
I left some comments
estate/models/__init__.py
Outdated
|
||
assert estate_property | ||
assert estate_property_type | ||
assert estate_property_tag | ||
assert estate_property_offer | ||
assert res_users |
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.
not needed
estate/models/estate_property.py
Outdated
from odoo import api, models, fields | ||
from odoo.exceptions import UserError, ValidationError | ||
from dateutil.relativedelta import relativedelta | ||
|
||
from odoo.tools.float_utils import float_compare, float_is_zero |
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.
from odoo import api, models, fields | |
from odoo.exceptions import UserError, ValidationError | |
from dateutil.relativedelta import relativedelta | |
from odoo.tools.float_utils import float_compare, float_is_zero | |
from dateutil.relativedelta import relativedelta | |
from odoo import api, models, fields | |
from odoo.exceptions import UserError, ValidationError | |
from odoo.tools.float_utils import float_compare, float_is_zero |
nitpick: we like to do 2 groups of import for external and internal imports
estate/models/estate_property.py
Outdated
postcode = fields.Char() | ||
date_availability = fields.Date( | ||
copy=False, | ||
default=_default_date_availability() |
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.
default=_default_date_availability() | |
default=_default_date_availability |
Here calling the function means it will called only once instead of at every new record creation
estate/models/estate_property.py
Outdated
def action_set_sold(self): | ||
for record in self: | ||
if record.state == 'cancelled': | ||
raise UserError("Canceled properties cannot be set as sold.") |
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.
try to wrap user facing string in a call to the _
function so the translation system sees them.
estate/models/estate_property.py
Outdated
return types.search([]) # this is equivalent to return self.env['estate.property.type'].search([]) | ||
|
||
def action_set_sold(self): | ||
for record in self: |
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.
nitpick: prefer descriptive names for the loop variable when looping over recordsets
property_id = val.get('property_id') | ||
price = val.get('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.
by default, get
will return None
if no 2nd argument is specified but you assume they exist later in the code.
property_id = val.get('property_id') | |
price = val.get('price') | |
property_id = val.get('property_id') | |
price = val.get('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.
ici, dans ce cas, qu'est ce que je devrais faire pour palier à ce problème
est ce que je dois mettre une valeur par défaut ou afficher une erreur quand le get return None
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.
I think here, for price
a fallback makes sense.
For property_id
it's require=True
(and has no default
) so you will already get an error if it's not in the keys (in the super().create
probably) -- but I think I'd still skip some of the logic when it's not defined (i mean with a condition for example)
<field name="facades"/> | ||
<filter name="available" string="Available" domain="[('state', 'in', ['new', 'offer_received'])]"/> | ||
<group expand="1" string="Group By"> | ||
<filter string="Postcode" name="postcode" context="{'group_by':'postcode'}"/> |
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.
nitpick:
<filter string="Postcode" name="postcode" context="{'group_by':'postcode'}"/> | |
<filter string="Postcode" name="postcode" context="{'group_by': 'postcode'}"/> |
estate/views/res_users_views.xml
Outdated
</field> | ||
</record> | ||
</data> | ||
</odoo> |
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.
missing eol character (editor config)
'data': [ | ||
], | ||
'installable': True, | ||
'application': False, |
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.
'application': False, | |
'application': False, | |
'auto_install': True, |
brigde modules typically contain functionally that we want to automatically "appear" when the dependencies are all installed
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.
Missing keys: 'author', etc
c93ae8a
to
47ebfcf
Compare
- Removed un necessary assert (for the unused imports in the __init__ files) - Renamed looping variables' names for better readability (property instead of record, and offer instead of record) - Added auto_install property to True in the estate_account link module (used to auto install dependencies when we install estate_account)
47ebfcf
to
77d0bd8
Compare
- Added Card and Counter components - Added markup html - Added props validation in Card
- Added todo list (with adding and deleting functionnality) - Added dynamic attributes for setting a todo item to Done - Added Focusing the input - Modified the Card component to accept a default slot as content instead of a simple text - Added toggle hide or show the content of the card
- Added dashboard layout - Added a statistics service for getting statistics using rpc call - Cached the statistics using memoize
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 work again !
I left some comments
/** @odoo-module **/ | ||
|
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.
These are no longer needed.
you can also remove them in the files they give you ^^
title: String, | ||
slots: { | ||
type: Object, | ||
} |
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.
nitpick:
} | |
}, |
static props = { | ||
title: String, | ||
slots: { | ||
type: Object, |
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.
here if you don't make it optional something like <Card .../>
will give an error and you will have to do <Card ...></Card>
this.state.isOpen = !this.state.isOpen; | ||
} | ||
|
||
static template = "awesome_owl.card"; |
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.
niptpicks:
- move to the top of the class
- prefer PascalCase for template names
static template = "awesome_owl.card"; | |
static template = "awesome_owl.Card"; |
/** @odoo-module **/ | ||
|
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.
/** @odoo-module **/ |
static components = { TodoList, Card, Counter }; | ||
|
||
html = markup("<div>some content</div>") | ||
counters_sum = useState({ value: 0 }); |
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.
nitpick: js-side use camelCase for variables
counters_sum = useState({ value: 0 }); | |
countersSum = useState({ value: 0 }); |
incrementSum() { | ||
this.counters_sum.value++; | ||
} |
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're defining it correctly but you're not actually using it in your playground
|
||
.o_dashboard { | ||
background-color: $bg-gray; | ||
} |
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.
nitpick: missing eol character
|
||
class AwesomeDashboard extends Component { | ||
static template = "awesome_dashboard.AwesomeDashboard"; | ||
static components = { | ||
Layout, | ||
DashboardItem |
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.
nitpick:
DashboardItem | |
DashboardItem, |
<t t-name="awesome_owl.todo_list"> | ||
<div class="card d-inline-block m-2" style="width: 300px;"> | ||
<input t-ref="input" t-on-keyup="onInputEnter"/> | ||
<t t-foreach="this.todos" t-as="i" t-key="i.id"> |
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.
<t t-foreach="this.todos" t-as="i" t-key="i.id"> | |
<t t-foreach="this.todos" t-as="todo" t-key="todo.id"> |
We have added a module as an application with a model a some basic properties like (name, description, expected price ...etc)
We have added security rules for read, write, create and delete actions on this model
We have added menu items and UI interaction to access a form view of the records we create and we also added attributes to some properties of the model like (copy, default, readonly, required)