diff --git a/README.md b/README.md index 0c6667bb6f2..a0158d919ee 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # Odoo tutorials -This repository hosts the code for the bases and solutions of the -[official Odoo tutorials](https://www.odoo.com/documentation/16.0/developer/howtos.html). +This repository hosts the code for the bases of the modules used in the +[official Odoo tutorials](https://www.odoo.com/documentation/latest/developer/tutorials.html). -It has 2 branches for each Odoo version: one for the bases and one for -the solutions. For example, `16.0` and `16.0-solutions`. The first -contains the code of the modules that serve as base for the tutorials, -and the second contains the code of the same modules with the complete -solution. \ No newline at end of file +It has 3 branches for each Odoo version: one for the bases, one for the +[Discover the JS framework](https://www.odoo.com/documentation/latest/developer/tutorials/discover_js_framework.html) +tutorial's solutions, and one for the +[Master the Odoo web framework](https://www.odoo.com/documentation/latest/developer/tutorials/master_odoo_web_framework.html) +tutorial's solutions. For example, `17.0`, `17.0-discover-js-framework-solutions` and +`17.0-master-odoo-web-framework-solutions`. diff --git a/awesome_clicker/__init__.py b/awesome_clicker/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/awesome_clicker/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/awesome_clicker/__manifest__.py b/awesome_clicker/__manifest__.py new file mode 100644 index 00000000000..e57ef4d5bb0 --- /dev/null +++ b/awesome_clicker/__manifest__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Clicker", + + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 1: Build a Clicker game" + """, + + 'author': "Odoo", + 'website': "https://www.odoo.com/", + 'category': 'Tutorials/AwesomeClicker', + 'version': '0.1', + 'application': True, + 'installable': True, + 'depends': ['base', 'web'], + + 'data': [], + 'assets': { + 'web.assets_backend': [ + 'awesome_clicker/static/src/**/*', + ], + + }, + 'license': 'AGPL-3' +} diff --git a/awesome_dashboard/__init__.py b/awesome_dashboard/__init__.py new file mode 100644 index 00000000000..b0f26a9a602 --- /dev/null +++ b/awesome_dashboard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py new file mode 100644 index 00000000000..31406e8addb --- /dev/null +++ b/awesome_dashboard/__manifest__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Dashboard", + + 'summary': """ + Starting module for "Discover the JS framework, chapter 2: Build a dashboard" + """, + + 'description': """ + Starting module for "Discover the JS framework, chapter 2: Build a dashboard" + """, + + 'author': "Odoo", + 'website': "https://www.odoo.com/", + 'category': 'Tutorials/AwesomeDashboard', + 'version': '0.1', + 'application': True, + 'installable': True, + 'depends': ['base', 'web', 'mail', 'crm'], + + 'data': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_dashboard/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_dashboard/controllers/__init__.py b/awesome_dashboard/controllers/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_dashboard/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_dashboard/controllers/controllers.py b/awesome_dashboard/controllers/controllers.py new file mode 100644 index 00000000000..56d4a051287 --- /dev/null +++ b/awesome_dashboard/controllers/controllers.py @@ -0,0 +1,36 @@ +# -*- 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='json', auth='user') + def get_statistics(self): + """ + Returns a dict of statistics about the orders: + 'average_quantity': the average number of t-shirts by order + 'average_time': the average time (in hours) elapsed between the + moment an order is created, and the moment is it sent + 'nb_cancelled_orders': the number of cancelled orders, this month + 'nb_new_orders': the number of new orders, this month + 'total_amount': the total amount of orders, this month + """ + + 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), + }, + 'total_amount': random.randint(100, 1000) + } + diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js new file mode 100644 index 00000000000..637fa4bb972 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.js @@ -0,0 +1,10 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; +import { registry } from "@web/core/registry"; + +class AwesomeDashboard extends Component { + static template = "awesome_dashboard.AwesomeDashboard"; +} + +registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml new file mode 100644 index 00000000000..1a2ac9a2fed --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.xml @@ -0,0 +1,8 @@ + + + + + hello dashboard + + + diff --git a/awesome_dashboard/views/views.xml b/awesome_dashboard/views/views.xml new file mode 100644 index 00000000000..47fb2b6f258 --- /dev/null +++ b/awesome_dashboard/views/views.xml @@ -0,0 +1,11 @@ + + + + Dashboard + awesome_dashboard.dashboard + + + + + + diff --git a/awesome_gallery/__init__.py b/awesome_gallery/__init__.py new file mode 100644 index 00000000000..a0fdc10fe11 --- /dev/null +++ b/awesome_gallery/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/awesome_gallery/__manifest__.py b/awesome_gallery/__manifest__.py new file mode 100644 index 00000000000..624766dca89 --- /dev/null +++ b/awesome_gallery/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Gallery View", + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" + """, + + 'version': '0.1', + 'application': True, + 'category': 'Tutorials/AwesomeGallery', + 'installable': True, + 'depends': ['web', 'contacts'], + 'data': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_gallery/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_gallery/models/__init__.py b/awesome_gallery/models/__init__.py new file mode 100644 index 00000000000..7f0930ee744 --- /dev/null +++ b/awesome_gallery/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# import filename_python_file_within_folder_or_subfolder +from . import ir_action +from . import ir_ui_view diff --git a/awesome_gallery/models/ir_action.py b/awesome_gallery/models/ir_action.py new file mode 100644 index 00000000000..eae20acbf5c --- /dev/null +++ b/awesome_gallery/models/ir_action.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from odoo import fields, models + + +class ActWindowView(models.Model): + _inherit = 'ir.actions.act_window.view' + + 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 new file mode 100644 index 00000000000..0c11b8298ac --- /dev/null +++ b/awesome_gallery/models/ir_ui_view.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from odoo import fields, models + + +class View(models.Model): + _inherit = 'ir.ui.view' + + type = fields.Selection(selection_add=[('gallery', "Awesome Gallery")]) diff --git a/awesome_gallery/static/src/gallery_view.js b/awesome_gallery/static/src/gallery_view.js new file mode 100644 index 00000000000..db904d1f478 --- /dev/null +++ b/awesome_gallery/static/src/gallery_view.js @@ -0,0 +1,3 @@ +/** @odoo-module */ + +// TODO: Begin here! diff --git a/awesome_gallery/views/views.xml b/awesome_gallery/views/views.xml new file mode 100644 index 00000000000..56327365875 --- /dev/null +++ b/awesome_gallery/views/views.xml @@ -0,0 +1,19 @@ + + + + + Contacts + res.partner + kanban,tree,form,activity + + {'default_is_company': True} + +

