Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aaha - Technical Training #49

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
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
13 changes: 13 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
'name': 'Real Estate',
'depends': ['base'],
'application': True,
'data': [
'security/ir.model.access.csv',
'views/estate_property_views.xml',
'views/estate_property_offer_views.xml',
'views/estate_property_type_views.xml',
'views/estate_property_tag_views.xml',
'views/estate_menus.xml',
]
}
4 changes: 4 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import estate_property_offer
from . import estate_property_tag
from . import estate_property_type
from . import estate_property
90 changes: 90 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_is_zero, float_compare
from odoo.exceptions import ValidationError


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

name = fields.Char(required=True, string="Title")
description = fields.Text(string="Description")
postcode = fields.Char(string="Postcode")
date_availability = fields.Date(default=fields.Date.add(fields.Date.today(), months=3), copy=False, string="Available From")
expected_price = fields.Float(required=True, string="Expected Price")
selling_price = fields.Float(readonly=True, copy=False, string="Selling Price")
bedrooms = fields.Integer(default=2, string="Bedrooms")
living_area = fields.Integer(string="Living Area (sqm)")
facades = fields.Integer(string="Facades")
garage = fields.Boolean(string="Garage")
garden = fields.Boolean(string="Garden")
garden_area = fields.Integer(string="Garden Area (sqm)")
garden_orientation = fields.Selection(
string="Garden Orientation",
selection=[("north", "North"), ("south", "South"), ("east", "East"), ("west", "West")],
help="Type to detect orientation of the garden")
active = fields.Boolean(default=True)
state = fields.Selection(
default='new',
selection=[
('new', 'New'),
('offer_received', 'Offer Received'),
('offer_accepted', 'Offer Accepted'),
('sold', 'Sold'),
('canceled', 'Canceled')])
salesperson = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user)
buyer = fields.Many2one("res.partner", copy=False, string="Buyer")
tag_ids = fields.Many2many("estate.property.tag")
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
total_area = fields.Integer(compute="_compute_total_area", string="Total Area (sqm)")
best_price = fields.Float(compute="_compute_best_price", string="Best Price")
type_id = fields.Many2one("estate.property.type", string="Property Type")

_sql_constraints = [
("check_expected_price", "CHECK(expected_price > 0)",
"A property expected price must be strictly positive."),
("check_selling_price", "CHECK(selling_price >= 0)",
"A property selling price must be positive.")
]

@api.constrains("selling_price", "expected_price")
def _check_selling_price(self):
for record in self:
if not float_is_zero(record.selling_price, precision_digits = 2) \
and float_compare(record.selling_price, 0.9 * record.expected_price, precision_digits = 2) < 0:
raise ValidationError(message="The selling price must be atleast 90% of exptected price")

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

@api.depends("offer_ids.price")
def _compute_best_price(self):
for record in self:
record.best_price = max(record.offer_ids.mapped("price"), default=0.0)

@api.onchange('garden')
def _onchange_garden(self):
if self.garden:
self.garden_orientation = "north"
self.garden_area = 10
else:
self.garden_orientation = ''
self.garden_area = 0

def action_set_sold(self):
for record in self:
if record.state == "canceled":
raise UserError("Canceled properties cannot be sold")
record.state = "sold"
return True

def action_set_canceled(self):
for record in self:
if record.state == "sold":
raise UserError("This property has already been sold")
record.state = "canceled"
return True
50 changes: 50 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from odoo import models, fields, api
from odoo.exceptions import UserError


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

price = fields.Float(string="Price")
status = fields.Selection(copy=False, string="Status", selection=[("accepted", "Accepted"), ("refused", "Refused")])
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
property_id = fields.Many2one("estate.property", required=True)
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("estate.property.type", related='property_id.type_id', store=True)

_sql_constraints = [
("check_price", "CHECK(price > 0)",
"An offer price must be strictly positive.")
]

@api.depends("validity")
def _compute_date_deadline(self):
for record in self:
record.date_deadline = fields.Date.add((record.create_date or fields.Date.today()), days=record.validity)

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

def action_accept_offer(self):
for record in self:
if record.property_id.state == 'offer_accepted' and record.property_id.buyer != record.partner_id:
raise UserError("This property has other accepted offer")
record.status = "accepted"
record.property_id.buyer = record.partner_id
record.property_id.selling_price = record.price
record.property_id.state = 'offer_accepted'
return True


def action_refuse_offer(self):
for record in self:
if record.property_id.buyer == record.partner_id:
record.property_id.buyer = None
record.property_id.selling_price = 0
record.property_id.state = 'new'
record.status = "refused"
return True
15 changes: 15 additions & 0 deletions estate/models/estate_property_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from odoo import models, fields


