69
OpenERP Tutorial: Module creation and modification of the Point Of Sale Par Thierry Godin Date de publication : 1 août 2013 This tutorial aims to show you how to create a module for OpenERP Point Of Sale from A to Z. You will learn to create a basic OpenERP module with its icon, manage access rights and registration rules, create a menu, modify the Point Of Sale by adding a drop-down list, put the name of the cashier on the receipt and finally make the translation files of the module

OpenERP POS Tutorial

Embed Size (px)

DESCRIPTION

OpenERP POS Tutorial

Citation preview

Page 1: OpenERP POS Tutorial

OpenERP Tutorial: Module creationand modification of the Point Of Sale

Par Thierry Godin

Date de publication : 1 août 2013

This tutorial aims to show you how to create a module for OpenERP Point Of Sale from A toZ. You will learn to create a basic OpenERP module with its icon, manage access rights andregistration rules, create a menu, modify the Point Of Sale by adding a drop-down list, putthe name of the cashier on the receipt and finally make the translation files of the module

Page 2: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 2 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

I - Introduction..............................................................................................................................................................3II - Requirements......................................................................................................................................................... 4III - Basics.................................................................................................................................................................... 4IV - Necessary tools.................................................................................................................................................... 4V - Stages of completion.............................................................................................................................................5VI - Module structure................................................................................................................................................... 6VII - Creation of a basic OpenERP module................................................................................................................6

VII-A - Creation of the directories.......................................................................................................................... 6VII-B - Required Python files................................................................................................................................. 8

VII-B-1 - The __init__.py file.............................................................................................................................8VII-B-2 - The __openerp__.py file.................................................................................................................... 8VII-B-3 - The pos_cashier.py file.................................................................................................................... 10

VII-B-3-a - Statements...............................................................................................................................12VII-B-3-b - Overload pos.order object of Point Of Sale............................................................................ 13

VII-B-4 - cashier_view.xml file.........................................................................................................................14VII-B-4-a - The form view..........................................................................................................................16VII-B-4-b - The Tree view..........................................................................................................................18VII-B-4-c - The search view...................................................................................................................... 18VII-B-4-d - The Cashiers menu................................................................................................................. 19VII-B-4-e - The action of the menu........................................................................................................... 21

VII-B-5 - The order_cashier_view.xml file.......................................................................................................23VII-B-5-a - The form view..........................................................................................................................24VII-B-5-b - The Tree View......................................................................................................................... 25

VII-C - Security Settings of the module............................................................................................................... 26VII-C-1 - Access Rights.................................................................................................................................. 26VII-C-2 - Record rules.....................................................................................................................................28

VII-D - Add an icon to the module.......................................................................................................................30VII-E - End of the basic OpenERP module......................................................................................................... 30

VIII - Creation of the Web module for the Point Of Sale.......................................................................................... 30VIII-A - The pos_cashier.js file............................................................................................................................. 31

VIII-A-1 - openerp_pos_cashier() function......................................................................................................39VIII-A-2 - The CashierWidget module............................................................................................................ 40VIII-A-3 - The CashierPayScreenWidget module........................................................................................... 50VIII-A-4 - The CashierReceiptScreenWidget module..................................................................................... 50VIII-A-5 - GoToPayWidget module..................................................................................................................51VIII-A-6 - GoToPayButtonWidget module (Pay button).................................................................................. 52VIII-A-7 - Order module.................................................................................................................................. 52VIII-A-8 - The best for last..............................................................................................................................57

VIII-B - the pos_cashier.xml file........................................................................................................................... 57VIII-B-1 - The dropdown cashiers...................................................................................................................58

VIII-C - pos_cashier.css file................................................................................................................................. 62IX - Installation of the module................................................................................................................................... 63X - Internationalisation............................................................................................................................................... 64XI - Conclusion.......................................................................................................................................................... 68XII - Download module.............................................................................................................................................. 68XIII - Thanks.............................................................................................................................................................. 69

Page 3: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 3 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

I - Introduction

WARNINGThis is the english translation of the french tutorial I made.My native language is french. I have some basic knowledge of english language, thus Itranslated the tutorial by myself and sometimes by the use of a famous translation service,so I hope the whole text is easily understandable.Whatever, the french version prevails.In case of misunderstanding, do not hesitate to contact me at OpenERP Official ForumThank you for reading

OpenERP programming is a rather complicated task. It is necessary to know several programming languages andyou must also have a good idea of how OpenERP does work.

The documentation is quite limited and very brief. There are very few forums or specialized blogs about OpenERP,and almost all are in English.

The few tutorials found on the Web are limited to specific problems.

They do not fully achieve a complex module, they just allow you to add a button or function somewhere. It's not enough.

The tutorial that I propose is the result of hundreds of hours of learning everything I could find in the officialdocumentation and on the Web, as well as number of lines of code, of countless tests, bugs and other gaieties. Youknow what I mean...

This is due to a request from a customer that I had the mission to make a module that will allow the creation ofcashiers for the Point Of Sale.The context

OpenERP is installed on a Debian server. The client sells products through franchises. Each society can access toOpenERP, which is configured with Multi-Company feature.

Each company has a PC in its location that is connected to the Point of Sale. And each company has several cashiersas employees.Customer demandHow could we make purchases with the Point Of Sale on the same computer (PC) without having to create a sessioneach time a cashier wants to make a sale?Point Of Sale actually allows to make sales with several seller. To do this, simply create users in the company, putthem in the Point Of Sale/User Group and assign them a Point Of Sale and voila.

But each seller must then log in to make the sale.These functions, however, native, did not suit the customer needs.So I made a module that allows to create a different kind of users, the cashiers. You'll see later that this is not verycomplicated.

Where it gets complicated is the part of the module, (The Web module), which operates in the Point Of Sale, andwhich allows to open only one session in the morning, make sales by several cashiers without leaving the Point OfSale, and thus prevent to close close the previous session to open a new one.Finally, the last statement of the customer: the cashier is required. The sale must not be possible if the Point OfSale has no cashiers.Here is what it is.

I will show you the steps that will help you for the creation of your own modules.

Page 4: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 4 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The source code certainly needs some improvements and optimizations, do not hesitate to share your comments, itwill also help me to move further into the intricacies of the OpenERP programming.

II - Requirements

To go with this tutorial, you need a good knowledge of programming languages used in OpenERP :

• Python ;• XML ;• JavaScript ;• Qweb/JQuery ;• Linux command line

III - Basics

To make it short, we can say that the making of a conventional module is done in three steps.:

• The creation of the initialization file of the module.• The creation of the Python Object.• The creation of the XML view.

Regarding the Point Of Sale, it is a « Web » module. When you login to the Point Of Sale, OpenERP disapears andthe Point Of Sale interface appears. You must then close the Point Of Sale to return to OpenERP.This is a special case which will require additional programming steps. The POS is not integrated with OpenERP, soits entire Web interface will keep our attention.

IV - Necessary tools

Here are the softwares I use, feel free to use them or find similar softwares.

• WinSCP : SFTP/FTP client, very pleasant to use, and allows to easily navigate through the file tree.• PuTTY : Telnet / SSH client that will run Linux commands on the server (WinSCP also allows, but with

some limitations)• Sublime : a very well made text editor. It is aptly named.• Firefox with Firebug extension. Essential for JavaScript debugging.

OpenERP is installed on a Debian server (Dev one). I'm working on a PC running Windows 7 pro.

Configure WinSCPWe will configure WinSCP for it opens directly with your favorite code editor when you double-click a file.

• Launch WinSCP.• Go to See menu, then Settings.• In the dialog form, click on Editor in the left column.• In the frame Editors preferences, click Add.• In the dialog box, clik External editor then select the exe file of your text editor.• In Use this editor for following files, select filter *.* (all files).• Validate.

In this tutorial, we assume that OpenERP is installed on a Linux/Debian server and thatwe are working on a Windows PC.I have installed OpenERP Version 7.0-20130703-231023 (version therefore dated 03July 2013).

Page 5: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 5 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

If you are working directly on the server, you will adapt the guidelines relating to the serveradministration (files, rights, etc..). The construction of the module remains the same.

V - Stages of completion

Creation of OpenERP internal module

• Creation of the module initialization file .• Creation of the file that contains Python Object• creation of the views (Form view, Tree view).• Creation of a menu for the POS/Manager users group• Creation of the access rights for the module• Creation of the recording rules• Creation of the icon

Creation of the Point Of Sale module

• Creation of the JavaScript file that contains module's actions and functions• Creation of the GUI elements (drop-down list, labels, etc.) in a XML file• Creation of the style file *.css for the design of the elements

Module internationalization

• Creation of the language template (*.pot)• Creation of the french tanslated file (*.po)

Warning :In this tutorial, Point Of Sale may be called POSSource code will be written in english, but texts and labels will be translated laterThe module is called pos_cashier.

Once completed, the POS Cashiers Module will appear in the list of installed modules, like in the image below

The pos_cashier module installed

WarningThe tutorial may seem very long, but I tried to dissect all stages of the implementation ofa module and I also tried to explain as best as I could all the source code and the variousfiles that compose the module

Page 6: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 6 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VI - Module structure

Here is the file-tree of the pos_cashier module

pos_cashier file tree

i18n directory :Contains the internationalization files of the module.security directory :Contains the access control file and recording rules file.static directory :Contains the « Web » part of the module.It contains the css directory that will host the stylesheet, the img directory that will host the icon of the module andthe requiered pictures, the js directory that will host the JavaScript file and the xml directory that will host the viewsof the module.Also , at the root of the module, there is the Python module and the XML views.

VII - Creation of a basic OpenERP module

First, we will achieve the module that will allow the creation of the cashiers within OpenERP. The Web part of themodule (which is in POS) will be discussed later.

VII-A - Creation of the directories

The OpenERP modules are usually placed in the « addons » directory, but I recommend that you create a specialdirectory (outside OpenERP) where you will place your own modules.

For the tutorial, we will create a modules-openerp directory in the /opt directory on your server.Log in with WinSCP (as root) and connect to your dev server.Navigate to the /opt directory and create a new folder. Name it modules-openerp.

Page 7: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 7 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Log in using PuTTY (from WinSCP) and enter the following commands:

Modify owner and rightscd /opt [+Enter]chown openerp:openerp ./modules-openerp [+Enter]chmod 0755 ./modules-openerp [+Enter]

We assigned the /opt/modules-openerp directory to the user openerp and the group openerp, then we changedthe rights.For our future modules to be taken into account by OpenERP, we have to modify the server configuration file andadd the path to our directory.

Modify openerp-server.conf file

• In WinSCP, go to /etc.• Depending on the version, the openerp-server.conf file can be found in /etc or /etc /openerp.• Double-click the file to edit.• Change the line below by adding the full path to the modules directory that we have just created.

openerp-server.confaddons_path = /opt/openerp/addons,/opt/openerp/server/openerp/addons,/opt/openerp/web/addons,/opt/modules-openerp

If this line does not exist, add it by putting only the path to your directory.There may be many paths to directories. They must be separated by a comma.

Save and close the file.Restart the server using the following command

Restart OpenERP/etc/init.d/openerp-server restart [+Enter]

Make sure the server is started by opening a Web page with the corresponding URL

http://IP_OF_YOUR_SERVER:8069Then create different directories within the modules-openerp directory

• pos_cashier• i18n• security• static

• src• css• img• js• xml

Then change the user, group and rights with the following command

Modify owner and rightscd /opt [+Enter]chown openerp:openerp ./modules-openerp -R [+Enter]chmod 0755 ./modules-openerp -R [+Enter]

Page 8: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 8 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VII-B - Required Python files

There are three mandatory files when you create a module.

• __init__.py• __openerp__.py• our_famous_module.py

VII-B-1 - The __init__.py file

This is the file that will invite OpenERP to load our module.The contents of this file is very simple:

__init__.pyimport pos_cashier

Put the name of the module. It is also the name of the directory.

VII-B-2 - The __openerp__.py file

This is the file that contains all the information about the module : name, version, category, description, files to load, etc.

__openerp__.py# -*- coding: utf-8 -*-{ 'name': 'POS Cashiers', 'version': '1.0.0', 'category': 'Point Of Sale', 'sequence': 3, 'author': 'Thierry Godin', 'summary': 'Manage cashiers for Point Of Sale', 'description': """Manage several cashiers for each Point Of Sale======================================

This could be handy in case of using the same POS at the same cash register while it is used by several cashiers.Cashier's name is displayed on the payement receipt and on the order.

Cashiers are allowed to change the current cashier (by choosing their name in the drop-down list) and can make a sell without creating a new session.

Cashier's name is mandatory. You cannot perform a sell if no cashier has been created or is active in your POS.

