Skip to content

Commit

Permalink
[ADD] estate module & estate account
Browse files Browse the repository at this point in the history
  • Loading branch information
apa-adhoc committed Sep 13, 2024
1 parent 5926311 commit fc54c51
Show file tree
Hide file tree
Showing 19 changed files with 558 additions and 0 deletions.
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
21 changes: 21 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

{
'name': 'Real Estate Managment',
'version': "16.0.1.0.0",
'author': 'ADHOC SA, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'depends': ['base'],
'application' : True,
'installable': True,
'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/res_users_views.xml',
'views/estate_menus.xml',
]
}
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 estate_property
from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
from . import res_users
85 changes: 85 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from odoo import models, fields, api
from odoo.tools.float_utils import float_compare
from odoo.tools.float_utils import float_is_zero
from odoo.exceptions import ValidationError

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

name = fields.Char(required=True)
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
tag_ids = fields.Many2many("estate.property.tag")
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(copy=False, default=fields.Date.add(fields.Date.today(),months=3), string= "Available From")
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.Integer()
garden = fields.Boolean()
active = fields.Boolean(default=True)
garden_area = fields.Integer()
garden_orientation = fields.Selection([('north', 'North'), ('south', 'South'),('east', 'East'),('west', 'West')])
state = fields.Selection([('new','New'), ('offer_received','Offer Received'),('offer_accepted','Offer Accepted'),('sold','Sold'),('canceled','Canceled')], required=True, copy=False, default='new')
user_id = fields.Many2one('res.users', string='Sale person', default=lambda self: self.env.user)
partner_id = fields.Many2one('res.partner', string='Buyer', copy=False)
offer_ids = fields.One2many('estate.property.offer', 'property_id')
total_area=fields.Float(compute="_compute_total_area")
amount=fields.Float()
best_price=fields.Float(compute="_compute_best_price")

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

@api.depends("offer_ids.price")
def _compute_best_price(self):
for rec in self:
rec.best_price = max(rec.offer_ids.mapped('price') or [0])

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

def action_sold(self):
for record in self:
if record.state == 'canceled':
raise Warning('No puede vender una propiedad cancelada')
record.state = 'sold'

def cancel_property(self):
for record in self:
if record.state == 'sold':
raise Warning('No puede cancelar una propiedad vendida')
record.state = 'canceled'

_sql_constraints = [
('check_expected_price', 'CHECK(expected_price > 0)',
'El precio esperado no puede ser negativo'),
('check_selling_price', 'CHECK(selling_price >= 0)',
'El precio de venta de una propiedad debe ser positivo')]

@api.constrains('selling_price', 'expected_price')
def check_selling_price(self):
for rec in self:
percentage = rec.selling_price / rec.expected_price
if float_is_zero(rec.selling_price, precision_digits=2) is False and percentage < 0.9:
raise ValidationError('El precio de venta no puede ser inferior al 90% del precio esperado')

@api.model
@api.ondelete(at_uninstall=False)
def _check_ondelete(self):
for record in self:
if record.state not in ['new', 'canceled']:
raise exceptions.UserError(
"No se puede eliminar una propiedad que no esté en estado 'Nuevo' o 'Cancelado'.")
54 changes: 54 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from odoo import models, fields, api, exceptions
from odoo.exceptions import ValidationError

class EstatePropertyOffer (models.Model):
_name = "estate.property.offer"
_description = 'Real Estate Properties Offers'
_order = "price asc"

price = fields.Float()
status = fields.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(string='Date Deadline', compute='_compute_date_deadline')
# state = fields.Selection(related='property_id.state', string="Property State", readonly=True)

@api.depends("create_date","validity")
def _compute_date_deadline(self):
for rec in self:
rec.date_deadline = fields.Date.add(
rec.create_date, days=rec.validity) if rec.create_date else False

def _inverse_date_deadline(self):
for rec in self:
rec.validity=(rec.date_deadline - rec.create_date.date()).days

def action_accept_offer(self):
for record in self:
if 'accepted' in record.property_id.offer_ids.mapped("status"):
raise Warning('No se puede aceptar más de una oferta')
else:
record.status = 'accepted'
record.property_id.partner_id = record.partner_id
record.property_id.selling_price = record.price
return True

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

_sql_constraints = [
('check_price', 'CHECK(price > 0)','El precio de oferta no puede ser negativo')]

@api.model
def create(self, vals):
if 'property_id' in vals:
property = self.env['estate.property'].browse(vals['property_id'])
property.write({'state': 'offer_accepted'})
existing_offers = self.search([('property_id', '=', property.id)])
max_existing_amount = max(existing_offers.mapped('price'), default=0)
if vals.get('price', 0) <= max_existing_amount:
raise exceptions.UserError("El monto de la oferta debe ser mayor que cualquier oferta existente para esta propiedad.")
return super(EstatePropertyOffer, self).create(vals)
13 changes: 13 additions & 0 deletions estate/models/estate_property_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from odoo import models,fields, api, exceptions
from odoo.exceptions import ValidationError

