-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] estate: Finish up to chapter 10 (included)
- Loading branch information
1 parent
b16e643
commit d6d9aeb
Showing
10 changed files
with
580 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# A custom real estate module, created for learning purposes | ||
|
||
{ | ||
'name': '[TUTO] Estate', | ||
'summary': 'Track your real estate properties', | ||
'depends': [ | ||
'base_setup' | ||
], | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
|
||
'views/estate_property_views.xml', | ||
'views/estate_settings_views.xml', | ||
'views/estate_menu_views.xml' | ||
], | ||
'installable': True, | ||
'application': True, | ||
'demo': [ | ||
"demo/estate_demo.xml", | ||
], | ||
'auto_install': True | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<odoo> | ||
<data> | ||
|
||
<!-- Demo Estate Property Types --> | ||
<record id="estate_property_type_1" model="estate_property_type"> | ||
<field name="name">Appartment</field> | ||
</record> | ||
<record id="estate_property_type_2" model="estate_property_type"> | ||
<field name="name">House</field> | ||
</record> | ||
|
||
<!-- Demo Estate Property Tags --> | ||
<record id="estate_property_tag_1" model="estate_property_tag"> | ||
<field name="name">cosy</field> | ||
</record> | ||
<record id="estate_property_tag_2" model="estate_property_tag"> | ||
<field name="name">renovated</field> | ||
</record> | ||
<record id="estate_property_tag_3" model="estate_property_tag"> | ||
<field name="name">renovation needed</field> | ||
</record> | ||
|
||
<!-- Demo Estate Property Offers --> | ||
<record id="estate_property_offer_1" model="estate_property_offer"> | ||
<field name="price">2000000</field> | ||
<field name="partner_id" ref="base.res_partner_4"/> | ||
<field name="validity">12</field> | ||
</record> | ||
<record id="estate_property_offer_2" model="estate_property_offer"> | ||
<field name="price">200000</field> | ||
<field name="partner_id" ref="base.res_partner_3"/> | ||
<field name="validity">10</field> | ||
</record> | ||
<record id="estate_property_offer_3" model="estate_property_offer"> | ||
<field name="price">220000</field> | ||
<field name="partner_id" ref="base.res_partner_5"/> | ||
<field name="validity">25</field> | ||
</record> | ||
<record id="estate_property_offer_4" model="estate_property_offer"> | ||
<field name="price">260000</field> | ||
<field name="partner_id" ref="base.res_partner_4"/> | ||
<field name="deadline" eval="(DateTime.today() + relativedelta(days=7)).strftime('%Y-%m-%d %H:%M')" /> | ||
</record> | ||
|
||
<!-- Demo Estate Properties --> | ||
<record id="estate_property_1" model="estate_property"> | ||
<field name="name">Beach House</field> | ||
<field name="status">canceled</field> | ||
<field name="description">A brand new house by the beach</field> | ||
<field name="postcode">8300</field> | ||
<field name="date_availability" eval="(DateTime.today() + relativedelta(months=3)).strftime('%Y-%m-%d %H:%M')" /> | ||
<field name="expected_price">2500000</field> | ||
<field name="selling_price">0</field> | ||
<field name="bedrooms">6</field> | ||
<field name="living_area">1050</field> | ||
<field name="facades">4</field> | ||
<field name="garage">True</field> | ||
<field name="garden">True</field> | ||
<field name="garden_area">420</field> | ||
<field name="garden_orientation">south</field> | ||
<field name="property_type" ref="estate_property_type_2" /> | ||
<field name="salesperson" ref="base.user_demo"/> | ||
<field name="tag_ids" eval="[(6, 0, [ref('estate_property_tag_1'), ref('estate_property_tag_2')])]"/> | ||
<field name="offer_ids" eval="[(6, 0, [ref('estate_property_offer_1')])]"/> | ||
</record> | ||
<record id="estate_property_2" model="estate_property"> | ||
<field name="name">City Apt</field> | ||
<field name="status">offer_accepted</field> | ||
<field name="description">A shitty appartment in Brussels</field> | ||
<field name="postcode">1090</field> | ||
<field name="date_availability" eval="(DateTime.today() + relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')" /> | ||
<field name="expected_price">250000</field> | ||
<field name="selling_price">0</field> | ||
<field name="bedrooms">2</field> | ||
<field name="living_area">95</field> | ||
<field name="facades">1</field> | ||
<field name="garage">False</field> | ||
<field name="garden">False</field> | ||
<field name="garden_area">0</field> | ||
<field name="property_type" ref="estate_property_type_1"/> | ||
<field name="salesperson" ref="base.user_admin"/> | ||
<field name="tag_ids" eval="[(6, 0, [ref('estate_property_tag_3')])]"/> | ||
<field name="offer_ids" eval="[(6, 0, [ref('estate_property_offer_2'), ref('estate_property_offer_4'), ref('estate_property_offer_3')])]"/> | ||
</record> | ||
|
||
<!-- Mass cancel --> | ||
<record id="model_estate_property_action_cancel" model="ir.actions.server"> | ||
<field name="name">Mass cancel</field> | ||
<field name="model_id" ref="estate.model_estate_property"/> | ||
<field name="binding_model_id" ref="estate.model_estate_property"/> | ||
<field name="binding_view_types">list</field> | ||
<field name="state">code</field> | ||
<field name="code">action = records.action_cancel()</field> | ||
</record> | ||
</data> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import estate_property_infos | ||
from . import estate_property |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
from odoo import api, exceptions, fields, models | ||
from datetime import date | ||
from dateutil.relativedelta import relativedelta | ||
|
||
|
||
class Estate_Property(models.Model): | ||
_name = "estate_property" | ||
_description = "Estate properties" | ||
active = False | ||
|
||
name = fields.Char(required=True, string="Title") | ||
|
||
status = fields.Selection( | ||
[ | ||
("new", "New"), | ||
("offer_received", "Offer received"), | ||
("offer_accepted", "Offer Accepted"), | ||
("sold", "Sold"), | ||
("canceled", "Canceled"), | ||
], | ||
default="new", | ||
readonly=True, | ||
copy=False, | ||
string="Sale State", | ||
) | ||
|
||
description = fields.Text(copy=False, string="Description") | ||
|
||
postcode = fields.Char( | ||
help="Une adresse serait mieux mais bon...", string="Postcode" | ||
) | ||
|
||
date_availability = fields.Date( | ||
default=(date.today() + relativedelta(months=+3)), | ||
copy=False, | ||
string="Available From", | ||
) | ||
|
||
expected_price = fields.Float( | ||
default=0.0, required=True, copy=False, string="Expected Price" | ||
) | ||
|
||
selling_price = fields.Float(readonly=True, string="Selling Price") | ||
|
||
bedrooms = fields.Integer(default=2, string="Bedrooms") | ||
|
||
living_area = fields.Integer(string="Living Area (sqm)") | ||
|
||
facades = fields.Integer(default=2, string="Facades") | ||
|
||
garage = fields.Boolean(default=False, string="Garage") | ||
|
||
garden = fields.Boolean(default=False, string="Garden") | ||
|
||
garden_area = fields.Integer(default=0, string="Garden Area (sqm)") | ||
|
||
garden_orientation = fields.Selection( | ||
[("north", "North"), ("south", "South"), ("west", "West"), ("east", "East")], | ||
string="Garden Orientation" | ||
) | ||
|
||
property_type = fields.Many2one("estate_property_type", string="Property Type") | ||
|
||
buyer = fields.Many2one("res.partner", copy=False, string="Buyer") | ||
|
||
salesperson = fields.Many2one( | ||
"res.users", default=(lambda self: self.env.user), string="Salesman" | ||
) | ||
|
||
tag_ids = fields.Many2many("estate_property_tag", string="Property Tags") | ||
|
||
offer_ids = fields.One2many("estate_property_offer", "property_id", string="Offers") | ||
|
||
total_area = fields.Integer(compute="_compute_total_area", string="Total Area") | ||
|
||
best_offer = fields.Float(compute="_compute_best_offer", default=0.0, string="Best Offer") | ||
|
||
_sql_constraints = [ | ||
("check_positive_expected_price", "CHECK(expected_price >= 0.0)", "Expected Price should be a positive number."), ("check_positive_selling_price", "CHECK(selling_price >= 0.0)", "Selling Price should be a positive number.") | ||
] | ||
|
||
@api.depends("garden_area", "living_area") | ||
def _compute_total_area(self): | ||
for record in self: | ||
record.total_area = record.garden_area + record.living_area | ||
|
||
@api.depends("offer_ids") | ||
def _compute_best_offer(self): | ||
for record in self: | ||
record.best_offer = max(record.offer_ids.mapped("price")) | ||
|
||
@api.onchange("garden") | ||
def _onchange_garden(self): | ||
if self.garden: | ||
self.garden_area = 10 | ||
self.garden_orientation = "north" | ||
else: | ||
self.garden_area = 0 | ||
self.garden_orientation = "" | ||
|
||
@api.constrains("selling_price", "expected_price") | ||
def _check_expected_vs_selling_price(self): | ||
for record in self: | ||
if (record.selling_price > 0.0) and (record.selling_price < 0.9 * record.expected_price): | ||
raise exceptions.ValidationError(r"Cannot sell for less than 90% of expected price.") | ||
|
||
def action_sold(self): | ||
for record in self: | ||
if record.status != "canceled": | ||
record.status = "sold" | ||
else: | ||
raise exceptions.UserError("Canceled properties cannot be sold.") | ||
return True | ||
|
||
def action_cancel(self): | ||
for record in self: | ||
if record.status != "sold": | ||
record.status = "canceled" | ||
else: | ||
raise exceptions.UserError("Sold properties cannot be canceled.") | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from odoo import api, exceptions, fields, models | ||
from datetime import date | ||
from dateutil.relativedelta import relativedelta | ||
|
||
|
||
class Estate_Property_Type(models.Model): | ||
_name = "estate_property_type" | ||
_description = "Estate property Types" | ||
active = False | ||
|
||
name = fields.Char( | ||
required=True, | ||
string="Type" | ||
) | ||
|
||
_sql_constraints = [ | ||
("check_unique_type", "UNIQUE(name)", "Property types must be unique.") | ||
] | ||
|
||
|
||
class Estate_Property_Tag(models.Model): | ||
_name = "estate_property_tag" | ||
_description = "Estate property Tags" | ||
|
||
name = fields.Char( | ||
required=True, | ||
string="Type" | ||
) | ||
|
||
property_estate_ids = fields.Many2many( | ||
"estate_property", | ||
string="Estate Properties" | ||
) | ||
|
||
_sql_constraints = [ | ||
("check_unique_tag", "UNIQUE(name)", "Property tags must be unique.") | ||
] | ||
|
||
|
||
class Estate_Property_Offer(models.Model): | ||
_name = "estate_property_offer" | ||
_description = "Estate Property Offers" | ||
|
||
price = fields.Float( | ||
string="Price" | ||
) | ||
|
||
status = fields.Selection( | ||
[("accepted", "Accepted"), ("refused", "Refused")], | ||
readonly=True, | ||
copy=False, | ||
string="Status" | ||
) | ||
|
||
partner_id = fields.Many2one( | ||
'res.partner', | ||
required=True, | ||
string="Partner" | ||
) | ||
|
||
property_id = fields.Many2one( | ||
'estate_property', | ||
string="Property" | ||
) | ||
|
||
validity = fields.Integer( | ||
default=7, | ||
string="Validity (days)" | ||
) | ||
|
||
deadline = fields.Date( | ||
compute="_compute_deadline", | ||
copy=False, | ||
string="Deadline" | ||
) | ||
|
||
_sql_constraints = [ | ||
("check_positive_price", "CHECK(price > 0.0)", "Offer Price should be a positive number (higher than 0).") | ||
] | ||
|
||
@api.depends("validity") | ||
def _compute_deadline(self): | ||
for record in self: | ||
record.deadline = date.today() + relativedelta(days=+record.validity) | ||
|
||
def _inverse_deadline(self): | ||
for record in self: | ||
record.validity = relativedelta(date.today(), record.deadline) | ||
|
||
def action_accept(self): | ||
for record in self: | ||
if not any(offer_status == "accepted" for offer_status in record.property_id.offer_ids.mapped("status")): | ||
# Set values in the Property itself | ||
record.property_id.selling_price = record.price | ||
record.property_id.buyer = record.partner_id | ||
|
||
record.status = "accepted" | ||
else: | ||
raise exceptions.UserError("An offer has already been accepted.") | ||
return True | ||
|
||
def action_refuse(self): | ||
for record in self: | ||
if record.status == "accepted": | ||
# Set values in the Property itself | ||
record.property_id.selling_price = 0.0 | ||
record.property_id.buyer = None | ||
record.status = "refused" | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1 | ||
estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1 | ||
estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 | ||
estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1 |
Oops, something went wrong.