The shop manager will know who made the sell. """, 'depends': ["point_of_sale"], 'data': [ 'security/pos_cashier_security.xml', 'security/ir.model.access.csv', 'cashier_view.xml', 'order_cashier_view.xml', ], 'js': [ 'static/src/js/pos_cashier.js', ], 'css': [ 'static/src/css/pos_cashier.css', ], 'qweb': [ 'static/src/xml/pos_cashier.xml', ], 'installable': True,

Page 9: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 9 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

__openerp__.py 'application': False, 'auto_install': False,}

If you copy the code from this pageBeware of Python code indentation. This can be estimated in this article. This is due tothe editor I used to write this article.The source code of the module can be downloaded at the bottom of the page.

The file is to fill like this

'parameter': 'value','parameter': ['value1','value2','value3'],

The data are noted as key:value separated by a comma (end of line).The value can also contain an array like in the case of depends, data, js parameters , etc..

Parameters :

• name : the module name;• version : the module version;• category : the category in which you put the module;• sequence : This is a number that will show your module in the list of modules. 1, it will be up, 100 it will be

down ;• author : author of the module ;• summary : a summary that explains what is your module. A very short text, it appears under the name of the

module in the module list ;• description : the full description of the module ;• depends : modules that your module depends;• data : files to load ;• js : in case of a Web module like this one, the JavaScript files;• css : the stylesheet;• qweb : View of the Web Part (Template);• installable : if your module is installable or not;• application : set it to False. Your module will not be recognized as an application. It's OpenERP that issues

certificates that qualify your module as an application;• auto_install : set it to False, we will install the module by hand. (With a button, anyway ...)

There are other parameters, but for this module we have enough like that,

The « description » parameterTo insert a text on multiple lines, you must enclose with three double quotes(""" text here """)Put the fullest possible description.To return to the line, you actually have to jump one more, otherwise the new line will not be visible in OpenERP.

Underline text with the = sign will appear as the <h1></h1> web tag.

We created two files (which still bear the same names) for module initialization. But this is not enough!As we stated in the __ init__.py file, OpenERP will attempt to load the pos_cashier module. We must now createthe pos_cashier.py file (the module itself).

Page 10: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 10 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VII-B-3 - The pos_cashier.py file

I put the contents of the entire file.

Do not worry, we'll dissect it all quietly.

pos_cashier.py # -*- coding: utf-8 -*-############################################################################### # Module : pos_cashier# Créé le : 2013-06-06 par Thierry Godin## Module permettant la création de vendeurs pour les points de vente###############################################################################import openerpfrom openerp import netsvc, tools, poolerfrom openerp.osv import fields, osvfrom openerp.tools.translate import _import time

class pos_cashier(osv.osv): _name = 'pos.cashier' _order = 'cashier_name asc'

_columns = { 'pos_config_id' : fields.many2one('pos.config', 'Point Of Sale', required=True), 'cashier_name': fields.char('Cashier', size=128, required=True), 'active': fields.boolean('Active', help="If a cashier is not active, it will not be displayed in POS"), }

_defaults = { 'cashier_name' : '', 'active' : True, 'pos_config_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).pos_config.id, }

_sql_constraints = [ ('uniq_name', 'unique(cashier_name, pos_config_id)', "A cashier already exists with this name in this Point Of sale. Cashier's name must be unique!"), ]

class inherit_pos_order_for_cashiers(osv.osv): _name='pos.order' _inherit='pos.order' def create_from_ui(self, cr, uid, orders, context=None): #_logger.info("orders: %r", orders) order_ids = [] for tmp_order in orders: order = tmp_order['data'] order_id = self.create(cr, uid, { 'name': order['name'], 'user_id': order['user_id'] or False, 'session_id': order['pos_session_id'], 'lines': order['lines'], 'pos_reference':order['name'], 'cashier_name': order['cashier_name'] }, context)

for payments in order['statement_ids']: payment = payments[2] self.add_payment(cr, uid, order_id, { 'amount': payment['amount'] or 0.0, 'payment_date': payment['name'],

Page 11: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 11 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.py 'statement_id': payment['statement_id'], 'payment_name': payment.get('note', False), 'journal': payment['journal_id'] }, context=context)

if order['amount_return']: session = self.pool.get('pos.session').browse(cr, uid, order['pos_session_id'], context=context) cash_journal = session.cash_journal_id cash_statement = False if not cash_journal: cash_journal_ids = filter(lambda st: st.journal_id.type=='cash', session.statement_ids) if not len(cash_journal_ids): raise osv.except_osv( _('error!'), _("No cash statement found for this session. Unable to record returned cash.")) cash_journal = cash_journal_ids[0].journal_id self.add_payment(cr, uid, order_id, { 'amount': -order['amount_return'], 'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'), 'payment_name': _('return'), 'journal': cash_journal.id, }, context=context) order_ids.append(order_id) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr) return order_ids

_columns = { 'cashier_name': fields.char('Cashier', size=128), }

inherit_pos_order_for_cashiers()

At the very beginning of the fileWe will import the libraries we need for the module.

import openerpfrom openerp import netsvc, tools, poolerfrom openerp.osv import fields, osvfrom openerp.tools.translate import _import time

This is necessary because we will use native OpenERP and Python functions.

Then we create the Python object

Object is stated like this class pos_cashier(osv.osv):

From now on, we must be very careful with the code indentation. You will notice that thereis no signal of the end of the object.This is why we must pay attention to the code editor we use, it must be able to handlePython for apropriate indentation.If in doubt, do not hesitate to read this page :

FAQ Python and this one :

Cours Python.

Page 12: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 12 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VII-B-3-a - Statements

_name : is the name of the table in OpenERP database. In fact, the table is really named « pos_cashier » in thedatabase.

_name _name = 'pos.cashier'

_order : as you may understand , this is like SQL statement « ORDER BY ». Here, cashiers will be sorted by theirnames

_order _order = 'cashier_name asc'

_columns : these are the fields that will be created in the pos_cashier table.

_columns _columns = {'pos_config_id' : fields.many2one('pos.config', 'Point Of Sale', required=True),'cashier_name': fields.char('Cashier', size=128, required=True),'active': fields.boolean('Active', help="If a cashier is not active, it will not be displayed in POS"),}

pos_config_id fieldHere we record the ID of the Point of Sale of the user. This field relationship with the pos_config table wich containssettings of each Point Of Sale.cashier_name fieldIt is in this field that will record the name of the cashier.active fieldThis field will allow us to enable or disable a cashier (when on leave due to illness or travel, for example).

In OpenERP, the active field is a special field. When active = False, the record isautomatically not visible.

_defaults : these are the default values for records .

_columns _defaults = {'cashier_name' : '','active' : True,'pos_config_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).pos_config.id,}

By default, the active check box in the form will be checked and we automatically retrieve the ID of the Point ofSale of the user. That means, that when we create a new cashier, the Point of Sale of the user will be selected in(pos_config_id) drop-down list in the form. The name field (cashier_name) will be empty._sql_constraints : that are record rules , which is in SQL is called CONSTRAINT.

_sql_constraints _sql_constraints = [('uniq_name', 'unique(cashier_name, pos_config_id)', "A cashier already exists with this name in this Point Of sale. Cashier's name must be unique!"),]

The rules are to be recorded as follows:

('NAME OF THE RULE', 'RULE', "MESSAGE IN CASE OF CONSTRAINT VIOLATION")

Page 13: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 13 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The rule unique(cashier_name, pos_config_id) means that there can be only one cashier with the same name inthe same Point Of Sale._sql_constraints is an array. You can set multiple rules separated by a comma.

The error message is displayed in a message box

VII-B-3-b - Overload pos.order object of Point Of Sale

In addition to creating the pos_cashier object that allows us to manage the cashiers, we need to override the originalpos_order object of the Point Of saleThis module is in the original directory of Point Of Sale. You find it in the file point_of_sale.py around line 479.

openerp_path/addons/point_of_sale/point_of_sale.pyWe need to change the create_from_ui () function and add a cashier_name field in the orders table calledpos_order.

For this, we will create a new object that inherits from the original parent class.

This is why we stated that our module depended of point_of_sale module in the __openerp__.py file.

inherit_pos_order_for_cashiers class inherit_pos_order_for_cashiers(osv.osv): _name='pos.order' _inherit='pos.order'

For our module inherits pos_order module, we will give it the same name

_name _name='pos.order'

And we will add the _inherit statement specifying the name of the parent module

_inherit _inherit='pos.order'

About OpenERP objects inheritance I suggest you to read this page on the publisher'swebsite :

OpenERP Object Inheritance.

Page 14: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 14 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Attention, this is the documentation for the version 6.x, but the instructions are still validfor version 7.x of OpenERP.

We will then just copy the entire original create_from_ui() function in our file.

Once done, we will add a field to the orders.

A little explanationPoint Of Sale works with JavaScript scripts.Orders are stored in the browser (LocalStorage).See : Principe de fonctionnement du Point De Vente.As long as you make an order, it is stored in the browser. When you confirm the order, thecreate_from_ui() function is called. It will send the order to the database of OpenERP.In fact, it will send all valid orders that are stored in the browser.This allows the Point Of Sale to work in offline mode

In the loop for tmp_order in orders:, we add the cashier_name field din self.create() function like below

for tmp_order in orders loop: for tmp_order in orders: order = tmp_order['data'] order_id = self.create(cr, uid, { 'name': order['name'], 'user_id': order['user_id'] or False, 'session_id': order['pos_session_id'], 'lines': order['lines'], 'pos_reference':order['name'], # <---------- COMMA 'cashier_name': order['cashier_name'] # <---------- ADD THE FIELD HERE }, context)

Do not forget to add a comma at the end of the previous line.

The cashier's name will be recorded in order[] array.We can then send the cashier's name in the cashier_name field of the pos_order tableThis is all we add to this function.The last thing to do is to add the cashier_name field to the pos_order table.As in the previous module, simply add the field in the _columns statement

_columns _columns = { 'cashier_name': fields.char('Cashier', size=128), }

We're almost there. It remains the call to the object for OpenERP to take it into account..

inherit_pos_order_for_cashiers()

We achieved pos_cashier Python module.Save the file to the root of the module.

VII-B-4 - cashier_view.xml file

This is the file of the views of pos_cashier module. More exact, there are the views of the cashiers. We will put theviews of the orders in another file.In this file we will create the tree_view, the form_view, menus, search_view, and the action of the « Cashiers » menu.As before, I put the complete code, and we will see that quietly.

Page 15: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 15 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

cashier_view.xml <?xml version="1.0" encoding="utf-8"?><openerp> <data>

<record id="pos_cashier_form" model="ir.ui.view"> <field name="name">pos.cashier.form</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <form string="Cashiers" version="7.0"> <group col="4"> <field name="cashier_name" /> <field name="pos_config_id" widget="selection" eval="ref('pos.config.name')" /> <field name="active"/> </group> </form> </field> </record> <record id="pos_cashier_tree" model="ir.ui.view"> <field name="name">pos.cashier.tree</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <tree string="Cashiers"> <field name="cashier_name"/> <field name="pos_config_id" ref="pos.config.name"/> <field name="active"/> </tree> </field> </record>

<record model="ir.ui.view" id="pos_cashier_search"> <field name="name">pos.cashier.search</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <search string="Point of Sale Cashier"> <field name="cashier_name" /> <filter name="filter_see_all" string="All" domain="['|', ('active', '=',True), ('active', '=',False)]" /> <filter name="filter_see_active" string="Active" domain="[('active', '=',True)]" /> <filter name="filter_see_inactive" string="Inactive" domain="[('active', '=',False)]" /> </search> </field> </record>

<!-- L'action du menu --> <record model="ir.actions.act_window" id="action_pos_cashier"> <field name="name">Cashiers</field> <field name="type">ir.actions.act_window</field> <field name="res_model">pos.cashier</field> <field name="view_type">form</field> <field name="view_mode">tree,form</field> <field name="view_id" ref="pos_cashier_tree"/> <field name="context">{"search_default_filter_see_all":1}</field> <field name="help" type="html"> <p class="oe_view_nocontent_create"> Click here to create a cashier for the Point Of Sale. </p> </field> </record>

<!-- Menu gauche Vendeurs --> <menuitem name="Cashiers" id="menu_point_of_sale_cashiers" parent="point_of_sale.menu_point_root" sequence="16" groups="point_of_sale.group_pos_manager" /> <menuitem id="menu_action_pos_cashier" parent="menu_point_of_sale_cashiers"

Page 16: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 16 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

cashier_view.xml action="action_pos_cashier" /> <!-- # --> </data></openerp>

OpenERP view file is always built this way

Structure of an OpenERP view <?xml version="1.0" encoding="utf-8"?><openerp> <data> <record> <!-- Here the various fields of the view --> </record> <menuitem/> <!-- Etc. -->

</data></openerp>

VII-B-4-a - The form view

pos_cashier_form View <record id="pos_cashier_form" model="ir.ui.view"> <field name="name">pos.cashier.form</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <form string="Cashiers" version="7.0"> <group col="4"> <field name="cashier_name" /> <field name="pos_config_id" widget="selection" eval="ref('pos.config.name')" /> <field name="active"/> </group> </form> </field> </record>

The first line contains the identifier of the view and the model used.id="pos_cashier_form"To make it easier to debug later, I recommend you put the module name, followed by the type of view.model="ir.ui.view"Since this is a « View », the model will always be ir.ui.view (the view is stored in the ir_ui_view table of OpenERP).

The following three fields (mandatory)

<field name="name">pos.cashier.form</field><field name="model">pos.cashier</field><field name="arch" type="xml"> <!-- other objects inside "arch" field --></field>

name="name" fieldThis is the name of the view. Return the identifier of the view, but replace underscores with a dot so that there isno confusion.name="model" fieldThis is the name of the table. Here we use the pos.cashier table.name="arch" field

Page 17: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 17 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

It is inside this tag that will put the view itself.So we will insert a form

<form string="Cashiers" version="7.0"> <group col="4"> <field name="cashier_name" /> <field name="pos_config_id" widget="selection" eval="ref('pos.config.name')" /> <field name="active"/> </group></form>

When you add the string attribute in a field, this is the text that will be displayed (insteadof the name of the field in the database, if that is the case).

So we add the nedded form fields.name="cashier_name"This is the text field that allows you to enter the name of the cashier.name="pos_config_id"This field will display the dropdown list of available Points Of Sale through the widget="selection" attributeWith the « eval » attribute, we ask OpenERP to display the name of the Point Of Salename="active"This is the checkbox that enables / disable a cashier.You will notice that the fields are inside a <group> tag.This tells OpenERP how to display the fields in the form pageHere we specify, with the col attribute, the number of columns to use.Form fields appear like this

Distribution of the fields in a form with <group> tag and col=4 attribute

Here's how the cashiers creation form will be displayed

Page 18: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 18 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Creation form of the cashiers

VII-B-4-b - The Tree view

pos_cashier_tree View <record id="pos_cashier_tree" model="ir.ui.view"> <field name="name">pos.cashier.tree</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <tree string="Cashiers"> <field name="cashier_name"/> <field name="pos_config_id" ref="pos.config.name"/> <field name="active"/> </tree> </field></record>

Instead of <form> tag, we will insert a <tree> tag.These columns appear in the cashiers table.

VII-B-4-c - The search view

This is a special view. It will create search filters that appear by clicking the arrow in the search form in the upperright of the page.

pos_cashier_search View <record model="ir.ui.view" id="pos_cashier_search"> <field name="name">pos.cashier.search</field> <field name="model">pos.cashier</field> <field name="arch" type="xml"> <search string="Point of Sale Cashier"> <field name="cashier_name" /> <filter name="filter_see_all" string="All" domain="['|', ('active', '=',True), ('active', '=',False)]" /> <filter name="filter_see_active" string="Active" domain="[('active', '=',True)]" /> <filter name="filter_see_inactive" string="Inactive" domain="[('active', '=',False)]" /> </search> </field></record>

This time, instead of <tree> tag, we will insert a <search> tag in which we specify a search field and several filters.So we add the following field

<field name="cashier_name" />

We will now add a search filter with the <filter> tag

<filter name="filter_see_all" string="All" domain="['|', ('active', '=',True), ('active', '=',False)]" />

name="filter_see_all"Here we call the filter : filter_see_all.

Page 19: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 19 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

string="All"This is the word that will be displayed in the search formdomain="['|', ('active', '=',True), ('active', '=',False)]"This is the area of research.Here we search for active or non-active cashiers. We want to see all cashiers.The domain attribute is an array in which you put the search parametershere, the « | » (or) operator indicates that at least one condition must be met.

Inactive objects are not visible in tree view nor form view by default. We must create afilter to display inactive cashiers in order to activate them when needed.

The other two filters will display the active or inactive cashiers

Search filters appear when we click on the arrow near the search field

VII-B-4-d - The Cashiers menu

We will now create a Cashiers menu that will appear in Cashiers heading in the Point Of Sale left menu

We could have simply to add only Cashiers menu without adding a Cashiers heading, butit will show you how to create a menu inside a heading.Moreover, you will see that this heading will be visible only by one user group. If in thefuture you decide to add a menu in this heading, only authorized users in the group cansee it..

I present to you the creation of the menu before the creation of the action for a betterunderstanding, but in fact, the code will require that the menu is written after the action,

Page 20: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 20 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

because as referring to the action, if the menu is written before, Python will return the erroraction_pos_cashier does not exist.

The « Cashiers » heading

Cashiers heading <menuitem name="Cashiers" id="menu_point_of_sale_cashiers" parent="point_of_sale.menu_point_root" sequence="16" groups="point_of_sale.group_pos_manager" />

A menu is written in <menuitem/> tag.name="Cashiers"This is the name of the heading.idAs usual, it specifies an identifier for the heading.parentThis is what allows us to insert the item in an existing menu.Here we insert our menu item in the Point of Sale menu, we must retrieve the identifier of the menu in the original fileof the Point Of Sale. As this menu does not belong to our module, we refer to it by using the usual dot syntax.sequenceThis is the number that is used to sort the heading. The lower the number, the higher the heading is.groupsWe want to restrict access to this menu for POS/Manager user group.

We use here also dot syntax to refer to the group. We could allow multiple groups, by adding them separated bya comma.

A menu which has no action attribute becomes a heading

The « Cashiers » menu

Cashiers menu <menuitem id="menu_action_pos_cashier" parent="menu_point_of_sale_cashiers" action="action_pos_cashier" />

This time, we add the action attribute that refers to the action that we will define later.You will also notice that the parent menu is the heading we created earlier. Clearly, the menu will be within thisheading.The menu appears in the Menu tab of the POS/Manager group (from Configuration/Groups menu) as shown inthe image below.

Page 21: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 21 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The menu appears in POS/Manager group

Here we can see the sorting of the menus according to their sequence.

VII-B-4-e - The action of the menu

When we click on the Cashiers menu, the following action will be executed.

action_pos_cashier <record model="ir.actions.act_window" id="action_pos_cashier"> <field name="name">Cashiers</field> <field name="type">ir.actions.act_window</field> <field name="res_model">pos.cashier</field> <field name="view_type">form</field> <field name="view_mode">tree,form</field> <field name="view_id" ref="pos_cashier_tree"/> <field name="context">{"search_default_filter_see_all":1}</field> <field name="help" type="html"> <p class="oe_view_nocontent_create">

Page 22: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 22 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

action_pos_cashier Click here to create a cashier for the Point Of Sale. </p> </field></record>

When it comes to action, then we use ir.actions.act_window model (the action will be recorded in the ir_act_windowtable of OpenERP).name="type"This is the type of the actionname="res_model"This is the name of the table usedname="view_type"This is the type of the viewname="view_mode"This is the type of available views. Here we will allow form view and tree view. There is another type of view, theKaban view.name="view_id"This is the ID of the view that this action will apply. Here, the tree view.name="context"The context of the view that apply to the tree view. Here, a default filter is applied, the filter_see_all filter we createdearlier. So we will see all cashiers.name="help" type="html"This field will be used to display the content in HTML format if the table is empty.Using oe_view_nocontent_create special class, a text will be displayed with an arrow to the Create button.

If no cashier has been created in the POS, the above text is displayed

In the Point Of Sale, when we will click on the « Cashiers » menu, the tee view will appearwith the « All » filter that will display all cashiers. A « Create » button will be displayedon top of the table.

Page 23: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 23 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The Cashiers menu in the POS heading

VII-B-5 - The order_cashier_view.xml file

We will now create the view for orders to the cashier's name appears.

order_cashier_view.xml <?xml version="1.0" encoding="utf-8"?><openerp> <data> <!-- Vue formulaire --> <record model="ir.ui.view" id="view_pos_cashier_form"> <field name="model">pos.order</field> <field name="name">view.inherit.pos.order.form</field> <field name="view_type">form</field> <field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> <field name="arch" type="xml"> <field name="partner_id" position="after"> <field name="cashier_name"/> </field> </field> </record>

<!-- Vue Tree --> <record model="ir.ui.view" id="view_pos_cashier_tree"> <field name="model">pos.order</field> <field name="name">view.inherit.pos.order.tree</field> <field name="view_type">tree</field> <field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/> <field name="arch" type="xml"> <field name="user_id" position="replace"> <field name="cashier_name"/>

Page 24: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 24 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

order_cashier_view.xml </field> </field> </record> </data></openerp>

As in the previous file, we will create a « form » view and a « tree » view.Warning !If you remember, the inherit_pos_order_for_cashiers object inherits from the pos_order object, the original objectof the Point Of Sale.We must therefore take the header of the original view, change the name field and add the inherit_id field.

inherit_id <field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/>

You will notice that we put the identifier of the original view, and do not forget to precede with the name of the originalmodule (dot syntax), since this view does not belong to our module, but to its parent.

VII-B-5-a - The form view

Vue formulaire <record model="ir.ui.view" id="view_pos_cashier_form"> <field name="model">pos.order</field> <field name="name">view.inherit.pos.order.form</field> <field name="view_type">form</field> <field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> <field name="arch" type="xml"> <field name="partner_id" position="after"> <field name="cashier_name"/> </field> </field></record>

We will insert the cashier_name field in the form.For this, we use a field that already exists and add the position attribute.

Availble positions

• after : the field will be inserted after the one that contains the position attribute ;• before : the field will be inserted before the one that contains the position attribute;• replace : replace the field that contains the position attribute ;

In this case, the cashier_name field will be placed after partner_id field (the client) in the form

Page 25: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 25 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The cashier_name field in the order form

VII-B-5-b - The Tree View

Tree view <record model="ir.ui.view" id="view_pos_cashier_tree"> <field name="model">pos.order</field> <field name="name">view.inherit.pos.order.tree</field> <field name="view_type">tree</field> <field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/> <field name="arch" type="xml"> <field name="user_id" position="replace"> <field name="cashier_name"/> </field> </field></record>

In the tree view, we will replace the user_id field (User of the Point Of Sale) by cashier_name field.

Page 26: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 26 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Remember that we create this module for several cashiers can place orders without havingto log in each time the cashier changes. This is why we do not want the user name ofthe Point Of Sale, which will be the same for all cashiers, appears in the orders view.However, reveal the name of the cashier will allow immediately the manager to see wichcashier has made such sale.

The cashier_name field in tree view of the orders

VII-C - Security Settings of the module

As we have defined the menu access to a particular group, we will now apply some security policies on the moduleto restrict access and set a rule on the records.

VII-C-1 - Access Rights

We will create a special file in the security directory of the module.

/opt/modules-openerp/pos_cashier/securityThe file that defines the access rights to the database records is a CSV file.It has always the same name : ir.model.access.csv.

The first line contains the names of the fields separated by a comma.

CSV fields id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink

idA unique identifier for the access rulenameThe name of the rule. It will appear in the configuration pages of OpenERP.model_id:idThe table to which this rule applies. The table name should always be prefixed with model_.group_id:idThe user group to which this rule applies.perm_read

Page 27: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 27 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Permission to read the data (1 or 0).perm_writePermission to modify the data (1 or 0).perm_createPermission to create data (1 or 0).perm_unlinkPermission to delete the data (1 or 0).We will now add two additional lines.

A line for the rights for the users of the POS (POS/User group) with read rights only.And a line for the rights of the managers of the POS (POS/Manager group) with all rights.

CSV fields id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkaccess_pos_cashier_u,pos.cashier user,model_pos_cashier,point_of_sale.group_pos_user,1,0,0,0access_pos_cashier_m,pos.cashier manager,model_pos_cashier,point_of_sale.group_pos_manager,1,1,1,1

About POS/User group

• id = access_pos_cashier_u• name = pos.cashier user• model_id:id = model_pos_cashier• group_id:id = point_of_sale.group_pos_user• perm_read = 1• perm_write = 0• perm_create = 0• perm_unlink = 0

About POS/Manager group

• id = access_pos_cashier_m• name = pos.cashier manager• model_id:id = model_pos_cashier• group_id:id = point_of_sale.group_pos_manager• perm_read = 1• perm_write = 1• perm_create = 1• perm_unlink = 1

When you go to the Configuration/Security/Access controls List menu of OpenERP you will see these two linesin the tree view.

Page 28: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 28 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier access rights

VII-C-2 - Record rules

Now let's define a record rule to ensure that the manager of a Point Of Sale can create a cashier for its Point OfSale only.

When creating a cashier, if the manager selects a Point Of Sale in the list which does not belong to him, an errormessage will be displayed.

The administrator of OpenERP (Admin user) can create cashiers in any Point Of Sale.The administrator has full rights to the database. It can therefore configure any application.Security rules do not apply to him.

To do this, still in the security directory of the module, we will create an XML file that we'll callpos_cashier_security.xml.

pos_cashier_security.xml <?xml version="1.0" encoding="utf-8"?><openerp> <data noupdate="0"> <record id="rule_pos_cashier" model="ir.rule"> <field name="name">Point Of Sale Cashiers</field> <field name="model_id" ref="model_pos_cashier" /> <field name="global" eval="True" /> <field name="domain_force">[('pos_config_id', '=', user.pos_config.id)]</field> </record> </data></openerp>

Here, as it comes to security rules, the model will be always ir.rule (the rule will be recorded in the ir_rule table ofOpenERP).As in previous XML file we will put an identifier, then we will add some fields.name="model_id"This is the name of the affected table (prefixed with model_).name="global" eval="True"If this rule is global, it applies to everyone. If it is not global, it must then specify the user groups to which it applies.name="domain_force"This is the rule itself,

Page 29: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 29 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

domain_force [('pos_config_id', '=', user.pos_config.id)]

Here, a recording can be done only if the selected Point Of Sale belongs to the user.

Here is how this rule will appear in the Configuration/Security/Records rules menu of OpenERP

Record rule for pos_cashier module (tree view)

If you click on this rule, it appears in the form below.

Record rule for pos_cashier module (form view)

Page 30: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 30 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VII-D - Add an icon to the module

For your module displays an icon in the Configuration/Modules menu of OpenERP, we'll just create a PNG imageof 64 pixels by 64 pixels we call icon.png.

This icon is put in the img subdirectory of the static directory of the module.

/opt/modules-openerp/pos_cashier/static/src/imgAt the loading of OpenERP, and at the loading of the modules, the application looks for icon.png file into this directoryto display next to the name of the module.

Icon is displayed near the module's name

VII-E - End of the basic OpenERP module

We finished the «basic» module for OpenERPAll files that we have created are added to the data[] array in the __ openerp__.py fileSee here.We still can not install our module, because as we stated other files in the __ openerp__.py file, if they are notcreated, OpenERP will return an error.

We'll have to wait a little…

VIII - Creation of the Web module for the Point Of Sale

Now that we have created the module to create cashiers in the Point Of Sale, we will create the necessary files thatwill allow to use the cashiers in the Point Of Sale.

I remind you that the Point Of Sale is not, strictly speaking, integrated into OpenERP. This is a completely differentweb interface.

Page 31: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 31 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The original POS GUI

When we are finished, you will see the cashiers list at the bottom left of the Point Of Sale, under the keypad, asshown in the image below.

The new POS GUI with cashiers dropdown list

VIII-A - The pos_cashier.js file

Well, here is a little hot. I put you though all the script then I will explain to you the different functions.

This file is created in the js directory of the module.

/opt/modules-openerp/pos_cashier/static/src/jspos_cashier.js function openerp_pos_cashier(instance, module){ //module is instance.point_of_sale var module = instance.point_of_sale; var QWeb = instance.web.qweb; _t = instance.web._t;

globalCashier = null;

module.CashierWidget = module.PosWidget.include({

Page 32: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 32 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js template: 'PosWidget',

init: function(parent, options) { this._super(parent); var self = this; },

// recuperation de l'ID du POS get_cur_pos_config_id: function(){ var self = this; var config = self.pos.get('pos_config'); var config_id = null; if(config){ config_id = config.id; return config_id; } return ''; },

fetch: function(model, fields, domain, ctx){ return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all() },

cashier_change: function(name){ globalCashier = name;

$('#pay-screen-cashier-name').html(name); console.log('cashier_change : ' + name); if(name != ''){ $('.gotopay-button').removeAttr('disabled'); } else{ $('.gotopay-button').attr('disabled', 'disabled'); } },

get_cashiers: function(config_id){ var self = this; var cashier_list = [];

var loaded = self.fetch('pos.cashier',['cashier_name'],[['pos_config_id','=', config_id], ['active', '=','true']]) .then(function(cashiers){ for(var i = 0, len = cashiers.length; i < len; i++){ cashier_list.push(cashiers[i].cashier_name); }

if(cashier_list.length > 0){ for(var i = 0, len = cashier_list.length; i < len; i++){ var content = self.$('#cashier-select').html(); var new_option = '<option value="' + cashier_list[i] + '">' + cashier_list[i] + '</option>\n'; self.$('#cashier-select').html(content + new_option); }

self.$('#AlertNoCashier').css('display', 'none'); self.$('#cashier-select').selectedIndex = 0; globalCashier = cashier_list[0]; self.cashier_change(globalCashier);

} else{

// if there are no cashier self.$('#AlertNoCashier').css('display', 'block'); self.$('.gotopay-button').attr('disabled', 'disabled'); } });

Page 33: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 33 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js },

renderElement: function() { var self = this; this._super();

self.$('#cashier-select').change(function(){ var name = this.value; self.cashier_change(name); }); },

build_widgets: function() { var self = this;

// -------- Screens ---------

this.product_screen = new module.ProductScreenWidget(this,{}); this.product_screen.appendTo($('#rightpane'));

this.receipt_screen = new module.ReceiptScreenWidget(this, {}); this.receipt_screen.appendTo($('#rightpane'));

this.payment_screen = new module.PaymentScreenWidget(this, {}); this.payment_screen.appendTo($('#rightpane'));

this.welcome_screen = new module.WelcomeScreenWidget(this,{}); this.welcome_screen.appendTo($('#rightpane'));

this.client_payment_screen = new module.ClientPaymentScreenWidget(this, {}); this.client_payment_screen.appendTo($('#rightpane'));

this.scale_invite_screen = new module.ScaleInviteScreenWidget(this, {}); this.scale_invite_screen.appendTo($('#rightpane'));

this.scale_screen = new module.ScaleScreenWidget(this,{}); this.scale_screen.appendTo($('#rightpane'));

// -------- Popups ---------

this.help_popup = new module.HelpPopupWidget(this, {}); this.help_popup.appendTo($('.point-of-sale'));

this.error_popup = new module.ErrorPopupWidget(this, {}); this.error_popup.appendTo($('.point-of-sale'));

this.error_product_popup = new module.ProductErrorPopupWidget(this, {}); this.error_product_popup.appendTo($('.point-of-sale'));

this.error_session_popup = new module.ErrorSessionPopupWidget(this, {}); this.error_session_popup.appendTo($('.point-of-sale'));

this.choose_receipt_popup = new module.ChooseReceiptPopupWidget(this, {}); this.choose_receipt_popup.appendTo($('.point-of-sale'));

this.error_negative_price_popup = new module.ErrorNegativePricePopupWidget(this, {}); this.error_negative_price_popup.appendTo($('.point-of-sale'));

// -------- Misc ---------

this.notification = new module.SynchNotificationWidget(this,{}); this.notification.appendTo(this.$('#rightheader'));

this.username = new module.UsernameWidget(this,{}); this.username.replace(this.$('.placeholder-UsernameWidget'));

this.action_bar = new module.ActionBarWidget(this); this.action_bar.appendTo($(".point-of-sale #rightpane"));

Page 34: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 34 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js this.left_action_bar = new module.ActionBarWidget(this); this.left_action_bar.appendTo($(".point-of-sale #leftpane"));

this.gotopay = new module.GoToPayWidget(this, {}); this.gotopay.replace($('#placeholder-GoToPayWidget'));

this.paypad = new module.PaypadWidget(this, {}); this.paypad.replace($('#placeholder-PaypadWidget'));

this.numpad = new module.NumpadWidget(this); this.numpad.replace($('#placeholder-NumpadWidget'));

this.order_widget = new module.OrderWidget(this, {}); this.order_widget.replace($('#placeholder-OrderWidget'));

this.onscreen_keyboard = new module.OnscreenKeyboardWidget(this, { 'keyboard_model': 'simple' }); this.onscreen_keyboard.appendTo($(".point-of-sale #content"));

this.close_button = new module.HeaderButtonWidget(this,{ label: _t('Close'), action: function(){ self.try_close(); }, }); this.close_button.appendTo(this.$('#rightheader'));

this.client_button = new module.HeaderButtonWidget(this,{ label: _t('Self-Checkout'), action: function(){ self.screen_selector.set_user_mode('client'); }, }); this.client_button.appendTo(this.$('#rightheader'));

// -------- Screen Selector ---------

this.screen_selector = new module.ScreenSelector({ pos: this.pos, screen_set:{ 'products': this.product_screen, 'payment' : this.payment_screen, 'client_payment' : this.client_payment_screen, 'scale_invite' : this.scale_invite_screen, 'scale': this.scale_screen, 'receipt' : this.receipt_screen, 'welcome' : this.welcome_screen, }, popup_set:{ 'help': this.help_popup, 'error': this.error_popup, 'error-product': this.error_product_popup, 'error-session': this.error_session_popup, 'error-negative-price': this.error_negative_price_popup, 'choose-receipt': this.choose_receipt_popup, }, default_client_screen: 'welcome', default_cashier_screen: 'products', default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier', });

if(this.pos.debug){ this.debug_widget = new module.DebugWidget(this); this.debug_widget.appendTo(this.$('#content')); } },

});

module.CashierPayScreenWidget = module.PaymentScreenWidget.include({ template: 'PaymentScreenWidget',

show: function(){

Page 35: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 35 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js this._super(); var self = this; this.$('#pay-screen-cashier-name').html(globalCashier); this.$('#ticket-screen-cashier-name').html(globalCashier); this.pos.get('selectedOrder').set_cashier_name(globalCashier);

this.paypad = new module.PaypadWidget(this, {}); this.paypad.replace($('#placeholder-PaypadWidget')); },

});

module.CashierReceiptScreenWidget = module.ReceiptScreenWidget.include({

refresh: function() { this._super(); $('.pos-receipt-container', this.$el).html(QWeb.render('PosTicket',{widget:this}));

if(globalCashier != ''){ this.$('#ticket-screen-cashier-name').html(globalCashier); } }, });

module.GoToPayWidget = module.PosBaseWidget.extend({ template: 'GoToPayWidget', init: function(parent, options) { this._super(parent); },

renderElement: function() { var self = this; this._super();

var button = new module.GoToPayButtonWidget(self); button.appendTo(self.$el); }, });

module.GoToPayButtonWidget = module.PosBaseWidget.extend({ template: 'GoToPayButtonWidget', init: function(parent, options) { this._super(parent); },

renderElement: function() { var self = this; this._super();

this.$el.click(function(){ self.pos_widget.screen_selector.set_current_screen('payment'); }); }, });

module.Order = Backbone.Model.extend({ initialize: function(attributes){ Backbone.Model.prototype.initialize.apply(this, arguments); this.set({ creationDate: new Date(), orderLines: new module.OrderlineCollection(), paymentLines: new module.PaymentlineCollection(), name: "Order " + this.generateUniqueId(), client: null, cashier_name: null, }); this.pos = attributes.pos; this.selected_orderline = undefined; this.screen_data = {}; // see ScreenSelector

Page 36: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 36 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js this.receipt_type = 'receipt'; // 'receipt' || 'invoice' return this; }, generateUniqueId: function() { return new Date().getTime(); }, addProduct: function(product, options){ options = options || {}; var attr = product.toJSON(); attr.pos = this.pos; attr.order = this; var line = new module.Orderline({}, {pos: this.pos, order: this, product: product});

if(options.quantity !== undefined){ line.set_quantity(options.quantity); } if(options.price !== undefined){ line.set_unit_price(options.price); }

var last_orderline = this.getLastOrderline(); if( last_orderline && last_orderline.can_be_merged_with(line) && options.merge !== false){ last_orderline.merge(line); }else{ this.get('orderLines').add(line); } this.selectLine(this.getLastOrderline()); }, removeOrderline: function( line ){ this.get('orderLines').remove(line); this.selectLine(this.getLastOrderline()); }, getLastOrderline: function(){ return this.get('orderLines').at(this.get('orderLines').length -1); }, addPaymentLine: function(cashRegister) { var paymentLines = this.get('paymentLines'); var newPaymentline = new module.Paymentline({},{cashRegister:cashRegister}); if(cashRegister.get('journal').type !== 'cash'){ newPaymentline.set_amount( this.getDueLeft() ); } paymentLines.add(newPaymentline); }, getName: function() { return this.get('name'); }, getSubtotal : function(){ return (this.get('orderLines')).reduce((function(sum, orderLine){ return sum + orderLine.get_display_price(); }), 0); }, getTotalTaxIncluded: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_price_with_tax(); }), 0); }, getDiscountTotal: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + (orderLine.get_unit_price() * (orderLine.get_discount()/100) * orderLine.get_quantity()); }), 0); }, getTotalTaxExcluded: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_price_without_tax(); }), 0); }, getTax: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_tax();

Page 37: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 37 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js }), 0); }, getPaidTotal: function() { return (this.get('paymentLines')).reduce((function(sum, paymentLine) { return sum + paymentLine.get_amount(); }), 0); }, getChange: function() { return this.getPaidTotal() - this.getTotalTaxIncluded(); }, getDueLeft: function() { return this.getTotalTaxIncluded() - this.getPaidTotal(); }, set_cashier_name: function(name){ this.set('cashier_name', name); }, // sets the type of receipt 'receipt'(default) or 'invoice' set_receipt_type: function(type){ this.receipt_type = type; }, get_receipt_type: function(){ return this.receipt_type; }, // the client related to the current order. set_client: function(client){ this.set('client',client); }, get_client: function(){ return this.get('client'); }, get_client_name: function(){ var client = this.get('client'); return client ? client.name : ""; }, // the order also stores the screen status, as the PoS supports // different active screens per order. This method is used to // store the screen status. set_screen_data: function(key,value){ if(arguments.length === 2){ this.screen_data[key] = value; }else if(arguments.length === 1){ for(key in arguments[0]){ this.screen_data[key] = arguments[0][key]; } } }, //see set_screen_data get_screen_data: function(key){ return this.screen_data[key]; }, // exports a JSON for receipt printing export_for_printing: function(){ var orderlines = []; this.get('orderLines').each(function(orderline){ orderlines.push(orderline.export_for_printing()); });

var paymentlines = []; this.get('paymentLines').each(function(paymentline){ paymentlines.push(paymentline.export_for_printing()); }); var client = this.get('client'); var cashier = this.pos.get('cashier') || this.pos.get('user'); var company = this.pos.get('company'); var shop = this.pos.get('shop'); var date = new Date();

return { orderlines: orderlines, paymentlines: paymentlines,

Page 38: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 38 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js subtotal: this.getSubtotal(), total_with_tax: this.getTotalTaxIncluded(), total_without_tax: this.getTotalTaxExcluded(), total_tax: this.getTax(), total_paid: this.getPaidTotal(), total_discount: this.getDiscountTotal(), change: this.getChange(), name : this.getName(), client: client ? client.name : null , invoice_id: null, //TODO cashier: cashier ? cashier.name : null, date: { year: date.getFullYear(), month: date.getMonth(), date: date.getDate(), // day of the month day: date.getDay(), // day of the week hour: date.getHours(), minute: date.getMinutes() }, company:{ email: company.email, website: company.website, company_registry: company.company_registry, contact_address: company.contact_address, vat: company.vat, name: company.name, phone: company.phone, }, shop:{ name: shop.name, }, currency: this.pos.get('currency'), }; }, exportAsJSON: function() { var orderLines, paymentLines; orderLines = []; (this.get('orderLines')).each(_.bind( function(item) { return orderLines.push([0, 0, item.export_as_JSON()]); }, this)); paymentLines = []; (this.get('paymentLines')).each(_.bind( function(item) { return paymentLines.push([0, 0, item.export_as_JSON()]); }, this)); return { name: this.getName(), amount_paid: this.getPaidTotal(), amount_total: this.getTotalTaxIncluded(), amount_tax: this.getTax(), amount_return: this.getChange(), lines: orderLines, statement_ids: paymentLines, pos_session_id: this.pos.get('pos_session').id, partner_id: this.pos.get('client') ? this.pos.get('client').id : undefined, user_id: this.pos.get('cashier') ? this.pos.get('cashier').id : this.pos.get('user').id, cashier_name: this.pos.get('selectedOrder').get('cashier_name'), }; }, getSelectedLine: function(){ return this.selected_orderline; }, selectLine: function(line){ if(line){ if(line !== this.selected_orderline){ if(this.selected_orderline){ this.selected_orderline.set_selected(false); } this.selected_orderline = line; this.selected_orderline.set_selected(true); }

Page 39: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 39 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.js }else{ this.selected_orderline = undefined; } }, });

};

openerp.point_of_sale = function(instance) { instance.point_of_sale = {};

var module = instance.point_of_sale;

openerp_pos_db(instance,module); // import db.js openerp_pos_models(instance,module); // import pos_models.js openerp_pos_basewidget(instance,module); // import pos_basewidget.js openerp_pos_keyboard(instance,module); // import pos_keyboard_widget.js openerp_pos_scrollbar(instance,module); // import pos_scrollbar_widget.js openerp_pos_screens(instance,module); // import pos_screens.js openerp_pos_widgets(instance,module); // import pos_widgets.js openerp_pos_devices(instance,module); // import pos_devices.js

// cashiers openerp_pos_cashier(instance,module); // import openerp_pos_cashier

instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.PosWidget');};

There are two main functions in this file.openerp_pos_cashier() functionIt will allow us to add the necessary functions to the module and it will also allow us to modify some original features.openerp.point_of_sale() functionWe will change that for our module is taken into account in the Point Of Sale.

VIII-A-1 - openerp_pos_cashier() function

This function is declared as follows:

openerp_pos_cashier()function declaration function openerp_pos_cashier(instance, module){ }

This function will be called later in the function that creates the Point Of Sale.

I'm not going to be able to explain all, because I'm not an OpenERP Guru. I proceeded bystudying the scripts of OpenERP modules magnifying glass to try to deduce how to do it.In fact, if at any time you find an error or an approximation in my explanations, or even inthe code, do not hesitate to contact me to let me know.

Then we will instantiate some objects:

var module = instance.point_of_sale;var QWeb = instance.web.qweb;_t = instance.web._t;

The module will be an instance of the Point Of Sale.QWeb is the template rendering engine. I invite you to read the documentation on the OpenERP website:

Documentation QWeb

Page 40: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 40 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

_t is an instance of _t (?!??). To be honest, I do not know what it is. When I created the module for the first time,this instance does not exist in OpenERP version I had. It was been added later. It is used for the action of the closebutton is at the top of the Point Of Sale. As you will see later, we import the close button of Point Of Sale, this instanceis required.We then declare a global variable. We will use it further to store the name of the selected cashier.

Global variable globalCashier = null;

For a variable to be global, it is stated without the var keyword.A local variable is declared like this: var myvar = 'something';

VIII-A-2 - The CashierWidget module

Now we will override the original PosWidget module.This is in fact the module that contains the entire Point Of Sale.We are not really going to « overload » the module, we will include additional functions when possible, with theinclude() function.

module.CashierWidget module.CashierWidget = module.PosWidget.include({ template: 'PosWidget',

// recuperation de l'ID du POS get_cur_pos_config_id: function(){ var self = this; var config = self.pos.get('pos_config'); var config_id = null; if(config){ config_id = config.id; return config_id; } return ''; },

fetch: function(model, fields, domain, ctx){ return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all() },

cashier_change: function(name){ globalCashier = name;

$('#pay-screen-cashier-name').html(name); //console.log('cashier_change : ' + name); if(name != ''){ $('.gotopay-button').removeAttr('disabled'); } else{ $('.gotopay-button').attr('disabled', 'disabled'); } },

get_cashiers: function(config_id){ var self = this; var cashier_list = [];

var loaded = self.fetch('pos.cashier',['cashier_name'],[['pos_config_id','=', config_id], ['active', '=','true']]) .then(function(cashiers){ for(var i = 0, len = cashiers.length; i < len; i++){ cashier_list.push(cashiers[i].cashier_name); }

Page 41: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 41 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.CashierWidget

if(cashier_list.length > 0){ for(var i = 0, len = cashier_list.length; i < len; i++){ var content = self.$('#cashier-select').html(); var new_option = '<option value="' + cashier_list[i] + '">' + cashier_list[i] + '</option>\n'; self.$('#cashier-select').html(content + new_option); }

self.$('#AlertNoCashier').css('display', 'none'); self.$('#cashier-select').selectedIndex = 0; globalCashier = cashier_list[0]; self.cashier_change(globalCashier);

} else{

// if there are no cashier self.$('#AlertNoCashier').css('display', 'block'); self.$('.gotopay-button').attr('disabled', 'disabled'); } }); },

renderElement: function() { var self = this; this._super();

self.$('#cashier-select').change(function(){ var name = this.value; self.cashier_change(name); }); },

build_widgets: function() { var self = this;

// -------- Screens ---------

this.product_screen = new module.ProductScreenWidget(this,{}); this.product_screen.appendTo($('#rightpane'));

this.receipt_screen = new module.ReceiptScreenWidget(this, {}); this.receipt_screen.appendTo($('#rightpane'));

this.payment_screen = new module.PaymentScreenWidget(this, {}); this.payment_screen.appendTo($('#rightpane'));

this.welcome_screen = new module.WelcomeScreenWidget(this,{}); this.welcome_screen.appendTo($('#rightpane'));

this.client_payment_screen = new module.ClientPaymentScreenWidget(this, {}); this.client_payment_screen.appendTo($('#rightpane'));

this.scale_invite_screen = new module.ScaleInviteScreenWidget(this, {}); this.scale_invite_screen.appendTo($('#rightpane'));

this.scale_screen = new module.ScaleScreenWidget(this,{}); this.scale_screen.appendTo($('#rightpane'));

// -------- Popups ---------

this.help_popup = new module.HelpPopupWidget(this, {}); this.help_popup.appendTo($('.point-of-sale'));

this.error_popup = new module.ErrorPopupWidget(this, {}); this.error_popup.appendTo($('.point-of-sale'));

this.error_product_popup = new module.ProductErrorPopupWidget(this, {});

Page 42: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 42 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.CashierWidget this.error_product_popup.appendTo($('.point-of-sale'));

this.error_session_popup = new module.ErrorSessionPopupWidget(this, {}); this.error_session_popup.appendTo($('.point-of-sale'));

this.choose_receipt_popup = new module.ChooseReceiptPopupWidget(this, {}); this.choose_receipt_popup.appendTo($('.point-of-sale'));

this.error_negative_price_popup = new module.ErrorNegativePricePopupWidget(this, {}); this.error_negative_price_popup.appendTo($('.point-of-sale'));

// -------- Misc ---------

this.notification = new module.SynchNotificationWidget(this,{}); this.notification.appendTo(this.$('#rightheader'));

this.username = new module.UsernameWidget(this,{}); this.username.replace(this.$('.placeholder-UsernameWidget'));

this.action_bar = new module.ActionBarWidget(this); this.action_bar.appendTo($(".point-of-sale #rightpane"));

this.left_action_bar = new module.ActionBarWidget(this); this.left_action_bar.appendTo($(".point-of-sale #leftpane"));

this.gotopay = new module.GoToPayWidget(this, {}); this.gotopay.replace($('#placeholder-GoToPayWidget'));

this.paypad = new module.PaypadWidget(this, {}); this.paypad.replace($('#placeholder-PaypadWidget'));

this.numpad = new module.NumpadWidget(this); this.numpad.replace($('#placeholder-NumpadWidget'));

this.order_widget = new module.OrderWidget(this, {}); this.order_widget.replace($('#placeholder-OrderWidget'));

this.onscreen_keyboard = new module.OnscreenKeyboardWidget(this, { 'keyboard_model': 'simple' }); this.onscreen_keyboard.appendTo($(".point-of-sale #content"));

this.close_button = new module.HeaderButtonWidget(this,{ label: _t('Close'), action: function(){ self.try_close(); }, }); this.close_button.appendTo(this.$('#rightheader'));

this.client_button = new module.HeaderButtonWidget(this,{ label: _t('Self-Checkout'), action: function(){ self.screen_selector.set_user_mode('client'); }, }); this.client_button.appendTo(this.$('#rightheader'));

// -------- Screen Selector ---------

this.screen_selector = new module.ScreenSelector({ pos: this.pos, screen_set:{ 'products': this.product_screen, 'payment' : this.payment_screen, 'client_payment' : this.client_payment_screen, 'scale_invite' : this.scale_invite_screen, 'scale': this.scale_screen, 'receipt' : this.receipt_screen, 'welcome' : this.welcome_screen, }, popup_set:{ 'help': this.help_popup, 'error': this.error_popup,

Page 43: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 43 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.CashierWidget 'error-product': this.error_product_popup, 'error-session': this.error_session_popup, 'error-negative-price': this.error_negative_price_popup, 'choose-receipt': this.choose_receipt_popup, }, default_client_screen: 'welcome', default_cashier_screen: 'products', default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier', });

if(this.pos.debug){ this.debug_widget = new module.DebugWidget(this); this.debug_widget.appendTo(this.$('#content')); } },

});

You will notice that the statements or functions within the module are separated by acomma.

First, we declare the template that will be used for the module.

template template: 'PosWidget',

This means that when the module is loaded, it is also made to the PosWidget view, which we will study further.We will then create a function that will allow to retrieve the ID of the Point Of Sale and then get cashiers who belongto this Point Of Sale.

get_cur_pos_config_id() // recuperation de l'ID du POS get_cur_pos_config_id: function(){ var self = this; var config = self.pos.get('pos_config'); var config_id = null; if(config){ config_id = config.id; return config_id; } return ''; },

This function uses the pos.get() function that was defined in the original module.When a function belongs to the original Point Of Sale Module, it is writen like this : pos.the_function(). If a recordis found, it returns the ID of the POS currently used.

We will then add a function that I grabbed from another module. This function allows to make a query to a table ofthe database.

fetch() fetch: function(model, fields, domain, ctx){ return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all()},

With the correct settings, you can get the data from the table. We will see this later.

Page 44: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 44 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

We will then create a function that will be called from the POS interface (when onchange() event of the cashiers list,for example).

cashier_change() cashier_change: function(name){ globalCashier = name;

$('#pay-screen-cashier-name').html(name); //console.log('cashier_change : ' + name); if(name != ''){ $('.gotopay-button').removeAttr('disabled'); } else{ $('.gotopay-button').attr('disabled', 'disabled'); }},

I left you for a special comment://console.log('cashier_change : ' + name);If you use Firebug extension, which is very effective for JavaScript debugging, and ifyou uncomment this line, you will see the message in the Firebug console each time thecashier_change() function will be called .When you build your personal unit, do not hesitate to use this trick in your JavaScripts,in particular to verify that the functions are executed and your variables do contain thevalues you expect.Obviously, you do not forget to remove your console.log() commands or comment thembefore going into production.Finally, the last little tip, if you use console.log() by passing an object, you will not forgetto use this: console.log(JSON.stringify (myObject));

When the function is called, the name of the cashier will be stored in the globalCashier global variable.Then the cashier's name will also be sent to <div id="pay-screen-cashier-name"></div> tag which appears on thepayment page.Also, if the cashier's name is empty (so there is no cashier in the Point Of Sale), it will disable the Pay button of thePoint Of Sale. No sale must be performed.

A little explanation !The left side of the Point Of Sale normally displays the keypad and some payment buttons.There can be as many buttons as you set up payment methods for the Point Of Sale.To prohibit the sale if no cashier has been created in the Point Of Sale, I moved thepayment buttons on the payment page, and instead I put a Pay button.It is easier to disable one button that is « hard coded » in the view, rather than make afunction that disables many payment buttons that are dynamically generated.

Page 45: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 45 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The standart payment interfacewith several payment buttons

The standart payment interface withseveral payment buttons

The payment interface with only one Paybutton + the dropdown list of the cashiers

The payment interface with only one Pay button+ the dropdown list of the cashiers

We will now add the get_cashiers() function that will retrieve the cashiers from the database and build options ofthe cashiers drop down list.

get_cashiers() get_cashiers: function(config_id){ var self = this; var cashier_list = [];

var loaded = self.fetch('pos.cashier',['cashier_name'],[['pos_config_id','=', config_id], ['active', '=','true']])

Page 46: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 46 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

get_cashiers() .then(function(cashiers){ for(var i = 0, len = cashiers.length; i < len; i++){ cashier_list.push(cashiers[i].cashier_name); }

if(cashier_list.length > 0){ for(var i = 0, len = cashier_list.length; i < len; i++){ var content = self.$('#cashier-select').html(); var new_option = '<option value="' + cashier_list[i] + '">' + cashier_list[i] + '</option>\n'; self.$('#cashier-select').html(content + new_option); }

self.$('#AlertNoCashier').css('display', 'none'); self.$('#cashier-select').selectedIndex = 0; globalCashier = cashier_list[0]; self.cashier_change(globalCashier);

} else{

// if there are no cashier self.$('#AlertNoCashier').css('display', 'block'); self.$('.gotopay-button').attr('disabled', 'disabled'); } });},

We first create an empty array

var cashier_list = [];

Then we make a query with the fetch() function that we seen earlier.

var loaded = self.fetch('pos.cashier',['cashier_name'],[['pos_config_id','=', config_id], ['active', '=','true']])

Here, we will perform a query (SELECT) on pos_cashier table, we will retrieve the field cashier_name of the cashierswho belong to the Point Of Sale which pos_config_id is equal to config_id we have passed as a parameter ANDthat are active!Then we will create options of the drop down list with the function that is performed after the query.

.then(function(cashiers){ for(var i = 0, len = cashiers.length; i < len; i++){ cashier_list.push(cashiers[i].cashier_name); }

if(cashier_list.length > 0){ for(var i = 0, len = cashier_list.length; i < len; i++){ var content = self.$('#cashier-select').html(); var new_option = '<option value="' + cashier_list[i] + '">' + cashier_list[i] + '</option>\n'; self.$('#cashier-select').html(content + new_option); }

self.$('#AlertNoCashier').css('display', 'none'); self.$('#cashier-select').selectedIndex = 0; globalCashier = cashier_list[0]; self.cashier_change(globalCashier);

} else{

// if there are no cashier self.$('#AlertNoCashier').css('display', 'block');

Page 47: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 47 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

self.$('.gotopay-button').attr('disabled', 'disabled'); }});

I let you dissect the function above.Note that if there is no cashier, we display an error message in the <div id="AlertNoCashier"></div> tag and wedisable the Pay button.

An error message is displayed and the Pay button is inactive

You also see that once the list of the cashiers is built, it stores the name of the first cashier in the globalCashierglobal variable then we call cashier_change() function, passing it the name of the first cashier of the list.Then we will add a function to be called when loading the module and call the cashier_change() function to initializethe Point Of Sale.

Page 48: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 48 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

renderElement() renderElement: function() { var self = this; this._super();

self.$('#cashier-select').change(function(){ var name = this.value; self.cashier_change(name); });},

And finally, we'll copy/paste and modify the original build_widgets() function, which is in widgets.js file ofpoint_of_sale module.

build_widgets() build_widgets: function() { var self = this;

// -------- Screens ---------

this.product_screen = new module.ProductScreenWidget(this,{}); this.product_screen.appendTo($('#rightpane'));

this.receipt_screen = new module.ReceiptScreenWidget(this, {}); this.receipt_screen.appendTo($('#rightpane'));

this.payment_screen = new module.PaymentScreenWidget(this, {}); this.payment_screen.appendTo($('#rightpane'));

this.welcome_screen = new module.WelcomeScreenWidget(this,{}); this.welcome_screen.appendTo($('#rightpane'));

this.client_payment_screen = new module.ClientPaymentScreenWidget(this, {}); this.client_payment_screen.appendTo($('#rightpane'));

this.scale_invite_screen = new module.ScaleInviteScreenWidget(this, {}); this.scale_invite_screen.appendTo($('#rightpane'));

this.scale_screen = new module.ScaleScreenWidget(this,{}); this.scale_screen.appendTo($('#rightpane'));

// -------- Popups ---------

this.help_popup = new module.HelpPopupWidget(this, {}); this.help_popup.appendTo($('.point-of-sale'));

this.error_popup = new module.ErrorPopupWidget(this, {}); this.error_popup.appendTo($('.point-of-sale'));

this.error_product_popup = new module.ProductErrorPopupWidget(this, {}); this.error_product_popup.appendTo($('.point-of-sale'));

this.error_session_popup = new module.ErrorSessionPopupWidget(this, {}); this.error_session_popup.appendTo($('.point-of-sale'));

this.choose_receipt_popup = new module.ChooseReceiptPopupWidget(this, {}); this.choose_receipt_popup.appendTo($('.point-of-sale'));

this.error_negative_price_popup = new module.ErrorNegativePricePopupWidget(this, {}); this.error_negative_price_popup.appendTo($('.point-of-sale'));

// -------- Misc ---------

this.notification = new module.SynchNotificationWidget(this,{}); this.notification.appendTo(this.$('#rightheader'));

this.username = new module.UsernameWidget(this,{}); this.username.replace(this.$('.placeholder-UsernameWidget'));

Page 49: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 49 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

build_widgets() this.action_bar = new module.ActionBarWidget(this); this.action_bar.appendTo($(".point-of-sale #rightpane"));

this.left_action_bar = new module.ActionBarWidget(this); this.left_action_bar.appendTo($(".point-of-sale #leftpane"));

this.gotopay = new module.GoToPayWidget(this, {}); // We add here the creation this.gotopay.replace($('#placeholder-GoToPayWidget')); // of the widget that displays the Pay button

this.paypad = new module.PaypadWidget(this, {}); this.paypad.replace($('#placeholder-PaypadWidget'));

this.numpad = new module.NumpadWidget(this); this.numpad.replace($('#placeholder-NumpadWidget'));

this.order_widget = new module.OrderWidget(this, {}); this.order_widget.replace($('#placeholder-OrderWidget'));

this.onscreen_keyboard = new module.OnscreenKeyboardWidget(this, { 'keyboard_model': 'simple' }); this.onscreen_keyboard.appendTo($(".point-of-sale #content"));

this.close_button = new module.HeaderButtonWidget(this,{ label: _t('Close'), action: function(){ self.try_close(); }, }); this.close_button.appendTo(this.$('#rightheader'));

this.client_button = new module.HeaderButtonWidget(this,{ label: _t('Self-Checkout'), action: function(){ self.screen_selector.set_user_mode('client'); }, }); this.client_button.appendTo(this.$('#rightheader'));

// -------- Screen Selector ---------

this.screen_selector = new module.ScreenSelector({ pos: this.pos, screen_set:{ 'products': this.product_screen, 'payment' : this.payment_screen, 'client_payment' : this.client_payment_screen, 'scale_invite' : this.scale_invite_screen, 'scale': this.scale_screen, 'receipt' : this.receipt_screen, 'welcome' : this.welcome_screen, }, popup_set:{ 'help': this.help_popup, 'error': this.error_popup, 'error-product': this.error_product_popup, 'error-session': this.error_session_popup, 'error-negative-price': this.error_negative_price_popup, 'choose-receipt': this.choose_receipt_popup, }, default_client_screen: 'welcome', default_cashier_screen: 'products', default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier', });

if(this.pos.debug){ this.debug_widget = new module.DebugWidget(this); this.debug_widget.appendTo(this.$('#content')); } },

We add the widget that will display the Pay button we will see later to the list of widgets to build .

Page 50: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 50 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

this.gotopay = new module.GoToPayWidget(this, {}); this.gotopay.replace($('#placeholder-GoToPayWidget'));

Here it says that the widget will be placed in the <div id="placeholder-GoToPayWidget"></ div> tag that we putin the view later.

VIII-A-3 - The CashierPayScreenWidget module

This module will allow us to add a function to the original module.PaymentScreenWidget module (which is inscreen.js file of point_of_sale module), again with the include() function

PaymentScreenWidget module.CashierPayScreenWidget = module.PaymentScreenWidget.include({ template: 'PaymentScreenWidget',

show: function(){ this._super(); var self = this; this.$('#pay-screen-cashier-name').html(globalCashier); this.$('#ticket-screen-cashier-name').html(globalCashier); this.pos.get('selectedOrder').set_cashier_name(globalCashier);

this.paypad = new module.PaypadWidget(this, {}); this.paypad.replace($('#placeholder-PaypadWidget')); },

});

The module will be attached to the PaymentScreenWidget template view .We will add some instructions in the show() function of the module.We will first of all get the name of the cashier who is in the globalCashier global variable that will be displayed onthe payment page and on the receipt.

It will then record the name of the cashier in the current order with the following function

set_cashier_name this.pos.get('selectedOrder').set_cashier_name(globalCashier);

This function does not exist yet, we'll add it later.Finally, we will recreate the payment buttons that I removed,. In addition, they will be destroyed at the end of eachorder.

PaypadWidget this.paypad = new module.PaypadWidget(this, {});this.paypad.replace($('#placeholder-PaypadWidget'));

The PaypadWidget module is the original one created for the Point Of Sale. This is theone that was removed before it was next to the keypad, which was replaced with the Paybutton.

VIII-A-4 - The CashierReceiptScreenWidget module

Here we will add instructions in the original function refresh() of ReceiptScreenWidget module that is in screen.jsfile of point_of_sale module. This is the module that will display the name of the cashier on the receipt.

In fact, it will copy the original function and add the last three lines (the if() statement).

Page 51: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 51 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

CashierReceiptScreenWidget module.CashierReceiptScreenWidget = module.ReceiptScreenWidget.include({

refresh: function() { this._super(); $('.pos-receipt-container', this.$el).html(QWeb.render('PosTicket',{widget:this}));

if(globalCashier != ''){ this.$('#ticket-screen-cashier-name').html(globalCashier); } }, });

You see that we get the name of the cashier who is in globalCashier variable to send it to <div id="ticket-screen-cashier-name"></ div> tag that is diplayed on the receipt. We'll see that later when we take care of the views (XML).

VIII-A-5 - GoToPayWidget module

Now we will create the module that will host the Pay button.Warning, this is not the button itself, it is simply the « container » that will host the button.

module.GoToPayWidget = module.PosBaseWidget.extend({ template: 'GoToPayWidget', init: function(parent, options) { this._super(parent); },

renderElement: function() { var self = this; this._super();

var button = new module.GoToPayButtonWidget(self); button.appendTo(self.$el); },});

As for the other original Point Of Sale modules, these are extensions of PosBaseWidget module.

We assign the template view with the following statement:

template: 'GoToPayWidget',

Then adding the init() function like the original modules.

We will then add a function that will command QWeb (the rendering engine templates) to add the Pay button, we willsee just after this module (in its container, somehow).

renderElement renderElement: function() { var self = this; this._super();

var button = new module.GoToPayButtonWidget(self); button.appendTo(self.$el);},

That's all for this module

Page 52: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 52 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

VIII-A-6 - GoToPayButtonWidget module (Pay button)

This time, we will create the module of the Pay button.As with the previous module, it will be an extension of the basic PosBaseWidget module, we assign theGoToPayButtonWidget template view , we add the init() function that goes well, then we also add therenderElement() function.

GoToPayButtonWidget module.GoToPayButtonWidget = module.PosBaseWidget.extend({ template: 'GoToPayButtonWidget', init: function(parent, options) { this._super(parent); },

renderElement: function() { var self = this; this._super();

this.$el.click(function(){ self.pos_widget.screen_selector.set_current_screen('payment'); }); }, });

We add click() function in renderElement().This function is performed, you guessed it, when clicking on the button (onclick() event).This function itself will call the function to display different views of Point Of Sale.

In this case, it will display the payment page.

set_current_screen() this.$el.click(function(){ self.pos_widget.screen_selector.set_current_screen('payment');});

VIII-A-7 - Order module

This is the module that creates the orders, which stores them in the browser (LocalStorage), and which then sendsthe orders to the database.

It is not possible to overload the original module, because when initializing, the module returns an object (the order)to the Point Of Sale, and we need to modify it to take into account the name of the cashier.We'll copy/paste the entire module you will find in model.js file of point_of_sale module and we will add two orthree things.

I put the code of the module and I'll explain only the functions or objects I added.

module.Order module.Order = Backbone.Model.extend({ initialize: function(attributes){ Backbone.Model.prototype.initialize.apply(this, arguments); this.set({ creationDate: new Date(), orderLines: new module.OrderlineCollection(), paymentLines: new module.PaymentlineCollection(), name: "Order " + this.generateUniqueId(), client: null, cashier_name: null, }); this.pos = attributes.pos;

Page 53: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 53 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.Order this.selected_orderline = undefined; this.screen_data = {}; // see ScreenSelector this.receipt_type = 'receipt'; // 'receipt' || 'invoice' return this; }, generateUniqueId: function() { return new Date().getTime(); }, addProduct: function(product, options){ options = options || {}; var attr = product.toJSON(); attr.pos = this.pos; attr.order = this; var line = new module.Orderline({}, {pos: this.pos, order: this, product: product});

if(options.quantity !== undefined){ line.set_quantity(options.quantity); } if(options.price !== undefined){ line.set_unit_price(options.price); }

var last_orderline = this.getLastOrderline(); if( last_orderline && last_orderline.can_be_merged_with(line) && options.merge !== false){ last_orderline.merge(line); }else{ this.get('orderLines').add(line); } this.selectLine(this.getLastOrderline()); }, removeOrderline: function( line ){ this.get('orderLines').remove(line); this.selectLine(this.getLastOrderline()); }, getLastOrderline: function(){ return this.get('orderLines').at(this.get('orderLines').length -1); }, addPaymentLine: function(cashRegister) { var paymentLines = this.get('paymentLines'); var newPaymentline = new module.Paymentline({},{cashRegister:cashRegister}); if(cashRegister.get('journal').type !== 'cash'){ newPaymentline.set_amount( this.getDueLeft() ); } paymentLines.add(newPaymentline); }, getName: function() { return this.get('name'); }, getSubtotal : function(){ return (this.get('orderLines')).reduce((function(sum, orderLine){ return sum + orderLine.get_display_price(); }), 0); }, getTotalTaxIncluded: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_price_with_tax(); }), 0); }, getDiscountTotal: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + (orderLine.get_unit_price() * (orderLine.get_discount()/100) * orderLine.get_quantity()); }), 0); }, getTotalTaxExcluded: function() { return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_price_without_tax(); }), 0); }, getTax: function() {

Page 54: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 54 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.Order return (this.get('orderLines')).reduce((function(sum, orderLine) { return sum + orderLine.get_tax(); }), 0); }, getPaidTotal: function() { return (this.get('paymentLines')).reduce((function(sum, paymentLine) { return sum + paymentLine.get_amount(); }), 0); }, getChange: function() { return this.getPaidTotal() - this.getTotalTaxIncluded(); }, getDueLeft: function() { return this.getTotalTaxIncluded() - this.getPaidTotal(); }, set_cashier_name: function(name){ this.set('cashier_name', name); }, // sets the type of receipt 'receipt'(default) or 'invoice' set_receipt_type: function(type){ this.receipt_type = type; }, get_receipt_type: function(){ return this.receipt_type; }, // the client related to the current order. set_client: function(client){ this.set('client',client); }, get_client: function(){ return this.get('client'); }, get_client_name: function(){ var client = this.get('client'); return client ? client.name : ""; }, // the order also stores the screen status, as the PoS supports // different active screens per order. This method is used to // store the screen status. set_screen_data: function(key,value){ if(arguments.length === 2){ this.screen_data[key] = value; }else if(arguments.length === 1){ for(key in arguments[0]){ this.screen_data[key] = arguments[0][key]; } } }, //see set_screen_data get_screen_data: function(key){ return this.screen_data[key]; }, // exports a JSON for receipt printing export_for_printing: function(){ var orderlines = []; this.get('orderLines').each(function(orderline){ orderlines.push(orderline.export_for_printing()); });

var paymentlines = []; this.get('paymentLines').each(function(paymentline){ paymentlines.push(paymentline.export_for_printing()); }); var client = this.get('client'); var cashier = this.pos.get('cashier') || this.pos.get('user'); var company = this.pos.get('company'); var shop = this.pos.get('shop'); var date = new Date();

return {

Page 55: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 55 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.Order orderlines: orderlines, paymentlines: paymentlines, subtotal: this.getSubtotal(), total_with_tax: this.getTotalTaxIncluded(), total_without_tax: this.getTotalTaxExcluded(), total_tax: this.getTax(), total_paid: this.getPaidTotal(), total_discount: this.getDiscountTotal(), change: this.getChange(), name : this.getName(), client: client ? client.name : null , invoice_id: null, //TODO cashier: cashier ? cashier.name : null, date: { year: date.getFullYear(), month: date.getMonth(), date: date.getDate(), // day of the month day: date.getDay(), // day of the week hour: date.getHours(), minute: date.getMinutes() }, company:{ email: company.email, website: company.website, company_registry: company.company_registry, contact_address: company.contact_address, vat: company.vat, name: company.name, phone: company.phone, }, shop:{ name: shop.name, }, currency: this.pos.get('currency'), }; }, exportAsJSON: function() { var orderLines, paymentLines; orderLines = []; (this.get('orderLines')).each(_.bind( function(item) { return orderLines.push([0, 0, item.export_as_JSON()]); }, this)); paymentLines = []; (this.get('paymentLines')).each(_.bind( function(item) { return paymentLines.push([0, 0, item.export_as_JSON()]); }, this)); return { name: this.getName(), amount_paid: this.getPaidTotal(), amount_total: this.getTotalTaxIncluded(), amount_tax: this.getTax(), amount_return: this.getChange(), lines: orderLines, statement_ids: paymentLines, pos_session_id: this.pos.get('pos_session').id, partner_id: this.pos.get('client') ? this.pos.get('client').id : undefined, user_id: this.pos.get('cashier') ? this.pos.get('cashier').id : this.pos.get('user').id, cashier_name: this.pos.get('selectedOrder').get('cashier_name'), }; }, getSelectedLine: function(){ return this.selected_orderline; }, selectLine: function(line){ if(line){ if(line !== this.selected_orderline){ if(this.selected_orderline){ this.selected_orderline.set_selected(false); } this.selected_orderline = line;

Page 56: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 56 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

module.Order this.selected_orderline.set_selected(true); } }else{ this.selected_orderline = undefined; } }, });

At the beginning of the module, we will add a cashier_name field to the order.

initialize() initialize: function(attributes){ Backbone.Model.prototype.initialize.apply(this, arguments); this.set({ creationDate: new Date(), orderLines: new module.OrderlineCollection(), paymentLines: new module.PaymentlineCollection(), name: "Order " + this.generateUniqueId(), client: null, <!-- DO NOT FORGET COMMA --> cashier_name: null, <!-- ADD cashier_name FIELD HERE --> }); this.pos = attributes.pos; this.selected_orderline = undefined; this.screen_data = {}; // see ScreenSelector this.receipt_type = 'receipt'; // 'receipt' || 'invoice' return this;},

As you can see, the order contains multiple fields. We simply add the cashier_name field.Now that the field is created, we can send the name of the cashier to the order when needed.

Then we will add a function in the list of functions that already exist.

set_cashier_name() set_cashier_name: function(name){ this.set('cashier_name', name);},

When set_cashier_name() function is called, it will send the name of the cashier in the field we added earlier.

If you well remember, this function is called in the show() function ofCashierPayScreenWidget module.So when the payment page will be displayed, the name of the cashier will be sent to theorder.

Now we will modify the function that sends the order to the database.

exportAsJSON() exportAsJSON: function() { var orderLines, paymentLines; orderLines = []; (this.get('orderLines')).each(_.bind( function(item) { return orderLines.push([0, 0, item.export_as_JSON()]); }, this)); paymentLines = []; (this.get('paymentLines')).each(_.bind( function(item) { return paymentLines.push([0, 0, item.export_as_JSON()]); }, this)); return { name: this.getName(), amount_paid: this.getPaidTotal(), amount_total: this.getTotalTaxIncluded(), amount_tax: this.getTax(),

Page 57: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 57 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

exportAsJSON() amount_return: this.getChange(), lines: orderLines, statement_ids: paymentLines, pos_session_id: this.pos.get('pos_session').id, partner_id: this.pos.get('client') ? this.pos.get('client').id : undefined, user_id: this.pos.get('cashier') ? this.pos.get('cashier').id : this.pos.get('user').id, cashier_name: this.pos.get('selectedOrder').get('cashier_name'), };},

We added the cashier_name field in the return of the function.

cashier_name cashier_name: this.pos.get('selectedOrder').get('cashier_name'),

This time, we get the name of the cashier who was sent to the order earlier.The openerp_pos_cashier module() is finished!

VIII-A-8 - The best for last

The JavaScript file is almost complete.We now include our module inside the Point Of Sale.

For this, there is no other way than to take the function that creates the Point Of Sale and add our module.

So we add, following the module, the openerp.point_of_sale() function that is in the main.js file of point_of_salemodule.

openerp.point_of_sale() openerp.point_of_sale = function(instance) { instance.point_of_sale = {};

var module = instance.point_of_sale;

openerp_pos_db(instance,module); // import db.js openerp_pos_models(instance,module); // import pos_models.js openerp_pos_basewidget(instance,module); // import pos_basewidget.js openerp_pos_keyboard(instance,module); // import pos_keyboard_widget.js openerp_pos_scrollbar(instance,module); // import pos_scrollbar_widget.js openerp_pos_screens(instance,module); // import pos_screens.js openerp_pos_widgets(instance,module); // import pos_widgets.js openerp_pos_devices(instance,module); // import pos_devices.js

// cashiers openerp_pos_cashier(instance,module); // import openerp_pos_cashier

instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.PosWidget');};

We add the openerp_pos_cashier line.

And that's it for the pos_cashier.js file !!!

VIII-B - the pos_cashier.xml file

This is the file of views needed to display the data in the Point Of Sale.

This file is placed in the xml directory of the module.

Page 58: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 58 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

/opt/modules-openerp/pos_cashiers/static/src/xmlpos_cashier.xml <?xml version="1.0" encoding="UTF-8"?><!-- vim:fdl=1:--><templates id="template" xml:space="preserve">

<!-- Cashiers drop-down list under NumPad --> <t t-extend="PosWidget" > <t t-jquery="footer" t-operation="append"> <div id="AlertNoCashier">You must create at least one cashier!</div> <div id="cashier-footer"> <div id="cashier-title"> Select a cashier : </div> <div id="cashier-frame"> <t t-esc="widget.get_cashiers(widget.get_cur_pos_config_id())" /> <select id="cashier-select"></select> </div> </div> </t> </t>

<!-- Name of the cashier on Payement Page --> <t t-extend="PaymentScreenWidget" > <t t-jquery=".pos-step-container" t-operation="prepend"> <div id="pay-screen-cashier">Cashier : <span id="pay-screen-cashier-name"> </span> </div> </t> </t>

<!-- Name of the cashier on Ticket --> <t t-extend="PosTicket" > <t t-jquery="#header-ticket" t-operation="append"> Cashier : <span id="ticket-screen-cashier-name"></span> </t> </t>

</templates>

Here we will use special tags that will allow Qweb rendering engine to insert objects in the page.

VIII-B-1 - The dropdown cashiers

We will place the dropdown cashiers under the keypad.

PosWidget <!-- Cashiers drop-down list under NumPad --> <t t-extend="PosWidget" > <t t-jquery="footer" t-operation="append"> <div id="AlertNoCashier">You must create at least one cashier!</div> <div id="cashier-footer"> <div id="cashier-title"> Select a cashier : </div> <div id="cashier-frame"> <t t-esc="widget.get_cashiers(widget.get_cur_pos_config_id())" /> <select id="cashier-select"></select> </div> </div> </t> </t>

To modify the original view, we use the t-extend attribute.

Page 59: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 59 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

t-extend <!-- Cashiers drop-down list under NumPad --> <t t-extend="PosWidget" > - - - </t>

As you see above, a template is written inside <t></t> tags.

To see the different attributes and functions, I invite you to read this page on the publisher'swebsite:

Documentation QWeb

Then, just as in the XML views of Python module where we used the position attribute to place objects before, afteror in place of the objects of the original template, we will use here the t-operation attribute preceded with the t-jqueryattribute to specify the object of original template.

t-jquery <t t-jquery="footer" t-operation="append"> <div id="AlertNoCashier">You must create at least one cashier!</div> <div id="cashier-footer"> <div id="cashier-title"> Select a cashier : </div> <div id="cashier-frame"> <t t-esc="widget.get_cashiers(widget.get_cur_pos_config_id())" /> <select id="cashier-select"></select> </div> </div> </t>

Here, we wish to add objects to <footer></ footer> tag , following those of the original PosWidget template.

We can see the tag which contains the error message in case of no cashier, followed by the drop-down list of cashiers.

Page 60: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 60 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The dropdown list

La liste déroulante

The error message if no cashier

Le message d'erreur pour défaut de caissier

Cashiers dorpdown list <t t-esc="widget.get_cashiers(widget.get_cur_pos_config_id())" /><select id="cashier-select"></select>

The first tag uses the t-esc attribute that can insert standard JavaScript commands.At the loading of the Point Of Sale, we get the ID of the Point Of Sale with get_cur_pos_config_id() function.

Then, just below, we insert the dropdown list of cashiers who belong to this Point Of Sale.

To display the name of the cashier on the payment page, we will extend the original PaymentScreenWidget module.

Page 61: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 61 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

PaymentScreenWidget <!-- Name of the cashier on Payement Page --> <t t-extend="PaymentScreenWidget" > <t t-jquery=".pos-step-container" t-operation="prepend"> <div id="pay-screen-cashier">Cashier : <span id="pay-screen-cashier-name"> </span> </div> </t> </t>

Name of the cashier on Payement Page

Finally, the cashier's name must also appear on the receipt, so we will also extend the original PosTicket module.

PosTicket <!-- Name of the cashier on Ticket --> <t t-extend="PosTicket" > <t t-jquery="#header-ticket" t-operation="append"> Cashier : <span id="ticket-screen-cashier-name"></span> </t> </t>

Page 62: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 62 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Name of the cashier on receipt

That's it for the XML file.

VIII-C - pos_cashier.css file

A simple *.CSS file to put in css directory of the module :

/opt/modules-openerp/pos_cashiers/static/src/csspos_cashier.css #cashier-title{ vertical-align: middle; display:inline-block; text-align: left; font-size: 16px;

Page 63: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 63 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.css font-weight: normal; font-style: italic; width: 45%;}

#cashier-frame { text-align: center; vertical-align: middle; display:inline-block; border: 1px solid #000000; width: 55%; padding: 5px 0px 5px 0px;}

#cashier-select{ width:95%;}

#cashier-footer{ background: linear-gradient(#7B7979, #393939) repeat scroll 0 0 transparent; display:block; color: #ffcc00; padding: 10px 5px 10px 5px;}

#pay-screen-cashier{ color: black; border-bottom: 1px dashed #666666; padding: 2px 2px 2px 2px; text-align: left; font-size: 14px; font-weight: normal; font-style: italic;}

#ticket-screen-cashier{ font-style: italic; border-bottom : 1px solid gray; padding-bottom: 2px;}

#AlertNoCashier{ background: red url("../img/error.png") no-repeat 4px; color: white; font-size: 14px; font-weight: bold; padding: 12px 4px 4px 30px; height: 24px; text-transform: uppercase;}

Here you can put your additional styles for your module, and you can also edit the original ones, if needed,

IX - Installation of the module

This time, we can install our module.Connect to OpenERP as an administrator, and then click the Configuration menu.

Click on « Update list of modules » linkThen click « Installed Modules » and delete the « Installed » filter in the search bar.

Our module will appear.

Click the Install button and wait until the end of the installation.

Page 64: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 64 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

The POS Cashiers module in installed modules

X - Internationalisation

You have noticed that the text, labels and titles were all in English?There are two reasons for this.

• The first one , is that the module is fully functional, it may therefore be useful to other people. It will just makethem translated into their language. I could do it, but I speak not very well Hungarian nor Korean ...

• The second reason is that I wanted to explain how to do the translation of a module. This is the best reason,finally.

The international system is a bit complex.Know that we need to create a pos_cashier.pot file, we put in the i18n directory.

/opt/modules-openerp/pos_cashier/i18nFrom this pos_cashier.pot file, we can create files for different languages.

A *.pot file is a translation template file. It contains only the original terms, it does not contain the translated words.

But creating a *.pot from A to Z is a bit complicated.Fortunately, our beloved OpenERP Dev Team have thought of everything.

Make a *.pot file

• Connect to OpenERP as administrator• click Configuration in top menu.• In Translation heading, click Export translation.• The form below appears

Page 65: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 65 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

Export translation file

• In Langage field, select New Language.• In File format, select PO File.• In Modules to export, select POS Cashiers.• Click Export.• A second window is displayed.

Download translation file

• Download the file by clicking the download link.• Rename the file to pos_cashier.pot.• And open it with your text editor.

pos_cashier.pot # Translation of OpenERP Server.# This file contains the translation of the following modules:# * pos_cashier#msgid ""msgstr """Project-Id-Version: OpenERP Server 7.0-20130703-231023\n""Report-Msgid-Bugs-To: \n""POT-Creation-Date: 2013-07-13 00:04+0000\n""PO-Revision-Date: 2013-07-13 00:04+0000\n""Last-Translator: <>\n"

