Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions estate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
14 changes: 14 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Real Estate",
"description": "Real Estate Management System",
"category": "Tutorials",
"version": "1.1",
"application": True,
"data": [
"security/ir.model.access.csv",
"views/views.xml",
"views/menus.xml"
],
"author": "Odoo S.A.",
"license": "LGPL-3",
}
5 changes: 5 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import building
from . import building_type
from . import tag
from . import offer
from . import salesperson
99 changes: 99 additions & 0 deletions estate/models/building.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from datetime import timedelta

from odoo import models, fields, api
from odoo.exceptions import UserError


class Building(models.Model):
_name = 'estate.building'
_description = 'Buildings'
_order = "id desc"

name = fields.Char()
description = fields.Text()
value = fields.Integer(copy=False)
availability_date = fields.Date(
default=lambda self: fields.Date.today() + timedelta(days=90), copy=False
)
number_of_rooms = fields.Integer(default=2)
garden_area = fields.Integer()
building_area = fields.Integer()
garden_orientation = fields.Selection(
[("north", "North"), ("south", "South"), ("east", "East"), ("west", "West")],
"garden Orientation",
)
active = fields.Boolean(default=True)
state = fields.Selection(
[
("new", "New"),
("offer_received", "Offer Received"),
("offer_accepted", "Offer Accepted"),
("sold", "Sold"),
("canceled", "Canceled"),
],
default="new",
)
post_code = fields.Integer(default=1000)
building_type_id = fields.Many2one("estate.building_type", string="Building Type")
buyer_id = fields.Many2one("res.partner", string="Buyer")
salesperson_id = fields.Many2one(
"res.users", string="Salesperson", default=lambda self: self.env.user
)
tag_ids = fields.Many2many("estate.building_tags", string="Tags")
offer_ids = fields.One2many("estate.offer", "building_id", string="Offers")

total_area = fields.Integer(string="Total Area", compute="_compute_total_area")

best_price = fields.Integer(
string="Best Offer Price",
compute="_compute_best_price",
)
has_garden = fields.Boolean(string="Has Garden", default=False)

_price_constraint = models.Constraint(
"CHECK (value > 0)", "Price must be POSITIVE."
)
_name_constraint = models.Constraint(
"UNIQUE(name)", "Building name must be UNIQUE."
)

@api.depends("building_area", "garden_area")
def _compute_total_area(self):
for record in self:
record.total_area = record.building_area + record.garden_area

@api.depends("offer_ids.price")
def _compute_best_price(self):
for record in self:
if record.offer_ids:
record.best_price = max(record.offer_ids.mapped("price"))
else:
record.best_price = 0

@api.onchange("has_garden")
def _onchange_garden_area(self):
if self.has_garden:
self.garden_area = 10
self.garden_orientation = "north"
else:
self.garden_area = 0
self.garden_orientation = False

def action_set_sold(self):
for record in self:
if record.state == "canceled":
raise UserError(self.env._("Canceled buildings cannot be sold."))
record.state = "sold"

def action_set_canceled(self):
for record in self:
if record.state == "sold":
raise UserError(self.env._("Sold buildings cannot be canceled."))
record.state = "canceled"

@api.ondelete(at_uninstall=False)
def _check_if_sold(self):
for record in self:
if record.state not in ("new", "canceled"):
raise UserError(self.env._("This building cannot be deleted."))
return self
32 changes: 32 additions & 0 deletions estate/models/building_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from odoo import models, fields


class BuildingType(models.Model):
_name = 'estate.building_type'
_description = 'Building Type'
_order = "sequence, name"

name = fields.Char(required=True)
building_ids = fields.One2many(
"estate.building", "building_type_id", string="Buildings"
)
offer_ids = fields.One2many("estate.offer", "property_type_id", string="Offers")
offers_count = fields.Integer(
string="Offers Count",
compute="_compute_offers_count",
)

_name_uniqueness_constraint = models.Constraint(
"UNIQUE (name)", "Building type name must be UNIQUE."
)

sequence = fields.Integer(
default=1,
help="Gives the sequence order when displaying a list of building types.",
)

