Note: This post demonstrates how to crack WEP passwords, an older and less often used network security protocol. If the network you want to crack is using the more popular WPA encryption, see our guide to cracking a Wi-Fi network's WPA password with Reaver instead.
Today we're going to run down, step-by-step, how to crack a Wi-Fi network with WEP security turned on. But first, a word: Knowledge is power, but power doesn't mean you should be a jerk, or do anything illegal. Knowing how to pick a lock doesn't make you a thief. Consider this post educational, or a proof-of-concept intellectual exercise.
Dozens of tutorials on how to crack WEP are already all over the internet using this method. Seriously—Google it. This ain't what you'd call "news." But what is surprising is that someone like me, with minimal networking experience, can get this done with free software and a cheap Wi-Fi adapter. Here's how it goes.
What You'll Need
Unless you're a computer security and networking ninja, chances are you don't have all the tools on hand to get this job done. Here's what you'll need:
A compatible wireless adapter—This is the biggest requirement. You'll need a wireless adapter that's capable of packet injection, and chances are the one in your computer is not. After consulting with my friendly neighborhood security expert, I purchased an Alfa AWUS050NH USB adapter, pictured here, and it set me back about $50 on Amazon. Update: Don't do what I did. Get the Alfa AWUS036H, not the US050NH, instead.The guy in this video below is using a $12 model he bought on Ebay (and is even selling his router of choice). There are plenty of resources on getting aircrack-compatible adapters out there.
A nearby WEP-enabled Wi-Fi network. The signal should be strong and ideally people are using it, connecting and disconnecting their devices from it. The more use it gets while you collect the data you need to run your crack, the better your chances of success.
Patience with the command line. This is an ten-step process that requires typing in long, arcane commands and waiting around for your Wi-Fi card to collect data in order to crack the password. Like the doctor said to the short person, be a little patient.
Crack That WEP
To crack WEP, you'll need to launch Konsole, BackTrack's built-in command line. It's right there on the taskbar in the lower left corner, second button to the right. Now, the commands.
First run the following to get a list of your network interfaces:
airmon-ng
The only one I've got there is labeled ra0. Yours may be different; take note of the label and write it down. From here on in, substitute it in everywhere a command includes (interface).
Now, run the following four commands. See the output that I got for them in the screenshot below.
If you don't get the same results from these commands as pictured here, most likely your network adapter won't work with this particular crack. If you do, you've successfully "faked" a new MAC address on your network interface, 00:11:22:33:44:55.
Now it's time to pick your network. Run:
airodump-ng (interface)
To see a list of wireless networks around you. When you see the one you want, hit Ctrl+C to stop the list. Highlight the row pertaining to the network of interest, and take note of two things: its BSSID and its channel (in the column labeled CH), as pictured below. Obviously the network you want to crack should have WEP encryption (in the ENC) column, not WPA or anything else.
S
Like I said, hit Ctrl+C to stop this listing. (I had to do this once or twice to find the network I was looking for.) Once you've got it, highlight the BSSID and copy it to your clipboard for reuse in the upcoming commands.
Now we're going to watch what's going on with that network you chose and capture that information to a file. Run:
Where (channel) is your network's channel, and (bssid) is the BSSID you just copied to clipboard. You can use the Shift+Insert key combination to paste it into the command. Enter anything descriptive for (file name). I chose "yoyo," which is the network's name I'm cracking.
S
You'll get output like what's in the window in the background pictured below. Leave that one be. Open a new Konsole window in the foreground, and enter this command:
aireplay-ng -1 0 -a (bssid) -h 00:11:22:33:44:55 -e (essid) (interface)
Here the ESSID is the access point's SSID name, which in my case is yoyo. What you want to get after this command is the reassuring "Association successful" message with that smiley face.
Here we're creating router traffic to capture more throughput faster to speed up our crack. After a few minutes, that front window will start going crazy with read/write packets. (Also, I was unable to surf the web with the yoyo network on a separate computer while this was going on.) Here's the part where you might have to grab yourself a cup of coffee or take a walk. Basically you want to wait until enough data has been collected to run your crack. Watch the number in the "#Data" column—you want it to go above 10,000. (Pictured below it's only at 854.)
Depending on the power of your network (mine is inexplicably low at -32 in that screenshot, even though the yoyo AP was in the same room as my adapter), this process could take some time. Wait until that #Data goes over 10k, though—because the crack won't work if it doesn't. In fact, you may need more than 10k, though that seems to be a working threshold for many.
S
Once you've collected enough data, it's the moment of truth. Launch a third Konsole window and run the following to crack that data you've collected:
aircrack-ng -b (bssid) (file name-01.cap)
Here the filename should be whatever you entered above for (file name). You can browse to your Home directory to see it; it's the one with .cap as the extension.
If you didn't get enough data, aircrack will fail and tell you to try again with more. If it succeeds, it will look like this:
S
The WEP key appears next to "KEY FOUND." Drop the colons and enter it to log onto the network.
Problems Along the Way
With this article I set out to prove that cracking WEP is a relatively "easy" process for someone determined and willing to get the hardware and software going. I still think that's true, but unlike the guy in the video below, I had several difficulties along the way. In fact, you'll notice that the last screenshot up there doesn't look like the others—it's because it's not mine. Even though the AP which I was cracking was my own and in the same room as my Alfa, the power reading on the signal was always around -30, and so the data collection was very slow, and BackTrack would consistently crash before it was complete. After about half a dozen attempts (and trying BackTrack on both my Mac and PC, as a live CD and a virtual machine), I still haven't captured enough data for aircrack to decrypt the key.
So while this process is easy in theory, your mileage may vary depending on your hardware, proximity to the AP point, and the way the planets are aligned. Oh yeah, and if you're on deadline—Murphy's Law almost guarantees it won't work if you're on deadline.
To see the video version of these exact instructions, check out this dude's YouTube video.
Here's the bad news: A new, free, open-source tool called Reaver exploits a security hole in wireless routers and can crack most routers' current passwords with relative ease. Here's how to crack a WPA or WPA2 password, step by step, with Reaver—and how to protect your network against Reaver attacks.
In the first section of this post, I'll walk through the steps required to crack a WPA password using Reaver. You can follow along with either the video or the text below. After that, I'll explain how Reaver works, and what you can do to protect your network against Reaver attacks.
First, a quick note: As we remind often remind readers when we discuss topics that appear potentially malicious: Knowledge is power, but power doesn't mean you should be a jerk, or do anything illegal. Knowing how to pick a lock doesn't make you a thief. Consider this post educational, or a proof-of-concept intellectual exercise. The more you know, the better you can protect yourself.
What You'll Need
You don't have to be a networking wizard to use Reaver, the command-line tool that does the heavy lifting, and if you've got a blank DVD, a computer with compatible Wi-Fi, and a few hours on your hands, you've got basically all you'll need. There are a number of ways you could set up Reaver, but here are the specific requirements for this guide:
The BackTrack 5 Live DVD. BackTrack is a bootable Linux distribution that's filled to the brim with network testing tools, and while it's not strictly required to use Reaver, it's the easiest approach for most users. Download the Live DVD from BackTrack's download page and burn it to a DVD. You can alternately download a virtual machine image if you're using VMware, but if you don't know what VMware is, just stick with the Live DVD. As of this writing, that means you should select BackTrack 5 R1 from the Release drop-down, select Gnome, 32- or 64-bit depending on your CPU (if you don't know which you have, 32 is a safe bet), ISO for image, and then download the ISO.
A computer with Wi-Fi and a DVD drive. BackTrack will work with the wireless card on most laptops, so chances are your laptop will work fine. However, BackTrack doesn't have a full compatibility list, so no guarantees. You'll also need a DVD drive, since that's how you'll boot into BackTrack. I used a six-year-old MacBook Pro.
A nearby WPA-secured Wi-Fi network. Technically, it will need to be a network using WPA security with the WPS feature enabled. I'll explain in more detail in the "How Reaver Works" section how WPS creates the security hole that makes WPA cracking possible.
A little patience. This is a 4-step process, and while it's not terribly difficult to crack a WPA password with Reaver, it's a brute-force attack, which means your computer will be testing a number of different combinations of cracks on your router before it finds the right one. When I tested it, Reaver took roughly 2.5 hours to successfully crack my password. The Reaver home page suggests it can take anywhere from 4-10 hours. Your mileage may vary.
Let's Get Crackin'
At this point you should have BackTrack burned to a DVD, and you should have your laptop handy.
Step 1: Boot into BackTrack
S
To boot into BackTrack, just put the DVD in your drive and boot your machine from the disc. (Google around if you don't know anything about live CDs/DVDs and need help with this part.) During the boot process, BackTrack will prompt you to to choose the boot mode. Select "BackTrack Text - Default Boot Text Mode" and press Enter.
Eventually BackTrack will boot to a command line prompt. When you've reached the prompt, type startx and press Enter. BackTrack will boot into its graphical interface.
Step 2: Install Reaver
Reaver has been added to the bleeding edge version of BackTrack, but it's not yet incorporated with the live DVD, so as of this writing, you need to install Reaver before proceeding. (Eventually, Reaver will simply be incorporated with BackTrack by default.) To install Reaver, you'll first need to connect to a Wi-Fi network that you have the password to.
Click Applications > Internet > Wicd Network Manager
Select your network and click Connect, enter your password if necessary, click OK, and then click Connect a second time.
Now that you're online, let's install Reaver. Click the Terminal button in the menu bar (or click Applications > Accessories > Terminal). At the prompt, type:
apt-get update
And then, after the update completes:
apt-get install reaver
If all went well, Reaver should now be installed. It may seem a little lame that you need to connect to a network to do this, but it will remain installed until you reboot your computer. At this point, go ahead and disconnect from the network by opening Wicd Network Manager again and clicking Disconnect. (You may not strictly need to do this. I did just because it felt like I was somehow cheating if I were already connected to a network.)
Step 3: Gather Your Device Information, Prep Your Crackin'
In order to use Reaver, you need to get your wireless card's interface name, the BSSID of the router you're attempting to crack (the BSSID is a unique series of letters and numbers that identifies a router), and you need to make sure your wireless card is in monitor mode. So let's do all that.
Find your wireless card: Inside Terminal, type:
iwconfig
Press Enter. You should see a wireless device in the subsequent list. Most likely, it'll be named wlan0, but if you have more than one wireless card, or a more unusual networking setup, it may be named something different.
Put your wireless card into monitor mode: Assuming your wireless card's interface name iswlan0, execute the following command to put your wireless card into monitor mode:
airmon-ng start wlan0
This command will output the name of monitor mode interface, which you'll also want to make note of. Most likely, it'll be mon0, like in the screenshot below. Make note of that.
S
Find the BSSID of the router you want to crack: Lastly, you need to get the unique identifier of the router you're attempting to crack so that you can point Reaver in the right direction. To do this, execute the following command:
airodump-ng wlan0
(Note: If airodump-ng wlan0 doesn't work for you, you may want to try the monitor interface instead—e.g., airodump-ng mon0.)
You'll see a list of the wireless networks in range—it'll look something like the screenshot below:
S
When you see the network you want, press Ctrl+C to stop the list from refreshing, then copy that network's BSSID (it's the series of letters, numbers, and colons on the far left). The network should have WPA or WPA2 listed under the ENC column. (If it's WEP, use our previous guide to cracking WEP passwords.)
Now, with the BSSID and monitor interface name in hand, you've got everything you need to start up Reaver.
Step 4: Crack a Network's WPA Password with Reaver
Now execute the following command in the Terminal, replacing bssid and moninterface with the BSSID and monitor interface and you copied down above:
reaver -i moninterface -b bssid -vv
For example, if your monitor interface was mon0 like mine, and your BSSID was 8D:AE:9D:65:1F:B2 (a BSSID I just made up), your command would look like:
reaver -i mon0 -b 8D:AE:9D:65:1F:B2 -vv
Press Enter, sit back, and let Reaver work its disturbing magic. Reaver will now try a series of PINs on the router in a brute force attack, one after another. This will take a while. In my successful test, Reaver took 2 hours and 30 minutes to crack the network and deliver me with the correct password. As mentioned above, the Reaver documentation says it can take between 4 and 10 hours, so it could take more or less time than I experienced, depending. When Reaver's cracking has completed, it'll look like this:
S
A few important factors to consider: Reaver worked exactly as advertised in my test, but it won't necessarily work on all routers (see more below). Also, the router you're cracking needs to have a relatively strong signal, so if you're hardly in range of a router, you'll likely experience problems, and Reaver may not work. Throughout the process, Reaver would sometimes experience a timeout, sometimes get locked in a loop trying the same PIN repeatedly, and so on. I just let it keep on running, and kept it close to the router, and eventually it worked its way through.
Also of note, you can also pause your progress at any time by pressing Ctrl+C while Reaver is running. This will quit the process, but Reaver will save any progress so that next time you run the command, you can pick up where you left off-as long as you don't shut down your computer (which, if you're running off a live DVD, will reset everything).
How Reaver Works
Now that you've seen how to use Reaver, let's take a quick overview of how Reaver works. The tool takes advantage of a vulnerability in something called Wi-Fi Protected Setup, or WPS. It's a feature that exists on many routers, intended to provide an easy setup process, and it's tied to a PIN that's hard-coded into the device. Reaver exploits a flaw in these PINs; the result is that, with enough time, it can reveal your WPA or WPA2 password.
Since the vulnerability lies in the implementation of WPS, your network should be safe if you can simply turn off WPS (or, even better, if your router doesn't support it in the first place). Unfortunately, as Gallagher points out as Ars, even with WPS manually turned off through his router's settings, Reaver was still able to crack his password.
In a phone conversation, Craig Heffner said that the inability to shut this vulnerability down is widespread. He and others have found it to occur with every Linksys and Cisco Valet wireless access point they've tested. "On all of the Linksys routers, you cannot manually disable WPS," he said. While the Web interface has a radio button that allegedly turns off WPS configuration, "it's still on and still vulnerable.
OpenERP Tutorial: Module creation and modification of the Point Of Sale
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
My native language is french. I have some basic knowledge of english language, thus I translated the tutorial by myself and sometimes by the use of a famous translation service, so I hope the whole text is easily understandable.
Thank you for reading
OpenERP programming is a rather complicated task. It is necessary to know several programming languages and you 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 official documentation and on the Web, as well as number of lines of code, of countless tests, bugs and other gaieties. You know 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 of cashiers for the Point Of Sale.
The context
OpenERP is installed on a Debian server. The client sells products through franchises. Each society can access to OpenERP, 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 cashiers as employees.
Customer demand
How could we make purchases with the Point Of Sale on the same computer (PC) without having to create a session each 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, put them 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 very complicated.
Where it gets complicated is the part of the module, (The Web module), which operates in the Point Of Sale, and which allows to open only one session in the morning, make sales by several cashiers without leaving the Point Of Sale, 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 Of Sale 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.
The source code certainly needs some improvements and optimizations, do not hesitate to share your comments, it will also help me to move further into the intricacies of the OpenERP programming.
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 and the 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, so its entire Web interface will keep our attention.
OpenERP is installed on a Debian server (Dev one). I'm working on a PC running Windows 7 pro. Configure WinSCP
We 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 that we are working on a Windows PC. I have installed OpenERP Version 7.0-20130703-231023 (version therefore dated 03 July 2013).
If you are working directly on the server, you will adapt the guidelines relating to the server administration (files, rights, etc..). The construction of the module remains the same.
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 POS
Source code will be written in english, but texts and labels will be translated later
The module is called pos_cashier.
Once completed, the POS Cashiers Module will appear in the list of installed modules, like in the image below
Warning
The tutorial may seem very long, but I tried to dissect all stages of the implementation of a module and I also tried to explain as best as I could all the source code and the various files that compose the module
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 and the requiered pictures, the js directory that will host the JavaScript file and the xml directory that will host the views of the module.
Also , at the root of the module, there is the Python module and the XML views.
First, we will achieve the module that will allow the creation of the cashiers within OpenERP. The Web part of the module (which is in POS) will be discussed later.
The OpenERP modules are usually placed in the « addons » directory, but I recommend that you create a special directory (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.
Log in using PuTTY (from WinSCP) and enter the following commands:
We assigned the /opt/modules-openerp directory to the user openerp and the group openerp, then we changed the rights.
For our future modules to be taken into account by OpenERP, we have to modify the server configuration file and add 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.
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
Sélectionnez
/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:8069
Then 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
If you copy the code from this page
Beware of Python code indentation. This can be estimated in this article. This is due to the editor I used to write this article.
The source code of the module can be downloaded at the bottom of the page.
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 » parameter
To 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 create the pos_cashier.py file (the module itself).
At the very beginning of the file
We will import the libraries we need for the module.
Sélectionnez
import openerp
from openerp import netsvc, tools, pooler
from openerp.osv import fields, osv
from 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
Sélectionnez
classpos_cashier(osv.osv):
From now on, we must be very careful with the code indentation. You will notice that there is 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 handle Python for apropriate indentation.
If in doubt, do not hesitate to read this page : FAQ PythonFAQ Python and this one : Cours PythonCours Python.
pos_config_id field
Here we record the ID of the Point of Sale of the user. This field relationship with the pos_config table wich contains settings of each Point Of Sale.
cashier_namefield
It is in this field that will record the name of the cashier.
activefield
This 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 is automatically not visible.
_defaults : these are the default values for records .
By default, the active check box in the form will be checked and we automatically retrieve the ID of the Point of Sale 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.
The rule unique(cashier_name, pos_config_id) means that there can be only one cashier with the same name in the same Point Of Sale.
_sql_constraints is an array. You can set multiple rules separated by a comma.
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 original pos_order object of the Point Of sale
This module is in the original directory of Point Of Sale. You find it in the file point_of_sale.py around line 479.
We need to change the create_from_ui () function and add a cashier_name field in the orders table called pos_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.
For our module inherits pos_order module, we will give it the same name
_name
Sélectionnez
_name='pos.order'
And we will add the _inherit statement specifying the name of the parent module
_inherit
Sélectionnez
_inherit='pos.order'
About OpenERP objects inheritance I suggest you to read this page on the publisher's website : OpenERP Object InheritanceOpenERP Object Inheritance.
Attention, this is the documentation for the version 6.x, but the instructions are still valid for 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 explanation
Point Of Sale works with JavaScript scripts.
Orders are stored in the browser (LocalStorage).
See : Principe de fonctionnement du Point De VentePrincipe de fonctionnement du Point De Vente.
As long as you make an order, it is stored in the browser. When you confirm the order, the create_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:
Sélectionnez
for tmp_order in orders:
order = tmp_order['data']
order_id = self.create(cr, uid, {
'name': order['name'],
'user_id': order['user_id'] orFalse,
'session_id': order['pos_session_id'],
'lines': order['lines'],
'pos_reference':order['name'], #<----------COMMA'cashier_name': order['cashier_name'] #<----------ADDTHEFIELDHERE
}, 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 table
This 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
This is the file of the views of pos_cashier module. More exact, there are the views of the cashiers. We will put the views 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.
cashier_view.xml
Sélectionnez
<?xmlversion="1.0"encoding="utf-8"?><openerp><data><recordid="pos_cashier_form"model="ir.ui.view"><fieldname="name">pos.cashier.form</field><fieldname="model">pos.cashier</field><fieldname="arch"type="xml"><formstring="Cashiers"version="7.0"><groupcol="4"><fieldname="cashier_name"/><fieldname="pos_config_id"widget="selection"eval="ref('pos.config.name')"/><fieldname="active"/></group></form></field></record><recordid="pos_cashier_tree"model="ir.ui.view"><fieldname="name">pos.cashier.tree</field><fieldname="model">pos.cashier</field><fieldname="arch"type="xml"><treestring="Cashiers"><fieldname="cashier_name"/><fieldname="pos_config_id"ref="pos.config.name"/><fieldname="active"/></tree></field></record><recordmodel="ir.ui.view"id="pos_cashier_search"><fieldname="name">pos.cashier.search</field><fieldname="model">pos.cashier</field><fieldname="arch"type="xml"><searchstring="PointofSaleCashier"><fieldname="cashier_name"/><filtername="filter_see_all"string="All"domain="['|',('active','=',True),('active','=',False)]"/><filtername="filter_see_active"string="Active"domain="[('active','=',True)]"/><filtername="filter_see_inactive"string="Inactive"domain="[('active','=',False)]"/></search></field></record><!--L'actiondumenu--><recordmodel="ir.actions.act_window"id="action_pos_cashier"><fieldname="name">Cashiers</field><fieldname="type">ir.actions.act_window</field><fieldname="res_model">pos.cashier</field><fieldname="view_type">form</field><fieldname="view_mode">tree,form</field><fieldname="view_id"ref="pos_cashier_tree"/><fieldname="context">{"search_default_filter_see_all":1}</field><fieldname="help"type="html"><pclass="oe_view_nocontent_create">
Click here to create a cashier for the Point Of Sale.
</p></field></record><!--MenugaucheVendeurs--><menuitemname="Cashiers"id="menu_point_of_sale_cashiers"parent="point_of_sale.menu_point_root"sequence="16"groups="point_of_sale.group_pos_manager"/><menuitemid="menu_action_pos_cashier"parent="menu_point_of_sale_cashiers"action="action_pos_cashier"/><!--#--></data></openerp>
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)
When you add the string attribute in a field, this is the text that will be displayed (instead of 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" attribute
With the « eval » attribute, we ask OpenERP to display the name of the Point Of Sale
name="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 page
Here we specify, with the col attribute, the number of columns to use.
Form fields appear like this
Here's how the cashiers creation form will be displayed
name="filter_see_all"
Here we call the filter : filter_see_all.
string="All"
This is the word that will be displayed in the search form
domain="['|', ('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 parameters
here, 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 a filter to display inactive cashiers in order to activate them when needed.
The other two filters will display the active or inactive cashiers
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, but it 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 the future you decide to add a menu in this heading, only authorized users in the group can see it..
I present to you the creation of the menu before the creation of the action for a better understanding, but in fact, the code will require that the menu is written after the action, because as referring to the action, if the menu is written before, Python will return the error action_pos_cashier does not exist.
id
As usual, it specifies an identifier for the heading.
parent
This 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 file of the Point Of Sale. As this menu does not belong to our module, we refer to it by using the usual dot syntax.
sequence
This is the number that is used to sort the heading. The lower the number, the higher the heading is.
groups
We 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 by a comma.
A menu which has no action attribute becomes a heading
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 this heading.
The menu appears in the Menu tab of the POS/Manager group (from Configuration/Groups menu) as shown in the image below.
Here we can see the sorting of the menus according to their sequence.
When we click on the Cashiers menu, the following action will be executed.
action_pos_cashier
Sélectionnez
<recordmodel="ir.actions.act_window"id="action_pos_cashier"><fieldname="name">Cashiers</field><fieldname="type">ir.actions.act_window</field><fieldname="res_model">pos.cashier</field><fieldname="view_type">form</field><fieldname="view_mode">tree,form</field><fieldname="view_id"ref="pos_cashier_tree"/><fieldname="context">{"search_default_filter_see_all":1}</field><fieldname="help"type="html"><pclass="oe_view_nocontent_create">
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_window table of OpenERP).
name="type"
This is the type of the action
name="res_model"
This is the name of the table used
name="view_type"
This is the type of the view
name="view_mode"
This is the type of available views. Here we will allow form view and tree view. There is another type of view, the Kaban 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 created earlier. 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.
In the Point Of Sale, when we will click on the « Cashiers » menu, the tee view will appear with the « All » filter that will display all cashiers. A « Create » button will be displayed on top of the table.
You will notice that we put the identifier of the original view, and do not forget to precede with the name of the original module (dot syntax), since this view does not belong to our module, but to its parent.
In the tree view, we will replace the user_id field (User of the Point Of Sale) by cashier_name field.
Remember that we create this module for several cashiers can place orders without having to log in each time the cashier changes. This is why we do not want the user name of the 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 wich cashier has made such sale.
As we have defined the menu access to a particular group, we will now apply some security policies on the module to restrict access and set a rule on the records.
We will create a special file in the security directory of the module.
/opt/modules-openerp/pos_cashier/security
The 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.
name
The name of the rule. It will appear in the configuration pages of OpenERP.
model_id:id
The table to which this rule applies. The table name should always be prefixed with model_.
group_id:id
The user group to which this rule applies.
perm_read
Permission to read the data (1 or 0).
perm_write
Permission to modify the data (1 or 0).
perm_create
Permission to create data (1 or 0).
perm_unlink
Permission 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.
Now let's define a record rule to ensure that the manager of a Point Of Sale can create a cashier for its Point Of Sale only.
When creating a cashier, if the manager selects a Point Of Sale in the list which does not belong to him, an error message 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 call pos_cashier_security.xml.
pos_cashier_security.xml
Sélectionnez
<?xmlversion="1.0"encoding="utf-8"?><openerp><datanoupdate="0"><recordid="rule_pos_cashier"model="ir.rule"><fieldname="name">Point Of Sale Cashiers</field><fieldname="model_id"ref="model_pos_cashier"/><fieldname="global"eval="True"/><fieldname="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 of OpenERP).
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,
domain_force
Sélectionnez
[('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
If you click on this rule, it appears in the form below.
For your module displays an icon in the Configuration/Modules menu of OpenERP, we'll just create a PNG image of 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/img
At the loading of OpenERP, and at the loading of the modules, the application looks for icon.png file into this directory to display next to the name of the module.
All files that we have created are added to the data[] array in the __ openerp__.py file See here.
We still can not install our module, because as we stated other files in the __ openerp__.py file, if they are not created, 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 that will 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 different web interface.
When we are finished, you will see the cashiers list at the bottom left of the Point Of Sale, under the keypad, as shown in the image below.
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.
openerp_pos_cashier() function
It 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() function
We will change that for our module is taken into account in the Point Of Sale.
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 by studying 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 in the code, do not hesitate to contact me to let me know.
Then we will instantiate some objects:
Sélectionnez
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 QWebDocummentation QWeb _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 close button is at the top of the Point Of Sale. As you will see later, we import the close button of Point Of Sale, this instance is required.
We then declare a global variable. We will use it further to store the name of the selected cashier.
Global variable
Sélectionnez
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';
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 record is 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 of the database.
With the correct settings, you can get the data from the table. We will see this later.
We will then create a function that will be called from the POS interface (when onchange() event of the cashiers list, for example).
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 if you uncomment this line, you will see the message in the Firebug console each time the cashier_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 the values you expect.
Obviously, you do not forget to remove your console.log() commands or comment them before going into production.
Finally, the last little tip, if you use console.log() by passing an object, you will not forget to 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 the payment 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 the Point 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 the payment 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 a function that disables many payment buttons that are dynamically generated.
The standart payment interface with
several payment buttons
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 of the cashiers drop down list.
get_cashiers()
Sélectionnez
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 ='<optionvalue="'+ 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{//iftherearenocashier
self.$('#AlertNoCashier').css('display','block');
self.$('.gotopay-button').attr('disabled','disabled');}});},
We first create an empty array
Sélectionnez
var cashier_list =[];
Then we make a query with the fetch() function that we seen earlier.
Sélectionnez
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 cashiers who belong to the Point Of Sale which pos_config_id is equal to config_id we have passed as a parameter AND that are active!
Then we will create options of the drop down list with the function that is performed after the query.
Sélectionnez
.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 ='<optionvalue="'+ 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{//iftherearenocashier
self.$('#AlertNoCashier').css('display','block');
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 we disable the Pay button.
You also see that once the list of the cashiers is built, it stores the name of the first cashier in the globalCashier global 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 initialize the Point Of Sale.
renderElement()
Sélectionnez
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 of point_of_sale module.
This module will allow us to add a function to the original module.PaymentScreenWidget module (which is in screen.js file of point_of_sale module), again with the include() function
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 on the payment page and on the receipt.
It will then record the name of the cashier in the current order with the following function
The PaypadWidget module is the original one created for the Point Of Sale. This is the one that was removed before it was next to the keypad, which was replaced with the Pay button.
Here we will add instructions in the original function refresh() of ReceiptScreenWidget module that is in screen.js file 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).
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).
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.
As for the other original Point Of Sale modules, these are extensions of PosBaseWidget module.
We assign the template view with the following statement:
Sélectionnez
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 will see just after this module (in its container, somehow).
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 the GoToPayButtonWidget template view , we add the init() function that goes well, then we also add the renderElement() function.
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.
This is the module that creates the orders, which stores them in the browser (LocalStorage), and which then sends the 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 or three things.
I put the code of the module and I'll explain only the functions or objects I added.
At the beginning of the module, we will add a cashier_name field to the order.
initialize()
Sélectionnez
initialize: function(attributes){
Backbone.Model.prototype.initialize.apply(this, arguments);this.set({creationDate: newDate(),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 ={};//seeScreenSelectorthis.receipt_type ='receipt';//'receipt'||'invoice'returnthis;},
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.
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 of CashierPayScreenWidget module.
So when the payment page will be displayed, the name of the cashier will be sent to the order.
Now we will modify the function that sends the order to the database.
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_sale module.
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.
/opt/modules-openerp/pos_cashiers/static/src/xml
pos_cashier.xml
Sélectionnez
<?xmlversion="1.0"encoding="UTF-8"?><!--vim:fdl=1:--><templatesid="template"xml:space="preserve"><!--Cashiersdrop-downlistunderNumPad--><tt-extend="PosWidget"><tt-jquery="footer"t-operation="append"><divid="AlertNoCashier">You must create at least one cashier!</div><divid="cashier-footer"><divid="cashier-title">
Select a cashier :
</div><divid="cashier-frame"><tt-esc="widget.get_cashiers(widget.get_cur_pos_config_id())"/><selectid="cashier-select"></select></div></div></t></t><!--NameofthecashieronPayementPage--><tt-extend="PaymentScreenWidget"><tt-jquery=".pos-step-container"t-operation="prepend"><divid="pay-screen-cashier">Cashier :
<spanid="pay-screen-cashier-name"></span></div></t></t><!--NameofthecashieronTicket--><tt-extend="PosTicket"><tt-jquery="#header-ticket"t-operation="append">
Cashier : <spanid="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.
We will place the dropdown cashiers under the keypad.
PosWidget
Sélectionnez
<!--Cashiersdrop-downlistunderNumPad--><tt-extend="PosWidget"><tt-jquery="footer"t-operation="append"><divid="AlertNoCashier">You must create at least one cashier!</div><divid="cashier-footer"><divid="cashier-title">
Select a cashier :
</div><divid="cashier-frame"><tt-esc="widget.get_cashiers(widget.get_cur_pos_config_id())"/><selectid="cashier-select"></select></div></div></t></t>
To modify the original view, we use the t-extend attribute.
Then, just as in the XML views of Python module where we used the position attribute to place objects before, after or in place of the objects of the original template, we will use here the t-operation attribute preceded with the t-jquery attribute to specify the object of original template.
t-jquery
Sélectionnez
<tt-jquery="footer"t-operation="append"><divid="AlertNoCashier">You must create at least one cashier!</div><divid="cashier-footer"><divid="cashier-title">
Select a cashier :
</div><divid="cashier-frame"><tt-esc="widget.get_cashiers(widget.get_cur_pos_config_id())"/><selectid="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.
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.
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 » link
Then 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.
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 make them 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/i18n
From 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
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 the file by clicking the download link.
Rename the file to pos_cashier.pot.
And open it with your text editor.
pos_cashier.pot
Sélectionnez
# 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"
"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:0
msgid "All"
msgstr ""
#. module: pos_cashier
#: model:ir.model,name:pos_cashier.model_pos_order
msgid "Point of Sale"
msgstr ""
#. module: pos_cashier
#: model:ir.actions.act_window,help:pos_cashier.action_pos_cashier
msgid "<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:0
msgid "Point of Sale Cashier"
msgstr ""
#. module: pos_cashier
#: field:pos.cashier,cashier_name:0
#: field:pos.order,cashier_name:0
msgid "Cashier"
msgstr ""
#. module: pos_cashier
#: view:pos.cashier:0
msgid "Inactive"
msgstr ""
#. module: pos_cashier
#: help:pos.cashier,active:0
msgid "If a cashier is not active, it will not be displayed in POS"
msgstr ""
#. module: pos_cashier
#: sql_constraint:pos.cashier:0
msgid "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:0
msgid "Active"
msgstr ""
#. module: pos_cashier
#: model:ir.model,name:pos_cashier.model_pos_cashier
msgid "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:0
msgid "Cashiers"
msgstr ""
#. module: pos_cashier
#: field:pos.cashier,pos_config_id:0
msgid "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 that we 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, we also want to translate the word « cashier », etc..
We will add portions of code as below.
pos_cashier.pot
Sélectionnez
#. module: pos_cashier
#. openerp-web
#: code:static/src/xml/pos_cashier.xml:9
#, python-format
msgid "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 by the 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.
Please note that the string to be translated is in front of the msgid keyword. This is the identifier of the chain. On the next 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
Sélectionnez
#. module: pos_cashier
#: help:pos.cashier,active:0
msgid "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:0
msgid ""
"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 . For different 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!