+ Create a Contact in your address book +

+ Odoo helps you track all activities related to your contacts. +

+
+
+
+
diff --git a/awesome_kanban/__init__.py b/awesome_kanban/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/awesome_kanban/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/awesome_kanban/__manifest__.py b/awesome_kanban/__manifest__.py new file mode 100644 index 00000000000..affef78bb12 --- /dev/null +++ b/awesome_kanban/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Kanban", + 'summary': """ + Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view" + """, + + 'description': """ + Starting module for "Master the Odoo web framework, chapter 4: Customize a kanban view. + """, + + 'version': '0.1', + 'application': True, + 'category': 'Tutorials/AwesomeKanban', + 'installable': True, + 'depends': ['web', 'crm'], + 'data': [ + 'views/views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'awesome_kanban/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/awesome_kanban/static/src/awesome_kanban_view.js b/awesome_kanban/static/src/awesome_kanban_view.js new file mode 100644 index 00000000000..9f33fc1300b --- /dev/null +++ b/awesome_kanban/static/src/awesome_kanban_view.js @@ -0,0 +1,3 @@ +/** @odoo-module */ + +// TODO: Define here your AwesomeKanban view diff --git a/awesome_kanban/views/views.xml b/awesome_kanban/views/views.xml new file mode 100644 index 00000000000..548b2907b6e --- /dev/null +++ b/awesome_kanban/views/views.xml @@ -0,0 +1,15 @@ + + + + + crm.lead.kanban.lead.awesome_gallery + crm.lead + + + + awesome_kanban + + + + + diff --git a/awesome_owl/__init__.py b/awesome_owl/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_owl/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py new file mode 100644 index 00000000000..77abad510ef --- /dev/null +++ b/awesome_owl/__manifest__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Awesome Owl", + + 'summary': """ + Starting module for "Discover the JS framework, chapter 1: Owl components" + """, + + 'description': """ + Starting module for "Discover the JS framework, chapter 1: Owl components" + """, + + '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/AwesomeOwl', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['base', 'web'], + 'application': True, + 'installable': True, + 'data': [ + 'views/templates.xml', + ], + 'assets': { + 'awesome_owl.assets_playground': [ + ('include', 'web._assets_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' +} diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py new file mode 100644 index 00000000000..457bae27e11 --- /dev/null +++ b/awesome_owl/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/awesome_owl/controllers/controllers.py b/awesome_owl/controllers/controllers.py new file mode 100644 index 00000000000..bccfd6fe283 --- /dev/null +++ b/awesome_owl/controllers/controllers.py @@ -0,0 +1,10 @@ +from odoo import http +from odoo.http import request, route + +class OwlPlayground(http.Controller): + @http.route(['/awesome_owl'], type='http', auth='public') + def show_playground(self): + """ + Renders the owl playground page + """ + return request.render('awesome_owl.playground') diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js new file mode 100644 index 00000000000..1af6c827e0b --- /dev/null +++ b/awesome_owl/static/src/main.js @@ -0,0 +1,11 @@ +import { whenReady } from "@odoo/owl"; +import { mountComponent } from "@web/env"; +import { Playground } from "./playground"; + +const config = { + dev: true, + name: "Owl Tutorial", +}; + +// Mount the Playground component when the document.body is ready +whenReady(() => mountComponent(Playground, document.body, config)); diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js new file mode 100644 index 00000000000..657fb8b07bb --- /dev/null +++ b/awesome_owl/static/src/playground.js @@ -0,0 +1,7 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; + +export class Playground extends Component { + static template = "awesome_owl.playground"; +} diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml new file mode 100644 index 00000000000..4fb905d59f9 --- /dev/null +++ b/awesome_owl/static/src/playground.xml @@ -0,0 +1,10 @@ + + + + +
+ hello world +
+
+ +
diff --git a/awesome_owl/views/templates.xml b/awesome_owl/views/templates.xml new file mode 100644 index 00000000000..aa54c1a7241 --- /dev/null +++ b/awesome_owl/views/templates.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/pos_uom/__init__.py b/pos_uom/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/pos_uom/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_uom/__manifest__.py b/pos_uom/__manifest__.py new file mode 100644 index 00000000000..cd6a48589e5 --- /dev/null +++ b/pos_uom/__manifest__.py @@ -0,0 +1,24 @@ +{ + 'name': "POS UOM Conversion", + 'summary': """ + Module for Adding Second Uom for POS + """, + 'description': """ + Module for Adding Second Uom for POS + """, + 'category': 'Sales/Point of Sale', + 'version': '0.1', + 'application': True, + 'installable': True, + 'data': ['views/product_template_form_view.xml'], + 'depends': ['point_of_sale', 'web'], + 'assets': { + 'point_of_sale._assets_pos': [ + 'pos_uom/static/src/**/*', + ], + 'web.assets_tests': [ + 'pos_uom/static/tests/tours/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/pos_uom/models/__init__.py b/pos_uom/models/__init__.py new file mode 100644 index 00000000000..049669dd0fe --- /dev/null +++ b/pos_uom/models/__init__.py @@ -0,0 +1,2 @@ +from . import product_template +from . import product_product diff --git a/pos_uom/models/product_product.py b/pos_uom/models/product_product.py new file mode 100644 index 00000000000..24f93d2fe0b --- /dev/null +++ b/pos_uom/models/product_product.py @@ -0,0 +1,11 @@ +from odoo import models, api + + +class ProductProduct(models.Model): + _inherit = 'product.product' + + @api.model + def _load_pos_data_fields(self, config_id): + data = super()._load_pos_data_fields(config_id) + data += ['second_uom_id'] + return data diff --git a/pos_uom/models/product_template.py b/pos_uom/models/product_template.py new file mode 100644 index 00000000000..38a6523b444 --- /dev/null +++ b/pos_uom/models/product_template.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + second_uom_id = fields.Many2one("uom.uom", string="Second UOM") diff --git a/pos_uom/static/src/control_buttons.js b/pos_uom/static/src/control_buttons.js new file mode 100644 index 00000000000..a7dce9ca5cb --- /dev/null +++ b/pos_uom/static/src/control_buttons.js @@ -0,0 +1,56 @@ +import { _t } from "@web/core/l10n/translation"; +import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons"; +import { patch } from "@web/core/utils/patch"; +import { useService } from "@web/core/utils/hooks"; +import { NumberInputPopup } from "./number_input_popup"; + +patch(ControlButtons.prototype, { + setup () { + super.setup(); + this.action = useService("action"); + }, + + async clickAddQuantity() { + this.dialog.add(NumberInputPopup, { + title: _t("Enter Quantity"), + getPayload: (inputValue) => { + return this.convertUom(inputValue); + } + }); + }, + convertUom(inputValue) { + const order = this.currentOrder; + const line = order.get_selected_orderline(); + if (line) { + const product = line.get_product(); + if (!product.second_uom_id){ + this.env.services.notification.add("Product Does not have Secondary Uom. Configure that first!", { + title: "Configuraion Issue!!", + type: "danger", + buttons: [ + { + name: "Configure", + onClick: () => { + this.action.doAction({ + type: 'ir.actions.act_window', + name: _t('Product'), + target: 'current', + res_id: product.id, + res_model: 'product.product', + views: [[false, 'form']], + }); + }, + }, + ], + }); + return false + } + const ratio = inputValue * (product.second_uom_id.factor_inv/product.uom_id.factor_inv); + line.qty = parseFloat(ratio.toFixed(2)); + return true + } + }, + get currentOrder() { + return this.pos.get_order(); + } +}); diff --git a/pos_uom/static/src/control_buttons.xml b/pos_uom/static/src/control_buttons.xml new file mode 100644 index 00000000000..d8df4109e3d --- /dev/null +++ b/pos_uom/static/src/control_buttons.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/pos_uom/static/src/number_input_popup.js b/pos_uom/static/src/number_input_popup.js new file mode 100644 index 00000000000..81621a364e5 --- /dev/null +++ b/pos_uom/static/src/number_input_popup.js @@ -0,0 +1,33 @@ +import { Component, onMounted, useRef, useState } from "@odoo/owl"; +import { Dialog } from "@web/core/dialog/dialog"; + +export class NumberInputPopup extends Component { + static template = "pos_uom.NumberInputPopup"; + static components = { Dialog }; + static props = { + title: String, + getPayload: Function, + close: Function, + }; + + setup() { + this.inputRef = useRef("input"); + onMounted(this.onMounted); + } + onMounted() { + this.inputRef.el.focus(); + this.inputRef.el.select(); + } + confirm() { + if (this.inputRef){ + const configure_success = this.props.getPayload(parseFloat(this.inputRef.el.value)); + if (configure_success){ + this.props.close() + } + } + } + + close() { + this.props.close(); + } +} diff --git a/pos_uom/static/src/number_input_popup.xml b/pos_uom/static/src/number_input_popup.xml new file mode 100644 index 00000000000..553fc72ff4e --- /dev/null +++ b/pos_uom/static/src/number_input_popup.xml @@ -0,0 +1,19 @@ + + + + + +
+ + +
+ + + + +
+
+ +
diff --git a/pos_uom/static/tests/tours/pos_uom_conversion.js b/pos_uom/static/tests/tours/pos_uom_conversion.js new file mode 100644 index 00000000000..c72a51ec898 --- /dev/null +++ b/pos_uom/static/tests/tours/pos_uom_conversion.js @@ -0,0 +1,29 @@ +import * as Dialog from "@point_of_sale/../tests/tours/utils/dialog_util"; +import * as Chrome from "@point_of_sale/../tests/tours/utils/chrome_util"; +import { registry } from "@web/core/registry"; +import * as Utils from "@point_of_sale/../tests/tours/utils/common"; +import { waitForLoading } from "@point_of_sale/../tests/tours/utils/common"; +import * as ProductScreen from "@point_of_sale/../tests/tours/utils/product_screen_util"; + +registry.category("web_tour.tours").add("pos_uom_conversion", { + steps: () => + [ + waitForLoading(), + Chrome.startPoS(), + Dialog.confirm("Open Register"), + ProductScreen.clickDisplayedProduct("Apple", "1.0"), + Utils.selectButton("Add Quantity"), + { + "trigger": ".o_input", + "content": "enter input", + "run": "edit 6" + }, + { + "trigger": ".o-default-button:nth-child(1)", + "content": "click confirm", + "run": "click" + }, + ProductScreen.selectedOrderlineHas("Apple", "0.5"), + ProductScreen.closePos(), + ].flat(), +}); diff --git a/pos_uom/tests/__init__.py b/pos_uom/tests/__init__.py new file mode 100644 index 00000000000..2204324d924 --- /dev/null +++ b/pos_uom/tests/__init__.py @@ -0,0 +1 @@ +from . import test_pos_uom_conversion diff --git a/pos_uom/tests/test_pos_uom_conversion.py b/pos_uom/tests/test_pos_uom_conversion.py new file mode 100644 index 00000000000..32a80e3575c --- /dev/null +++ b/pos_uom/tests/test_pos_uom_conversion.py @@ -0,0 +1,43 @@ +from odoo.tests import tagged +from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon + + +@tagged('post_install', '-at_install') +class TestPOS(TestPointOfSaleHttpCommon): + + def setUp(self): + super().setUp() + + self.uom_category_unit = self.env['uom.category'].create({ + 'name': 'Unit Category' + }) + + self.uom_unit = self.env['uom.uom'].create({ + 'name': 'Unit', + 'category_id': self.uom_category_unit.id, + 'uom_type': 'reference', + 'factor_inv': 1.0, + 'rounding': 0.01, + }) + + self.uom_dozen = self.env['uom.uom'].create({ + 'name': 'Dozen', + 'category_id': self.uom_category_unit.id, + 'uom_type': 'smaller', + 'factor_inv': 12.0, + 'rounding': 0.01, + }) + + self.letter_tray = self.env['product.product'].create({ + 'name': 'Apple', + 'uom_id': self.uom_dozen.id, + 'uom_po_id': self.uom_dozen.id, + 'second_uom_id': self.uom_unit.id, + 'available_in_pos': True, + 'list_price': 12.0, + }) + + def test_pos_uom_conversion_tour(self): + self.main_pos_config.with_user(self.pos_user).open_ui() + self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, + 'pos_uom_conversion', login="pos_user", watch=True) diff --git a/pos_uom/views/product_template_form_view.xml b/pos_uom/views/product_template_form_view.xml new file mode 100644 index 00000000000..821c25a9801 --- /dev/null +++ b/pos_uom/views/product_template_form_view.xml @@ -0,0 +1,14 @@ + + + + + product.template.form.inherit.pos_uom + product.template + + + + + + + + diff --git a/website_airproof/README.md b/website_airproof/README.md new file mode 100644 index 00000000000..6c6390b9424 --- /dev/null +++ b/website_airproof/README.md @@ -0,0 +1,18 @@ +# Odoo Tutorial : Build a website theme + +This branch contains the code necessary for the creation of the website for our Airproof example. +Example used to illustrate the exercises given in the Odoo tutorial: Build a website theme. + +Here is the final design of the 4 pages of Airproof that will be created throughout this tutorial. + +**Home** +![Airproof home page](airproof-home-page.jpg) + +**Contact page** +![Airproof contact page](airproof-contact-page.jpg) + +**Shop page** +![Airproof shop page](airproof-shop-page.jpg) + +**Product page** +![Airproof product page](airproof-product-page.jpg) diff --git a/website_airproof/__init__.py b/website_airproof/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website_airproof/__manifest__.py b/website_airproof/__manifest__.py new file mode 100644 index 00000000000..f6cd9dc0d5e --- /dev/null +++ b/website_airproof/__manifest__.py @@ -0,0 +1,59 @@ +{ + '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': [ + # Options + 'data/presets.xml', + 'data/website.xml', + # Menu + 'data/menu.xml', + # Gradients + 'data/gradients.xml', + # Shapes + 'data/shapes.xml', + # Pages + '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', + # Snippets + 'views/snippets/options.xml', + 'views/snippets/s_airproof_carousel.xml', + # Images + 'data/images.xml', + ], + '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': [ + # 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', + ], + }, + 'new_page_templates': { + 'airproof': { + 'services': ['s_parallax', 's_airproof_key_benefits_h2', 's_call_to_action', 's_airproof_carousel'] + } + }, +} diff --git a/website_airproof/airproof-contact-page.jpg b/website_airproof/airproof-contact-page.jpg new file mode 100644 index 00000000000..cc1008a28cb Binary files /dev/null and b/website_airproof/airproof-contact-page.jpg differ diff --git a/website_airproof/airproof-home-page.jpg b/website_airproof/airproof-home-page.jpg new file mode 100644 index 00000000000..53eb1d617b2 Binary files /dev/null and b/website_airproof/airproof-home-page.jpg differ diff --git a/website_airproof/airproof-product-page.jpg b/website_airproof/airproof-product-page.jpg new file mode 100644 index 00000000000..bf07f58651a Binary files /dev/null and b/website_airproof/airproof-product-page.jpg differ diff --git a/website_airproof/airproof-shop-page.jpg b/website_airproof/airproof-shop-page.jpg new file mode 100644 index 00000000000..c77e724d7f1 Binary files /dev/null and b/website_airproof/airproof-shop-page.jpg differ diff --git a/website_airproof/data/gradients.xml b/website_airproof/data/gradients.xml new file mode 100644 index 00000000000..fd68f07b17c --- /dev/null +++ b/website_airproof/data/gradients.xml @@ -0,0 +1,14 @@ + + + + website_airproof.colorpicker + Custom Gradients + qweb + + + + + + + + diff --git a/website_airproof/data/images.xml b/website_airproof/data/images.xml new file mode 100644 index 00000000000..e3c7414a4d0 --- /dev/null +++ b/website_airproof/data/images.xml @@ -0,0 +1,188 @@ + + + + + + + + + White arrow icon + + ir.ui.view + + + + Glasses icon + + ir.ui.view + + + + 4K icon + + ir.ui.view + + + + Hand with drone icon + + ir.ui.view + + + + Control icon + + ir.ui.view + + + + Shopping icon + + ir.ui.view + + + + Phone icon + + ir.ui.view + + + + Envelop icon + + ir.ui.view + + + + Arrow icon + + ir.ui.view + + + + Small arrow icon + + ir.ui.view + + + + Check icon + + ir.ui.view + + + + Black Phone icon + + ir.ui.view + + + + Black Envelop icon + + ir.ui.view + + + + + + Drone Airproof Mini + + ir.ui.view + + + + Drone Airproof Pro + + ir.ui.view + + + + Drone Airproof Robin + + ir.ui.view + + + + Drone Airproof Falcon + + ir.ui.view + + + + Drone Airproof Eagle + + ir.ui.view + + + + + + + Drone accessories picture + + ir.ui.view + + + + Drone Robin picture + + ir.ui.view + + + + Drone school picture + + ir.ui.view + + + + Drone flying picture + + ir.ui.view + + + + + + Fields topview + + ir.ui.view + + + + + + Highway topview + + ir.ui.view + + + + + + Drone with blue background picture + + ir.ui.view + + + + + + Sticker logo + + ir.ui.view + + + + Drone picture + + ir.ui.view + + + diff --git a/website_airproof/data/menu.xml b/website_airproof/data/menu.xml new file mode 100644 index 00000000000..ee0a9319f19 --- /dev/null +++ b/website_airproof/data/menu.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + Waterproof drones + + 1 + 10 + +
+ +
+
+
+ + + + About us + /about-us + 1 + + 20 + + + + + Blog + + 1 + 30 + + + Our latest news + /blog/our-latest-news-2 + 1 + + 31 + + + Tutorials + /blog/tutorials-3 + 1 + + 32 + + + + + Contact us + /contactus + 1 + + 40 + +
diff --git a/website_airproof/data/pages/contact.xml b/website_airproof/data/pages/contact.xml new file mode 100644 index 00000000000..f6a4502dc75 --- /dev/null +++ b/website_airproof/data/pages/contact.xml @@ -0,0 +1,156 @@ + + + + + + + + + Contact us + + website_airproof.page_contact + /contactus + + qweb + + + + + Contact us + + + +