Page 66: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 66 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.pot"Language-Team: \n""MIME-Version: 1.0\n""Content-Type: text/plain; charset=UTF-8\n""Content-Transfer-Encoding: \n""Plural-Forms: \n"

#. module: pos_cashier#: view:pos.cashier:0msgid "All"msgstr ""

#. module: pos_cashier#: model:ir.model,name:pos_cashier.model_pos_ordermsgid "Point of Sale"msgstr ""

#. module: pos_cashier#: model:ir.actions.act_window,help:pos_cashier.action_pos_cashiermsgid "<p class=\"oe_view_nocontent_create\">\n"" Click here to create a cashier for the Point Of Sale.\n"" </p>\n"" "msgstr ""

#. module: pos_cashier#: view:pos.cashier:0msgid "Point of Sale Cashier"msgstr ""

#. module: pos_cashier#: field:pos.cashier,cashier_name:0#: field:pos.order,cashier_name:0msgid "Cashier"msgstr ""

#. module: pos_cashier#: view:pos.cashier:0msgid "Inactive"msgstr ""

#. module: pos_cashier#: help:pos.cashier,active:0msgid "If a cashier is not active, it will not be displayed in POS"msgstr ""

#. module: pos_cashier#: sql_constraint:pos.cashier:0msgid "A cashier already exists with this name in this Point Of sale. Cashier's name must be unique!"msgstr ""

