Skip to content

Commit e79b517

Browse files
author
youness benbraitit (yoben)
committed
[IMP] estate: added acceptance criteria
added acceptance criteria for the offers and the types, and colors..
1 parent 4f64cde commit e79b517

15 files changed

+198
-82
lines changed

estate/__manifest__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
'depends': ['base'],
1111
'data': [
1212
'security/ir.model.access.csv',
13-
'views/estate_property_type_views.xml',
1413
'views/estate_property_tag_views.xml',
1514
'views/estate_property_offer_views.xml',
15+
'views/estate_property_form_views.xml',
16+
'views/estate_property_type_views.xml',
1617
'views/estate_property_views.xml',
1718
'views/estate_list.xml',
1819
'views/estate_view_form.xml',

estate/models/estate_property.py

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from datetime import date
22
from dateutil.relativedelta import relativedelta
3-
from odoo.exceptions import UserError
3+
from odoo.exceptions import UserError, ValidationError
44
from odoo import api, fields, models
5+
from odoo.tools.float_utils import float_compare, float_is_zero
56

67

78
class EstateProperty(models.Model):
89
_name = "estate.property"
910
_description = "Estate property"
10-
_order = ""
11+
_order = "id desc"
1112

12-
name = fields.Text('Title', required=True)
13+
name = fields.Text('Title', required=True, default='Unknown', translate=True)
1314
description = fields.Text('Description')
1415
post_code = fields.Char('Postcode')
1516
date_availability = fields.Date(
@@ -53,14 +54,34 @@ class EstateProperty(models.Model):
5354
user_id = fields.Many2one(
5455
'res.users', string='Salesman', default=lambda self: self.env.user
5556
)
56-
buyer_id = fields.Many2one("res.partner", string="Buyer", readonly=True, copy=False)
57+
buyer_id = fields.Many2one(
58+
"res.partner",
59+
string="Buyer",
60+
copy=False,
61+
readonly=True,
62+
domain=[('is_company', '=', False)],
63+
)
5764
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
5865
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
5966
total_area = fields.Integer("Total Area (sqm)", compute="_compute_total_area")
6067
best_price = fields.Float(
6168
"Best Offer", compute="_compute_best_price", readonly=True
6269
)
6370

71+
# 💡 REPLACED deprecated models.Constraint with _sql_constraints
72+
_sql_constraints = [
73+
(
74+
'check_expected_price',
75+
'CHECK(expected_price > 0)',
76+
'The expected price must be strictly positive.',
77+
),
78+
(
79+
'check_selling_price',
80+
'CHECK(selling_price >= 0)',
81+
'The selling price must be positive or zero.',
82+
),
83+
]
84+
6485
@api.depends('living_area', 'garden_area')
6586
def _compute_total_area(self):
6687
for rec in self:
@@ -70,12 +91,7 @@ def _compute_total_area(self):
7091
def _compute_best_price(self):
7192
for rec in self:
7293
prices = rec.offer_ids.mapped('price')
73-
rec.best_price = max(prices) if prices else 0.0
74-
75-
@api.depends("living_area", "garden_area")
76-
def _compute_total_area(self):
77-
for prop in self:
78-
prop.total_area = prop.living_area + prop.garden_area
94+
rec.best_price = max(prices, default=0.0)
7995

8096
@api.onchange("garden")
8197
def _onchange_garden(self):
@@ -87,11 +103,35 @@ def _onchange_garden(self):
87103
self.garden_orientation = False
88104

89105
def action_sold(self):
90-
if "cancelled" in self.mapped("state"):
106+
if any([prop.state == "cancelled" for prop in self]):
91107
raise UserError("Canceled property cannot be sold !")
92-
return self.write({"state": "sold"})
108+
self.state = 'sold'
109+
return True
93110

94111
def action_cancel(self):
95112
if "sold" in self.mapped("state"):
96113
raise UserError("Sold property cannot be canceled !")
97114
return self.write({"state": "cancelled"})
115+
116+
@api.constrains('selling_price', 'expected_price')
117+
def _check_selling_price_constraint(self):
118+
for rec in self:
119+
if float_is_zero(rec.selling_price or 0.0, precision_digits=2):
120+
continue
121+
if not rec.expected_price:
122+
raise ValidationError(
123+
"Expected price must be set to validate selling price."
124+
)
125+
threshold = 0.9 * rec.expected_price
126+
if float_compare(rec.selling_price, threshold, precision_digits=2) < 0:
127+
raise ValidationError(
128+
"The selling price cannot be lower than 90% of the expected price."
129+
)
130+
131+
_check_expected_price = models.Constraint(
132+
'CHECK(expected_price > 0)', 'The expected price must be strictly positive.'
133+
)
134+
135+
_check_selling_price = models.Constraint(
136+
'CHECK(selling_price >= 0)', 'The selling price must be positive or zero.'
137+
)

estate/models/estate_property_offer.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from odoo import api, fields, models
2+
from datetime import timedelta
23

34

45
class EstatePropertyOffer(models.Model):
56
_name = "estate.property.offer"
67
_description = "Estate Property Offers"
7-
_order = "price"
8+
_order = "price desc"
89

910
price = fields.Float("Price", required=True)
1011
state = fields.Selection(
@@ -15,27 +16,37 @@ class EstatePropertyOffer(models.Model):
1516
)
1617
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
1718
property_id = fields.Many2one("estate.property", string="Property", required=True)
19+
property_type_id = fields.Many2one(
20+
"estate.property.type",
21+
related="property_id.property_type_id",
22+
store=True,
23+
string="Property Type",
24+
)
1825
validity = fields.Integer("Validity (days)", default=7)
1926
date_deadline = fields.Date(
2027
"Deadline", compute="_compute_date_deadline", store=True
2128
)
2229

23-
@api.depends('validity')
30+
@api.depends('validity', 'create_date')
2431
def _compute_date_deadline(self):
2532
for offer in self:
26-
if offer._origin.validity:
27-
offer.date_deadline = fields.Date.add(
28-
offer.create_date.date(), days=offer.validity
29-
)
33+
if offer.create_date:
34+
base_dt = fields.Datetime.from_string(offer.create_date)
3035
else:
31-
offer.date_deadline = False
36+
base_dt = fields.Datetime.now()
37+
deadline_dt = base_dt + timedelta(days=offer.validity or 0)
38+
offer.date_deadline = fields.Date.to_string(deadline_dt.date())
3239

3340
def action_accept(self):
3441
for offer in self:
3542
offer.state = 'accepted'
36-
offer.property_id.selling_price = offer.price
37-
offer.property_id.buyer_id = offer.partner_id.id
38-
offer.property_id.state = 'offer_accepted'
43+
offer.property_id.write(
44+
{
45+
'selling_price': offer.price,
46+
'buyer_id': offer.partner_id.id,
47+
'state': 'offer_accepted',
48+
}
49+
)
3950
other_offers = offer.property_id.offer_ids.filtered(
4051
lambda o: o.id != offer.id and o.state != 'refused'
4152
)

estate/models/estate_property_tag.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ class EstatePropertyTag(models.Model):
77
_order = "name"
88

99
name = fields.Char("Name", required=True)
10+
color = fields.Integer("Color")
11+
12+
_check_tag_uniqueness = models.Constraint(
13+
'UNIQUE(name)', 'The property tag name must be unique'
14+
)

estate/models/estate_property_type.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from odoo import fields, models
1+
from odoo import api, fields, models
22

33

44
class EstatePropertyType(models.Model):
@@ -12,3 +12,15 @@ class EstatePropertyType(models.Model):
1212
"estate.property", "property_type_id", string="Properties"
1313
)
1414
offer_count = fields.Integer(string="Offers count", compute="_compute_offer")
15+
offer_ids = fields.One2many(
16+
"estate.property.offer", "property_type_id", string="Offers"
17+
)
18+
19+
_sql_constraints = [
20+
('unique_type_name', 'UNIQUE(name)', 'The property type name must be unique.')
21+
]
22+
23+
@api.depends('offer_ids')
24+
def _compute_offer(self):
25+
for record in self:
26+
record.offer_count = len(record.offer_ids)

estate/security/ir.model.access.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
22
access_estate_property,access.estate.property,model_estate_property,base.group_user,1,1,1,1
33
access_estate_property_type,access.estate.property.type,model_estate_property_type,base.group_user,1,1,1,1
44
access_estate_property_tag,access.estate.property.tag,model_estate_property_tag,base.group_user,1,1,1,1
5-
access_estate_property_offer,access.estate.property.offer,model_estate_property_offer,base.group_user,1,1,1,1
5+
access_estate_property_offer,access.estate.property.offer,model_estate_property_offer,base.group_user,1,1,1,1

estate/views/estate_list.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
</list>
1616
</field>
1717
</record>
18-
</odoo>
18+
</odoo>

estate/views/estate_menus.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
<menuitem id="estate_property_tag_menu_action" name="Property Tags" action="estate_property_tag_action" />
99
</menuitem>
1010
</menuitem>
11-
</odoo>
11+
</odoo>

estate/views/estate_property_form_views.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
<odoo>
2-
<record id="view_property_offer_form" model="ir.ui.view">
1+
<odoo>
2+
<record id="view_property_offer_form" model="ir.ui.view">
33
<field name="name">estate.property.offer.form</field>
44
<field name="model">estate.property.offer</field>
55
<field name="arch" type="xml">
66
<form string="Property Offer">
77
<sheet>
88
<group>
99
<field name="price"/>
10-
<field name="status"/>
10+
<field name="state"/>
1111
</group>
1212
<group>
1313
<field name="partner_id"/>
@@ -21,6 +21,6 @@
2121
<record id="estate_property_offer_action" model="ir.actions.act_window">
2222
<field name="name">Property Offers</field>
2323
<field name="res_model">estate.property.offer</field>
24-
<field name="view_mode">tree,form</field>
24+
<field name="view_mode">list,form</field>
2525
</record>
26-
</odoo>
26+
</odoo>

estate/views/estate_property_offer_views.xml

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,41 @@
1212
</form>
1313
</field>
1414
</record>
15-
<!-- Add the buttons ‘Accept’ and ‘Refuse’ to the estate.property.offer model. -->
15+
16+
<record id="estate_property_offer_search" model="ir.ui.view">
17+
<field name="name">estate.property.offer.search</field>
18+
<field name="model">estate.property.offer</field>
19+
<field name="arch" type="xml">
20+
<search>
21+
<field name="price"/>
22+
<field name="partner_id"/>
23+
<field name="property_type_id"/>
24+
<field name="state"/>
25+
</search>
26+
</field>
27+
</record>
28+
1629
<record id="estate_property_offer_view_tree" model="ir.ui.view">
1730
<field name="name">estate.property.offer.tree</field>
1831
<field name="model">estate.property.offer</field>
1932
<field name="arch" type="xml">
20-
<list string="Property Offers">
33+
<list string="Property Offers" editable="bottom" decoration-danger="state == 'refused'" decoration-success="state == 'accepted'">
2134
<field name="price"/>
2235
<field name="partner_id"/>
23-
<field name="state"/>
36+
<field name="property_type_id"/>
37+
<field name="state" invisible="1"/>
2438
<field name="validity"/>
2539
<field name="date_deadline"/>
26-
<button name="action_accept" type="object" icon="fa-check" title="Accept"
27-
/>
28-
<button name="action_refuse" type="object" icon="fa-times" title="Accept"
29-
/>
40+
<button name="action_accept" type="object" icon="fa-check" title="Accept" invisible="state"/>
41+
<button name="action_refuse" type="object" icon="fa-times" title="Accept" invisible="state"/>
3042
</list>
3143
</field>
3244
</record>
45+
46+
<record id="estate_property_offer_action" model="ir.actions.act_window">
47+
<field name="name">Property Offers</field>
48+
<field name="res_model">estate.property.offer</field>
49+
<field name="view_mode">tree,form</field>
50+
<field name="domain">[('property_type_id', '=', active_id)]</field>
51+
</record>
3352
</odoo>

0 commit comments

Comments
 (0)