Skip to content

Commit 2af55db

Browse files
committed
[ADD] estate: Offer count button
1 parent 71ed848 commit 2af55db

9 files changed

+185
-94
lines changed

estate/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
'views/estate_property_views.xml',
1414
'views/estate_property_type.xml',
1515
'views/estate_property_tags_view.xml',
16+
'views/estate_property_offer_view.xml',
1617
'views/menu_views.xml',
1718
],
18-
'installable': True,
1919
'application': True,
2020
}

estate/models/estate_property.py

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,18 @@ class EstateProperty(models.Model):
3333
('east', 'East'), ('west', 'West')])
3434
active = fields.Boolean(default=True)
3535
state = fields.Selection(
36-
copy=False,
37-
readonly=True,
38-
default='new',
39-
string='States',
40-
selection=[
41-
('new', 'New'),
42-
('offer_received', 'Offer Received'),
43-
('offer_accepted', 'Offer Accepted'),
44-
('sold', 'Sold'),
45-
('cancelled', 'Cancelled')]
36+
copy=False,
37+
readonly=True,
38+
default='new',
39+
string='Property_States',
40+
selection=[
41+
('new', 'New'),
42+
('offer_received', 'Offer Received'),
43+
('offer_accepted', 'Offer Accepted'),
44+
('sold', 'Sold'),
45+
('cancelled', 'Cancelled')]
4646
)
4747

48-
def action_set_sold(self):
49-
if self.state != "cancelled":
50-
self.state = "sold"
51-
else:
52-
raise UserError("A cancelled property can not be sold")
53-
return True
54-
55-
def action_set_cancelled(self):
56-
if (self.state != "sold"):
57-
self.state = "cancelled"
58-
else:
59-
raise UserError("A sold property can not be cancelled")
60-
return True
61-
6248
property_type_id = fields.Many2one('estate.property.type', string='Type')
6349
buyer_id = fields.Many2one('res.partner', string='Buyer', copy=False)
6450
salesman_id = fields.Many2one('res.users', string='Salesman', default=lambda self: self.env.user)
@@ -67,15 +53,28 @@ def action_set_cancelled(self):
6753
total_area = fields.Integer(string='Total Area(m2)', compute='_compute_total_area', store=True)
6854
best_price = fields.Float(string='Best Offer', compute='_compute_best_price', store=True)
6955

56+
_check_expected_price = models.Constraint(
57+
'CHECK(expected_price >= 0)', 'The expected price must be strictly positive.')
58+
59+
_check_selling_price = models.Constraint(
60+
'CHECK(selling_price > 0)', 'The selling price must be positive.')
61+
62+
@api.constrains('selling_price', 'expected_price')
63+
def _check_selling_price_expected_price(self):
64+
for record in self:
65+
if record.selling_price == 0:
66+
continue
67+
if float_compare(record.selling_price, 0.9 * record.expected_price, precision_digits=2) == -1:
68+
raise UserError("The selling price must be at least 90% of the expected price.")
69+
7070
@api.depends('living_area', 'garden_area')
7171
def _compute_total_area(self):
7272
for property in self:
73-
property.total_area = property.living_area + (property.garden_area or 0)
73+
property.total_area = property.living_area + property.garden_area
7474

7575
@api.depends('offer_ids.price')
7676
def _compute_best_price(self):
7777
for record in self:
78-
if record.offer_ids:
7978
record.best_price = max(record.offer_ids.mapped('price')) if record.offer_ids else 0
8079

8180
@api.onchange('garden')
@@ -87,16 +86,25 @@ def _onchange_garden(self):
8786
self.garden_area = 0
8887
self.garden_orientation = False
8988

90-
_check_expected_price = models.Constraint(
91-
'CHECK(expected_price >= 0)', 'The expected price must be strictly positive.')
89+
@api.onchange('offer_ids')
90+
def _onchange_offers(self):
91+
for record in self:
92+
has_offers = any(offer.status not in ('refused', 'accepted') for offer in record.offer_ids)
93+
if record.state == 'new' and has_offers:
94+
record.state = 'offer_received'
9295

93-
_check_selling_price = models.Constraint(
94-
'CHECK(selling_price > 0)', 'The selling price must be positive.')
96+
if not has_offers and not any(offer.status == 'accepted' for offer in record.offer_ids) and record.state in ('offer_received',):
97+
record.state = 'offer_receive'
9598

