Skip to content

Commit 536d4cc

Browse files
committed
[IMP] estate: added stat button, inline views, list order
added stat button in property type to show quick offer list. added inline views in property types to get related fields from other model. added order method in models, views, manual. improved some logic in percentage calculation. code formation.
1 parent 7ffb6fb commit 536d4cc

File tree

5 files changed

+128
-69
lines changed

5 files changed

+128
-69
lines changed

estate/models/estate_property.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
class EstateProperty(models.Model):
99
_name = "estate.property"
1010
_description = "Estate Property"
11+
_order = "id desc"
1112
_check_expected_price = models.Constraint(
12-
"CHECK(expected_price > 0)", "A property expected price must be strictly positive."
13+
"CHECK(expected_price > 0)",
14+
"A property expected price must be strictly positive.",
1315
)
1416
_check_selling_price = models.Constraint(
1517
"CHECK(selling_price >= 0)", "A property selling price must be positive."
@@ -52,18 +54,20 @@ class EstateProperty(models.Model):
5254
copy=False,
5355
default="new",
5456
)
55-
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
57+
property_type_id = fields.Many2one(
58+
"estate.property.type", string="Property Type"
59+
)
5660
customer = fields.Many2one("res.partner", string="Customer", copy=False)
5761
salesperson = fields.Many2one(
5862
"res.users", string="Salesperson", default=lambda self: self.env.user
5963
)
6064
tag_ids = fields.Many2many("estate.property.tag", string="Property Tags")
6165
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offer")
62-
total_area = fields.Integer(compute="_compute_area")
66+
total_area = fields.Integer(compute="_compute_total_area")
6367
best_price = fields.Integer(compute="_compute_best_price")
6468

6569
@api.depends("living_area", "garden_area")
66-
def _compute_area(self):
70+
def _compute_total_area(self):
6771
for record in self:
6872
record.total_area = record.living_area + record.garden_area
6973

@@ -103,12 +107,8 @@ def action_cancel_offer(self):
103107
@api.constrains("selling_price", "expected_price")
104108
def _check_selling_price_persentage(self):
105109
for record in self:
106-
selling_price_persentage = (
107-
record.selling_price / record.expected_price
108-
) * 100
109-
if selling_price_persentage >= 90 or selling_price_persentage == 0:
110+
selling_price_persentage = (record.selling_price / record.expected_price) * 100
111+
if selling_price_persentage >=90 or selling_price_persentage == 0:
110112
pass
111113
else:
112-
raise ValidationError(
113-
"The selling price cannot be lower than 90% of the expected price."
114-
)
114+
raise ValidationError("the selling price cannot be lower than 90% of the expected price.")

estate/models/estate_property_offer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class EstatePropertyOffer(models.Model):
77
_name = "estate.property.offer"
88
_description = "Estate Property Offer"
9+
_order = "price desc"
910
_check_offer_price = models.Constraint(
1011
"CHECK(price > 0)", "An offer price must be strictly positive"
1112
)
@@ -18,6 +19,9 @@ class EstatePropertyOffer(models.Model):
1819
property_id = fields.Many2one("estate.property", string="Property", required=True)
1920
validity = fields.Integer(default=7)
2021
date_deadline = fields.Date(compute="_compute_deadline", inverse="_inverse_date")
22+
property_type_id = fields.Many2one(
23+
related="property_id.property_type_id", store=True
24+
)
2125

2226
@api.depends("validity")
2327
def _compute_deadline(self):
@@ -39,6 +43,7 @@ def action_accept(self):
3943
record.status = "accepted"
4044
record.property_id.selling_price = record.price
4145
record.property_id.customer = record.partner_id
46+
record.property_id.state = "offer_accepted"
4247
return True
4348

4449
def action_refuse(self):

estate/models/estate_property_tag.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
class EstatePropertyTags(models.Model):
55
_name = "estate.property.tag"
66
_description = "Estate Property Tag"
7+
_order = "name"
78
_check_tag_name = models.Constraint(
89
"UNIQUE(name)", "A property tag name should be unique."
910
)
1011

1112
name = fields.Char(required=True)
13+
color = fields.Integer()
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
#!/usr/bin/env python3
2-
from odoo import models, fields
2+
from odoo import models, fields, api
33

44

55
class EstatePropertyType(models.Model):
66
_name = "estate.property.type"
77
_description = "Estate Property Type"
8+
_order = "sequence,name"
89
_check_type_name = models.Constraint(
910
"UNIQUE(name)", "A property type name should be unique."
1011
)
1112

