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 Offer Form
+ estate.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/estate/views/menus.xml b/estate/views/menus.xml
new file mode 100644
index 00000000000..4bff1d24f7a
--- /dev/null
+++ b/estate/views/menus.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/estate/views/search_views.xml b/estate/views/search_views.xml
new file mode 100644
index 00000000000..5f2773c03d4
--- /dev/null
+++ b/estate/views/search_views.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ Property Search
+ estate.property
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruff.toml b/ruff.toml
new file mode 100644
index 00000000000..6a7ce0e3a7e
--- /dev/null
+++ b/ruff.toml
@@ -0,0 +1,85 @@
+# automatically generated file by the runbot nightly ruff checks, do not modify
+# for ruff version 0.11.4 (or higher)
+# note: 'E241', 'E272', 'E201', 'E221' are ignored on runbot in test files when formating a table like structure (more than two space)
+# some rules present here are not enabled on runbot (yet) but are still advised to follow when possible : ["B904", "COM812", "E741", "EM101", "I001", "RET", "RUF021", "TRY002", "UP006", "UP007"]
+
+
+target-version = "py310"
+
+[lint]
+preview = true
+select = [
+ "BLE", # flake8-blind-except
+ "C", # flake8-comprehensions
+ "COM", # flake8-commas
+ "E", # pycodestyle Error
+ "EM", # flake8-errmsg
+ "EXE", # flake8-executable
+ "F", # Pyflakes
+ "FA", # flake8-future-annotations
+ "FLY", # flynt
+ "G", # flake8-logging-format
+ "I", # isort
+ "ICN", # flake8-import-conventions
+ "INT", # flake8-gettext
+ "ISC", # flake8-implicit-str-concat
+ "LOG", # flake8-logging
+ "PGH", # pygrep-hooks
+ "PIE", # flake8-pie
+ "PLC", # Pylint Convention
+ "PLE", # Pylint Error
+ "PLW", # Pylint Warning
+ "PYI", # flake8-pyi
+ "RET", # flake8-return
+ "RUF", # Ruff-specific rules
+ "SIM", # flake8-simplify
+ "SLOT", # flake8-slots
+ "T", # flake8-print
+ "TC", # flake8-type-checking
+ "TID", # flake8-tidy-imports
+ "TRY", # tryceratops
+ "UP", # pyupgrade
+ "W", # pycodestyle Warning
+ "YTT", # flake8-2020
+]
+ignore = [
+ "C408", # unnecessary-collection-call
+ "C420", # unnecessary-dict-comprehension-for-iterable
+ "C901", # complex-structure
+ "E266", # multiple-leading-hashes-for-block-comment
+ "E501", # line-too-long
+ "E302",
+ "E301",
+ "E713", # not-in-test
+ "EM102", # f-string-in-exception
+ "FA100", # future-rewritable-type-annotation
+ "PGH003", # blanket-type-ignore
+ "PIE790", # unnecessary-placeholder
+ "PIE808", # unnecessary-range-start
+ "PLC2701", # import-private-name
+ "PLW2901", # redefined-loop-name
+ "RUF001", # ambiguous-unicode-character-string
+ "RUF005", # collection-literal-concatenation
+ "RUF012", # mutable-class-default
+ "RUF100", # unused-noqa
+ "SIM102", # collapsible-if
+ "SIM108", # if-else-block-instead-of-if-exp
+ "SIM117", # multiple-with-statements
+ "TID252", # relative-imports
+ "TRY003", # raise-vanilla-args
+ "TRY300", # try-consider-else
+ "TRY400", # error-instead-of-exception
+ "UP031", # printf-string-formatting
+ "UP038", # non-pep604-isinstance
+]
+
+[lint.per-file-ignores]
+"**/__init__.py" = [
+ "F401", # unused-import
+]
+
+[lint.isort]
+# https://www.odoo.com/documentation/master/contributing/development/coding_guidelines.html#imports
+section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
+known-first-party = ["odoo"]
+known-local-folder = ["odoo.addons"]
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000000..98ae51447b6
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[pycodestyle]
+ignore = ["E501","E302","E301"]
diff --git a/website_airproof/__manifest__.py b/website_airproof/__manifest__.py
index 2c2c62d6a18..48267ad98aa 100644
--- a/website_airproof/__manifest__.py
+++ b/website_airproof/__manifest__.py
@@ -1,59 +1,69 @@
{
- 'name': 'Airproof Theme',
- 'description': 'Airproof Theme - Drones, modelling, camera',
- 'category': 'Website/Theme',
+ "name": "Airproof Theme",
+ "description": "Airproof Theme - Drones, modelling, camera",
+ "category": "Website/Theme",
# 'version': '18.0.1.0',
- 'author': 'PSBE Designers',
- 'license': 'LGPL-3',
- 'depends': ['website_sale', 'website_sale_wishlist', 'website_blog', 'website_mass_mailing'],
- 'data': [
+ "author": "PSBE Designers",
+ "license": "LGPL-3",
+ "depends": [
+ "website_sale",
+ "website_sale_wishlist",
+ "website_blog",
+ "website_mass_mailing",
+ ],
+ "data": [
# Snippets
- 'views/snippets/options.xml',
- 'views/snippets/s_airproof_carousel.xml',
+ "views/snippets/options.xml",
+ "views/snippets/s_airproof_carousel.xml",
# Options
- 'data/presets.xml',
- 'data/website.xml',
+ "data/presets.xml",
+ "data/website.xml",
# Menu
- 'data/menu.xml',
+ "data/menu.xml",
# Gradients
- 'data/gradients.xml',
+ "data/gradients.xml",
# Shapes
- 'data/shapes.xml',
+ "data/shapes.xml",
# Pages
- 'data/pages/home.xml',
- 'data/pages/contact.xml',
+ "data/pages/home.xml",
+ "data/pages/contact.xml",
# Frontend
- 'views/new_page_template_templates.xml',
- 'views/website_templates.xml',
- 'views/website_sale_templates.xml',
- 'views/website_sale_wishlist_templates.xml',
+ "views/new_page_template_templates.xml",
+ "views/website_templates.xml",
+ "views/website_sale_templates.xml",
+ "views/website_sale_wishlist_templates.xml",
# Images
- 'data/images.xml',
+ "data/images.xml",
],
- 'assets': {
- 'web._assets_primary_variables': [
- 'website_airproof/static/src/scss/primary_variables.scss',
+ "assets": {
+ "web._assets_primary_variables": [
+ "website_airproof/static/src/scss/primary_variables.scss",
],
- 'web._assets_frontend_helpers': [
- ('prepend', 'website_airproof/static/src/scss/bootstrap_overridden.scss'),
+ "web._assets_frontend_helpers": [
+ ("prepend", "website_airproof/static/src/scss/bootstrap_overridden.scss"),
],
- 'web.assets_frontend': [
+ "web.assets_frontend": [
# SCSS
- 'website_airproof/static/src/scss/font.scss',
- 'website_airproof/static/src/scss/components/mouse_follower.scss',
- 'website_airproof/static/src/scss/layout/header.scss',
- 'website_airproof/static/src/scss/pages/product_page.scss',
- 'website_airproof/static/src/scss/pages/shop.scss',
- 'website_airproof/static/src/scss/snippets/caroussel.scss',
- 'website_airproof/static/src/scss/snippets/newsletter.scss',
- 'website_airproof/static/src/snippets/s_airproof_carousel/000.scss',
+ "website_airproof/static/src/scss/font.scss",
+ "website_airproof/static/src/scss/components/mouse_follower.scss",
+ "website_airproof/static/src/scss/layout/header.scss",
+ "website_airproof/static/src/scss/pages/product_page.scss",
+ "website_airproof/static/src/scss/pages/shop.scss",
+ "website_airproof/static/src/scss/snippets/caroussel.scss",
+ "website_airproof/static/src/scss/snippets/newsletter.scss",
+ "website_airproof/static/src/snippets/s_airproof_carousel/000.scss",
# JS
- 'website_airproof/static/src/js/mouse_follower.js',
+ "website_airproof/static/src/js/mouse_follower.js",
],
},
- 'new_page_templates': {
- 'airproof': {
- 'services': ['s_parallax', 's_airproof_key_benefits_h2', 's_call_to_action', 's_airproof_carousel']
- }
+ "new_page_templates": {
+ "airproof": {
+ "services": [
+ "s_parallax",
+ "s_airproof_key_benefits_h2",
+ "s_call_to_action",
+ "s_airproof_carousel",
+ ],
+ },
},
}