#. module: pos_cashier#: view:pos.cashier:0#: field:pos.cashier,active:0msgid "Active"msgstr ""

#. module: pos_cashier#: model:ir.model,name:pos_cashier.model_pos_cashiermsgid "pos.cashier"msgstr ""

#. module: pos_cashier#: model:ir.actions.act_window,name:pos_cashier.action_pos_cashier#: model:ir.ui.menu,name:pos_cashier.menu_action_pos_cashier#: model:ir.ui.menu,name:pos_cashier.menu_point_of_sale_cashiers#: view:pos.cashier:0msgid "Cashiers"msgstr ""

#. module: pos_cashier#: field:pos.cashier,pos_config_id:0

Page 67: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 67 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

pos_cashier.potmsgid "Point Of Sale"msgstr ""

Here's what looks like a *.pot.

Before the copy, we will add some instructions.You may have noticed that the words that are in this file are the names of the fields, constraints or comments thatwe have created in the tables.

We also want to translate words that we « hard coded » in the XML files of some views.

In particular, we want to translate the error message that appears in the Point Of Sale when there is no cashier, wealso want to translate the word « cashier », etc..

We will add portions of code as below.

pos_cashier.pot

#. module: pos_cashier#. openerp-web#: code:static/src/xml/pos_cashier.xml:9#, python-formatmsgid "You must create at least one cashier!"msgstr ""