def _compute_offers_count(self):
for record in self:
record.offers_count = self.env["estate.offer"].search_count(
[("property_type_id", "=", record.id)]
)
84 changes: 84 additions & 0 deletions estate/models/offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from datetime import timedelta

from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_compare


class Offer(models.Model):
_name = 'estate.offer'
_description = 'Offers'
_order = "price desc"

price = fields.Integer(required=True)
status = fields.Selection(
[("accepted", "Accepted"), ("refused", "Refused")],
string="Status",
required=False,
)
building_id = fields.Many2one("estate.building", string="Building")
partner_id = fields.Many2one("res.partner", string="Partner")
validity = fields.Integer(string="Validity (days)", default=7)
date_deadline = fields.Date(
string="Deadline",
compute="_compute_date_deadline",
inverse="_inverse_date_deadline",
)
property_type_id = fields.Many2one(
related="building_id.building_type_id", string="Property Type", store=True
)

_price_positive_constraint = models.Constraint(
"CHECK (price > 0)", "Offer price must be positive."
)

@api.depends("validity")
def _compute_date_deadline(self):
for record in self:
record.date_deadline = fields.Date.today() + timedelta(days=record.validity)

def _inverse_date_deadline(self):
for record in self:
record.validity = (record.date_deadline - fields.Date.today()).days

def action_accept_offer(self):
for record in self:
if record.status != "accepted" and record.building_id.state not in ["sold", "canceled"]:
record.status = "accepted"
record.building_id.state = "offer_accepted"
record.building_id.buyer_id = record.partner_id
record.building_id.value = record.price
other_offers = self.search(
[
("building_id", "=", record.building_id.id),
("id", "!=", record.id),
]
)
other_offers.write({"status": "refused"})
elif record.building_id.state in ["sold", "canceled"]:
raise UserError(self.env._("Cannot accept offers for sold or canceled buildings."))
else:
raise UserError(self.env._("Offer is already accepted."))

def action_refuse_offer(self):
for record in self:
if record.status != "refused":
record.status = "refused"
record.building_id.state = "offer_received"
record.building_id.buyer_id = False
else:
raise UserError(self.env._("Offer is already refused."))

@api.constrains("building_id", "price")
def _check_price(self):
for record in self:
if float_compare(0.9 * record.building_id.value, record.price, precision_digits=2) > 0:
raise UserError(self.env._("Offer price must be at least 90% of the building's value."))

@api.model
def create(self, vals):
for val in vals:
self.env["estate.building"].browse(
val["building_id"]
).state = "offer_received"
return super().create(vals)
8 changes: 8 additions & 0 deletions estate/models/salesperson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from odoo import models, fields


class ResUsers(models.Model):
_name = 'res.users'
_inherit = ['res.users']

building = fields.One2many("estate.building", "salesperson_id", string="Listings")
14 changes: 14 additions & 0 deletions estate/models/tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from odoo import models, fields


class BuildingTag(models.Model):
_name = 'estate.building_tags'
_description = 'Building Tags'
_order = "name"

name = fields.Char(required=True)
color = fields.Integer()

_name_uniqueness_constraint = models.Constraint(
"UNIQUE (name)", "Building tag name must be UNIQUE."
)
5 changes: 5 additions & 0 deletions estate/security/ir.model.access.csv
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
access_first_model,access_first_model,model_estate_building,base.group_user,1,1,1,1
access_building_type_model,access_building_type_model,model_estate_building_type,base.group_user,1,1,1,1
access_building_tags_model,access_building_tags_model,model_estate_building_tags,base.group_user,1,1,1,1
access_offers_model,access_offers_model,model_estate_offer,base.group_user,1,1,1,1
9 changes: 9 additions & 0 deletions estate/views/menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="test_menu_root" name="Estate FelBeit">
<menuitem id="test_first_level_menu" name="First Level">
<menuitem id="test_model_menu_action" action="some_model_action_1"/>
<menuitem id="test_building_type_menu_action" action="some_model_action_2"/>
</menuitem>
</menuitem>
</odoo>
Loading