Merge lp:~andrei-levin/openerp-pos/openerp-pos into lp:openerp-pos

Proposed by Andrei Levin
Status: Needs review
Proposed branch: lp:~andrei-levin/openerp-pos/openerp-pos
Merge into: lp:openerp-pos
Diff against target: 857 lines (+791/-0)
12 files modified
pos_fiscal_printer/__init__.py (+23/-0)
pos_fiscal_printer/__openerp__.py (+47/-0)
pos_fiscal_printer/ecr.py (+75/-0)
pos_fiscal_printer/fiscal_printer.py (+211/-0)
pos_fiscal_printer/fiscal_printer_view.xml (+99/-0)
pos_fiscal_printer/readme.txt (+52/-0)
pos_fiscal_printer/security/ir.model.access.csv (+7/-0)
pos_fiscal_printer/static/src/js/pos_fiscal_printer.js (+65/-0)
pos_fp_dummy/__init__.py (+22/-0)
pos_fp_dummy/__openerp__.py (+41/-0)
pos_fp_dummy/driver.py (+139/-0)
pos_fp_dummy/dummy.xml (+10/-0)
To merge this branch: bzr merge lp:~andrei-levin/openerp-pos/openerp-pos
Reviewer Review Type Date Requested Status
Yannick Vaucher @ Camptocamp description Needs Fixing
Review via email: mp+196201@code.launchpad.net

Description of the change

Added modules that gives possibility to print on a Fiscal Printer

To post a comment you must log in.
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Please improve the description

Anything to do to setup the fiscol printer ?

review: Needs Fixing (description)
Revision history for this message
Andrei Levin (andrei-levin) wrote :

This module creates a base for printing to fiscal printer. It contains
all the functions that can be useful for creating a "driver" - a
simple module which contains functions that should be different for
various printer models.
The second module is a "dummy" driver that shows how to write a driver.

2014-03-14 10:49 GMT+01:00 Yannick Vaucher @ Camptocamp
<email address hidden>:
> Review: Needs Fixing description
>
> Please improve the description
>
> Anything to do to setup the fiscol printer ?
> --
> https://code.launchpad.net/~andrei-levin/openerp-pos/openerp-pos/+merge/196201
> You are the owner of lp:~andrei-levin/openerp-pos/openerp-pos.

--
Didotech Srl

Via T.Aspetti, 248
35133 Padova (PD)

Tel 049 8592286
Cell.: 347-2426694
www.didotech.com

3. By Andrei Levin

Fix: Resolved problems with non administrator user

4. By Andrei Levin

[pos_fiscal_printer]: Refactoring: removed duplicated code, added new function dry_print() to base Ecr class. This function save receipt as text file every time "dry run" is selected.

5. By Andrei Levin

[pos_fp_dummy]: Changed to use payments instead of journals

Unmerged revisions

5. By Andrei Levin

[pos_fp_dummy]: Changed to use payments instead of journals

4. By Andrei Levin

[pos_fiscal_printer]: Refactoring: removed duplicated code, added new function dry_print() to base Ecr class. This function save receipt as text file every time "dry run" is selected.

3. By Andrei Levin

Fix: Resolved problems with non administrator user

2. By Andrei Levin

Added readme file

1. By Andrei Levin