1213
name = fields.Char(required=True)
14+
property_ids = fields.One2many("estate.property", "property_type_id")
15+
sequence = fields.Integer("Sequence", default=1)
16+
offer_ids = fields.One2many("estate.property.offer", "property_type_id")
17+
offer_count = fields.Integer(compute="_compute_offer_count")
18+
19+
@api.depends("offer_ids")
20+
def _compute_offer_count(self):
21+
for record in self:
22+
record.offer_count = len(record.property_ids.mapped('offer_ids'))

estate/views/estate_property_views.xml

Lines changed: 99 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<field name="name">Properties</field>
55
<field name="res_model">estate.property</field>
66
<field name="view_mode">list,form</field>
7+
<field name="context">{'search_default_avaliable': 1}</field>
78
<field name="help" type="html">
89
<p class="o_view_nocontent_smiling_face">
910
Create your first Property!
@@ -33,20 +34,39 @@
3334
</field>
3435
</record>
3536

36-
<record id="action_estate_view_list" model="ir.ui.view">
37-
<field name="name">estate.property.list</field>
38-
<field name="model">estate.property</field>
37+
<record id="action_estate_property_offer" model="ir.actions.act_window">
38+
<field name="name">Property Offers</field>
39+
<field name="res_model">estate.property.offer</field>
40+
<field name="view_mode">list,form</field>
41+
<field name="domain">[('property_type_id', '=', active_id)]</field>
42+
</record>
43+
44+
<record id="action_estate_property_type_form" model="ir.ui.view">
45+
<field name="name">estate.property.type.form</field>
46+
<field name="model">estate.property.type</field>
3947
<field name="arch" type="xml">
40-
<list string="Channel">
41-
<field name="name" string="Title"/>
42-
<field name="property_type_id"/>
43-
<field name="postcode"/>
44-
<field name="bedrooms"/>
45-
<field name="living_area" string="Living Area(sqm)"/>
46-
<field name="expected_price"/>
47-
<field name="selling_price"/>
48-
<field name="date_avaliability" string="Avaliable From"/>
49-
</list>
48+
<form name="Property Type List">
49+
<header>
50+
<button class="oe_stat_button" type="action" name="%(estate.action_estate_property_offer)d" icon="fa-list" string="offer"/>
51+
<field name="offer_count"/>
52+
</header>
53+
<sheet>
54+
<h1>
55+
<field name="name"/>
56+
</h1>
57+
<notebook>
58+
<page string="Properties">
59+
<field name="property_ids">
60+
<list>
61+
<field name="name" string="Title"/>
62+
<field name="expected_price"/>
63+
<field name="state"/>
64+
</list>
65+
</field>
66+
</page>
67+
</notebook>
68+
</sheet>
69+
</form>
5070
</field>
5171
</record>
5272

@@ -56,22 +76,23 @@
5676
<field name="arch" type="xml">
5777
<form string="Property">
5878
<header>
59-
<button name="action_sold_property" type="object" string="Sold"/>
60-
<button name="action_cancel_offer" type="object" string="Cancel"/>
79+
<button name="action_sold_property" type="object" string="Sold" invisible="state in ('sold','cancelled')"/>
80+
<button name="action_cancel_offer" type="object" string="Cancel" invisible="state in ('sold','cancelled')"/>
81+
<field name="state" widget="statusbar"/>
6182
</header>
6283
<sheet>
6384
<h1>
6485
<field name="name" string="Title"/>
6586
</h1>
87+
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
88+
<hr/>
6689
<group>
6790
<group>
68-
<field name="state" string="Status"/>
69-
<field name="tag_ids" widget="many2many_tags"/>
70-
<field name="postcode"/>
91+
<field name="postcode"/>
7192
<field name="date_avaliability" string="Avaliable From"/>
7293
</group>
7394
<group>
74-
<field name="property_type_id"/>
95+
<field name="property_type_id" options="{'no_create': true}"/>
7596
<field name="expected_price"/>
7697
<field name="selling_price"/>
7798
<field name="best_price" string="Best Offer"/>
@@ -87,15 +108,15 @@
87108
<field name="facades"/>
88109
<field name="garage"/>
89110
<field name="garden"/>
90-
<field name="garden_area" string="Garden Area(sqm)"/>
91-
<field name="garden_orientation"/>
111+
<field name="garden_area" string="Garden Area(sqm)" invisible="not garden"/>
112+
<field name="garden_orientation" invisible="not garden"/>
92113
<field name="total_area" string="Total Area(sqm)"/>
93114
<field name="active"/>
94115
</group>
95116
</group>
96117
</page>
97118
<page string="Offers">
98-
<field name="offer_ids"/>
119+
<field name="offer_ids" readonly="state in ('offer_accepted','sold','cancelled')"/>
99120
</page>
100121
<page string="Other info">
101122
<group>
@@ -109,57 +130,78 @@
109130
</field>
110131
</record>
111132