Again, since there is no documentation on this, I poked around in the translation files of other modules.It can translate a word or phrase in an XML file specifying the source of the file (from the root module) followed bythe line number.

In the example above, the sentence to be translated is line 9 of static/src/xml/pos_cashier.xml file.

Then we add the following two translations.

pos_cashier.pot

#. module: pos_cashier#. openerp-web#: code:static/src/xml/pos_cashier.xml:12#, python-formatmsgid "Select a cashier :"msgstr ""

#. module: pos_cashier#. openerp-web#: code:static/src/xml/pos_cashier.xml:26#: code:static/src/xml/pos_cashier.xml:36#, python-formatmsgid "Cashier :"msgstr ""

Please note that the string to be translated is in front of the msgid keyword. This is the identifier of the chain. On thenext line, we have the msgstr keyword followed by an empty string.Save the file, then copy the file renaming, this time to fr.po. This will be our translation file for the French language.Obviously, you'll understand it then just add the translations of the strings in the corresponding msgstr.Here is an excerpt of fr.po file:

fr.po

#. module: pos_cashier#: help:pos.cashier,active:0

Page 68: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 68 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

fr.pomsgid "If a cashier is not active, it will not be displayed in POS"msgstr "Un caissier désactivé ne sera pas visible dans le Point De Vente"

