Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
'name': "Real Estate",
'author': "Kunj Koradiya",
'description': "This is the description",
'license': "LGPL-3",
'depends': ['base', 'web'],
'data': [
'security/ir.model.access.csv',
'views/res_users_view.xml',
'views/estate_property_offers.xml',
'views/estate_property_maintenance.xml',
'views/estate_property_views.xml',
'views/estate_type_views.xml',
'views/estate_property_tags.xml',
'views/estate_menus.xml',
],
}
7 changes: 7 additions & 0 deletions estate/models/ResUsers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from odoo import fields, models


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

property_ids = fields.One2many('estate.property', 'partner_id')
6 changes: 6 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from . import estate_property
from . import estate_property_offer
from . import estate_property_tags
from . import estate_property_type
from . import estate_property_maintenance
from . import ResUsers
127 changes: 127 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from datetime import date
from dateutil.relativedelta import relativedelta

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


class EstateProperty(models.Model):
_name = 'estate.property'
_description = "Estate Property"
_order = "id desc"

name = fields.Char(default="Unknown", required=True)
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(
default=date.today() + relativedelta(months=3), copy=False
)
expected_price = fields.Float(required=True)
selling_price = fields.Float(readonly=True)
bedrooms = fields.Integer(default=2)
living_area = fields.Integer("Living Area (sqm)")
facades = fields.Integer()
garage = fields.Boolean()
garden = fields.Boolean()
last_seen = fields.Datetime(default=fields.Datetime.now)
garden_area = fields.Integer("Garden Area (sqm)")
active = fields.Boolean(default=True)
partner_id = fields.Many2one(
'res.users', string="Salesperson", default=lambda self: self.env.user)
buyer_id = fields.Many2one('res.partner')
property_type_id = fields.Many2one('estate.property.type')
property_tag_ids = fields.Many2many('estate.property.tags')
offer_ids = fields.One2many('estate.property.offer', 'property_id')
color = fields.Integer('Color Index')
maintenance_id = fields.One2many(
'estate.property.maintenance', 'property_id')
garden_orientation = fields.Selection(
selection=[
('east', "East"),
('west', "West"),
('north', "North"),
('south', "South"),
],
help="This field tells us the direction of the garden"
)
state = fields.Selection(
default='new',
selection=[
('new', "New"),
('offer_received', "Offer Received"),
('offer_accepted', "Offer Accepted"),
('sold', "Sold"),
('cancelled', "Cancelled"),
],
help="This field tells us the state of the property.",

)
total_area = fields.Integer(compute='_compute_total_area')
total_cost = fields.Integer(compute='_compute_total_cost')
best_price = fields.Integer(compute='_compute_best_price', store=True)

# SQL CONSTRAINT
_check_expected_price = models.Constraint(
'CHECK(expected_price > 0)', "Expected Price must be positive"
)
_check_selling_price = models.Constraint(
'CHECK(selling_price >= 0)', "Selling Price must be positive"
)

# DEPENDS DECORATOR
@api.depends('living_area', 'garden_area')
def _compute_total_area(self):
self.total_area = (self.living_area or 0) + (self.garden_area or 0)

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

best = [offer.price for offer in self.offer_ids]
record.best_price = max(best) if best else 0.0

@api.depends('maintenance_id.cost')
def _compute_total_cost(self):
for record in self:
record.total_cost = (
sum(record.maintenance_id.mapped('cost')
) if record.maintenance_id else 0.0
)

# ONCHANGE DECORATOR
@api.onchange('garden')
def _onchange_garden(self):
if self.garden:
self.garden_area = 10
self.garden_orientation = 'north'
else:
self.garden_area = None
self.garden_orientation = None

# CONSTRAIN DECORATOR
@api.constrains('selling_price', 'expected_price')
def _constrain_selling_price(self):
if self.selling_price < self.expected_price * 0.90 and self.buyer_id:
raise UserError(
_("Selling price cannot be lower then the 90% percent of the expected price")
)

# BUTTON ACTION - SOLD/CANCEL
def action_sold(self):
if self.state == 'cancelled':
raise UserError("There is not any maintenance !")
else:
for record in self.maintenance_id:
if record.status != 'done':
raise UserError("property is not under maintenance")
self.state = 'sold'

def action_cancel(self):
if self.state == 'sold':
raise UserError("Sold Property can not be cancel !")
else:
self.state = 'cancelled'
29 changes: 29 additions & 0 deletions estate/models/estate_property_maintenance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from odoo import api, fields, models
from odoo.exceptions import UserError


class EstatePropertyMaintenance(models.Model):
_name = 'estate.property.maintenance'
_description = "EstatePropertyMaintenance"

name = fields.Char("Title")
cost = fields.Integer()
property_id = fields.Many2one(
'estate.property', required=True
)
status = fields.Selection(
default='new',
selection=[
('new', "New"),
('approved', "Approved"),
('done', "Done")
]
)