class EstatePropertyTag(models.Model):
_name = "estate.property.tag"
_description = "Real Estate Property Tag"
_order = "name"

_sql_constraints = [
("check_unique_name", "UNIQUE(name)",
"A property tag name must be unique")
]

name = fields.Char(required=True)
color = fields.Integer(string="Color")
23 changes: 23 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from odoo import models, fields, api


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

_sql_constraints = [
("check_unique_name", "UNIQUE(name)",
"A property tag name must be unique")
]

name = fields.Char(required=True)
property_ids = fields.One2many("estate.property", "type_id")
sequence = fields.Integer("Sequence")
offer_ids = fields.One2many("estate.property.offer", "property_type_id")
offer_count = fields.Integer(compute="_compute_offers_count")

@api.depends("offer_ids")
def _compute_offers_count(self):
for record in self:
record.offer_count = len(record.offer_ids)
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
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
12 changes: 12 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<odoo>
<menuitem id="estate_menu_root" name="Real Estate">
<menuitem id="estate_level_menu_advertisements" name="Advertisements">
<menuitem id="estate_property_menu_action" name="Properties" action="estate_property_action"/>
</menuitem>
<menuitem id="estate_level_menu_settings" name="Settings">
<menuitem id="estate_property_type_menu_action" name="Property Types" action="estate_property_type_action"/>
<menuitem id="estate_property_tag_menu_action" name="Property Tags" action="estate_property_tag_action"/>
</menuitem>
</menuitem>
</odoo>
44 changes: 44 additions & 0 deletions estate/views/estate_property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0"?>
<odoo>
<record id="estate_property_offer_view_tree" model="ir.ui.view">
<field name="name">estate.property.offer.tree</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Channel" decoration-success="status == 'accepted'"
decoration-danger="status == 'refused'">
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<button name="action_accept_offer" type="object" string="Accept" icon="fa-check" invisible="status in ('accepted', 'refused')"/>
<button name="action_refuse_offer" type="object" string="Refuse" icon="fa-times" invisible="status in ('accepted', 'refused')"/>
<field name="status" invisible="1"/>
</tree>
</field>
</record>

<record id="estate_property_offer_view_form" model="ir.ui.view">
<field name="name">estate.property.offer.form</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<form string="Property">
<sheet>
<group>
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="status"/>
</group>
</sheet>
</form>
</field>
</record>

<record id="estate_property_offer_action" model="ir.actions.act_window">
<field name="name">Property Offers</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">tree,form</field>
<field name="domain">[("property_type_id", "=", active_id)]</field>
</record>
</odoo>
42 changes: 42 additions & 0 deletions estate/views/estate_property_tag_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0"?>
<odoo>
<record id="estate_property_tag_action" model="ir.actions.act_window">
<field name="name">Add Tag</field>
<field name="res_model">estate.property.tag</field>
<field name="view_mode">tree,form</field>
</record>

<record id="estate_property_tag_view_tree" model="ir.ui.view">
<field name="name">estate.property.tag.tree</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Channel">
<field name="name"/>
</tree>
</field>
</record>

<record id="estate_property_tag_view_form" model="ir.ui.view">
<field name="name">estate.property.tag.form</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<form string="Property">
<sheet>
<h2>
<field name="name"/>
</h2>
</sheet>
</form>
</field>
</record>

<record id="estate_property_tag_view_search" model="ir.ui.view">
<field name="name">estate.property.tag.search</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<search string="Search Properties">
<field name="name"/>
</search>
</field>
</record>
</odoo>
60 changes: 60 additions & 0 deletions estate/views/estate_property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0"?>
<odoo>
<record id="estate_property_type_action" model="ir.actions.act_window">
<field name="name">Add Type</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">tree,form</field>
</record>

<record id="estate_property_type_view_tree" model="ir.ui.view">
<field name="name">estate.property.type.tree</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<tree string="Channel">
<field name="name"/>
<field name="sequence" widget="handle"/>
</tree>
</field>
</record>

<record id="estate_property_type_view_form" model="ir.ui.view">
<field name="name">estate.property.type.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form string="Property">
<sheet>
<h2>
<field name="name"/>
</h2>
<notebook>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="action" name="%(estate_property_offer_action)d" icon="fa-dollar">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="offer_count"/>
</span>
<span class="o_stat_text"> Offers</span>
</div>
</button>
</div>
<page string="Properties">
<group>
<field name="property_ids"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

<record id="estate_property_type_view_search" model="ir.ui.view">
<field name="name">estate.property.type.search</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<search string="Search Properties">
<field name="name"/>
</search>
</field>
</record>
</odoo>