Skip to content

Commit 0164016

Browse files
committed
[IMP] estate: improve offer handling and property visibility rules
- Expired offers are now automatically refused, ensuring cleaner records and preventing outdated offers from staying active. - "Sold" and "Cancelled" actions are now hidden when the property is already in a sold or cancelled state, avoiding redundant operations. - Bedrooms, living area, and description fields are now read-only once the property is sold or cancelled, ensuring data consistency. - Price column in the offers list view is now displayed left-aligned for better readability, as numeric fields are right-aligned by default. - Minor layout adjustments applied to XML views for improved consistency.
1 parent a7acb9e commit 0164016

14 files changed

+95
-49
lines changed

estate/__manifest__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
"sequence": 1,
66
"data": [
77
"security/ir.model.access.csv",
8+
"data/ir_cron_data.xml",
89
"views/estate_property_views.xml",
910
"views/estate_property_offer_views.xml",
1011
"views/estate_property_type_views.xml",
1112
"views/estate_property_tag_views.xml",
1213
"views/estate_menus.xml",
1314
"views/res_users_views.xml",
1415
],
16+
'assets': {
17+
'web.assets_backend': [
18+
'estate/static/src/css/custom.css',
19+
],
20+
},
1521
"license": "LGPL-3",
1622
"application": True,
1723
"installable": True,

estate/data/ir_cron_data.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<data noupdate="1">
4+
<record id="ir_cron_estate_property_offer_expire" model="ir.cron">
5+
<field name="name">Expire Property Offers</field>
6+
<field name="model_id" ref="model_estate_property_offer"></field>
7+
<field name="state">code</field>
8+
<field name="code">model._cron_refuse_expired_offers()</field>
9+
<field name="active" eval="True"/>
10+
<field name="interval_number">1</field>
11+
<field name="interval_type">days</field>
12+
<field name="nextcall">2025-08-26 18:30:00</field>
13+
</record>
14+
</data>
15+
</odoo>

estate/models/estate_property.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
class EstateProperty(models.Model):
88
_name = "estate.property"
99
_description = "Estate Property"
10+
_order = "id desc"
11+
1012
_sql_constraints = [
1113
(
1214
"check_expected_price",
1315
"CHECK(expected_price > 0)",
1416
"The expected price must be greater than 0.",
1517
),
1618
]
17-
_order = "id desc"
1819

1920
name = fields.Char(string="Name", required=True)
2021
description = fields.Text(string="Description")
@@ -58,8 +59,8 @@ class EstateProperty(models.Model):
5859
copy=False,
5960
selection=[
6061
("new", "New"),
61-
("offer received", "Offer Received"),
62-
("offer accepted", "Offer Accepted"),
62+
("offer_received", "Offer Received"),
63+
("offer_accepted", "Offer Accepted"),
6364
("sold", "Sold"),
6465
("cancelled", "Cancelled"),
6566
],
@@ -138,7 +139,7 @@ def action_set_sold(self):
138139
property.state = "sold"
139140
elif property.state == "cancelled":
140141
raise UserError("A cancelled property cannot be sold.")
141-
elif property.state == "new" or property.state == "offer received":
142+
elif property.state == "new" or property.state == "offer_received":
142143
raise UserError(
143144
"This property must have an accepted offer before it can be sold."
144145
)

estate/models/estate_property_offer.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
class EstatePropertyOffer(models.Model):
77
_name = "estate.property.offer"
88
_description = "Estate Property Offer"
9+
_order = "price desc"
10+
911
_sql_constraints = [
1012
("check_price", "CHECK(price > 0)", "The price must be greater than 0."),
1113
]
12-
_order = "price desc"
1314

1415
price = fields.Float(string="Price")
1516
status = fields.Selection(
@@ -71,17 +72,29 @@ def create(self, vals_list):
7172
"You cannot create an offer lower than an existing one."
7273
)
7374

74-
property.state = "offer received"
75+
property.state = "offer_received"
7576
return super().create(vals_list)
7677

