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

[ADD] estate : added the sprinkles. #214

Draft
wants to merge 16 commits into
base: 18.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 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
4 changes: 4 additions & 0 deletions estate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import models



Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

24 changes: 24 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
'name': 'estate',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove extra lines

'category': 'real estate',

'summary': 'create a estate property',

'website': 'https://www.odoo.com',

'depends': ['base'],
'installable': True,
'application': True,
'license': 'LGPL-3',

'data': [
'security/ir.model.access.csv',
'views/estate_property_views.xml',
'views/estate_property_type_views.xml',
'views/estate_property_tags_views.xml',
'views/estate_property_offer_views.xml',
'views/estate_menus.xml'
],

}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use proper format

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
from . import estate_property_type
from . import estate_property_tags
from . import estate_property_offer

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arrange in alphabetical order

159 changes: 159 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
from odoo import models, fields
from datetime import timedelta, date
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare, float_is_zero

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove duplicated code and use alphabetical order




Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only 2 lines after importing files

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a new line after defining the class's private variables

name = fields.Char(required=True)
description = fields.Text(string="Description")
postcode = fields.Char(string="Postcode")
date_availability = fields.Date(copy=False, default=lambda self: date.today() + timedelta(days=90))
expected_price = fields.Float(string="Expected Price", required=True)
selling_price = fields.Float(string="Selling Price")
bedrooms = fields.Integer(default=2)
active = fields.Boolean(default=True)
living_area = fields.Integer(string="Living Area (sqm)")
facades = fields.Integer(string="Facades")
garage = fields.Boolean(string="Garage Available")
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")
]
)
state = fields.Selection(selection=[
('new', 'New'),
('offer_received', 'Offer Received'),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove extra space

('offer_accepted', 'Offer Accepted'),
('sold', 'Sold'),
('cancelled', 'Cancelled'),
], default='new', string="Status", copy=False)
property_type_id = fields.Many2one('estate.property.type', string="Property Type",required=True,
options={'no_create': True, 'no_edit': True})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use proper formatting. Refer to code base.

