diff --git a/awesome_clicker/__init__.py b/awesome_clicker/__init__.py index 40a96afc6ff..e69de29bb2d 100644 --- a/awesome_clicker/__init__.py +++ b/awesome_clicker/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/awesome_clicker/__manifest__.py b/awesome_clicker/__manifest__.py index 56dc2f779b9..0ee7372dadf 100644 --- a/awesome_clicker/__manifest__.py +++ b/awesome_clicker/__manifest__.py @@ -1,29 +1,23 @@ -# -*- coding: utf-8 -*- { - 'name': "Awesome Clicker", - - 'summary': """ + "name": "Awesome Clicker", + "summary": """ Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" """, - - 'description': """ + "description": """ Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" """, - - 'author': "Odoo", - 'website': "https://www.odoo.com/", - 'category': 'Tutorials', - 'version': '0.1', - 'application': True, - 'installable': True, - 'depends': ['base', 'web'], - - 'data': [], - 'assets': { - 'web.assets_backend': [ - 'awesome_clicker/static/src/**/*', + "author": "Odoo", + "website": "https://www.odoo.com/", + "category": "Tutorials", + "version": "0.1", + "application": True, + "installable": True, + "depends": ["base", "web"], + "data": [], + "assets": { + "web.assets_backend": [ + "awesome_clicker/static/src/**/*", ], - }, - 'license': 'AGPL-3' + "license": "AGPL-3", } diff --git a/awesome_dashboard/__init__.py b/awesome_dashboard/__init__.py index b0f26a9a602..f705942f8f1 100644 --- a/awesome_dashboard/__init__.py +++ b/awesome_dashboard/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- from . import controllers diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index a1cd72893d7..0be8062fbbb 100644 --- a/awesome_dashboard/__manifest__.py +++ b/awesome_dashboard/__manifest__.py @@ -1,30 +1,25 @@ -# -*- coding: utf-8 -*- { - 'name': "Awesome Dashboard", - - 'summary': """ + "name": "Awesome Dashboard", + "summary": """ Starting module for "Discover the JS framework, chapter 2: Build a dashboard" """, - - 'description': """ + "description": """ Starting module for "Discover the JS framework, chapter 2: Build a dashboard" """, - - 'author': "Odoo", - 'website': "https://www.odoo.com/", - 'category': 'Tutorials', - 'version': '0.1', - 'application': True, - 'installable': True, - 'depends': ['base', 'web', 'mail', 'crm'], - - 'data': [ - 'views/views.xml', + "author": "Odoo", + "website": "https://www.odoo.com/", + "category": "Tutorials", + "version": "0.1", + "application": True, + "installable": True, + "depends": ["base", "web", "mail", "crm"], + "data": [ + "views/views.xml", ], - 'assets': { - 'web.assets_backend': [ - 'awesome_dashboard/static/src/**/*', + "assets": { + "web.assets_backend": [ + "awesome_dashboard/static/src/**/*", ], }, - 'license': 'AGPL-3' + "license": "AGPL-3", } diff --git a/awesome_dashboard/controllers/__init__.py b/awesome_dashboard/controllers/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_dashboard/controllers/__init__.py +++ b/awesome_dashboard/controllers/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_dashboard/controllers/controllers.py b/awesome_dashboard/controllers/controllers.py index 05977d3bd7f..2d0d9f4cbff 100644 --- a/awesome_dashboard/controllers/controllers.py +++ b/awesome_dashboard/controllers/controllers.py @@ -1,15 +1,14 @@ -# -*- coding: utf-8 -*- import logging import random from odoo import http -from odoo.http import request logger = logging.getLogger(__name__) + class AwesomeDashboard(http.Controller): - @http.route('/awesome_dashboard/statistics', type='jsonrpc', auth='user') + @http.route("/awesome_dashboard/statistics", type="jsonrpc", auth="user") def get_statistics(self): """ Returns a dict of statistics about the orders: @@ -22,15 +21,14 @@ def get_statistics(self): """ return { - 'average_quantity': random.randint(4, 12), - 'average_time': random.randint(4, 123), - 'nb_cancelled_orders': random.randint(0, 50), - 'nb_new_orders': random.randint(10, 200), - 'orders_by_size': { - 'm': random.randint(0, 150), - 's': random.randint(0, 150), - 'xl': random.randint(0, 150), + "average_quantity": random.randint(4, 12), + "average_time": random.randint(4, 123), + "nb_cancelled_orders": random.randint(0, 50), + "nb_new_orders": random.randint(10, 200), + "orders_by_size": { + "m": random.randint(0, 150), + "s": random.randint(0, 150), + "xl": random.randint(0, 150), }, - 'total_amount': random.randint(100, 1000) + "total_amount": random.randint(100, 1000), } - diff --git a/awesome_gallery/__init__.py b/awesome_gallery/__init__.py index a0fdc10fe11..0650744f6bc 100644 --- a/awesome_gallery/__init__.py +++ b/awesome_gallery/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- from . import models diff --git a/awesome_gallery/__manifest__.py b/awesome_gallery/__manifest__.py index f0fe026a9c6..76200eff3a4 100644 --- a/awesome_gallery/__manifest__.py +++ b/awesome_gallery/__manifest__.py @@ -1,27 +1,24 @@ -# -*- coding: utf-8 -*- { - 'name': "Gallery View", - 'summary': """ + "name": "Gallery View", + "summary": """ Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" """, - - 'description': """ + "description": """ Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" """, - - 'version': '0.1', - 'application': True, - 'category': 'Tutorials', - 'installable': True, - 'depends': ['web', 'contacts'], - 'data': [ - 'views/views.xml', + "version": "0.1", + "application": True, + "category": "Tutorials", + "installable": True, + "depends": ["web", "contacts"], + "data": [ + "views/views.xml", ], - 'assets': { - 'web.assets_backend': [ - 'awesome_gallery/static/src/**/*', + "assets": { + "web.assets_backend": [ + "awesome_gallery/static/src/**/*", ], }, - 'author': 'Odoo S.A.', - 'license': 'AGPL-3' + "author": "Odoo S.A.", + "license": "AGPL-3", } diff --git a/awesome_gallery/models/__init__.py b/awesome_gallery/models/__init__.py index 7f0930ee744..c1bbf7a7f7d 100644 --- a/awesome_gallery/models/__init__.py +++ b/awesome_gallery/models/__init__.py @@ -1,4 +1,2 @@ -# -*- coding: utf-8 -*- # import filename_python_file_within_folder_or_subfolder -from . import ir_action -from . import ir_ui_view +from . import ir_action, ir_ui_view diff --git a/awesome_gallery/models/ir_action.py b/awesome_gallery/models/ir_action.py index eae20acbf5c..00d0ff823a3 100644 --- a/awesome_gallery/models/ir_action.py +++ b/awesome_gallery/models/ir_action.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- from odoo import fields, models class ActWindowView(models.Model): - _inherit = 'ir.actions.act_window.view' + _inherit = "ir.actions.act_window.view" - view_mode = fields.Selection(selection_add=[ - ('gallery', "Awesome Gallery") - ], ondelete={'gallery': 'cascade'}) + view_mode = fields.Selection( + selection_add=[("gallery", "Awesome Gallery")], ondelete={"gallery": "cascade"}, + ) diff --git a/awesome_gallery/models/ir_ui_view.py b/awesome_gallery/models/ir_ui_view.py index 0c11b8298ac..72d3816cb90 100644 --- a/awesome_gallery/models/ir_ui_view.py +++ b/awesome_gallery/models/ir_ui_view.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- from odoo import fields, models class View(models.Model): - _inherit = 'ir.ui.view' + _inherit = "ir.ui.view" - type = fields.Selection(selection_add=[('gallery', "Awesome Gallery")]) + type = fields.Selection(selection_add=[("gallery", "Awesome Gallery")]) diff --git a/awesome_kanban/__init__.py b/awesome_kanban/__init__.py index 40a96afc6ff..e69de29bb2d 100644 --- a/awesome_kanban/__init__.py +++ b/awesome_kanban/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/awesome_kanban/__manifest__.py b/awesome_kanban/__manifest__.py index 6f31bc8de0d..c388dc533b2 100644 --- a/awesome_kanban/__manifest__.py +++ b/awesome_kanban/__manifest__.py @@ -1,27 +1,24 @@ -# -*- coding: utf-8 -*- { - 'name': "Awesome Kanban", - 'summary': """ + "name": "Awesome Kanban", + "summary": """ Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view" """, - - 'description': """ + "description": """ Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view. """, - - 'version': '0.1', - 'application': True, - 'category': 'Tutorials', - 'installable': True, - 'depends': ['web', 'crm'], - 'data': [ - 'views/views.xml', + "version": "0.1", + "application": True, + "category": "Tutorials", + "installable": True, + "depends": ["web", "crm"], + "data": [ + "views/views.xml", ], - 'assets': { - 'web.assets_backend': [ - 'awesome_kanban/static/src/**/*', + "assets": { + "web.assets_backend": [ + "awesome_kanban/static/src/**/*", ], }, - 'author': 'Odoo S.A.', - 'license': 'AGPL-3' + "author": "Odoo S.A.", + "license": "AGPL-3", } diff --git a/awesome_kanban/static/src/awesome_kanban_view.js b/awesome_kanban/static/src/awesome_kanban_view.js index 0da52b22c9d..d4f0211ca90 100644 --- a/awesome_kanban/static/src/awesome_kanban_view.js +++ b/awesome_kanban/static/src/awesome_kanban_view.js @@ -1 +1 @@ -// TODO: Define here your AwesomeKanban view +// Todo: Define here your AwesomeKanban view diff --git a/awesome_owl/__init__.py b/awesome_owl/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_owl/__init__.py +++ b/awesome_owl/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py index 55002ab81de..52b5287856c 100644 --- a/awesome_owl/__manifest__.py +++ b/awesome_owl/__manifest__.py @@ -1,43 +1,37 @@ -# -*- coding: utf-8 -*- { - 'name': "Awesome Owl", - - 'summary': """ + "name": "Awesome Owl", + "summary": """ Starting module for "Discover the JS framework, chapter 1: Owl components" """, - - 'description': """ + "description": """ Starting module for "Discover the JS framework, chapter 1: Owl components" """, - - 'author': "Odoo", - 'website': "https://www.odoo.com", - + "author": "Odoo", + "website": "https://www.odoo.com", # Categories can be used to filter modules in modules listing # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml # for the full list - 'category': 'Tutorials', - 'version': '0.1', - + "category": "Tutorials", + "version": "0.1", # any module necessary for this one to work correctly - 'depends': ['base', 'web'], - 'application': True, - 'installable': True, - 'data': [ - 'views/templates.xml', + "depends": ["base", "web"], + "application": True, + "installable": True, + "data": [ + "views/templates.xml", ], - 'assets': { - 'awesome_owl.assets_playground': [ - ('include', 'web._assets_helpers'), - ('include', 'web._assets_backend_helpers'), - 'web/static/src/scss/pre_variables.scss', - 'web/static/lib/bootstrap/scss/_variables.scss', - 'web/static/lib/bootstrap/scss/_maps.scss', - ('include', 'web._assets_bootstrap'), - ('include', 'web._assets_core'), - 'web/static/src/libs/fontawesome/css/font-awesome.css', - 'awesome_owl/static/src/**/*', + "assets": { + "awesome_owl.assets_playground": [ + ("include", "web._assets_helpers"), + ("include", "web._assets_backend_helpers"), + "web/static/src/scss/pre_variables.scss", + "web/static/lib/bootstrap/scss/_variables.scss", + "web/static/lib/bootstrap/scss/_maps.scss", + ("include", "web._assets_bootstrap"), + ("include", "web._assets_core"), + "web/static/src/libs/fontawesome/css/font-awesome.css", + "awesome_owl/static/src/**/*", ], }, - 'license': 'AGPL-3' + "license": "AGPL-3", } diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_owl/controllers/__init__.py +++ b/awesome_owl/controllers/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_owl/controllers/controllers.py b/awesome_owl/controllers/controllers.py index bccfd6fe283..6e83f679212 100644 --- a/awesome_owl/controllers/controllers.py +++ b/awesome_owl/controllers/controllers.py @@ -1,10 +1,11 @@ from odoo import http -from odoo.http import request, route +from odoo.http import request + class OwlPlayground(http.Controller): - @http.route(['/awesome_owl'], type='http', auth='public') + @http.route(["/awesome_owl"], type="http", auth="public") def show_playground(self): """ Renders the owl playground page """ - return request.render('awesome_owl.playground') + return request.render("awesome_owl.playground") diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..7deaa55cb75 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,19 @@ +{ + "name": "Estate Advirtisements", + "version": "1.0", + "summary": "Track advertisements added for real estate and allow selling them", + "website": "https://www.odoo.com/app/estate", + "depends": ["base"], + "application": True, + "installable": True, + "author": "moali", + "license": "LGPL-3", + "data": [ + "security/ir.model.access.csv", + "views/estate_property_views.xml", + "views/menus.xml", + "views/list_views.xml", + "views/form_views.xml", + "views/search_views.xml", + ], +} diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..0187ac91511 --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property, property_offer, property_tag, property_type diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..59a84d99528 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,104 @@ +from odoo import api, exceptions, fields, models, tools + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Estate Property" + _order = "id desc" + + name = fields.Char(string="Property Name", required=True) + description = fields.Char(string="Property Description") + postcode = fields.Char(string="Postal Code") + date_availability = fields.Date( + string="Available From", + default=fields.Date.add(value=fields.Date.today(), months=3), + copy=False, + ) + expected_price = fields.Float(string="Expected Selling Price", required=True) + selling_price = fields.Float( + string="Actual Selling Price", readonly=True, copy=False, + ) + bedrooms = fields.Integer(string="Number of Bedrooms", default=2) + living_area = fields.Float(string="Living Area (sqm)") + facades = fields.Integer(string="Number of Facades") + garage = fields.Boolean(string="Garage") + garden = fields.Boolean(string="Garden") + garden_area = fields.Float(string="Garden Area (sqm)", compute="_automate_garden") + garden_orientation = fields.Selection( + string="Garden Orientation", + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), + ], + compute="_automate_garden", + ) + total_area = fields.Float(string="Total Area (sqm)", compute="_compute_area") + active = fields.Boolean(string="Active", default=True) + status = fields.Selection( + string="Status", + selection=[ + ("new", "New"), + ("offer received", "Offer Received"), + ("offer accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], + default="new", + copy=False, + ) + property_type_id = fields.Many2one("estate.property.type", string="Property Type") + user_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + partner_id = fields.Many2one("res.partner", string="Buyer", copy=False) + property_tag_ids = fields.Many2many("estate.property.tag", string="Property Tag") + property_offers_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + best_offer = fields.Float(string="Best Offer", compute="_compute_best_offer") + + @api.depends("living_area", "garden_area") + def _compute_area(self): + for record in self: + record.total_area = record.garden_area + record.living_area + + @api.depends("property_offers_ids.price") + def _compute_best_offer(self): + for record in self: + if record.property_offers_ids and record.status == 'new': + record.status = "offer received" + record.best_offer = max(record.mapped("property_offers_ids.price"), default=0) + + @api.onchange("garden") + def _automate_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = None + self.garden_orientation = None + + def sell_apartment(self): + for record in self: + if record.status == "cancelled": + raise exceptions.UserError("Cancelled apartments can not be sold") + record.status = "sold" + return True + + def cancel_apartment(self): + for record in self: + if record.status == "sold": + raise exceptions.UserError("Sold apartments can not be cancelled") + record.status = "cancelled" + return False + + _check_expected_price = models.Constraint( + 'CHECK(expected_price >= 0)', + 'The expected price of an should be greater than 0.', + ) + + @api.constrains("expected_price", "selling_price") + def _check_valid_transaction(self): + for record in self: + if record.property_offers_ids: + if tools.float_compare(record.selling_price, 0.9 * record.expected_price, 2) < 1: + raise exceptions.ValidationError("Selling price can not be less than 90% of your expected price. Lower your expected price to accept this transaction.") + # TODO check this diff --git a/estate/models/property_offer.py b/estate/models/property_offer.py new file mode 100644 index 00000000000..57e6016cf1c --- /dev/null +++ b/estate/models/property_offer.py @@ -0,0 +1,56 @@ +from odoo import api, exceptions, fields, models + + +class PropertyOffer (models.Model): + _name = "estate.property.offer" + _description = "Property Purchase Offers" + _order = "price desc" + + price = fields.Float(string="Price") + property_id = fields.Many2one("estate.property", string="Property Name", required=True, ondelete="cascade") + partner_id = fields.Many2one("res.partner", string="Partner", required=True) + property_type_id = fields.Many2one("estate.property.type", related="property_id.property_type_id", string="Property Type", store=True) + status = fields.Selection(string="Status", selection=[("accepted", "Accepted"), ("refused", "Refused")], copy=False) + validity = fields.Integer(string="Validity", default="7") + date_deadline = fields.Date(string="Deadline", compute="_compute_validity", inverse="_inverse_date") + + @api.depends("validity") + def _compute_validity(self): + for record in self: + if record.create_date: + record.date_deadline = fields.Date.add(record.create_date, days=record.validity) + else: + record.date_deadline = fields.Date.add(fields.Date.today(), days=record.validity) + + def _inverse_date(self): + for record in self: + if record.create_date: + record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days + else: + record.validity = (record.date_deadline - fields.Date.today()).days + + def action_confirm(self): + for record in self: + if not record.status: + if record.property_id.status in ("sold", "cancelled", "offer accepted"): + raise exceptions.UserError("This offer can not be accepted") + record.property_id.status = "offer accepted" + print("status changed") + record.status = "accepted" + record.property_id.selling_price = record.price + record.property_id.active = False + record.property_id.partner_id = record.partner_id + + return True + + def action_cancel(self): + for record in self: + if not record.status: + record.status = "refused" + return True + + @api.constrains("price") + def _check_price(self): + for record in self: + if record.price < 0: + raise exceptions.ValidationError("Enter a valid offer") diff --git a/estate/models/property_tag.py b/estate/models/property_tag.py new file mode 100644 index 00000000000..39e085aaa63 --- /dev/null +++ b/estate/models/property_tag.py @@ -0,0 +1,15 @@ +from odoo import fields, models + + +class PropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Estate Property Tag" + _order = "name" + + name = fields.Char(string="Property Tag", required=True) + color = fields.Integer('Color') + + _check_tag_uniqueness = models.Constraint( + 'unique(name)', + 'This tag is already used, please use it or add a new tag', + ) diff --git a/estate/models/property_type.py b/estate/models/property_type.py new file mode 100644 index 00000000000..b03d55e758d --- /dev/null +++ b/estate/models/property_type.py @@ -0,0 +1,23 @@ +from odoo import api, fields, models + + +class PropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate Property Type" + _order = "sequence" + + name = fields.Char(string="Property Type", required=True) + estate_property_ids = fields.One2many("estate.property", "property_type_id", string="Properties") + sequence = fields.Integer("Sequence", default=1) + offer_ids = fields.One2many("estate.property.offer", "property_type_id", string="Offers") + offer_count = fields.Integer("# Offers", compute="_compute_offer_count") + + _check_type_uniqueness = models.Constraint( + 'unique(name)', + 'This type is already used, please use it or add a new type', + ) + + @api.depends("offer_ids") + def _compute_offer_count(self): + for record in self: + record.offer_count = len(record.offer_ids) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..0795184f311 --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +estate_property_access,access_estate_property,model_estate_property,base.group_user,1,1,1,1 +estate_property_type_access,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +estate_property_tag_access,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +estate_property_offer_access,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..a05d43dd74d --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,31 @@ + + + + + Properties + estate.property + list,form + {'search_default_available':True} + + + + Property Types + estate.property.type + list,form + + + + Property Tags + estate.property.tag + list,form + + + + Property Offers + estate.property.offer + list,form + [('property_type_id', '=', active_id)] + {'default_property_id': active_id} + + + diff --git a/estate/views/form_views.xml b/estate/views/form_views.xml new file mode 100644 index 00000000000..2b606ab0399 --- /dev/null +++ b/estate/views/form_views.xml @@ -0,0 +1,148 @@ + + + + + Property Form + estate.property + +
+
+
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + Property Type Form + estate.property.type + +
+ +
+
+

+
+
+ +
+
+ + + + + + + + + + + + +
+
+
+
+ + + Property Tag Form + estate.property.tag + +
+ +

+ Property Tag +

+ + + + + +
+
+
+
+ + + Property Offer Form + estate.property.offer + +
+ +

+ Property Offer +

+ + + + + + + + + +
+
+
+
+ +
diff --git a/estate/views/list_views.xml b/estate/views/list_views.xml new file mode 100644 index 00000000000..5b11e098f66 --- /dev/null +++ b/estate/views/list_views.xml @@ -0,0 +1,60 @@ + + + + + Property List + estate.property + + + + + + + + + + + + + + + + + Property Type List + estate.property.type + + + + + + + + + + + Property Tag List + estate.property.tag + + + + + + + + + Property Offer List + estate.property.offer + + + + + + + +