-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[ADD] estate: create a new module for real estate management #326
base: 18.0
Are you sure you want to change the base?
Conversation
635a8e6
to
30bce68
Compare
Day 1: Chapter 2: created directory structure along with manifest file for estate module Chapter 3: created estate_properties model Day 2: Chapter 4: created ir.model.access.csv to enable CRUD operation on property Chapter 5: created basic action and menu for estate property Chapter 6: created basic views for estate property i.e. list, form, search Chapter 7: created property type model and defined Many2one relation.
30bce68
to
c80414f
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 👋,
Added few comments and suggestions please have a look into it.
PR message is missing and commit messages can be improved.
Thank You :)
Added the estate.property.offer model with One2many relation to estate.property, allowing offers to be managed from the property form view. Introduced the estate.property.tag model with a Many2many relation, enabling tag creation via Settings -> Property Tags and assignment through the Many2many widget. Added computed fields: total_area (sum of garden_area and living_area) and best_price (highest offer price). Implemented an onchange handler for the garden field to set or reset related fields automatically.
f4bf858
to
ae28070
Compare
200a5a9
to
5a94e27
Compare
Day 4: Added 'sold' and 'cancel' actions to the property form view, allowing properties to be marked as sold or canceled with proper validations. Implemented logic to automatically set the selling price and buyer, when an offer is accepted. Added SQL constraints to ensure all price-related fields remain positive, with selling_price required to be greater than 90% of expected_price. Enforced unique constraints to prevent duplicate property tags and types. Added default sorting across all estate models, with sequence-based sorting for property types. Enhanced the property, offers list view with color coding and adjusted button visibility based on the property's status.
5a94e27
to
8cf6b22
Compare
Day 5: Added an Offers stat button in the property types view, which displays all offers made on properties under the selected type. Implemented restrictions on property deletion, allowing deletion only when the property's state is New or Cancelled. Extended res.users model with property_ids, enabling properties to be viewed in the user profile. Developed the estate_account module to facilitate invoicing, ensuring an invoice is generated when a property is sold, even if the user lacks access to the invoicing module. Created a Kanban view for properties, grouped by property type. Created Manager and Agent user groups with distinct access rights, along with a security rule limiting Agents to viewing only the properties they have created.
… property Day 6: Restricted property visibility for Agents to only those belonging to their company by implementing a multi-company rule. Updated access control to ensure that only users with the Manager role can view the settings menu in the estate module. Added demo data for the property, property_type, and property_offer models to facilitate testing and development. Integrated a chatter feature in the property model to track changes in the property name.
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.
Hii 👋
Here is an another quick review
class User(models.Model): | ||
_inherit = "res.users" | ||
|
||
property_ids = fields.One2many( | ||
string="Properties", | ||
comodel_name="estate.property", | ||
inverse_name="salesperson_id", | ||
domain="[('state', 'in', ['new', '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.
Add this in a different file
record.validity = (record.date_deadline - record.create_date.date()).days | ||
|
||
def action_accept_offer(self): | ||
if any([x.status == "accepted" for x in self.property_id.offer_ids]): |
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.
if any([x.status == "accepted" for x in self.property_id.offer_ids]): | |
if any([property.status == "accepted" for property in self.property_id.offer_ids]): |
copy=False | ||
) | ||
active = fields.Boolean(default=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.
Unnecessary diff
|
||
total_area = fields.Integer(string="Total Area (sqm)", compute="_compute_total_area") | ||
best_price = fields.Float(string="Best Price", 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.
Unnecessary diff
def action_sell_property(self): | ||
if self.state == "cancelled": | ||
raise UserError("Cancelled property cannot be 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.
Unnecessary diff
<field name="name" width="200px" /> | ||
<field name="property_type_id" width="150px" /> | ||
<field name="postcode" width="150px" /> | ||
<field name="tag_ids" widget="many2many_tags" width="200px" /> |
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.
Avoid using hard-coded style rules as this might not work for every screen size or for every case.
<div> Expected Price: <field name="expected_price" /> | ||
</div> | ||
<div t-if="record.state.raw_value == 'offer_received'"> Best Offer: <field | ||
name="best_price" /> | ||
</div> | ||
<div t-if="record.state.raw_value == 'offer_accepted'"> Selling Price: <field | ||
name="selling_price" /> | ||
</div> |
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.
<div> Expected Price: <field name="expected_price" /> | |
</div> | |
<div t-if="record.state.raw_value == 'offer_received'"> Best Offer: <field | |
name="best_price" /> | |
</div> | |
<div t-if="record.state.raw_value == 'offer_accepted'"> Selling Price: <field | |
name="selling_price" /> | |
</div> | |
<div> | |
Expected Price: <field name="expected_price" /> | |
</div> | |
<div t-if="record.state.raw_value == 'offer_received'"> | |
Best Offer: <field name="best_price" /> | |
</div> | |
<div t-if="record.state.raw_value == 'offer_accepted'"> | |
Selling Price: <field name="selling_price" /> | |
</div> |
Indentation
<button name="action_sell_property" type="object" string="Sold" | ||
invisible="state in ['offer_accepted', 'sold', 'cancelled']" /> |
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.
<button name="action_sell_property" type="object" string="Sold" | |
invisible="state in ['offer_accepted', 'sold', 'cancelled']" /> | |
<button name="action_sell_property" | |
invisible="state in ['offer_accepted', 'sold', 'cancelled']" | |
type="object" | |
string="Sold" | |
/> |
<button name="action_sell_property" type="object" string="Sold" | ||
invisible="state in ['new', 'offer_received', 'sold', 'cancelled']" | ||
class="btn-primary" /> | ||
<!-- Cancel button--> | ||
<button name="action_cancel_property" type="object" string="Cancel" | ||
invisible="state in ['sold', 'cancelled']" /> |
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.
Refer to above comment ☝️
if not self.buyer_id.id: | ||
raise UserError("Property without buyer cannot be sold") | ||
|
||
self.env["estate.property"].check_access("write") |
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.
Put this in try.. expect block to avoid error
Created a new Real Estate module for managing real estate properties as part of the training.