-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
702 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/** @odoo-module */ | ||
|
||
import { Component } from "@odoo/owl"; | ||
|
||
export class Card extends Component {} | ||
|
||
Card.template = "awesome_owl.Card"; | ||
Card.props = { | ||
slots: { | ||
type: Object, | ||
shape: { | ||
default: Object, | ||
title: { type: Object, optional: true }, | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<templates xml:space="preserve"> | ||
<t t-name="awesome_owl.Card" owl="1"> | ||
<div class="card" style="width: 18rem;"> | ||
<div class="card-body"> | ||
<t t-if="props.slots.title"> | ||
<h5 class="card-title"><t t-slot="title"/></h5> | ||
</t> | ||
<p class="card-text"><t t-slot="default"/></p> | ||
</div> | ||
</div> | ||
</t> | ||
</templates> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** @odoo-module **/ | ||
|
||
import { Component, useState } from "@odoo/owl"; | ||
|
||
export class Counter extends Component { | ||
static template = "awesome_owl.Counter"; | ||
|
||
setup() { | ||
this.state = useState({ value: 0 }); | ||
} | ||
|
||
increment() { | ||
this.state.value++; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<templates xml:space="preserve"> | ||
<t t-name="awesome_owl.Counter" owl="1"> | ||
<p>Counter: <t t-esc="state.value"/></p> | ||
<button class="btn btn-primary" t-on-click="increment">Increment</button> | ||
</t> | ||
</templates> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
/** @odoo-module **/ | ||
|
||
import { Component } from "@odoo/owl"; | ||
import { Counter } from "./counter/counter"; | ||
import { Card } from "./card/card" | ||
|
||
export class Playground extends Component { | ||
static template = "awesome_owl.playground"; | ||
static components = { Counter, Card } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,4 +12,4 @@ | |
</html> | ||
</template> | ||
</data> | ||
</odoo> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Part of Odoo. See LICENSE file for full copyright and licensing details. | ||
|
||
{ | ||
'name': 'Estate', | ||
'category': 'Tutorials/Estate', | ||
'summary': 'Real estate application', | ||
'description': "", | ||
'depends': [ | ||
'base_setup', | ||
], | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
'views/estate_property_views.xml', | ||
'views/estate_property_tag_views.xml', | ||
'views/estate_property_type_views.xml', | ||
'views/estate_property_offer_views.xml', | ||
'views/res_users_views.xml', | ||
'views/estate_menu.xml', | ||
], | ||
'installable': True, | ||
'application': True, | ||
'auto_install': False, | ||
'license': 'OEEL-1' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<odoo> | ||
<data> | ||
<record id="model_estate_property_action_cancel" model="ir.actions.server"> | ||
<field name="name">Mass cancel</field> | ||
<field name="model_id" ref="estate.model_estate_property"/> | ||
<field name="binding_model_id" ref="estate.model_estate_property"/> | ||
<field name="binding_view_types">list</field> | ||
<field name="state">code</field> | ||
<field name="code">action = records.action_cancel()</field> | ||
</record> | ||
</data> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
from odoo import api, models, fields | ||
from datetime import date | ||
from dateutil.relativedelta import relativedelta | ||
from odoo.exceptions import UserError, ValidationError | ||
from odoo.tools.float_utils import float_compare | ||
|
||
|
||
class EstateProperty(models.Model): | ||
_name = "estate.property" | ||
_description = "Real Estate Property" | ||
|
||
name = fields.Char("Estate Name", required=True) | ||
description = fields.Text("Description") | ||
postcode = fields.Char("Postalcode") | ||
date_availability = fields.Date('Date Availability', default=lambda self: date.today() + relativedelta(months=3)) | ||
expected_price = fields.Float('Expected Price', required=True) | ||
selling_price = fields.Float('Selling Price', readonly=True) | ||
bedrooms = fields.Integer("Bedrooms", default=2) | ||
living_area = fields.Integer("Living Area (sqm)") | ||
facades = fields.Integer("Facades") | ||
garage = fields.Boolean("Garage") | ||
garden = fields.Boolean("Garden") | ||
garden_area = fields.Integer("Garden Area (sqm)") | ||
garden_orientation = fields.Selection(selection=[ | ||
('north', 'NORTH'), | ||
('south', 'SOUTH'), | ||
('west', 'WEST'), | ||
('east', 'EAST') | ||
]) | ||
active = fields.Boolean("Active", default=True) | ||
state = fields.Selection(selection=[ | ||
('new', 'NEW'), | ||
('offer_received', 'OFFER RECEIVED'), | ||
('offer_accepted', 'OFFER ACCEPTED'), | ||
('sold', 'SOLD'), | ||
('cancelled', 'CANCELLED') | ||
], default='new') | ||
property_type_id = fields.Many2one('estate.property.type', string='Real Estate Type') | ||
buyer_id = fields.Many2one('res.partner', string='Buyer', copy=False) | ||
salesperson_id = fields.Many2one('res.partner', string='Salesperson', default=lambda self: self.env.user) | ||
tag_ids = fields.Many2many('estate.property.tag', string='Real Estate Tag') | ||
offer_ids = fields.One2many('estate.property.offer', inverse_name='property_id') | ||
total_area = fields.Float('Total Area (sqm)', compute='_compute_total_area', readonly=True) | ||
best_offer = fields.Float('Best Offer', compute='_compute_best_offer', readonly=True) | ||
_order = 'id desc' | ||
|
||
_sql_constraints = [ | ||
('expected_price', 'CHECK(expected_price > 0)', | ||
'The expected price should be strictly greater than 0.'), | ||
('selling_price', 'CHECK(selling_price >= 0)', | ||
'The selling price should be zero or strictly greater than 0 if an offer is accepted.'), | ||
] | ||
|
||
def action_reset_to_draft(self): | ||
for record in self: | ||
if record.state == 'sold': | ||
raise UserError("You cannot reset a sold property to draft.") | ||
record.state = 'new' | ||
|
||
def action_open_offers(self): | ||
self.ensure_one() | ||
return { | ||
'name': 'Property Offer', | ||
'views': [(self.env.ref('estate.estate_property_offer_view_list').id, 'list')], | ||
'type': 'ir.actions.act_window', | ||
'domain': [('id', 'in', self.offer_ids.ids)], | ||
'res_model': 'estate.property.offer' | ||
} | ||
|
||
def action_cancel(self): | ||
if self.state != 'cancelled': | ||
self.state = 'cancelled' | ||
|
||
def action_sold(self): | ||
if self.state == 'cancelled': | ||
raise UserError("You can't sold an estate marked as CANCELLED") | ||
self.state = 'sold' | ||
|
||
@api.ondelete(at_uninstall=False) | ||
def on_delete(self, vals_list): | ||
for val in vals_list: | ||
if val and val['state'] == 'new' or val['state'] == 'cancelled': | ||
raise UserError('You can not delete a new or cancelled property') | ||
|
||
@api.constrains('expected_price', 'selling_price') | ||
def _check_expected_price(self): | ||
for record in self: | ||
if float_compare(record.expected_price * 0.9, record.selling_price, 3) == 1 and record.selling_price != 0: | ||
raise ValidationError("The selling price must be at least the 90% of the expected 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 or 0) | ||
|
||
@api.depends("offer_ids.price") | ||
def _compute_best_offer(self): | ||
for record in self: | ||
if record.offer_ids: | ||
record.best_offer = max(offer.price for offer in record.offer_ids) | ||
else: | ||
record.best_offer = 0 | ||
|
||
@api.onchange("garden") | ||
def _onchange_garden(self): | ||
if self.garden: | ||
self.garden_area = 10 | ||
self.garden_orientation = 'north' | ||
else: | ||
self.garden_area = 0 | ||
self.garden_orientation = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
from odoo import api, models, fields | ||
from dateutil.relativedelta import relativedelta | ||
from odoo.exceptions import UserError | ||
from odoo.tools.float_utils import float_compare | ||
|
||
|
||
class EstatePropertyOffer(models.Model): | ||
_name = "estate.property.offer" | ||
_description = "Real Estate Property Offer" | ||
|
||
price = fields.Float("Offer Price", required=True) | ||
status = fields.Selection(selection=[ | ||
('accepted', 'ACCEPTED'), | ||
('refused', 'REFUSED') | ||
]) | ||
partner_id = fields.Many2one('res.partner', required=True) | ||
property_id = fields.Many2one('estate.property', required=True) | ||
validity = fields.Integer('Validity', default=7) | ||
date_deadline = fields.Date('Date Deadline', compute='_compute_date_deadline', inverse='_inverse_date_deadline', store=True) | ||
property_type_id = fields.Many2one( | ||
"estate.property.type", related="property_id.property_type_id", string="Property Type", store=True | ||
) | ||
_order = 'price desc' | ||
|
||
_sql_constraints = [ | ||
('price', 'CHECK(price > 0)', | ||
'The price of an offer should be strictly grater than 0.') | ||
] | ||
|
||
@api.model_create_multi | ||
def create(self, vals_list): | ||
for val in vals_list: | ||
if val.get("property_id") and val.get("price"): | ||
prop = self.env["estate.property"].browse(val["property_id"]) | ||
|
||
if prop.offer_ids: | ||
max_offer = max(prop.mapped("offer_ids.price")) | ||
if float_compare(val["price"], max_offer, precision_rounding=0.01) <= 0: | ||
raise UserError("The offer must be higher than %.2f" % max_offer) | ||
prop.state = "offer_received" | ||
return super().create(vals_list) | ||
|
||
def action_accept(self): | ||
for offer in self.property_id.offer_ids: | ||
if offer.status == 'accepted': | ||
raise UserError("An offer has already been accepted for this property.") | ||
if self.status != 'accepted': | ||
if self.property_id.state == 'sold': | ||
raise UserError("You can't accept an offer for a property already sold") | ||
self.status = 'accepted' | ||
self.property_id.state = 'offer_accepted' | ||
self.property_id.selling_price = self.price | ||
self.property_id.buyer_id = self.partner_id.id | ||
else: | ||
raise UserError("You can't accept an offer already accepted") | ||
|
||
def action_refuse(self): | ||
if not self.status: | ||
self.status = 'refused' | ||
else: | ||
raise UserError("You can't refuse an offer already refused or already accepted") | ||
|
||
@api.depends("create_date", "validity") | ||
def _compute_date_deadline(self): | ||
for record in self: | ||
create_date = record.create_date or fields.Date.context_today(record) | ||
record.date_deadline = create_date + relativedelta(days=record.validity) | ||
|
||
def _inverse_date_deadline(self): | ||
for record in self: | ||
if record.create_date: | ||
record.validity = (record.date_deadline - record.create_date.date()).days | ||
else: | ||
record.validity = 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
|
||
name = fields.Char("Estate Tag", required=True) | ||
color = fields.Integer('Color') | ||
_order = 'name desc' | ||
|
||
_sql_constraints = [ | ||
('name', 'UNIQUE(name)', | ||
'The name of the tag should be unique.') | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from odoo import models, fields | ||
|
||
|
||
class EstatePropertyType(models.Model): | ||
_name = "estate.property.type" | ||
_description = "Real Estate Property Type" | ||
|
||
name = fields.Char("Estate Type", required=True) | ||
property_ids = fields.One2many('estate.property', inverse_name='property_type_id') | ||
sequence = fields.Integer('Sequence', default=1, help="Used to order types on the business needs") | ||
offer_ids = fields.One2many('estate.property.offer', inverse_name='property_type_id') | ||
_order = 'name desc' | ||
|
||
_sql_constraints = [ | ||
('name', 'UNIQUE(name)', | ||
'The name of the type should be unique.') | ||
] | ||
|
||
def action_open_offers(self): | ||
self.ensure_one() | ||
return { | ||
'name': 'Property Offer', | ||
'views': [(False, 'list')], | ||
'type': 'ir.actions.act_window', | ||
'domain': [('id', 'in', self.offer_ids.ids)], | ||
'res_model': 'estate.property.offer' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class ResUsers(models.Model): | ||
_inherit = "res.users" | ||
|
||
property_ids = fields.One2many( | ||
"estate.property", inverse_name="salesperson_id", domain=[("state", "in", ["new", "offer_received"])] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.