diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 41179d6..42f7839 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,6 +10,8 @@ ], 'data': [ 'views/estate_property_offer_views.xml', + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', 'views/estate_property_views.xml', 'views/estate_menus_view.xml', 'security/ir.model.access.csv' diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2b0365e..b837358 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -8,6 +8,7 @@ class EstateProperty(models.Model): _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'), diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 792461f..496c4a2 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -3,8 +3,18 @@ from odoo import api, fields, models, exceptions from odoo.tools import float_utils as floatTool class EstatePropertyOffer(models.Model): + + # ------------- Private attributes ------------------------- # + _name = "estate.property.offer" _description = "Offers made on properties" + _order = "price desc" + + _sql_constraints = [ + ('check_price', 'CHECK (price > 0)', 'Expected price should be superior to 0'), + ] + + # ------------- Fields ------------------------- # price = fields.Float() state = fields.Selection(copy=False, selection=[('accepted', 'Accepted'), ('refused', 'Refused')]) @@ -12,10 +22,9 @@ class EstatePropertyOffer(models.Model): property_id = fields.Many2one("estate.property", required=True) validity = fields.Integer(default=7, string='validity (days)') date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline") - - _sql_constraints = [ - ('check_price', 'CHECK (price > 0)', 'Expected price should be superior to 0'), - ] + property_type_id = fields.Many2one(related="property_id.property_type_id", store="True") + + # ------------- Compute methods ------------------------- # @api.depends('validity', 'create_date') def _compute_date_deadline(self): @@ -26,6 +35,8 @@ class EstatePropertyOffer(models.Model): for record in self: record.validity = (record.date_deadline - (record.create_date.date() or fields.Date.today())).days + # ------------- Actions ------------------------- # + def action_accept(self): if self.exists(): if "accepted" in self.mapped("property_id.offer_ids.state"): diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 0221d7f..27da22f 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -4,5 +4,8 @@ from odoo import fields, models class EstatePropertyTag(models.Model): _name = "estate.property.tag" _description = "Tags for properties" + _order = "sequence asc, name asc" - name = fields.Char(required=True) \ No newline at end of file + name = fields.Char(required=True) + sequence = fields.Integer('Order', default=1) + color = fields.Integer() \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 4d4b655..1402d42 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -1,9 +1,26 @@ # -*- coding: utf-8 -*- -from odoo import fields, models +from itertools import count +from odoo import fields, models, api class EstatePropertyType(models.Model): + + # ------------------ Private attributes ---------------------- + _name = "estate.property.type" _description = "Types of properties" + _order = "name asc" - name = fields.Char(required=True) \ No newline at end of file + # ------------------ Fields ---------------------- + + name = fields.Char(required=True) + property_ids = fields.One2many(comodel_name="estate.property", inverse_name="property_type_id") + offer_ids = fields.One2many(comodel_name="estate.property.offer", inverse_name="property_type_id") + offer_count = fields.Integer(compute="_compute_offer_count") + + # ------------------ Computed fields ---------------------- + + @api.depends('offer_ids') + def _compute_offer_count(self): + for record in self: + record.offer_count = len(record.mapped('offer_ids')) diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index d43a079..5cb7520 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -4,14 +4,14 @@ <field name="name">estate.property.offer.tree</field> <field name="model">estate.property.offer</field> <field name="arch" type="xml"> - <tree string="Offers"> + <tree string="Offers" editable="top" decoration-success="state == 'accepted'" decoration-danger="state == 'refused'"> <field name="price" /> <field name="partner_id" /> <field name="validity" /> <field name="date_deadline" /> - <button name="action_accept" string="Accept" type="object" icon="fa-check"/> - <button name="action_reject" string="Reject" type="object" icon="fa-close"/> - <field name="state" /> + <button name="action_accept" string="Accept" type="object" icon="fa-check" invisible="state" /> + <button name="action_reject" string="Reject" type="object" icon="fa-close" invisible="state" /> + <field name="state" invisible="True"/> </tree> </field> </record> diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 0000000..5f0478b --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<odoo> + <record id="estate_property_tag_action" model="ir.actions.act_window"> + <field name="name">Property Tags</field> + <field name="res_model">estate.property.tag</field> + <field name="view_mode">tree,form</field> + </record> + + <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="sequence" widget="handle" /> + <field name="name" /> + </tree> + </field> + </record> +</odoo> \ No newline at end of file diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 0000000..2df645a --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<odoo> + <record id="estate_property_type_action" model="ir.actions.act_window"> + <field name="name">Property Types</field> + <field name="res_model">estate.property.type</field> + <field name="view_mode">tree,form</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> + <div name="button_box" position="inside"> + <button class="oe_stat_button" type="action" name="%(estate.estate_property_action)d" icon="fa-money"> + <field name="offer_count" string="Offers" widget="statinfo" /> + </button> + </div> + <h1> + <field name="name" /> + </h1> + <notebook> + <page string="Properties"> + <field name="property_ids"> + <tree create="False" edit="False" delete="False" open_form_view="False"> + <field name="name" string="Title" /> + <field name="expected_price" /> + <field name="state" string="Status" /> + </tree> + </field> + </page> + </notebook> + </sheet> + </form> + </field> + </record> +</odoo> \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 370c32c..d652a76 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,21 +4,25 @@ <field name="name">Properties</field> <field name="res_model">estate.property</field> <field name="view_mode">tree,form</field> + <field name="context">{'search_default_available': True}</field> + <field name="domain">[('property_type_id', '=', active_id)]</field> </record> <record id="estate_property_tree_view" model="ir.ui.view"> <field name="name">estate.property.tree</field> <field name="model">estate.property</field> <field name="arch" type="xml"> - <tree string="Properties"> + <tree string="Properties" decoration-success="state in ('offer_accepted', 'offer_received')" decoration-muted="state == 'sold'" decoration-bf="state == 'offer_accepted'" > <field name="name" /> <field name="property_type_id" /> + <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}" /> <field name="postcode" /> <field name="bedrooms" /> <field name="living_area" /> <field name="expected_price" /> <field name="selling_price" /> - <field name="date_availability" /> + <field name="date_availability" optional="hide" /> + <field name="state" invisible="True" /> </tree> </field> </record> @@ -29,18 +33,18 @@ <field name="arch" type="xml"> <form> <header> - <button name="action_sold" type="object" string="Sold"/> - <button name="action_cancel" type="object" string="Cancel"/> + <button name="action_sold" type="object" string="Sold" invisible="state in ('sold', 'cancelled')"/> + <button name="action_cancel" type="object" string="Cancel" invisible="state in ('sold', 'cancelled')"/> + <field name="state" widget="statusbar" statusbar_visible="new,offer_received,offer_accepted,sold" /> </header> <sheet> <h1> <field name="name" /> </h1> - <field name="tag_ids" widget="many2many_tags" /> + <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}" /> <group> <group> - <field name="state"/> - <field name="property_type_id" /> + <field name="property_type_id" can_create="False" can_write="False" options="{'no_create': true, 'no_open': true}" /> <field name="postcode" /> <field name="date_availability" /> </group> @@ -59,8 +63,8 @@ <field name="facades" /> <field name="garage" /> <field name="garden" /> - <field name="garden_area" string="Garden area (sqm)" /> - <field name="garden_orientation" /> + <field name="garden_area" string="Garden area (sqm)" invisible="not garden"/> + <field name="garden_orientation" invisible="not garden" /> <field name="total_area" string="Total area (sqm)" /> </group> </page> @@ -71,7 +75,7 @@ </group> </page> <page string="Offers"> - <field name="offer_ids" /> + <field name="offer_ids" readonly="state in ('sold', 'cancelled', 'offer_accepted')"/> </page> </notebook> </sheet> @@ -89,7 +93,7 @@ <field name="property_type_id" /> <field name="bedrooms"/> <field name="expected_price" string="Expected price (sqm)"/> - <field name="living_area"/> + <field name="living_area" string="Minimum Living area" filter_domain="[('living_area', '>=', self)]" /> <field name="facades"/> <filter string="Available" name="available" domain="['|',('state', '=', 'new'), ('state', '=', 'offer_received')]"/> <group expand="1" string="Group By"> @@ -98,16 +102,4 @@ </search> </field> </record> - - <record id="estate_property_type_action" model="ir.actions.act_window"> - <field name="name">Property Types</field> - <field name="res_model">estate.property.type</field> - <field name="view_mode">tree,form</field> - </record> - - <record id="estate_property_tag_action" model="ir.actions.act_window"> - <field name="name">Property Tags</field> - <field name="res_model">estate.property.tag</field> - <field name="view_mode">tree,form</field> - </record> </odoo> \ No newline at end of file