@api.constrains('cost', 'status')
def _check_cost(self):
for record in self:
if record.status == 'approved' and record.cost <= 0:
raise UserError(
'Approved cost must be greater then 0'
)
87 changes: 87 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from dateutil.relativedelta import relativedelta

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


class EstatePropertyOffer(models.Model):
_name = 'estate.property.offer'
_description = "Estate Property Offer"
_order = "price desc"

price = fields.Float()
status = fields.Selection(
selection=[('accepted', "Accepted"), ('refused', "Refused")], copy=False
)
partner_id = fields.Many2one('res.partner', required=True)
property_id = fields.Many2one('estate.property', required=True)
validity = fields.Integer(default=7)
date_deadline = fields.Date(
"Deadline", compute='_compute_date_deadline', inverse='_inverse_date_deadline'
)
_offer_price_check = models.Constraint(
'CHECK(price >= 0)', "Offer price should be strictly positive"
)
property_type_id = fields.Many2one(
related='property_id.property_type_id', store=True)

# DEPENDS DECORATOR
@api.depends('validity', 'create_date')
def _compute_date_deadline(self):
for record in self:
start_date = (
record.create_date.date() if record.create_date else fields.Date.today()
)
record.date_deadline = start_date + \
relativedelta(days=record.validity)

def _inverse_date_deadline(self):
for record in self:
start_date = (
record.create_date.date() if record.create_date else fields.Date.today()
)
record.validity = (record.date_deadline - start_date).days

# BUTTON ACTION - OFFER
def action_accept(self):
if self.property_id.state == 'offer_accepted':
raise UserError(
_("An offer has already been accepted for this property.")
)
self.write({'status': 'accepted'})
for offer in self:
offer.property_id.write({
'buyer_id': offer.partner_id.id,
'selling_price': offer.price,
'state': 'sold',
'active': False
})

def action_refuse(self):
for record in self:
record.status = 'refused'
record.property_id.write({
'buyer_id': None,
'selling_price': None,
})

@api.model_create_multi
def create(self, vals_list):
if not vals_list:
return super().create(vals_list)
property_id = vals_list[0].get('property_id')
new_prices = [vals.get('price', 0) for vals in vals_list]
max_new_price = max(new_prices)
existing_offers = self.env['estate.property.offer'].search([
('property_id', '=', property_id)
])
max_db_price = max(existing_offers.mapped(
'price')) if existing_offers else 0
if max_new_price <= max_db_price:
raise UserError(
"Offer price should be higher then the Existing One!"
)
self.env['estate.property'].browse(
property_id).state = 'offer_received'

return super().create(vals_list)
19 changes: 19 additions & 0 deletions estate/models/estate_property_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import random

from odoo import fields, models


class EstatePropertyTags(models.Model):
_name = 'estate.property.tags'
_description = "Estate Property Tags"
_order = "name"

name = fields.Char("Property Tags", required=True)
color = fields.Integer(
'Color Index', default=lambda self: random.randint(1, 11)
)

# SQL CONSTRAINT
_property_tag_uniq = models.Constraint(
'unique(name)', "Property Tags already exist in database"
)
27 changes: 27 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from odoo import api, fields, models


class EstatePropertyType(models.Model):
_name = 'estate.property.type'
_description = "Estate Property Type"
_order = "name"

sequence = fields.Integer('Sequence', default=1,
help="Used to order Property Type")
name = fields.Char("Property Type", required=True)
offer_ids = fields.One2many('estate.property.offer', 'property_type_id')
offer_count = fields.Integer(compute='_compute_offer')
property_ids = fields.One2many(
'estate.property', "property_type_id", required=True
)

# SQL CONSTRAINT
_property_type_uniq = models.Constraint(
'UNIQUE(name)', "Property Type already exist in database"
)

# DEPEND DECORATOR
@api.depends('offer_ids')
def _compute_offer(self):
for record in self:
record.offer_count = len(record.offer_ids)
6 changes: 6 additions & 0 deletions estate/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1
access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1
access_estate_property_tags,access_estate_property_tags,model_estate_property_tags,base.group_user,1,1,1,1
access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1
access_estate_property_maintenance,access_estate_property_maintenance,model_estate_property_maintenance,base.group_user,1,1,1,1
39 changes: 39 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Estate -->
<menuitem
id="estate_menu_root"
name="Estate"/>

<!-- Adevertisement -->
<menuitem
id="estate_menu_overview"
name="Advertisement"
parent="estate_menu_root"/>
<menuitem
id="estate_prop"
name="Properties"
parent="estate_menu_overview"
action="estate_property_action"/>

<!-- Settings -->
<menuitem
id="estate_menu_setting"
name="Settings"
parent="estate_menu_root"/>
<menuitem
id="estate_prop_type"
name="Property Type"
parent="estate_menu_setting"
action="estate_propety_type_action"/>
<menuitem
id="estate_prop_tags"
name="Property Tags"
parent="estate_menu_setting"
action="estate_property_tags_action"/>
<menuitem
id="estate_prop_maintenance"
name="Property Maintenance"
parent="estate_menu_setting"
action="estate_property_maintenance_action"/>
</odoo>
Loading