-
Notifications
You must be signed in to change notification settings - Fork 2.4k
[ADD] estate : Real Estate Advertisement App #927
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
base: 18.0
Are you sure you want to change the base?
Changes from 8 commits
6b97ae5
42f72a9
ae10966
25213fe
8afd388
dec6f49
830bfc6
d02d21f
5782473
1d2d753
9b50772
1065ee5
cd2b9e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "Real Estate", | ||
"application": True, | ||
"installable": True, | ||
"category": "Real Estate/Brokerage", | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/estate_property_views.xml", | ||
"views/estate_property_type_views.xml", | ||
"views/estate_property_tag_views.xml", | ||
"views/estate_property_offer_views.xml", | ||
"views/estate_menus.xml", | ||
], | ||
"license": "LGPL-3" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from . import estate_property | ||
from . import estate_property_type | ||
from . import estate_property_tag | ||
from . import estate_property_offer |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,83 @@ | ||||||||||||||||||||||
from datetime import timedelta | ||||||||||||||||||||||
from odoo import api, fields, models | ||||||||||||||||||||||
from odoo.exceptions import UserError | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
class EstateModel(models.Model): | ||||||||||||||||||||||
_name = "estate.property" | ||||||||||||||||||||||
_description = "Real Estate Advertisement Model" | ||||||||||||||||||||||
|
||||||||||||||||||||||
name = fields.Char(required=True) | ||||||||||||||||||||||
description = fields.Text() | ||||||||||||||||||||||
postcode = fields.Char() | ||||||||||||||||||||||
date_availability = fields.Date( | ||||||||||||||||||||||
copy=False, default=fields.Date.today() + timedelta(days=90) | ||||||||||||||||||||||
) | ||||||||||||||||||||||
active = fields.Boolean(default=True) | ||||||||||||||||||||||
expected_price = fields.Float(required=True) | ||||||||||||||||||||||
selling_price = fields.Float(readonly=True, copy=False) | ||||||||||||||||||||||
bedrooms = fields.Integer(default=2) | ||||||||||||||||||||||
living_area = fields.Integer() | ||||||||||||||||||||||
facades = fields.Integer() | ||||||||||||||||||||||
garage = fields.Boolean() | ||||||||||||||||||||||
garden = fields.Boolean() | ||||||||||||||||||||||
garden_area = fields.Integer() | ||||||||||||||||||||||
state = fields.Selection( | ||||||||||||||||||||||
string="state", | ||||||||||||||||||||||
default="New", | ||||||||||||||||||||||
required=True, | ||||||||||||||||||||||
copy=False, | ||||||||||||||||||||||
selection=[ | ||||||||||||||||||||||
("New", "New"), | ||||||||||||||||||||||
("Offer Received", "Offer Received"), | ||||||||||||||||||||||
("Offer Accepted", "Offer Accepted"), | ||||||||||||||||||||||
("Sold", "Sold"), | ||||||||||||||||||||||
("Cancelled", "Cancelled"), | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
], | ||||||||||||||||||||||
) | ||||||||||||||||||||||
garden_orientation = fields.Selection( | ||||||||||||||||||||||
string="Garden Orientation", | ||||||||||||||||||||||
selection=[ | ||||||||||||||||||||||
("north", "North"), | ||||||||||||||||||||||
("south", "South"), | ||||||||||||||||||||||
("east", "East"), | ||||||||||||||||||||||
("west", "West"), | ||||||||||||||||||||||
], | ||||||||||||||||||||||
help="Select the direction the garden faces", | ||||||||||||||||||||||
) | ||||||||||||||||||||||
property_type_id = fields.Many2one("estate.property.type") | ||||||||||||||||||||||
buyer = fields.Many2one("res.partner", readonly=True) | ||||||||||||||||||||||
salesman = fields.Many2one("res.users") | ||||||||||||||||||||||
tag_ids = fields.Many2many("estate.property.tag") | ||||||||||||||||||||||
offer_ids = fields.One2many("estate.property.offer", inverse_name="property_id") | ||||||||||||||||||||||
total_area = fields.Float(compute="_compute_total_area") | ||||||||||||||||||||||
best_price = fields.Float(compute="_compute_best_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 _set_garden_default_values(self): | ||||||||||||||||||||||
if self.garden: | ||||||||||||||||||||||
self.garden_area = 10 | ||||||||||||||||||||||
self.garden_orientation = "north" | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
self.garden_area = 0 | ||||||||||||||||||||||
self.garden_orientation = "" | ||||||||||||||||||||||
|
||||||||||||||||||||||
def action_property_sold(self): | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without any offer accepted should not to able to change status to sold. |
||||||||||||||||||||||
if self.state in ["Sold", "Cancelled"]: | ||||||||||||||||||||||
raise UserError(f"Property is already {self.state}") | ||||||||||||||||||||||
self.state = "Sold" | ||||||||||||||||||||||
|
||||||||||||||||||||||
def action_property_cancelled(self): | ||||||||||||||||||||||
if self.state in ["Sold", "Cancelled"]: | ||||||||||||||||||||||
raise UserError(f"Property is already {self.state}") | ||||||||||||||||||||||
self.state = "Cancelled" |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,52 @@ | ||||||
from datetime import timedelta | ||||||
from odoo import api, fields, models | ||||||
from odoo.exceptions import UserError | ||||||
|
||||||
|
||||||
class EstateOfferModel(models.Model): | ||||||
_name = "estate.property.offer" | ||||||
_description = "Real Estate Property Offer Model" | ||||||
|
||||||
price = fields.Float() | ||||||
status = fields.Selection( | ||||||
[("Accepted", "Accepted"), ("Refused", "Refused")], copy=False | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
) | ||||||
partner_id = fields.Many2one("res.partner", required=True) | ||||||
property_id = fields.Many2one("estate.property", required=True) | ||||||
validity = fields.Integer(default=7) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the use of this field? |
||||||
date_deadline = fields.Date(default=fields.Date.today() + timedelta(days=7)) | ||||||
|
||||||
@api.depends("validity", "create_date") | ||||||
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 - record.create_date.date()).days | ||||||
if record.date_deadline | ||||||
else 0 | ||||||
) | ||||||
|
||||||
def action_offer_confirm(self): | ||||||
for record in self: | ||||||
if record.status in ["Accepted", "Refused"]: | ||||||
raise UserError(f"Offer is already {record.status}") | ||||||
|
||||||
for offer in record.property_id.offer_ids: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why two for loops?. |
||||||
if offer.id == record.id: | ||||||
record.status = "Accepted" | ||||||
record.property_id.state = "Offer Accepted" | ||||||
record.property_id.buyer = record.partner_id | ||||||
record.property_id.selling_price = record.price | ||||||
else: | ||||||
offer.status = "Refused" | ||||||
|
||||||
def action_offer_cancel(self): | ||||||
for record in self: | ||||||
if record.status in ["Accepted", "Refused"]: | ||||||
raise UserError(f"Offer is already {record.status}") | ||||||
record.status = "Refused" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class EstateTagModel(models.Model): | ||
_name = "estate.property.tag" | ||
_description = "Real Estate Property Tag Model" | ||
|
||
name = fields.Char(required=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class EstateTypeModel(models.Model): | ||
_name = "estate.property.type" | ||
_description = "Real Estate Property Type Model" | ||
|
||
name = fields.Char(required=True) |
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_estate_property_user,model_estate_property,model_estate_property,base.group_user,1,1,1,1 | ||
access_estate_property_type_user,model_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 | ||
access_estate_property_tag_user,model_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 | ||
access_estate_property_offer_user,model_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
|
||
<odoo> | ||
<menuitem id="estate_menu_root" name="Real Estate"> | ||
<menuitem id="estate_advertisements_menu" name="Advertisements"> | ||
<menuitem id="estate_property_adv_menu_action" action="action_estate_property" name="Property" /> | ||
</menuitem> | ||
<menuitem id="estate_settings_menu" name="Settings"> | ||
<menuitem id="estate_property_menu_action" action="action_estate_property" name="Property" /> | ||
<menuitem id="estate_property_type_menu_action" action="action_estate_property_type" name="Property Types" /> | ||
<menuitem id="estate_property_tag_menu_action" action="action_estate_property_tag" name="Property Tags" /> | ||
</menuitem> | ||
</menuitem> | ||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?xml version="1.0"?> | ||
|
||
<odoo> | ||
<record id="action_estate_property_offer" model="ir.actions.act_window"> | ||
<field name="name">Property Offers</field> | ||
<field name="res_model">estate.property.offer</field> | ||
<field name="view_mode">list,form</field> | ||
<field name="help" type="html"> | ||
<p class="o_view_nocontent_smiling_face"> | ||
Create the first property Type | ||
</p> | ||
</field> | ||
</record> | ||
<record id="list_view_estate_property_offer" model="ir.ui.view"> | ||
<field name="name">Estate Properties Offer list</field> | ||
<field name="model">estate.property.offer</field> | ||
<field name="arch" type="xml"> | ||
<list> | ||
<field name="price" string="Price" /> | ||
<field name="partner_id" string="Partner" /> | ||
<field name="validity" string="Validity" /> | ||
<field name="date_deadline" string="Deadline" /> | ||
<button name="action_offer_confirm" type="object" icon="fa-check" /> | ||
<button name="action_offer_cancel" type="object" icon="fa-times" /> | ||
<field name="status" string="Status" /> | ||
</list> | ||
</field> | ||
</record> | ||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?xml version="1.0"?> | ||
|
||
<odoo> | ||
<record id="action_estate_property_tag" model="ir.actions.act_window"> | ||
<field name="name">Property Tag</field> | ||
<field name="res_model">estate.property.tag</field> | ||
<field name="view_mode">list,form</field> | ||
<field name="help" type="html"> | ||
<p class="o_view_nocontent_smiling_face"> | ||
Create the first property Tag | ||
</p> | ||
</field> | ||
</record> | ||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?xml version="1.0"?> | ||
|
||
<odoo> | ||
<record id="action_estate_property_type" model="ir.actions.act_window"> | ||
<field name="name">Property Types</field> | ||
<field name="res_model">estate.property.type</field> | ||
<field name="view_mode">list,form</field> | ||
<field name="help" type="html"> | ||
<p class="o_view_nocontent_smiling_face"> | ||
Create the first property Type | ||
</p> | ||
</field> | ||
</record> | ||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<?xml version="1.0"?> | ||
|
||
<odoo> | ||
<record id="action_estate_property" model="ir.actions.act_window"> | ||
<field name="name">Properties</field> | ||
<field name="res_model">estate.property</field> | ||
<field name="view_mode">list,form</field> | ||
<field name="help" type="html"> | ||
<p class="o_view_nocontent_smiling_face"> | ||
Create the first property | ||
</p> | ||
</field> | ||
</record> | ||
<record id="list_view_estate_property" model="ir.ui.view"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be one empty line before it for better visibility. |
||
<field name="name">Estate Properties list</field> | ||
<field name="model">estate.property</field> | ||
<field name="arch" type="xml"> | ||
<list> | ||
<field name="name" string="Title" /> | ||
<field name="postcode" string="Postcode" /> | ||
<field name="bedrooms" string="Bedrooms" /> | ||
<field name="living_area" string="Living Area (sqm)" /> | ||
<field name="expected_price" string="Expected Price" /> | ||
<field name="selling_price" string="Selling Price" /> | ||
<field name="date_availability" string="Available From" /> | ||
</list> | ||
</field> | ||
</record> | ||
<record id="form_view_estate_property" model="ir.ui.view"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be one empty line before it for better visibility. |
||
<field name="name">Estate Property Form</field> | ||
<field name="model">estate.property</field> | ||
<field name="arch" type="xml"> | ||
<form> | ||
<header> | ||
<button name="action_property_sold" type="object" string="Sold"/> | ||
<button name="action_property_cancelled" type="object" string="Cancelled"/> | ||
</header> | ||
<sheet> | ||
<div> | ||
<h1> | ||
<field name="name"/> | ||
</h1> | ||
<span> | ||
<field name="tag_ids" widget="many2many_tags" /> | ||
</span> | ||
</div> | ||
<group> | ||
<group> | ||
<field name="state" string="State" /> | ||
<field name="postcode" string="Postcode" /> | ||
<field name="property_type_id"/> | ||
<field name="date_availability" string="Available From" /> | ||
</group> | ||
<group> | ||
<field name="expected_price" string="Expected Price" /> | ||
<field name="best_price" string="Best Offer" /> | ||
<field name="selling_price" string="Selling Price" /> | ||
</group> | ||
</group> | ||
<notebook> | ||
<page string="Description"> | ||
<group> | ||
<field name="description" string="Description" /> | ||
<field name="bedrooms" string="Bedrooms" /> | ||
<field name="living_area" string="Living Area (sqm)" /> | ||
<field name="facades" string="Facades" /> | ||
<field name="garage" string="Garage" /> | ||
<field name="garden" string="Garden" /> | ||
<field name="garden_area" string="Garden Area (sqm)" invisible="not garden" /> | ||
<field name="garden_orientation" string="Garden Orientation" invisible="not garden" /> | ||
<field name="total_area" string="Total Area (sqm)" /> | ||
</group> | ||
</page> | ||
<page string="Offers"> | ||
<group> | ||
<field name="offer_ids" /> | ||
</group> | ||
</page> | ||
<page string="Other Info"> | ||
<group> | ||
<field name="salesman" string="Salesman"/> | ||
<field name="buyer" string="Buyer" /> | ||
</group> | ||
</page> | ||
</notebook> | ||
</sheet> | ||
</form> | ||
</field> | ||
</record> | ||
<record id="search_view_estate_property" model="ir.ui.view"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be one empty line before it for better visibility. |
||
<field name="name">Estate Property Search</field> | ||
<field name="model">estate.property</field> | ||
<field name="arch" type="xml"> | ||
<search string="Search Properties"> | ||
<field name="name" string="Title" /> | ||
<field name="postcode" string="Postcode" /> | ||
<field name="expected_price" string="Expected Price" /> | ||
<field name="bedrooms" string="Bedrooms" /> | ||
<field name="living_area" string="Living Area (sqm)" /> | ||
<field name="facades" string="Facades" /> | ||
<filter string="Available" name="state" domain="['|', ('state', '=', 'New'), ('state', '=', 'Offer Received')]"/> | ||
<group> | ||
<filter string="Postcode" name="postcode" context="{'group_by': 'postcode'}"/> | ||
</group> | ||
</search> | ||
</field> | ||
</record> | ||
</odoo> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state field should display in the header of the form view.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please make these changes?