#. module: pos_cashier#: sql_constraint:pos.cashier:0msgid """A cashier already exists with this name in this Point Of sale. Cashier's ""name must be unique!"msgstr """Un caissier existe déjà avec le même nom dans ce Point De Vente. Le nom du ""caissier doit être unique!"

If you want to translate into several languages, simply copy and rename the pos_cashier.pot file to a xx.po file . Fordifferent languages taken into account, just look in the i18n directory of the other modules.

While you're there, then duplicate the fr.po file for Belgium and Switzerland.

When you have completed the translation files, you will need to restart OpenERP sure everything loads properly.

Then you will be able to go into the POS, tickle the drop-down list after creating two or three cashiers!

XI - Conclusion

In this tutorial we have seen a lot of things, finally:

• the creation of a Python object;• the creation of XML views (form view and tree view) ;• the creation of search filters;• the creation of a menu ;• the module access rights;• the records rules ;• add an icon to the module ;• modify the Point Of sale (add a dropdown list and a button) ;• QWeb and templates;• the installation of a module ;• the translation of a module.

Do not hesitate to look at documentation on the publisher's website, including :

• OpenERP Server Developers Documentation ;• OpenERP Web's documentation ;• QWeb ;• OpenERP technical Memento.

If you have any improvements or even corrections, do not hesitate to send me your comments.

Thank you.

XII - Download module

Download POS Cashier Module

Page 69: OpenERP POS Tutorial

OpenERP Tutorial: Module creation and modification of the Point Of Sale par Thierry Godin

- 69 -Copyright ® 2013 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expressede l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

http://thierry-godin.developpez.com/openerp/tutorial-module-creation-pos-modification-english-version/

XIII - Thanks

Many thanks to the members of the Developpez.com team for their advice and corrections.

• fafabzh6• Claude Leloup