Skip to content

[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

Open
wants to merge 18 commits into
base: 18.0
Choose a base branch
from

Conversation

abeg-odoo
Copy link

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)

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)
@robodoo
Copy link

robodoo commented Apr 23, 2025

Pull request status dashboard

Changed the individual definition of menuitems to nested menu items for better readability
Added linting with flake8 and fixed some linting warnings
@abeg-odoo abeg-odoo marked this pull request as ready for review April 23, 2025 10:44
Copy link

@SergeBayet SergeBayet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some linting remarks. 👍

@@ -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

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>

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>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank line missing

Copy link

@SergeBayet SergeBayet left a 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')]"/>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nitpick :)

Suggested change
<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">

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
@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from 0cc4cde to 7f831ed Compare April 24, 2025 06:35
@@ -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

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
@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from 3d88445 to 4c14c9b Compare April 24, 2025 09:56
@@ -0,0 +1,17 @@
from odoo import models, fields

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,

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
@SergeBayet
Copy link

@naja628 You can take over :)

Copy link

@naja628 naja628 left a 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
Copy link

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

Comment on lines 1 to 7
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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


name = fields.Char(required=True)
description = fields.Text()
property_tags_ids = fields.Many2many("estate.property.tag")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick:

Suggested change
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')]"/>
Copy link

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

Suggested change
<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
@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from 0fc52fe to 8826e2b Compare April 25, 2025 12:06
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
@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from 68304dd to d270336 Compare April 28, 2025 15:23
Copy link

@naja628 naja628 left a 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

Comment on lines 6 to 11

assert estate_property
assert estate_property_type
assert estate_property_tag
assert estate_property_offer
assert res_users
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

Comment on lines 1 to 5
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

postcode = fields.Char()
date_availability = fields.Date(
copy=False,
default=_default_date_availability()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

def action_set_sold(self):
for record in self:
if record.state == 'cancelled':
raise UserError("Canceled properties cannot be set as sold.")
Copy link

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.

return types.search([]) # this is equivalent to return self.env['estate.property.type'].search([])

def action_set_sold(self):
for record in self:
Copy link

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

Comment on lines 35 to 36
property_id = val.get('property_id')
price = val.get('price')
Copy link

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.

Suggested change
property_id = val.get('property_id')
price = val.get('price')
property_id = val.get('property_id')
price = val.get('price')

Copy link
Author

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

Copy link

@naja628 naja628 Apr 30, 2025

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'}"/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick:

Suggested change
<filter string="Postcode" name="postcode" context="{'group_by':'postcode'}"/>
<filter string="Postcode" name="postcode" context="{'group_by': 'postcode'}"/>

</field>
</record>
</data>
</odoo>
Copy link

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,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'application': False,
'application': False,
'auto_install': True,

brigde modules typically contain functionally that we want to automatically "appear" when the dependencies are all installed

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing keys: 'author', etc

@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from c93ae8a to 47ebfcf Compare April 29, 2025 15:53
- 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)
@abeg-odoo abeg-odoo force-pushed the 18.0-add-estate-module-abeg branch from 47ebfcf to 77d0bd8 Compare April 30, 2025 08:27
- 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
Copy link

@naja628 naja628 left a 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

Comment on lines +1 to +2
/** @odoo-module **/

Copy link

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,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick:

Suggested change
}
},

static props = {
title: String,
slots: {
type: Object,
Copy link

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";
Copy link

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
Suggested change
static template = "awesome_owl.card";
static template = "awesome_owl.Card";

Comment on lines +1 to +2
/** @odoo-module **/

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @odoo-module **/

static components = { TodoList, Card, Counter };

html = markup("<div>some content</div>")
counters_sum = useState({ value: 0 });
Copy link

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

Suggested change
counters_sum = useState({ value: 0 });
countersSum = useState({ value: 0 });

Comment on lines +16 to +18
incrementSum() {
this.counters_sum.value++;
}
Copy link

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;
}
Copy link

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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick:

Suggested change
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">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<t t-foreach="this.todos" t-as="i" t-key="i.id">
<t t-foreach="this.todos" t-as="todo" t-key="todo.id">

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants