# -*- coding: utf-8 -*- from odoo import api, fields, models, exceptions from odoo.tools import float_utils as floatTool class EstateProperty(models.Model): # ------------- Private attributes ------------------------- # _name = "estate.property" _description = "Properties for the Estate module" _order = "id desc" _sql_constraints = [ ('check_expected_price', 'CHECK (expected_price > 0)', 'Expected rice should be superior to 0'), ('check_selling_price', 'CHECK (selling_price >= 0)', 'Selling price cannot be negative'), ('unique_name', 'UNIQUE (name)', 'A property with this name aready exists. Name should be unique.'), ] # ------------- Fields ------------------------- # name = fields.Char(required=True) description = fields.Text() active = fields.Boolean(default=True) state = fields.Selection(selection=[('new','New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], required=True, copy=False, default='new') postcode = fields.Char() date_availability = fields.Date(copy=False, default=fields.Date.add(fields.Date.today(), months=3)) 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() garden_orientation = fields.Selection(selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')]) property_type_id = fields.Many2one("estate.property.type", "Property Type") salesman_id = fields.Many2one("res.users", string="Salesman") buyer_id = fields.Many2one("res.partner", string="Buyer") tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") total_area = fields.Integer(compute="_get_total_area", readonly=True) best_price = fields.Float(compute="_compute_best_price") # ------------- Compute methods ------------------------- # @api.depends('living_area', 'garden_area') def _get_total_area(self): for entry in self: entry.total_area = entry.living_area + entry.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')) if record.offer_ids else None # ------------- OnChange ------------------------- # @api.onchange('garden') def _onchange_garden(self): if self.garden: self.garden_area = 10 self.garden_orientation = 'north' else: self.garden_area = None self.garden_orientation = None @api.onchange('date_availability') def _onchange_date_availability(self): if self.date_availability < fields.Date.today(): return {'warning': { 'title': ("Warning"), 'message': ("The date is in the past.")}} # ------------- Constrains ------------------------- # @api.constrains('selling_price', 'expected_price') def _check_selling_price(self): for property in self: if ( not floatTool.float_is_zero(property.selling_price, precision_rounding=0.01) and floatTool.float_compare((property.expected_price * 0.9), property.selling_price, precision_rounding=0.01) > 0 ): raise exceptions.ValidationError("Selling price can't be less than 90% of the expected price") # ------------- Actions ------------------------- # def action_sold(self): if self.exists(): if self.state == 'cancelled': raise exceptions.UserError('A cancelled property cannot be sold') return False else: self.state = 'sold' return True else: raise exceptions.MissingError('Property not found') return False def action_cancel(self): if self.exists(): if self.state == 'sold': raise exceptions.UserError('A sold property cannot be cancelled') return False else: self.state = 'cancelled' return True else: raise exceptions.MissingError('Property not found') return False