133+
<record id="action_estate_property_type_view_list" model="ir.ui.view">
134+
<field name="name">estate.property.type.list</field>
135+
<field name="model">estate.property.type</field>
136+
<field name="arch" type="xml">
137+
<list string="Types">
138+
<field name="sequence" widget="handle"/>
139+
<field name="name" string="Type"/>
140+
</list>
141+
</field>
142+
</record>
143+
144+
<record id="action_estate_view_list" model="ir.ui.view">
145+
<field name="name">estate.property.list</field>
146+
<field name="model">estate.property</field>
147+
<field name="arch" type="xml">
148+
<list string="Property" decoration-success="state in ('offer_received','offer_accepted')" decoration-bf="state in ('offer_accepted')" decoration-muted="state in ('sold')">
149+
<field name="name" string="Title"/>
150+
<field name="property_type_id"/>
151+
<field name="postcode"/>
152+
<field name="bedrooms"/>
153+
<field name="living_area" string="Living Area(sqm)"/>
154+
<field name="expected_price"/>
155+
<field name="selling_price"/>
156+
<field name="date_avaliability" string="Avaliable From" optional="hide"/>
157+
</list>
158+
</field>
159+
</record>
160+
112161
<record id="action_estate_offer_view_list" model="ir.ui.view">
113162
<field name="name">estate.property.offer.list</field>
114163
<field name="model">estate.property.offer</field>
115-
<field name="arch" type="xml">
116-
<list string="Channel">
164+
<field name="arch" type="xml">
165+
<list string="Offer" editable="bottom" decoration-danger="status=='refused'" decoration-success="status=='accepted'">
117166
<field name="price"/>
118167
<field name="partner_id"/>
119168
<field name="validity" string="Validity(days)"/>
120169
<field name="date_deadline"/>
121170
<button name="action_accept" string="Accept" type="object" icon="fa-check" invisible="status in ('accepted', 'refused')"/>
122171
<button name="action_refuse" string="Refuse" type="object" icon="fa-times" invisible="status in ('accepted', 'refused')"/>
123-
<field name="status"/>
124172
</list>
125173
</field>
126174
</record>
127175

128-
<record id="action_estate_offer_view_form" model="ir.ui.view">
129-
<field name="name">estate.property.offer.form</field>
130-
<field name="model">estate.property.offer</field>
131-
<field name="arch" type="xml">
132-
<form string="Property">
133-
<sheet>
134-
<group>
135-
<field name="price"/>
136-
<field name="partner_id"/>
137-
<field name="validity" string="Validity(days)"/>
138-
<field name="date_deadline"/>
139-
<field name="status"/>
140-
</group>
141-
</sheet>
142-
</form>
176+
<record id="action_estate_property_tag_view_list" model="ir.ui.view">
177+
<field name="name">estate.property.tag.list</field>
178+
<field name="model">estate.property.tag</field>
179+
<field name="arch" type="xml">
180+
<list string="Tag" editable="bottom">
181+
<field name="name"/>
182+
<field name="color" widget="color_picker"/>
183+
</list>
143184
</field>
144185
</record>
145186

146187
<record id="action_estate_view_search" model="ir.ui.view">
147-
<field name="name">estate.property.search</field>
148-
<field name="model">estate.property</field>
149-
<field name="arch" type="xml">
150-
<search string="Delivery Carrier">
151-
<field name="name" string="Title"/>
152-
<field name="postcode"/>
153-
<field name="bedrooms"/>
154-
<field name="living_area" string="Living Area(sqm)"/>
155-
<field name="expected_price"/>
156-
<field name="facades"/>
157-
<field name="property_type_id"/>
158-
<separator/>
159-
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
160-
<filter string="Postcode" name="postcode" context="{'group_by':'postcode'}"/>
161-
<filter string="State" name="state" domain="['|',('state', '=', 'new'),('state', '=', 'offer_received')]"/>
162-
</search>
163-
</field>
188+
<field name="name">estate.property.search</field>
189+
<field name="model">estate.property</field>
190+
<field name="arch" type="xml">
191+
<search string="Delivery Carrier">
192+
<field name="name" string="Title"/>
193+
<field name="postcode"/>
194+
<field name="bedrooms"/>
195+
<field name="living_area" string="Living Area(sqm)" filter_domain="[('living_area', '>=', self)]"/>
196+
<field name="expected_price"/>
197+
<field name="facades"/>
198+
<field name="property_type_id"/>
199+
<separator/>
200+
<filter string="Avaliable" name="avaliable" domain="[('state', '=', 'new')]"/>
201+
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
202+
<filter string="Postcode" name="postcode" context="{'group_by':'postcode'}"/>
203+
<filter string="State" name="state" domain="['|',('state', '=', 'new'),('state', '=', 'offer_received')]"/>
204+
</search>
205+
</field>
164206
</record>
165207
</odoo>

0 commit comments

Comments
 (0)