@@ -42,8 +46,8 @@
+
-
From e6f7271ec832c29f5b67f845f92734b8e2e80650 Mon Sep 17 00:00:00 2001
From: Rs-appez <37080870+Rs-appez@users.noreply.github.com>
Date: Thu, 17 Sep 2026 16:45:07 +0200
Subject: [PATCH 36/40] [IMP] estate : add btn to accept/refuse offer
---
estate/models/estate_property_offer.py | 18 +++++++++++++++++-
estate/views/estate_property_offer_views.xml | 4 ++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py
index 1a560f2fe19..501022a17aa 100644
--- a/estate/models/estate_property_offer.py
+++ b/estate/models/estate_property_offer.py
@@ -27,4 +27,20 @@ def _compute_deadline(self):
def _inverse_deadline(self):
for record in self:
create_date = record.create_date or fields.Date.today()
- record.validity = (record.date_deadline - fields.Date.to_date(create_date)).days
+ record.validity = (
+ record.date_deadline - fields.Date.to_date(create_date)
+ ).days
+
+ # ------------------------------------------------------------
+ # ACTIONS
+ # ------------------------------------------------------------
+
+ def action_accept_offer(self):
+ for record in self:
+ record.status = "accepted"
+ return True
+
+ def action_refuse_offer(self):
+ for record in self:
+ record.status = "refused"
+ return True
diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml
index 0f4da46e00f..898973540d6 100644
--- a/estate/views/estate_property_offer_views.xml
+++ b/estate/views/estate_property_offer_views.xml
@@ -28,6 +28,10 @@
+
+
From b59e0125391f89b61e128e126cdc650aa3d1187a Mon Sep 17 00:00:00 2001
From: Rs-appez <37080870+Rs-appez@users.noreply.github.com>
Date: Fri, 18 Sep 2026 09:28:39 +0200
Subject: [PATCH 37/40] [IMP] estate : asign price and buyer to property when
offer is accepted
---
estate/models/estate_property_offer.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py
index 501022a17aa..2a619b55df9 100644
--- a/estate/models/estate_property_offer.py
+++ b/estate/models/estate_property_offer.py
@@ -38,6 +38,13 @@ def _inverse_deadline(self):
def action_accept_offer(self):
for record in self:
record.status = "accepted"
+ record.property_id.selling_price = record.price
+ record.property_id.buyer = record.partner_id
+
+ for offer in record.property_id.offer_ids:
+ if offer != record:
+ offer.status = "refused"
+
return True
def action_refuse_offer(self):
From 0e18f8b89fee4960a6142a7da1d88d315f9481a9 Mon Sep 17 00:00:00 2001
From: Rs-appez <37080870+Rs-appez@users.noreply.github.com>
Date: Fri, 18 Sep 2026 10:04:28 +0200
Subject: [PATCH 38/40] [IMP] estate : add sql constraint on model
---
estate/models/estate_property.py | 8 ++++++++
estate/models/estate_property_offer.py | 4 ++++
estate/models/estate_property_tag.py | 4 ++++
estate/models/estate_property_type.py | 4 ++++
4 files changed, 20 insertions(+)
diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py
index 3c7303aea26..0ee764277aa 100644
--- a/estate/models/estate_property.py
+++ b/estate/models/estate_property.py
@@ -5,6 +5,14 @@
class Property(models.Model):
_name = "estate.property"
_description = "Estate Property"
+ _check_positive_expected_price = models.Constraint(
+ "CHECK(expected_price > 0)",
+ "The expected price must be stricly positive",
+ )
+ _check_positive_selling_price = models.Constraint(
+ "CHECK(selling_price >= 0)",
+ "The selling price must be positive",
+ )
name = fields.Char(required=True)
postcode = fields.Char()
diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py
index 2a619b55df9..648e2fe0225 100644
--- a/estate/models/estate_property_offer.py
+++ b/estate/models/estate_property_offer.py
@@ -4,6 +4,10 @@
class PropertyType(models.Model):
_name = "estate.property.offer"
_description = "Estate Property Offer"
+ _check_positive_price = models.Constraint(
+ "CHECK(price > 0)",
+ "The offer price must be stricly positive",
+ )
price = fields.Float()
status = fields.Selection(
diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py
index c1c8cee01b3..facfa0f24fd 100644
--- a/estate/models/estate_property_tag.py
+++ b/estate/models/estate_property_tag.py
@@ -4,5 +4,9 @@
class PropertyType(models.Model):
_name = "estate.property.tag"
_description = "Estate Property Tag"
+ _check_unique_name = models.Constraint(
+ "UNIQUE (name)",
+ "The name must be unique",
+ )
name = fields.Char(required=True)
diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py
index 3519fec3eaf..5b13cc628ae 100644
--- a/estate/models/estate_property_type.py
+++ b/estate/models/estate_property_type.py
@@ -4,5 +4,9 @@
class PropertyType(models.Model):
_name = "estate.property.type"
_description = "Estate Property Type"
+ _check_unique_name = models.Constraint(
+ "UNIQUE (name)",
+ "The name must be unique",
+ )
name = fields.Char(required=True)
From 8ae7b23a46e1825c122ec8dcbafef03cf8ce4ea7 Mon Sep 17 00:00:00 2001
From: Rs-appez <37080870+Rs-appez@users.noreply.github.com>
Date: Fri, 18 Sep 2026 10:36:22 +0200
Subject: [PATCH 39/40] [IMP] estate : add constraint on the selling price
---
estate/models/estate_property.py | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py
index 0ee764277aa..d413c4eb004 100644
--- a/estate/models/estate_property.py
+++ b/estate/models/estate_property.py
@@ -1,5 +1,8 @@
from odoo import _, api, fields, models
-from odoo.exceptions import UserError
+from odoo.exceptions import UserError, ValidationError
+from odoo.tools.float_utils import float_compare, float_is_zero
+
+THRESOLD_MIN_SELLING_POURCENT = 90
class Property(models.Model):
@@ -83,6 +86,29 @@ def _onchange_garden(self):
self.garden_area = 0
self.garden_orientation = None
+ # ------------------------------------------------------------
+ # CONSTRAINS
+ # ------------------------------------------------------------
+
+ @api.constrains("selling_price")
+ def _check_selling_price(self):
+ for record in self:
+ if not float_is_zero(record.selling_price, 2):
+ if (
+ float_compare(
+ record.selling_price,
+ record.expected_price * (THRESOLD_MIN_SELLING_POURCENT / 100),
+ 2,
+ )
+ < 0
+ ):
+ raise ValidationError(
+ _(
+ "The selling price cannot be lower than %s%% of the expected price",
+ )
+ % THRESOLD_MIN_SELLING_POURCENT,
+ )
+
# ------------------------------------------------------------
# ACTIONS
# ------------------------------------------------------------
From d19029cb1d63e7029b68ebeb21f2bea24ab9ac18 Mon Sep 17 00:00:00 2001
From: Rs-appez <37080870+Rs-appez@users.noreply.github.com>
Date: Fri, 18 Sep 2026 10:53:32 +0200
Subject: [PATCH 40/40] [IMP] estate : add inline property in property type
view
---
estate/models/estate_property_type.py | 1 +
estate/views/estate_property_type_views.xml | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py
index 5b13cc628ae..b032792e7a4 100644
--- a/estate/models/estate_property_type.py
+++ b/estate/models/estate_property_type.py
@@ -10,3 +10,4 @@ class PropertyType(models.Model):
)
name = fields.Char(required=True)
+ property_ids = fields.One2many("estate.property", "property_type_id", "Property")
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml
index 048b808ba00..f32a65ab1ec 100644
--- a/estate/views/estate_property_type_views.xml
+++ b/estate/views/estate_property_type_views.xml
@@ -15,6 +15,17 @@
+