The Point of Sale module is an integral part of the Odoo ERP system, which will be useful for managing and registering daily sales transactions. In this blog, we are going to explain how to create a custom POS Screen. In Odoo 15, we use OWL(Odoo web Library) to create custom screens. OWL is the latest framework developed by Odoo.
Let’s create a screen to view the product categories in POS. For that, first, we need to add a button ‘View Categories’ in POS.
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="CategoryControlButton'" owl="1">
<div class="control-button o_sale_orders_button">
<i class="fa fa-list" />View Categories
</div>
</t>
</templates>
Here we created a template named ‘CategoryControlButton'. While creating the template we specified owl=”1”, which denotes that it’s an owl template. After adding the qweb template to the manifest file under the assets section as follows:-
'assets': {
'web.assets_qweb': [
'module_name/static/src/xml/CategoryControlButton.xml',
],
},
There is a difference in adding the Qweb template in Odoo 15 as compared to Odoo 14, In the case of Odoo 14 specifying the template inside the qweb section of the manifest. In Odoo 15 add the templates inside the web.assets_qweb.
After that, we defined the js for the CategoryControlButton,
odoo.define('pos_custom_screen.CategoryControlButton', function (require) {
'use strict';
const PosComponent = require('point_of_sale.PosComponent');
const ProductScreen = require('point_of_sale.ProductScreen');
const Registries = require('point_of_sale.Registries');
const { useListener } = require('web.custom_hooks');
class CategoryControlButton extends PosComponent {
}
CategoryControlButton.template = 'pos_custom_screen.CategoryControlButton';
ProductScreen.addControlButton({
component: CategoryControlButton,
condition: function () {
return true;
},
position: ['before', 'SetPricelistButton'],
});
Registries.Component.add(CategoryControlButton);
return CategoryControlButton;
});
Also, the js files are added under the assets section of the manifest file. Here by extending the ‘PosComponent’ we created a class ‘CategoryControlButton’ for our newly added button. Then specify the template to be specified to this class as ‘module_name.CategoryControlButton’. After adding the button ’View Categories’ to the Pos Screen, for that, we specify the class as a component, also the before or after the position for the button we want to display and the conditions. Then the button will be before the SetPricelistButton in the Pos Screen. After that add the component to the Registries. The result is as follows:
The next step is to define the click action for the View Categories button. For this, let’s add an onClick function and define it in the constructor of our CategoryControlButton class.
class CategoryControlButton extends PosComponent {
constructor() {
super(...arguments);
useListener('click', this._onClick);
}
_onClick() {
this.showTempScreen('CategoryScreen');
}
}
Inside the _onClick function specified that when we click on the button it should display the ‘CategoryScreen’ template. So next is to define the CategoryScreen template.
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="CategoryScreen" owl="1">
<div class="clientlist-screen screen">
<div class="screen-content">
<div class="top-content">
<div class="button back" t-on-click="back">
Back
</div>
</div>
<section class="full-content">
<div class="client-window">
<section class="subwindow list">
<div class="subwindow-container">
<div class="subwindow-container-fix scrollable-y">
<table class="client-list">
<thead>
<tr>
<th>Name </th>
<th>Costing Method </th>
<th>Inventory Valuation </th>
</tr>
</thead>
</table>
</div>
</div>
</section>
</div>
</section>
</div>
</div>
</t>
</templates>
This template also needs to be added to the manifest just like the CategoryControlButton. In the CategoryScreen template added a back button with an onclick event, and a table to display the fields from the product category. Then add the js for the CategoryScreen. Just like CategoryControlButton this js file also needs to specify inside the manifest. The assets section of the manifest will be updated like this,
'assets': {
'point_of_sale.assets': [
'module_name/static/src/js/CategoryControlButton.js',
'module_name/static/src/js/CategoryScreen.js',
],
'web.assets_qweb': [
'module_name/static/src/xml/CategoryControlButton.xml',
'module_name/static/src/xml/CategoryScreen.xml',
],
},
The CategoryScreen.js,
odoo.define('module_name.CategoryScreen', function(require) {
'use strict';
const PosComponent = require('point_of_sale.PosComponent');
const ProductScreen = require('point_of_sale.ProductScreen');
const {useListener} = require('web.custom_hooks');
const Registries = require('point_of_sale.Registries');
class CategoryScreen extends PosComponent {
back() {
this.trigger('close-temp-screen');
}
}
CategoryScreen.template = 'CategoryScreen';
Registries.Component.add(CategoryScreen);
return CategoryScreen;
});
Here is also we extends the PosComponent and added a class CategoryScreen, and added the template for that. Defined the onclick event for the back button inside the class. When clicking the button it will look like this,
Now we need to display the data from the product category. The model product.category is already loaded in the pos, using the load_fields we are going to load the fields 'costing method' and 'inventory valuation'.
const models = require('point_of_sale.models');
models.load_fields('product.category', ['property_cost_method', 'property_valuation']);
Now we have loaded the data, we can access these data in this.env.pos.product_categories. Next, add it to the constructor class of our CategoryScreen.
class CategoryScreen extends PosComponent {
constructor() {
super (... arguments);
this.categories = this.env.pos.product_categories;
}
back() {
this.trigger('close-temp-screen');
}
}
The data is now in the categories as a dictionary. Let's update the XML as follows,
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml: space="preserve">
<t t-name="CategoryScreen" owl="1">
<div class="clientlist-screen screen">
<div class="screen-content">
<div class="top-content">
<div class="button back "t-on-click="back">
Back
</div>
</div>
<section class="full-content">
<div class="client-window">
<section class="subwindow list">
<div class="subwindow-container">
<div class="subwindow-container-fix scrollable-y">
<table class="client-list">
<thead>
<tr>
<th> Name </th>
<th> Costing Method </th>
<th > Inventory Valuation </th>
</tr>
</thead>
<tbody>
<t t-foreach="categories" t-as="categ" t-key="categ.id">
<tr>
<td> <t t-esc="categ.name"/> </td>
<td> <t t-esc="categ.property_cost_method"/> </td>
<td> <t t-esc="categ.property_valuation" /> </td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</section>
</ div>
</section>
</div>
</div>
</t>
</templates>
In the t-for each part of the table, looping through the categories data that we have now added and displaying its name, costing method, and valuation. Then the Category Screen looks like this,
This is how a custom screen is added in Odoo 15 POS.