96-
@api.constrains('selling_price', 'expected_price')
97-
def _check_selling_price_expected_price(self):
98-
for record in self:
99-
if record.selling_price == 0:
100-
continue
101-
if float_compare(record.selling_price, 0.9 * record.expected_price, precision_digits=2) == -1:
102-
raise UserError("The selling price must be at least 90% of the expected price.")
99+
def action_set_sold(self):
100+
print(self.state)
101+
if self.state == "cancelled":
102+
raise UserError("A cancelled property can not be sold")
103+
self.state = "sold"
104+
return True
105+
106+
def action_set_cancelled(self):
107+
if self.state == "sold":
108+
raise UserError("A sold property can not be cancelled")
109+
self.state = "cancelled"
110+
return True

estate/models/estate_property_offer.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ class EstatePropertyOffer(models.Model):
99
_order = 'price desc'
1010

1111
price = fields.Float(string='price', required=True)
12-
state = fields.Selection(selection=[('accepted', 'Accepted'),
12+
status = fields.Selection(selection=[('accepted', 'Accepted'),
1313
('refused', 'Refused')],
1414
string="Status",
1515
copy=False,
16-
default='accepted',
16+
# default='accepted',
1717
)
1818
validity = fields.Integer(string='Validity(days)', default=7)
1919
partner_id = fields.Many2one('res.partner', string='Partner', required=True)
2020
property_id = fields.Many2one('estate.property', required=True)
2121
date_deadline = fields.Date(string='Deadline', compute='_compute_date_deadline', store=True)
22+
property_type_id = fields.Many2one("estate.property.type", related="property_id.property_type_id", store=True, string="Property Type")
2223

2324
@api.depends('validity', 'create_date')
2425
def _compute_date_deadline(self):
@@ -27,17 +28,19 @@ def _compute_date_deadline(self):
2728
offer.date_deadline = fields.Date.today() + relativedelta(days=offer.validity)
2829

2930
def action_accept(self):
31+
print("Accepting offer...")
3032
for offer in self:
31-
if offer.state != 'refused':
32-
offer.state = 'accepted'
33-
else:
33+
if any(prop_offer.status == 'accepted' for prop_offer in offer.property_id.offer_ids):
34+
raise UserError("An offer has already been accepted for this property.")
35+
if offer.status == 'refused':
3436
raise UserError("A refused offer cannot be accepted.")
37+
else:
38+
offer.status = 'accepted'
39+
offer.property_id.status = 'offer_accepted'
3540
return True
3641

3742
def action_refuse(self):
38-
for offer in self:
39-
if offer.state != 'accepted':
40-
offer.state = 'refused'
41-
else:
43+
if any(offer.status == 'accepted' for offer in self):
4244
raise UserError("An accepted offer cannot be refused.")
43-
return True
45+
self.status = 'refused'
46+
return True

estate/models/estate_property_tags.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ class PropertyTypeTags(models.Model):
77
_order = 'name'
88

99
name = fields.Char(required=True)
10+
color = fields.Integer()

estate/models/estate_property_type.py

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

33

44
class PropertyType(models.Model):
@@ -9,3 +9,10 @@ class PropertyType(models.Model):
99
name = fields.Char(required=True)
1010
property_ids = fields.One2many('estate.property', 'property_type_id', string='Properties')
1111
sequence = fields.Integer(string="Sequence", default=10)
12+
offer_ids = fields.One2many("estate.property.offer", "property_type_id", string="Offers")
13+
offer_count = fields.Integer(string="Offer Count", compute="_compute_offer_count")
14+
15+
@api.depends("offer_ids")
16+
def _compute_offer_count(self):
17+
for record in self:
18+
record.offer_count = len(record.offer_ids)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0"?>
2+
<odoo>
3+
<record id="estate_property_action" model="ir.actions.act_window">
4+
<field name="name">Property</field>
5+
<field name="res_model">estate.property</field>
6+
<field name="view_mode">list,form</field>
7+
</record>
8+
<record id="estate_property_offer_view_list" model="ir.ui.view">
9+
<field name="name">estate.property.offer.list</field>
10+
<field name="model">estate.property.offer</field>
11+
<field name="arch" type="xml">
12+
<list string="Property Offers" editable="bottom" decoration-danger="status=='refused'" decoration-success="status=='accepted'">
13+
<field name="partner_id"/>
14+
<field name="property_type_id"/>
15+
<field name="price"/>
16+
<field name="status"/>
17+
<field name="validity"/>
18+
<field name="date_deadline"/>
19+
<button name="action_accept" type="object" icon="fa-check" title="Accept" invisible="status in ['accepted', 'refused']"/>
20+
<button name="action_refuse" type="object" icon="fa-times" title="Refuse" invisible="status in ['accepted', 'refused']"/>
21+
</list>
22+
</field>
23+
</record>
24+
<record id="estate_property_offer_view_form" model="ir.ui.view">
25+
<field name="name">estate.property.offer.form</field>
26+
<field name="model">estate.property.offer</field>
27+
<field name="arch" type="xml">
28+
<form string="Property Offer">
29+
<sheet>
30+
<group>
31+
<field name="partner_id"/>
32+
<field name="price"/>
33+
<field name="status"/>
34+
<field name="validity"/>
35+
<field name="date_deadline"/>
36+
</group>
37+
</sheet>
38+
</form>
39+
</field>
40+
</record>
41+
</odoo>

estate/views/estate_property_tags_view.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,26 @@
44
<field name="res_model">estate.property.tags</field>
55
<field name="view_mode">list,form</field>
66
</record>
7+
<record id="estate_property_tag_view_list" model="ir.ui.view">
8+
<field name="name">estate.property.tag.list</field>
9+
<field name="model">estate.property.tags</field>
10+
<field name="arch" type="xml">
11+
<list string="Property Tags" editable="bottom">
12+
<field name="name"/>
13+
</list>
14+
</field>
15+
</record>
16+
<record id="estate_property_tag_view_form" model="ir.ui.view">
17+
<field name="name">estate.property.tag.form</field>
18+
<field name="model">estate.property.tags</field>
19+
<field name="arch" type="xml">
20+
<form string="Property Tag">
21+
<sheet>
22+
<group>
23+
<field name="name"/>
24+
</group>
25+
</sheet>
26+
</form>
27+
</field>
28+
</record>
729
</odoo>

estate/views/estate_property_type.xml

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,54 @@
55
<field name="res_model">estate.property.type</field>
66
<field name="view_mode">list,form</field>
77
</record>
8+
9+
<record id="estate_property_offer_action" model="ir.actions.act_window">
10+
<field name="name">Offers</field>
11+
<field name="res_model">estate.property.offer</field>
12+
<field name="view_mode">list,form</field>
13+
<field name="domain">[('property_type_id', '=', active_id)]</field>
14+
</record>
15+
816
<record id="estate_property_type_list" model="ir.ui.view">
9-
<field name="name">estate.property.list</field>
10-
<field name="model">estate.property.type</field>
17+
<field name="name">estate.property.type.list</field>
18+
<field name="model">estate.property.type</field>
1119
<field name="arch" type="xml">
12-
<list string="Property_type">
13-
<field name ="sequence" widget="handle"/>
20+
<list string="Property Types">
21+
<field name="sequence" widget="handle"/>
1422
<field name="name"/>
15-
<field name="property_ids" widget="one2many_list" mode="list"/>
23+
<field name="property_ids"/>
1624
</list>
1725
</field>
1826
</record>
27+
1928
<record id="estate_property_type_form" model="ir.ui.view">
2029
<field name="name">estate.property.type.form</field>
2130
<field name="model">estate.property.type</field>
2231
<field name="arch" type="xml">
2332
<form string="Property Type">
2433
<sheet>
34+
<div name="button_box" class="oe_button_box">
35+
<button name="%(estate_property_offer_action)d"
36+
type="action"
37+
class="oe_stat_button"
38+
icon="fa-money">
39+
<field name="offer_count" widget="statinfo"/>
40+
</button>
41+
</div>
2542
<group>
2643
<field name="name"/>
27-
<field name="property_ids" widget="one2many_list" mode="list,form">
28-
<list editable="bottom">
29-
<field name="name"/>
30-
<field name="expected_price"/>
31-
<field name="state"/>
32-
</list>
33-
</field>
34-
</group>
44+
</group>
45+
<notebook>
46+
<page string="Properties">
47+
<field name="property_ids">
48+
<form editable="bottom">
49+
<field name="name"/>
50+
<field name="expected_price"/>
51+
<field name="state"/>
52+
</form>
53+
</field>
54+
</page>
55+
</notebook>
3556
</sheet>
3657
</form>
3758
</field>

0 commit comments

Comments
 (0)