Add Estate Property Model#1229
Conversation
| @@ -0,0 +1,9 @@ | |||
| <odoo> | |||
| <!-- Here id = unique id in DB, name = "what will be shown on screen" --> | |||
There was a problem hiding this comment.
Writing a comment is good, but no need to write a comment here. It's only required when there is complex computation, etc.
| garden_area = fields.Integer(string="Garden_area") | ||
| garden_orientation = fields.Selection(string="Garden Orientation", selection=[("north", "North"), ("east", "East"), ("west", "West"), ("south", "South")]) | ||
|
|
||
| # If it is false then newly created record won't be appear. but record is created when active is set true record will appear. |
There was a problem hiding this comment.
Writing a comment is good, but no need to write a comment here. It's only required when there is complex computation, etc.
|
|
||
| # If it is false then newly created record won't be appear. but record is created when active is set true record will appear. | ||
| active = fields.Boolean("Active", default=True) | ||
| # State can get selected and as copy is set False in duplicate it cannot get copied |
There was a problem hiding this comment.
Writing a comment is good, but no need to write a comment here. It's only required when there is a complex computation, etc.
| # If it is false then newly created record won't be appear. but record is created when active is set true record will appear. | ||
| active = fields.Boolean("Active", default=True) | ||
| # State can get selected and as copy is set False in duplicate it cannot get copied | ||
| state = fields.Selection(string="state", selection=[("new", "New"), ("offer received", "Offer Received"), ("accepted", "Accepted"), ("sold", "Sold"), ("cancelled", "Cancelled")], default="new", copy=False) |
Enables users to access and use estate management features directly within the system. Simplifies setup so users can quickly start managing property-related tasks without additional configuration. Chapter 1: Architecture Overview
Allows users to store and manage detailed property information in a structured way. Improves tracking of property-related activities by linking them with recurring plans, making workflows more organized and efficient. Chapter 2: A NEW MODEL
Enables users to maintain structured property records with all necessary details in one place. Improves workflow efficiency by connecting properties with suggestion from recurring plans for better tracking and management. Chapter 3: Model and some basic fields
Ensures users have appropriate access to estate data based on their roles. Improves data security and prevents unauthorized actions while allowing smooth and controlled interactions with the system. Chapter 4: Security : A brief introduction
Provides users with controlled access to perform necessary actions like viewing, editing, and deleting data. Ensures a secure and reliable experience by preventing unauthorized operations while maintaining usability. Chapter 4: Security : A brief
Allows users to easily access and navigate estate data through a dedicated interface. Improves usability by providing a clear and structured view for managing records. Chapter 5: Finally some UI to play with.
3a7112b to
4f768a0
Compare
Added menu hierarchy to improve navigation and feature accessibility for users to navigate using provided views Chapter 5: Finally some UI to play with
Added active and state fields to ensure better record visibility and track property status clearly for users Chapter 5: Finally some UI to play with
Added list view to help users quickly browse, compare, and manage multiple properties efficiently Chapter 6: Basic Views
Added form view for detailed property management enables users to easily view, create, and update property records improves data entry accuracy and overall usability Chapter 6: Basic Views
Added search view with state filters and postcode grouping helps users quickly find and organize properties based on status and location improves efficiency in browsing and managing large datasets Chapter 6: Basic Views
link property with property type using Many2one relationship allows users to categorize properties for better organization and filtering improves data structure and usability across the estate module Chapter 7: Relations between models
Added property tags (Many2Many) to enhance property classification and flexibility. Enables users to quickly filter and identify properties based on features like cozy, renovated, etc.Improves searchability and overall user experience. Chapter 7: Relations between model : Many2many
Allows users to view and manage all buyer offers in one place, making it easier to compare prices and track offer status. Improves decision-making and overall property management experience. Chapter 7: Relations between model : One2many
Added computed field for total area by summing garden and living space, giving users a quick and accurate view of overall property size. Chapter 8: Computed fields and onChanges
Auto-updates garden area and orientation based on garden selection, reducing manual input and preventing user errors.Clears dependent fields when disabled, ensuring data consistency and a cleaner user experience. Chapter : 8 Computed fields and onChanges
Add function to surface the best (highest) price prominently in the header. Improves user experience by making optimal pricing instantly visible without extra effort. Chapter 8: Computed fields and onChanges
Add computed validity & deadline fields with inverse sync for seamless updates that ensures accurate offer timelines and reduces manual date calculations for users. Chapter : 8 Computed fields and onChanges
Helps users efficiently manage offers while automatically assigning buyer and final price to the property. Chapter 9 : Ready For Some Action?
Improves data integrity by restricting invalid transitions saved offers cannot be cancelled and cancelled offers cannot be saved. Chapter 9 : Ready For Some Action?
ccc16fb to
944e1e8
Compare
Improve data integrity by enforcing positive price constraints and correct types. Prevents negative or invalid pricing values from being stored in the database Chapter 10: Constraint
944e1e8 to
a8dc03b
Compare
ensure selling price is at least 90% of expected price by adding python constraint to prevent very low offers and helps users maintain fair property pricing Chapter 10: Constraint
Improve UI in real estate module by adding inline list views and statusbar widget for clearer data display. Enhance user experience with cleaner layouts and better state visibility for properties. chapter 11: Add the sprinkles
Improved user experience by restricting property type edits, adding colorized tags using color, and dynamically showing/hiding fields and buttons based on state. using invisible This reduces invalid actions, simplifies the interface, and ensures cleaner data entry. ch.11: Add the sprinklers
fe852b7 to
fa6668f
Compare
bit-odoo
left a comment
There was a problem hiding this comment.
Hello,
I have added some new comments. Also, can you adapt the changes that are suggested to you in previous comments?
Thanks
| _order = "id desc" # to order how it is presented on list view in which order | ||
|
|
||
| name = fields.Char(string="Name", required=True, default="Unknown") | ||
| last_seen = fields.Datetime("Last Seen", default=fields.Datetime.now) |
| date_availability = fields.Date( | ||
| string="Available From", | ||
| copy=False, | ||
| default=fields.Date.add(fields.Date.today(), months=3), |
There was a problem hiding this comment.
The default value is computed just once when the server is started, not every time a record is created. You can pass a lambda to default, and it will be computed on each record creation
| postcode = fields.Char(string="Postcode", required=True) | ||
| expected_price = fields.Float(string="Expected Price") | ||
| selling_price = fields.Float(string="Selling Price", readonly=True) | ||
| bedrooms = fields.Integer(string="Bedrooms", default=2) | ||
| living_area = fields.Integer(string="Living Area") | ||
| facades = fields.Integer(string="Facades") | ||
| garage = fields.Boolean(string="Garage") | ||
| garden = fields.Boolean(string="Garden") | ||
| garden_area = fields.Integer(string="Garden area") |
There was a problem hiding this comment.
Odoo generates a string by default. If the technical name and the string are the same, then there is no need to define the string.
| @api.depends("garden_area", "living_area") | ||
| def _compute_total(self): | ||
| for record in self: | ||
| record.total_area = record.garden_area + record.living_area | ||
|
|
||
| @api.depends("offer_ids.price") | ||
| def _compute_best_price(self): | ||
| for record in self: | ||
| prices = record.mapped("offer_ids.price") | ||
| record.best_price = max(prices) if prices else 0 | ||
|
|
||
| # to add when garden is clicked then its area and orientation is set to default values. works on decorators concepts | ||
| @api.onchange("garden") | ||
| def _onchange_garden(self): | ||
| if self.garden: | ||
| self.garden_area = 10 | ||
| self.garden_orientation = "north" | ||
| else: | ||
| self.garden_area = 0 | ||
| self.garden_orientation = False | ||
|
|
||
| def action_cancel_offer(self): | ||
| for record in self: | ||
| if record.state == "sold": | ||
| raise UserError("Saved properties can't be cancelled") | ||
| else: | ||
| record.state = "cancelled" | ||
| record.status = "cancelled" | ||
|
|
||
| def action_save_offer(self): | ||
| for record in self: | ||
| if record.state == "cancelled": | ||
| raise UserError("Cancelled properties can't be saved") | ||
| else: | ||
| record.state = "sold" | ||
| record.status = "sold" | ||
|
|
||
| _check_expected_price = models.Constraint( | ||
| "CHECK(expected_price > 0)", "Expected price must be positive" | ||
| ) | ||
|
|
||
| _check_selling_price = models.Constraint( | ||
| "CHECK(selling_price > 0)", "Selling Price must be positive" | ||
| ) |
There was a problem hiding this comment.
Can you followe the coding guidelines?
https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#symbols-and-conventions
| validity = fields.Integer(string="Validity", default=7) | ||
| date_deadline = fields.Date( | ||
| string="Deadline", | ||
| compute="_compute_deadline", |
There was a problem hiding this comment.
can you followe the coding guidelines for naming?
| if records.date_deadline: | ||
| records.validity = (records.date_deadline - default_date).days | ||
|
|
||
| def save_offer(self): |
There was a problem hiding this comment.
Can you followe the coding guidelines for naming?
|
i will implement suggested changes by end of the day
…On Thu, Apr 23, 2026 at 11:48 AM Bhaumik Pittalia ***@***.***> wrote:
***@***.**** commented on this pull request.
Hello,
I have added some new comments. Also, can you adapt the changes that are
suggested to you in previous comments?
Thanks
------------------------------
In estate/models/estate_property.py
<#1229?email_source=notifications&email_token=CA6NRT4SGLTCZ6LQNJWWTOT4XGYRNA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128671105>
:
> @@ -0,0 +1,143 @@
+from odoo import fields, models, api
+from odoo.exceptions import UserError, ValidationError
+
+
+class EstateProperty(models.Model):
+ _name = "estate.property"
+ _description = "Estate Property"
+ _order = "id desc" # to order how it is presented on list view in which order
+
+ name = fields.Char(string="Name", required=True, default="Unknown")
+ last_seen = fields.Datetime("Last Seen", default=fields.Datetime.now)
What is the purpose of these fields?
------------------------------
In estate/models/estate_property.py
<#1229?email_source=notifications&email_token=CA6NRT4SGLTCZ6LQNJWWTOT4XGYRNA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128673473>
:
> +from odoo import fields, models, api
+from odoo.exceptions import UserError, ValidationError
+
+
+class EstateProperty(models.Model):
+ _name = "estate.property"
+ _description = "Estate Property"
+ _order = "id desc" # to order how it is presented on list view in which order
+
+ name = fields.Char(string="Name", required=True, default="Unknown")
+ last_seen = fields.Datetime("Last Seen", default=fields.Datetime.now)
+ description = fields.Text(string="Description")
+ date_availability = fields.Date(
+ string="Available From",
+ copy=False,
+ default=fields.Date.add(fields.Date.today(), months=3),
The default value is computed just once when the server is started, not
every time a record is created. You can pass a lambda to default, and it
will be computed on each record creation
------------------------------
In estate/models/estate_property.py
<#1229?email_source=notifications&email_token=CA6NRT4SGLTCZ6LQNJWWTOT4XGYRNA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128675304>
:
> + postcode = fields.Char(string="Postcode", required=True)
+ expected_price = fields.Float(string="Expected Price")
+ selling_price = fields.Float(string="Selling Price", readonly=True)
+ bedrooms = fields.Integer(string="Bedrooms", default=2)
+ living_area = fields.Integer(string="Living Area")
+ facades = fields.Integer(string="Facades")
+ garage = fields.Boolean(string="Garage")
+ garden = fields.Boolean(string="Garden")
+ garden_area = fields.Integer(string="Garden area")
Odoo generates a string by default. If the technical name and the string
are the same, then there is no need to define the string.
------------------------------
In estate/models/estate_property.py
<#1229?email_source=notifications&email_token=CA6NRT4SGLTCZ6LQNJWWTOT4XGYRNA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128682629>
:
> + @api.depends("garden_area", "living_area")
+ def _compute_total(self):
+ for record in self:
+ record.total_area = record.garden_area + record.living_area
+
+ @api.depends("offer_ids.price")
+ def _compute_best_price(self):
+ for record in self:
+ prices = record.mapped("offer_ids.price")
+ record.best_price = max(prices) if prices else 0
+
+ # to add when garden is clicked then its area and orientation is set to default values. works on decorators concepts
+ @api.onchange("garden")
+ def _onchange_garden(self):
+ if self.garden:
+ self.garden_area = 10
+ self.garden_orientation = "north"
+ else:
+ self.garden_area = 0
+ self.garden_orientation = False
+
+ def action_cancel_offer(self):
+ for record in self:
+ if record.state == "sold":
+ raise UserError("Saved properties can't be cancelled")
+ else:
+ record.state = "cancelled"
+ record.status = "cancelled"
+
+ def action_save_offer(self):
+ for record in self:
+ if record.state == "cancelled":
+ raise UserError("Cancelled properties can't be saved")
+ else:
+ record.state = "sold"
+ record.status = "sold"
+
+ _check_expected_price = models.Constraint(
+ "CHECK(expected_price > 0)", "Expected price must be positive"
+ )
+
+ _check_selling_price = models.Constraint(
+ "CHECK(selling_price > 0)", "Selling Price must be positive"
+ )
Can you followe the coding guidelines?
https://www.odoo.com/documentation/19.0/contributing/development/coding_guidelines.html#symbols-and-conventions
------------------------------
In estate/models/estate_property_offer.py
<#1229?email_source=notifications&email_token=CA6NRT6P5IEGW74UA2AELAD4XGYRPA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128691479>
:
> + _description = "Estate Property Offer"
+ _order = "price desc"
+
+ name = fields.Char(string="Property Offer", required=True)
+ price = fields.Integer(string="Price", required=True)
+ status = fields.Selection(
+ string="Status",
+ selection=[("accepted", "Accepted"), ("refused", "Refused")],
+ copy=False,
+ )
+ partner_id = fields.Many2one("res.partner", string="Partner", required=True)
+ property_id = fields.Many2one("estate.property", string="Property", required=True)
+ validity = fields.Integer(string="Validity", default=7)
+ date_deadline = fields.Date(
+ string="Deadline",
+ compute="_compute_deadline",
can you followe the coding guidelines for naming?
------------------------------
In estate/models/estate_property_offer.py
<#1229?email_source=notifications&email_token=CA6NRT6P5IEGW74UA2AELAD4XGYRPA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJL3QOJPXEZLWNFSXOX3DNRUWG2Y#discussion_r3128692618>
:
> + else fields.Date.today()
+ )
+ records.date_deadline = fields.Date.add(default_date, days=records.validity)
+
+ # Inverse is triggered when the computed field is written (usually during save),not during live editing.
+ def _inverse_deadline(self):
+ for records in self:
+ default_date = (
+ records.create_date.date()
+ if records.create_date
+ else fields.Date.today()
+ )
+ if records.date_deadline:
+ records.validity = (records.date_deadline - default_date).days
+
+ def save_offer(self):
Can you followe the coding guidelines for naming?
—
Reply to this email directly, view it on GitHub
<#1229?email_source=notifications&email_token=CA6NRT6UCQLDG5O4SS7QORD4XGYRPA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTIMJWGAYDKMRXHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJPLQOJPXEZLWNFSXOX3ON52GSZTJMNQXI2LPNZZV6Y3MNFRWW#pullrequestreview-4160052797>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/CA6NRTZKPRZ5FT2SCCE2LBD4XGYRPAVCNFSM6AAAAACXLZCJC2VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHM2DCNRQGA2TENZZG4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
This feature gives users quick visibility into how many properties exist in each category, saving time and reducing manual counting. It improves navigation by letting them jump directly to the relevant property list with one click. This makes managing and reviewing properties more efficient. Overall, it enhances usability and decision-making when working with property categories. ch. 11 : Add the sprinkles
This feature gives users quick visibility into how many properties exist in each category, saving time and reducing manual counting. It improves navigation by letting them jump directly to the relevant property list with one click. This makes managing and reviewing properties more efficient. Overall, it enhances usability and decision-making when working with property categories. ch. 11 : Add the sprinkles
652c3fd to
0724a0f
Compare
When a new offer is created, the property status changes to “Offer Received.” It differentiate the properties from new and offer received. If someone makes an offer lower than the existing price, it raises an error. To makes sure only better offers are accepted. It helps users get the best price for their property. ch. 12 : Inheritance
Adds a Real Estate page in the Salesperson form to view all assigned properties and their offers. Users can quickly see how many offers each salesperson is handling.Improves tracking and workload distribution across the team. Helps managers make better decisions and ensures efficient follow-ups. ch. 12 : Inheritance
created estate account module to generate invoices for sold properties. it will automates the invoicing process, reducing manual effort and errors. ch. 13 : Interact with other modules
2d95b70 to
d43058b
Compare
Automatically generates an invoice using invoice functionality, when a property is marked as sold. Reduces manual effort for users and administrators in creating invoices. ch. 13: Interact with other modules

Created the estate.property model with required fields and attributes, with the reference of crm_recurring_plan.
Chapters 1 to 3 completed, and the Estate module has been created with the estate_property model.
Changes