78+
@api.model
79+
def _cron_refuse_expired_offers(self):
80+
today = fields.Date.context_today(self)
81+
expired_offers = self.search(
82+
[
83+
("status", "!=", "accepted"),
84+
("date_deadline", "<=", today),
85+
]
86+
)
87+
expired_offers.write({"status": "refused"})
88+
7789
def action_set_accepted(self):
7890
for offer in self:
91+
breakpoint()
7992
if offer.property_id.selling_price == 0.0:
8093
offer.write({"status": "accepted"})
8194

8295
offer.property_id.write(
8396
{
84-
"state": "offer accepted",
97+
"state": "offer_accepted",
8598
"selling_price": offer.price,
8699
"buyer_id": offer.partner_id.id,
87100
}
@@ -96,7 +109,7 @@ def action_set_accepted(self):
96109
def action_set_refused(self):
97110
for offer in self:
98111
if offer.status == "accepted":
99-
offer.property_id.state = "offer received"
112+
offer.property_id.state = "offer_received"
100113
offer.property_id.buyer_id = False
101114
offer.property_id.selling_price = 0.0
102115
offer.status = "refused"

estate/models/estate_property_tag.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
class EstatePropertyTag(models.Model):
55
_name = "estate.property.tag"
66
_description = "Estate Property Tag"
7+
_order = "name asc"
8+
79
_sql_constraints = [
810
("unique_name", "UNIQUE(name)", "A tag with same name is already exists."),
911
]
10-
_order = "name asc"
11-
12+
1213
name = fields.Char(string="Tag Name", required=True)
1314
description = fields.Text(string="Description")
1415
color = fields.Integer(string="Color")

estate/models/estate_property_type.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
class EstatePropertyType(models.Model):
55
_name = "estate.property.type"
66
_description = "Estate Property Type"
7+
_order = "sequence,name"
8+
79
_sql_constraints = [
810
("unique_name", "UNIQUE(name)", "A type with same name is already exists."),
911
]
10-
_order = "sequence,name"
1112

1213
name = fields.Char(required=True)
1314
property_ids = fields.One2many(

estate/models/res_users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ class ResUser(models.Model):
88
"estate.property",
99
"salesman_id",
1010
string="Properties",
11-
domain=[("state", "in", ["new", "offer received"])],
11+
domain=[("state", "in", ["new", "offer_received"])],
1212
)

estate/static/src/css/custom.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* Apply only inside this specific list view */
2+
/* Left-align the price column cells */
3+
.o_list_view.price-left-align td.o_list_number[name="price"] {
4+
text-align: left !important;
5+
}
6+
7+
/* Left-align the price column header */
8+
.o_list_view.price-left-align th[data-name="price"],
9+
.o_list_view.price-left-align th[data-name="price"] .o_list_number_th {
10+
text-align: left !important;
11+
justify-content: flex-start !important; /* override flex alignment */
12+
}

estate/views/estate_menus.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@
1111
</menuitem>
1212
</menuitem>
1313
</odoo>
14-

estate/views/estate_property_offer_views.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
<field name="name">estate.property.offer.view.list</field>
1414
<field name="model">estate.property.offer</field>
1515
<field name="arch" type="xml">
16-
<list editable="bottom" decoration-success="status == 'accepted'" decoration-danger="status == 'refused'">
17-
<field name="price"/>
18-
<field name="partner_id"/>
19-
<field name="validity"/>
16+
<list class="price-left-align" editable="bottom" decoration-success="status == 'accepted'" decoration-danger="status == 'refused'">
17+
<field name="price" width="20%"/>
18+
<field name="partner_id" width="40%"/>
19+
<field name="validity" width="10%"/>
2020
<button name="action_set_accepted" string="Accepted" type="object" icon="fa-check"
21-
invisible="status != False"/>
21+
invisible="status != False" width="5%"/>
2222
<button name="action_set_refused" string="Refused" type="object" icon="fa-times"
23-
invisible="status != False"/>
24-
<field name ="status" readonly="1"/>
25-
<field name="date_deadline"/>
23+
invisible="status != False" width="5%"/>
24+
<field name ="status" readonly="1" width="10%"/>
25+
<field name="date_deadline" width="10%"/>
2626
</list>
2727
</field>
2828
</record>

0 commit comments

Comments
 (0)