class EstatePropertyTag (models.Model):
_name = "estate.property.tag"
_description = 'Real Estate Properties Tags'
_order = "name desc"

name = fields.Char(string='Nombre')
color = fields.Integer()

_sql_constraints = [
('name_uniq', 'UNIQUE(name)', 'El nombre debe ser único.')]
14 changes: 14 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from odoo import models, fields, api, exceptions
from odoo.exceptions import ValidationError

class EstatePropertyType (models.Model):
_name = "estate.property.type"
_description = 'Real Estate Properties Types'
_order = "name asc"

name = fields.Char(required=True)
sequence = fields.Integer()
property_ids = fields.One2many("estate.property", "property_type_id")

_sql_constraints = [
('name_uniq', 'UNIQUE(name)', 'El nombre debe ser único.')]
11 changes: 11 additions & 0 deletions estate/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from odoo import models, fields

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

property_ids = fields.One2many(
comodel_name='estate.property',
inverse_name='user_id',
string='Properties',
# domain=[('state', 'in', ['offer_accepted','offer_received', 'new'])]
)
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,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_tag,access_estate_property_tag,model_estate_property_tag,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
10 changes: 10 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<menuitem id="real_estate_menu" name="Real Estate"/>
<menuitem id="advertisements_menus" name="Advertisements" parent="real_estate_menu"/>
<menuitem id="settings_menu" name="Settings" sequence="99" parent="real_estate_menu"/>
<menuitem id="properties_menu" action="estate_property_action" parent="advertisements_menus"/>
<menuitem id="property_types_menu" name="Properties Types" action="estate_property_type_action" parent="settings_menu"/>
<menuitem id="property_tags_menu" name="Properties Tags" action="estate_property_tag_action" parent="settings_menu"/>
<menuitem id="property_offers_menu" name="Properties Offers" action="estate_property_offer_action" parent="settings_menu"/>
</odoo>
43 changes: 43 additions & 0 deletions estate/views/estate_property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<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" decoration-danger="status == 'rejected'" decoration-success="status == 'accepted'" >
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<button name="action_refuse_offer" type="object" icon="fa-close" title='refused' attrs="{'invisible': [('status', '!=', False)]}"/>
<button name="action_accept_offer" type="object" icon="fa-check" title='accepted' attrs="{'invisible': [('status', '!=', False)]}"/>
<field name="status"/>
</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>
<sheet>
<group>
<field name="state" invisible="1"/>
<field name="price" attrs="{'readonly': [('state', 'in', ['offer_accepted', 'sold', 'canceled'])]}"/>
<field name="partner_id" attrs="{'readonly': [('state', 'in', ['offer_accepted', 'sold', 'canceled'])]}"/>
<field name="status" attrs="{'readonly': [('state', 'in', ['offer_accepted', 'sold', 'canceled'])]}"/>
<field name="validity" attrs="{'readonly': [('state', 'in', ['offer_accepted', 'sold', 'canceled'])]}"/>
<field name="date_deadline" attrs="{'readonly': [('state', 'in', ['offer_accepted', 'sold', 'canceled'])]}"/>
</group>
</sheet>
</form>
</field>
</record>


<record id="estate_property_offer_action" model="ir.actions.act_window">
<field name="name">Properties offers</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">tree</field>
</record>
</odoo>
41 changes: 41 additions & 0 deletions estate/views/estate_property_tag_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<odoo>
<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">
<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>
<sheet>
<group>
<field name="name" class="mb16" placeholder="Title"/>
<field name="color" widget="color_picker"/>
</group>
</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>
<field name="name"/>
</search>
</field>
</record>

<record id="estate_property_tag_action" model="ir.actions.act_window">
<field name="name">Properties Tags</field>
<field name="res_model">estate.property.tag</field>
</record>
</odoo>
53 changes: 53 additions & 0 deletions estate/views/estate_property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<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>
<field name="sequence" widget="handle"/>
<field name="name"/>
</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>
<sheet>
<group>
<field name="name" class="mb16" placeholder="Title"/>
</group>
<notebook>
<page string="Properties">
<field name="property_ids">
<tree>
<field name="name" string="Title"/>
<field name="expected_price"/>
<field name="state" string= "Status"/>
</tree>
</field>
</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>
<field name="name"/>
</search>
</field>
</record>

<record id="estate_property_type_action" model="ir.actions.act_window">
<field name="name">Properties Types</field>
<field name="res_model">estate.property.type</field>
</record>
</odoo>
Loading

0 comments on commit fc54c51

Please sign in to comment.