buyer_id = fields.Many2one('res.partner', string="Buyer")
seller_id = fields.Many2one('res.users', string="Salesperson", default=lambda self: self.env.user,required=False)
status = fields.Selection([('accepted', 'Accepted'), ('refused', 'Refused')], string="Status")
partner_id = fields.Many2one('res.partner', string="Partner",required=True, ondelete='restrict')
salesperson = fields.Char(string = "Salesperson", required=True)
buyer = fields.Char(string = "Buyers", required=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why buyer?

price = fields.Float(string="Price")
partners = fields.Char(string = "Partner", required=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why partners?

tag_ids = fields.Many2one('estate.property.tag' , string="Tags")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why tag_ids is defined as Many2one?
Also it is defined twice.

total_area = fields.Float(string="Total Area (sqm)", compute="_compute_total_area", store=True,copy=False)
best_offers = fields.Float(string="Best Offers")
offer_ids = fields.One2many(
'estate.property.offer',
'property_id',
string="Offers"
)
validity = fields.Integer(string="Validity (days)")
date_deadline = fields.Date(
string="Deadline",
compute="_compute_date_deadline",
inverse="_inverse_date_deadline",
store=True)
tag_ids = fields.Many2many(
'estate.property.tag',
string='Tags'
)
offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defined twice

best_price = fields.Float(string="Best Price", compute="_compute_best_price", store=True)
offer_received = fields.Boolean(string="Offer Received", compute="_compute_offer_received", store=True)
offer_accepted = fields.Boolean(string="Offer Accepted", compute="_compute_offer_accepted", store=True)



@api.onchange('garden')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arrange all functions properly

def _onchange_garden(self):
if self.garden:
self.garden_area = 10
self.garden_orientation = 'north'
else:
self.garden_area = 0
self.garden_orientation = False

def action_cancel(self):
for record in self:
if record.state == 'sold':
raise UserError("A sold property cannot be cancelled.")
record.state = 'cancelled'

def action_sold(self):
for record in self:
if record.state == 'cancelled':
raise UserError("A cancelled property cannot be sold.")
record.state = 'sold'

_sql_constraints = [
('expected_price_positive', 'CHECK(expected_price > 0)',
'The expected price must be strictly positive.'),
('selling_price_positive', 'CHECK(selling_price >= 0)',
'The selling price must be positive.')
]

@api.constrains('expected_price')
def _check_expected_price(self):
for record in self:
if record.expected_price <= 0:
raise ValidationError("The expected price must be strictly positive.")


@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)

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

@api.constrains('expected_price', 'selling_price')
def _check_selling_price(self):
for record in self:
if float_is_zero(record.selling_price, precision_rounding=0.01):
continue
min_price = record.expected_price * 0.9
if float_compare(record.selling_price, min_price, precision_rounding=0.01) < 0:
raise ValidationError(
"The selling price cannot be lower than 90% of the expected price."
)
def action_sold(self):
self.state = 'sold'

def action_cancel(self):
self.state = 'canceled'


@api.depends('state')
def _compute_offer_received(self):
for record in self:
record.offer_received = record.state == 'offer_received'

@api.depends('state')
def _compute_offer_accepted(self):
for record in self:
record.offer_accepted = record.state == 'offer_accepted'

@api.ondelete(at_uninstall=False)
def _check_state_on_delete(self):
for record in self:
if record.state not in ('new', 'cancelled'):
raise UserError(
"You cannot delete a property unless it is in 'New' or 'Cancelled' state."
)



Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong indentation and extra spaces

101 changes: 101 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from odoo import models, fields
from datetime import timedelta
from odoo.exceptions import UserError
from odoo import models, fields, api


class EstatePropertyOffer(models.Model):
_name = 'estate.property.offer'
_description = 'Real Estate Property Offer'
_order = 'price desc'
price = fields.Float()
state= fields.Selection([('new', 'New'),('accepted', 'Accepted'), ('refused', 'Refused')], string= "Status" ,default='new')
partner_id = fields.Many2one('res.partner', string="Partner", required=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why partner_id

property_id = fields.Many2one('estate.property', string="Property", required=True)
status = fields.Selection([('accepted', 'Accepted'), ('refused', 'Refused')], string="Status")
property_type_id = fields.Many2one(
related='property_id.property_type_id',
string="Property Type",
readonly=True,
store=True
)
buyer_id = fields.Many2one(
'res.partner',
string="Buyer",
required=True
)
seller_id = fields.Many2one(
'res.partner',
string="Seller"
)
validity = fields.Integer(string="Validity (days)")
date_deadline = fields.Date(
string="Deadline",
compute="_compute_date_deadline",
inverse="_inverse_date_deadline",
store=True
)
def action_offer_accepted(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

action_offer_accepted defined twice

pass

@api.depends('create_date', 'validity')
def _compute_date_deadline(self):
for record in self:
if record.create_date:
record.date_deadline = record.create_date + timedelta(days=record.validity)
else:
record.date_deadline = fields.Date.today() + timedelta(days=record.validity)

def _inverse_date_deadline(self):
for record in self:
if record.create_date and record.date_deadline:
delta = (record.date_deadline - record.create_date.date()).days
record.validity = max(delta, 0)
else:
record.validity = 7

def action_offer_accepted(self):
for record in self:
record.status = 'accepted'
record.property_id.selling_price = record.price
record.property_id.buyer_id = record.partner_id

# set status 'refused' in the other offers of that particular property
for offer in record.property_id.offer_ids:
if offer.id != record.id:
offer.status = 'refused'
return True

def action_offer_refused(self):
for record in self:
record.status = 'refused'
return True

_sql_constraints = [

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer to code guidelines for proper file formatting

('offer_price_positive', 'CHECK(price > 0)',
'The offer price must be strictly positive.')
]


@api.model
def create(self, vals):
# Ensure property_id exists in vals
property_id = self.env['estate.property'].browse(vals.get('property_id'))
if not property_id:
raise UserError("The property associated with this offer does not exist.")

# Check if the new offer amount is lower than any existing offers
existing_offers = self.search([('property_id', '=', property_id.id)])
for offer in existing_offers:
if vals.get('price', 0.0) <= offer.price:
raise UserError(
"You cannot create an offer with a price lower than an existing offer."
)

# Update the property's state to 'Offer Received'
property_id.state = 'offer_received'

# Create the offer as usual
return super(EstatePropertyOffer, self).create(vals)


10 changes: 10 additions & 0 deletions estate/models/estate_property_resusers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from odoo import models, fields

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File not included in __init__.py

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

property_ids = fields.One2many(
'estate.property',
'seller_id',
string="Properties",
domain=[('state', 'in', ['new', 'offer_received'])]
)
20 changes: 20 additions & 0 deletions estate/models/estate_property_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from odoo import models, fields
class EstatePropertyTag(models.Model):
_name = 'estate.property.tag'
_description = 'Real Estate Property Tag'
_order = "name"

name = fields.Char(string="Tag Name", required=True)
color = fields.Integer(string='Color')
tag_ids = fields.Many2many(
'estate.property.tag',
Comment on lines +9 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relation with the same model?

'estate_property_tag_rel',
'tag_id1',
'tag_id2',
string="Related Tags"
)

_sql_constraints = [
('unique_tag_name', 'UNIQUE(name)',
'The tag name must be unique.')
]
35 changes: 35 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from odoo import models, fields, api

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check odoo coding guidelines and do proper formatting for all files

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

sequence = fields.Integer(default=10)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why default=10

name = fields.Char(string="Type Name", required=True)
property_ids = fields.One2many('estate.property', 'property_type_id', string="Properties")
offer_ids = fields.One2many('estate.property.offer', 'property_type_id', string="Offers")
offer_count = fields.Integer(string="Offer Count", compute="_compute_offer_count")

_sql_constraints = [
('unique_type_name', 'UNIQUE(name)',
'The property type name must be unique.')
]


@api.depends('offer_ids')
def _compute_offer_count(self):
for record in self:
record.offer_count = len(record.offer_ids)

def action_view_offers(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Offers',
'view_mode': 'tree,form',
'res_model': 'estate.property.offer',
'domain': [('property_type_id', '=', self.id)],
'context': {'default_property_type_id': self.id},
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove new line


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_estate_property_user,access_estate_property_user,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_offer,access_estate_property_offer,estate.model_estate_property_offer,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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for estate.

9 changes: 9 additions & 0 deletions estate/views/estate_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="estate_menu_root" name="Estate"/>
<menuitem id="estate_properties_menu" name="Advertisements" parent="estate_menu_root" action="estate_property_action"/>
<menuitem id="estate_properties_menu_two" name="Settings" parent="estate_menu_root"/>
<menuitem id="estate_property_type_menu" name="Property Types" parent="estate_properties_menu_two" action="estate_property_type_action"/>
<menuitem id="estate_property_tag_menu" name="Property Tags" parent="estate_properties_menu_two" action="estate_property_tag_action"/>
</odoo>
Loading