Initial commit

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'pos_fiscal_printer'
=== added file 'pos_fiscal_printer/__init__.py'
--- pos_fiscal_printer/__init__.py 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/__init__.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,23 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Didotech srl (<http://www.didotech.com>)
5# All Rights Reserved
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import fiscal_printer
23
024
=== added file 'pos_fiscal_printer/__openerp__.py'
--- pos_fiscal_printer/__openerp__.py 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/__openerp__.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,47 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013-2014 Didotech srl (<http://www.didotech.com>)
5# All Rights Reserved
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{
22 'name': 'Fiscal Printer Management',
23 'version': '0.0.3',
24 'category': 'Point Of Sale',
25 'description': """
26 This module adds possibility to print a receipt on fiscal printer
27 It prepares all values you may need when writing driver for your printer.
28
29 """,
30 'author': 'Andrei Levin',
31 'depends': [
32 'point_of_sale',
33 ],
34 'init_xml': [
35 ],
36 'update_xml': [
37 'security/ir.model.access.csv', # load access rights after groups
38 'fiscal_printer_view.xml',
39 ],
40 'demo_xml': [],
41 'installable': True,
42 'active': False,
43 'js': [
44 'static/src/js/pos_fiscal_printer.js',
45 ],
46}
47
048
=== added file 'pos_fiscal_printer/ecr.py'
--- pos_fiscal_printer/ecr.py 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/ecr.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,75 @@
1# -*- coding: utf-8 -*-
2###############################################################################
3#
4# Copyright (c) 2013-2014 Andrei Levin (andrei.levin at didotech.com)
5# All Rights Reserved.
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20###############################################################################
21
22import tempfile
23import os
24from datetime import datetime
25
26
27class Ecr():
28 reference = ''
29
30 def __init__(self, config, cash_register_name):
31 self.__name__ = config.name
32 self.config = config
33 self.cash_register_name = cash_register_name
34
35 def get_product_line(self):
36 if self.product_lines:
37 line = self.product_lines.pop(0)
38 self.subtotal += line.price_subtotal
39 if line.discount:
40 self.discount += line.product_id.list_price * line.qty - line.price_subtotal
41 return line
42 else:
43 return False
44
45 def create(self, receipt):
46 self.discount = 0.0
47 self.subtotal = 0.0
48 self.product_lines = receipt.lines
49 self.receipt_data = receipt
50 self.receipt_data.cash_register_name = self.cash_register_name
51
52 self.receipt = self.compose()
53
54 def __unicode__(self):
55 return u'\r\n'.join(self.receipt) + u'\r\n\r\n'
56
57 def __str__(self):
58 return u'\r\n'.join(self.receipt) + u'\r\n\r\n'
59
60 def compose(self):
61 pass
62
63 def print_receipt(self):
64 pass
65
66 def dry_print(self):
67 destination = os.path.join(tempfile.gettempdir(), 'fp_tmp')
68 if not os.path.exists(destination):
69 os.makedirs(destination)
70 ticket = datetime.now().strftime("%Y%m%d.%H%M") + '.txt'
71
72 file(os.path.join(destination, ticket), 'w').write(
73 unicode(self).encode('utf8'))
74
75 return True
076
=== added file 'pos_fiscal_printer/fiscal_printer.py'
--- pos_fiscal_printer/fiscal_printer.py 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/fiscal_printer.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,211 @@
1# -*- coding: utf-8 -*-
2###############################################################################
3#
4# Copyright (c) 2013-2014 Andrei Levin (andrei.levin at didotech.com)
5# All Rights Reserved.
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20###############################################################################
21
22from openerp import netsvc
23from openerp.osv import fields, osv
24from openerp.tools.translate import _
25
26import time
27import datetime
28import pooler
29
30import logging
31_logger = logging.getLogger(__name__)
32_logger.setLevel(logging.INFO)
33
34
35class pos_order(osv.osv):
36 _inherit = "pos.order"
37
38 def create_from_ui(self, cr, uid, orders, context=None):
39 #_logger.info("orders: %r", orders)
40 order_ids = []
41 # print orders
42
43 for tmp_order in orders:
44 order = tmp_order['data']
45 order_id = self.create(cr, uid, {
46 'name': order['name'],
47 'user_id': order['user_id'] or False,
48 'session_id': order['pos_session_id'],
49 'lines': order['lines'],
50 'pos_reference': order['name']
51 }, context)
52
53 for payments in order['statement_ids']:
54 payment = payments[2]
55 self.add_payment(cr, uid, order_id, {
56 'amount': payment['amount'] or 0.0,
57 'payment_date': payment['name'],
58 'statement_id': payment['statement_id'],
59 'payment_name': payment.get('note', False),
60 'journal': payment['journal_id']
61 }, context=context)
62
63 if order['amount_return']:
64 session = self.pool['pos.session'].browse(
65 cr, uid, order['pos_session_id'], context=context)
66 cash_journal = session.cash_journal_id
67
68 if not cash_journal:
69 cash_journal_ids = filter(
70 lambda st: st.journal_id.type == 'cash', session.statement_ids)
71 if not len(cash_journal_ids):
72 raise osv.except_osv(_('error!'),
73 _("No cash statement found for this session. Unable to record returned cash."))
74 cash_journal = cash_journal_ids[0].journal_id
75 self.add_payment(cr, uid, order_id, {
76 'amount': -order['amount_return'],
77 'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'),
78 'payment_name': _('return'),
79 'journal': cash_journal.id,
80 }, context=context)
81 order_ids.append(order_id)
82 wf_service = netsvc.LocalService("workflow")
83 wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr)
84
85 self.print_receipt(cr, uid, order_id, order['pos_session_id'], context)
86
87 return order_ids
88
89 def print_receipt(self, cr, uid, order_id, pos_session_id, context):
90 receipt = Receipt(cr, uid, order_id, context)
91 printer = fiscal_printer(cr, uid, pos_session_id)
92 printer.print_receipt(receipt)
93
94
95class Receipt():
96 def __init__(self, cr, uid, order_id, context=None):
97 self.pool = pooler.get_pool(cr.dbname)
98
99 self.order = self.pool['pos.order'].browse(cr, uid, order_id, context)
100
101 utc_date_order = datetime.datetime.strptime(
102 self.order.date_order, '%Y-%m-%d %H:%M:%S')
103 self.date = fields.datetime.context_timestamp(
104 cr, uid, utc_date_order, context=context)
105 self.name = self.order.name
106 self.reference = self.order.pos_reference
107 self.user = self.pool['res.users'].browse(cr, uid, uid)
108
109 self.lines = self.order.lines
110 self.amount_total = self.order.amount_total
111 self.amount_paid = self.order.amount_paid
112 self.amount_tax = self.order.amount_tax
113 self.amount_return = self.order.amount_return
114 self.payments = self.order.statement_ids
115
116
117class fiscal_printer():
118 def __init__(self, cr, uid, pos_session_id):
119 self.pool = pooler.get_pool(cr.dbname)
120 fp_config_obj = self.pool['fp.config']
121 pos_session = self.pool['pos.session'].browse(cr, uid, pos_session_id)
122 cash_register_id = pos_session.config_id.id
123
124 printer_configs = fp_config_obj.search(
125 cr, uid, [('cash_register_id', '=', cash_register_id)])
126 self.cash_register = self.pool['pos.config'].browse(cr, uid, cash_register_id)
127
128 if printer_configs:
129 self.config = fp_config_obj.browse(cr, uid, printer_configs[0])
130 else:
131 raise osv.except_osv(
132 'Warning', _('Cash register {cash_register} has no fiscal printers'.format(cash_register=self.cash_register.name)))
133
134 module = __import__(self.config.driver_id.module + '.driver', fromlist=[str(self.config.driver_id.class_name)])
135 self.driver = getattr(module, str(self.config.driver_id.class_name))(self.config, self.cash_register.name)
136
137 def print_receipt(self, receipt):
138 self.driver.create(receipt)
139 if self.config.dry:
140 _logger.info('Discarding receipt for order {0}'.format(receipt.reference))
141 self.driver.dry_print()
142 else:
143 if self.driver.print_receipt():
144 _logger.info('Receipt for {0} printed successfully'.format(receipt.reference))
145 else:
146 _logger.error('There are problems with printing Receipt for {0}'.format(receipt.reference))
147
148
149class fp_config(osv.osv):
150 _name = 'fp.config'
151 _description = "Fiscal Printer configuration"
152
153 def _get_name(self, cr, uid, ids, field_name, arg, context=None):
154 if not ids:
155 return {}
156
157 res = {}
158
159 configs = self.browse(cr, uid, ids)
160
161 for config in configs:
162 res[config.id] = config.cash_register_id.name + \
163 ' : ' + config.driver_id.name
164
165 return res
166
167 _columns = {
168 "name": fields.function(_get_name, string='Name', type='char', method=True),
169 'cash_register_id': fields.many2one('pos.config', 'Cash Register', required=True),
170 "driver_id": fields.many2one('fp.driver', "Driver", required=True, help="Printer driver used for this client"),
171 'ecr_password': fields.char("Password ECR", size=16, required=False, help="Password, if needed to print to fiscal printer"),
172 'host': fields.char("Fiscal Printer Host Address", size=15, required=False, help="Fiscal Printer IP Address or Hostname (if Hostname can be resolved)"),
173 'port': fields.integer("Port", required=False, help="Fiscal Printer Port"),
174 'user': fields.char("Username", size=15, required=False, help="Username, if needed to access fiscal printer"),
175 'password': fields.char("Password", size=15, required=False, help="Password, if needed to access fiscal printer"),
176 'destination': fields.char("Destination", size=256, required=False, help="Destination directory, where receipt should be placed"),
177 'dry': fields.boolean('Dry Run')
178 }
179
180 _sql_constraints = [
181 ('cash_register_uniq', 'unique(cash_register_id)', 'Cash register must be unique!')
182 ]
183
184
185class fp_driver(osv.osv):
186 _name = 'fp.driver'
187 _description = "Fiscal Printer Drivers"
188
189 _columns = {
190 'name': fields.char("FP Description", size=32, required=True, help="The Description of the Fiscal Printer"),
191 'class_name': fields.char("Class Name", size=32, required=True, help="Name of the class that contain driver for printing on Fiscal Printer"),
192 'module': fields.char("Driver module name", size=32, required=True, help="The name of the driver module"),
193 }
194
195
196class department(osv.osv):
197 _name = 'department'
198 _description = "Tax department"
199
200 _columns = {
201 'name': fields.char("Department description", size=32, required=True, help="The Description of the department"),
202 'department': fields.integer("Department", required=True)
203 }
204
205
206class account_tax(osv.osv):
207 _inherit = 'account.tax'
208
209 _columns = {
210 'department': fields.many2one('department', 'Department', required=False)
211 }
0212
=== added file 'pos_fiscal_printer/fiscal_printer_view.xml'
--- pos_fiscal_printer/fiscal_printer_view.xml 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/fiscal_printer_view.xml 2014-07-10 14:31:27 +0000
@@ -0,0 +1,99 @@
1<openerp>
2 <data>
3
4 <record id="view_fp_config_form" model="ir.ui.view">
5 <field name="name">fp.config.form</field>
6 <field name="model">fp.config</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">
9 <form string="Configure Fiscal Printer">
10 <field name="name"/>
11 <field name="cash_register_id"/>
12 <field name="driver_id" />
13 <field name="ecr_password" />
14 <field name="host" />
15 <field name="port" />
16 <field name="user" />
17 <field name="password" />
18 <field name="destination" />
19 <separator colspan="4" />
20 <field name="dry" />
21 </form>
22 </field>
23 </record>
24
25 <record id="view_fp_config_tree" model="ir.ui.view">
26 <field name="name">fp.config.tree</field>
27 <field name="model">fp.config</field>
28 <field name="type">tree</field>
29 <field name="arch" type="xml">
30 <tree string="Cash Registers">
31 <field name="name"/>
32 <field name="host" />
33 <field name="cash_register_id"/>
34 <field name="driver_id" />
35 </tree>
36 </field>
37 </record>
38
39 <record id="action_fiscal_printer" model="ir.actions.act_window">
40 <field name="name">Fiscal Printer Configuration</field>
41 <field name="res_model">fp.config</field>
42 <field name="view_type">form</field>
43 <field name="view_mode">tree,form</field>
44 <field name="view_id" ref="view_fp_config_tree"/>
45 </record>
46
47 <!-- Menu Definitions -->
48 <menuitem id="cash_register" name="Fiscal Printer" parent="point_of_sale.menu_point_config_product" action="action_fiscal_printer"/>
49
50 <!-- Add field department to account.tax -->
51 <record id="view_account_tax_department_form" model="ir.ui.view">
52 <field name="name">account.tax.department.form</field>
53 <field name="model">account.tax</field>
54 <field name="inherit_id" ref="account.view_tax_form" />
55 <field name="type">form</field>
56 <field name="arch" type="xml">
57 <field name="description" position="after">
58 <field name="department"/>
59 </field>
60 </field>
61 </record>
62
63 <record id="view_department_form" model="ir.ui.view">
64 <field name="name">department.form</field>
65 <field name="model">department</field>
66 <field name="type">form</field>
67 <field name="arch" type="xml">
68 <form string="Configure Department">
69 <field name="name"/>
70 <field name="department"/>
71 </form>
72 </field>
73 </record>
74
75 <record id="view_department_tree" model="ir.ui.view">
76 <field name="name">department.tree</field>
77 <field name="model">department</field>
78 <field name="type">tree</field>
79 <field name="arch" type="xml">
80 <tree string="Departments">
81 <field name="name"/>
82 <field name="department"/>
83 </tree>
84 </field>
85 </record>
86
87 <record id="action_department" model="ir.actions.act_window">
88 <field name="name">Department Configuration</field>
89 <field name="res_model">department</field>
90 <field name="view_type">form</field>
91 <field name="view_mode">tree,form</field>
92 <field name="view_id" ref="view_department_tree"/>
93 </record>
94
95 <!-- Menu Definitions -->
96 <menuitem id="department" name="Department Configuration" parent="point_of_sale.menu_point_config_product" action="action_department"/>
97
98 </data>
99</openerp>
0\ No newline at end of file100\ No newline at end of file
1101
=== added file 'pos_fiscal_printer/readme.txt'
--- pos_fiscal_printer/readme.txt 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/readme.txt 2014-07-10 14:31:27 +0000
@@ -0,0 +1,52 @@
1This module creates all that is necessary to print on a Fiscal Printer.
2
3The solution is composed of 2 modules:
4- pos_fiscal_printer - a core module
5- pos_fp_<driver name> - driver module
6
7Core module:
8- disable printing from browser
9- create configuration menu inside POS
10- add departments
11- load driver
12- prepare all the data needed for creating a receipt
13
14Driver module:
15- compose a receipt
16- sent receipt to printer
17
18Menu Fiscal Printer gives you a possibility to match a Fiscal Printer
19to a POS. Very often Fiscal Printers has only program for Windows,
20which they call "Driver". This resident program expects to find a
21receipt file in some directory. When it finds a new receipt it is
22interpreted and send to a printer. We can't write to a file system
23directly from JavaScript, so Client start printing and then Server
24send a receipt to a computer which has fiscal printer attached.
25Sometimes we also need to wright a password for the Fiscal Printer
26inside receipt. This is the reason for 2 password fields.
27
28Another type of printers accept printing via ethernet. Again we need
29host/user/password.
30
31An ECR (Electronic Cash Register) should register a
32"department". Department depends on tax paid, so inside my Dummy
33driver you will see:
34reparto = line.product_id.taxes_id[0].department.department
35
36Core module creates Department table, which should be compiled (in
37Italy there are 3 main Departments: Reparto 1, Reparto 2, Reparto 3)
38with corresponding numbers. These numbers are used to tell ECR to
39which department a product belongs. After compiling the table, one
40should go to Accounting / Configuration and select a right department
41for the tax.
42
43There is another option which can sound strange - "Dry Run". When we
44print a receipt and something goes wrong, receipt will not disappear,
45every time we try to print it will be send to a Fiscal Printer, so if
46for any reason a receipt can't be printed it will block our POS until
47the problem is resolved (a red ball appears in the right upper angle
48of the POS). In this case one can select "Dry Run" option and when one
49enters POS the queue will be emptied and a red ball became green. This
50option can also be used if some receipts were printed directly from
51ECR and one want to register this selling without reprinting a
52receipt.
053
=== added directory 'pos_fiscal_printer/security'
=== added file 'pos_fiscal_printer/security/ir.model.access.csv'
--- pos_fiscal_printer/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/security/ir.model.access.csv 2014-07-10 14:31:27 +0000
@@ -0,0 +1,7 @@
1id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2access_fp_config_user,fp.config_user,model_fp_config,point_of_sale.group_pos_user,1,1,1,1
3access_fp_config_manager,fp.config_manager,model_fp_config,point_of_sale.group_pos_manager,1,1,1,1
4access_fp_driver_user,fp.driver_user,model_fp_driver,point_of_sale.group_pos_user,1,1,1,1
5access_fp_driver_manager,fp.driver_manager,model_fp_driver,point_of_sale.group_pos_manager,1,1,1,1
6access_department_user,fp.department_user,model_department,point_of_sale.group_pos_user,1,1,1,1
7access_department,fp.department_manager,model_department,point_of_sale.group_pos_manager,1,1,1,1
08
=== added directory 'pos_fiscal_printer/static'
=== added directory 'pos_fiscal_printer/static/src'
=== added directory 'pos_fiscal_printer/static/src/js'
=== added file 'pos_fiscal_printer/static/src/js/pos_fiscal_printer.js'
--- pos_fiscal_printer/static/src/js/pos_fiscal_printer.js 1970-01-01 00:00:00 +0000
+++ pos_fiscal_printer/static/src/js/pos_fiscal_printer.js 2014-07-10 14:31:27 +0000
@@ -0,0 +1,65 @@
1openerp.pos_fiscal_printer = function(instance) {
2 // loading the namespace of the 'point_of_sale' module
3 var module = instance.point_of_sale;
4 var _t = instance.web._t;
5
6 module.ReceiptScreenWidget.include({
7
8 show: function(){
9 var self = this;
10
11 this.hidden = false;
12 if(this.$el){
13 this.$el.show();
14 }
15
16 if(this.pos_widget.action_bar.get_button_count() > 0){
17 this.show_action_bar();
18 }else{
19 this.hide_action_bar();
20 }
21
22 // we add the help button by default. we do this because the buttons are cleared on each refresh so that
23 // the button stay local to each screen
24 this.pos_widget.left_action_bar.add_new_button({
25 label: _t('Help'),
26 icon: '/point_of_sale/static/src/img/icons/png48/help.png',
27 click: function(){ self.help_button_action(); },
28 });
29
30 var self = this;
31 var cashier_mode = this.pos_widget.screen_selector.get_user_mode() === 'cashier';
32
33 this.pos_widget.set_numpad_visible(this.show_numpad && cashier_mode);
34 this.pos_widget.set_leftpane_visible(this.show_leftpane);
35 this.pos_widget.set_left_action_bar_visible(this.show_leftpane && !cashier_mode);
36 this.pos_widget.set_cashier_controls_visible(cashier_mode);
37
38 if(cashier_mode && this.pos.iface_self_checkout){
39 this.pos_widget.client_button.show();
40 }else{
41 this.pos_widget.client_button.hide();
42 }
43 if(cashier_mode){
44 this.pos_widget.close_button.show();
45 }else{
46 this.pos_widget.close_button.hide();
47 }
48
49 this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode());
50
51 this.pos.barcode_reader.set_action_callback({
52 'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined ,
53 'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined ,
54 'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined ,
55 'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined,
56 });
57
58 this.add_action_button({
59 label: _t('Next Order'),
60 icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
61 click: function() { self.finishOrder(); },
62 });
63 },
64 });
65}
066
=== added directory 'pos_fp_dummy'
=== added file 'pos_fp_dummy/__init__.py'
--- pos_fp_dummy/__init__.py 1970-01-01 00:00:00 +0000
+++ pos_fp_dummy/__init__.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,22 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Didotech srl (<http://www.didotech.com>)
5# All Rights Reserved
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22
023
=== added file 'pos_fp_dummy/__openerp__.py'
--- pos_fp_dummy/__openerp__.py 1970-01-01 00:00:00 +0000
+++ pos_fp_dummy/__openerp__.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,41 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013-2014 Didotech.com (<http://www.didotech.com>)
5# All Rights Reserved
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{
22 'name': 'Dummy FP driver',
23 'version': '0.0.2',
24 'category': 'Point Of Sale',
25 'description': """
26 This module contains Fiscal Printer "Dummy" driver.
27 It can be used as an example and for testing purpose.
28 """,
29 'author': 'Andrei Levin',
30 'depends': [
31 'pos_fiscal_printer',
32 ],
33 'init_xml': [
34 'dummy.xml',
35 ],
36 'update_xml': [
37 ],
38 'demo_xml': [],
39 'installable': True,
40 'active': False,
41}
042
=== added file 'pos_fp_dummy/driver.py'
--- pos_fp_dummy/driver.py 1970-01-01 00:00:00 +0000
+++ pos_fp_dummy/driver.py 2014-07-10 14:31:27 +0000
@@ -0,0 +1,139 @@
1# -*- coding: utf-8 -*-
2###############################################################################
3#
4# Copyright (c) 2013-2014 Andrei Levin (andrei.levin at didotech.com)
5# All Rights Reserved.
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20###############################################################################
21
22import os
23import tempfile
24
25from pos_fiscal_printer.ecr import Ecr
26
27
28def italian_number(number, precision=1, no_zero=False):
29 if not number:
30 return '0,00'
31
32 if number < 0:
33 sign = '-'
34 else:
35 sign = ''
36 # Requires Python >= 2.7:
37 # before, after = "{:.{digits}f}".format(number, digits=precision).split('.')
38 # Works with Python 2.6:
39 before, after = "{0:10.{digits}f}".format(
40 number, digits=precision).strip('- ').split('.')
41
42 belist = []
43 end = len(before)
44 for i in range(3, len(before) + 3, 3):
45 start = len(before) - i
46 if start < 0:
47 start = 0
48 belist.append(before[start: end])
49 end = len(before) - i
50 before = '.'.join(reversed(belist))
51
52 if no_zero and int(number) == float(number):
53 return sign + before
54 else:
55 return sign + before + ',' + after
56
57
58class Dummy(Ecr):
59 def compose(self):
60 '''
61 line attributes:
62 product_id - Product
63 order_id - Order Ref
64 price_unit - Unit Price
65 price_subtotal - Subtotal w/o Tax
66 company_id - Company
67 price_subtotal_incl - Subtotal
68 qty - Quantity
69 discount - Discount (%)
70 name - Line No
71 receipt attributes:
72 payments
73 '''
74 receipt = self.receipt_data
75 ticket = []
76 ticket.append(receipt.date.strftime(
77 '%d/%m/%Y %H:%M:%S') + ' ' + receipt.reference)
78 ticket.append(u'')
79 ticket.append(receipt.user.company_id.name)
80 ticket.append(u'Phone: ' + str(receipt.user.company_id.phone))
81 ticket.append(u'User: ' + receipt.user.name)
82 ticket.append(u'POS: ' + receipt.cash_register_name)
83 ticket.append(u'')
84
85 line = self.get_product_line()
86 while line:
87 qty = italian_number(line.qty, 1, True)
88
89 if line.product_id and line.product_id.taxes_id and line.product_id.taxes_id[0]:
90 reparto = line.product_id.taxes_id[0].department.department
91 else:
92 reparto = 1
93
94 ticket.append(u"rep={reparto} {name:<24}{qty: ^3}{price:>6.2f} €".format(
95 reparto=reparto, name=line.product_id.name, qty=qty, price=line.price_subtotal_incl))
96
97 if line.discount:
98 ticket.append(
99 u'With a {discount}% discount'.format(discount=line.discount))
100
101 line = self.get_product_line()
102
103 ticket.append(u'')
104
105 ticket.append(u'{text:<30}{subtotal:>9.2f} €'.format(
106 text='Subtotal: ', subtotal=self.subtotal))
107 ticket.append(
108 u'Tax: {tax:9.2f} €'.format(tax=receipt.amount_tax))
109 ticket.append(
110 u'Discount: {discount:9.2f} €'.format(discount=self.discount))
111 ticket.append(
112 u'Total: {total:9.2f} €'.format(total=receipt.amount_total))
113
114 ticket.append(u'')
115
116 for payment in receipt.payments:
117 ticket.append(u'{name:<30}{amount:9.2f} €'.format(
118 name=payment.name_get()[0][1], amount=payment.amount))
119
120 ticket.append(u'')
121
122 ticket.append(
123 u'Change: {a_return:9.2f} €'.format(a_return=receipt.amount_return))
124
125 return ticket
126
127 def print_receipt(self):
128 if self.config.destination:
129 destination = self.config.destination
130 else:
131 destination = os.path.join(tempfile.gettempdir(), 'opentmp')
132 if not os.path.exists(destination):
133 os.makedirs(destination)
134 ticket = 'ticket.txt'
135
136 file(os.path.join(destination, ticket), 'w').write(
137 unicode(self).encode('utf8'))
138
139 return True
0140
=== added file 'pos_fp_dummy/dummy.xml'
--- pos_fp_dummy/dummy.xml 1970-01-01 00:00:00 +0000
+++ pos_fp_dummy/dummy.xml 2014-07-10 14:31:27 +0000
@@ -0,0 +1,10 @@
1<?xml version="1.0"?>
2<openerp>
3 <data>
4 <record id="fp_driver" model="fp.driver">
5 <field name="class_name">Dummy</field>
6 <field name="name">Dummy driver</field>
7 <field name="module">pos_fp_dummy</field>
8 </record>
9 </data>
10</openerp>

Subscribers

People subscribed via source and target branches