Merge lp:~camptocamp/openobject-addons/6.0-fix-l10n_ch-20110914 into lp:openobject-addons/6.0

Proposed by Yannick Vaucher @ Camptocamp
Status: Needs review
Proposed branch: lp:~camptocamp/openobject-addons/6.0-fix-l10n_ch-20110914
Merge into: lp:openobject-addons/6.0
Diff against target: 2892 lines (+1825/-504)
30 files modified
l10n_ch/__openerp__.py (+6/-3)
l10n_ch/account_move_line.py (+0/-87)
l10n_ch/bank.py (+31/-10)
l10n_ch/bank_view.xml (+190/-27)
l10n_ch/company.py (+17/-0)
l10n_ch/company_view.xml (+14/-6)
l10n_ch/demo/demo.xml (+0/-2)
l10n_ch/dta.py (+0/-85)
l10n_ch/dta_data.xml (+11/-26)
l10n_ch/dta_view.xml (+0/-37)
l10n_ch/invoice.py (+4/-4)
l10n_ch/journal_data.xml (+2/-2)
l10n_ch/partner.py (+0/-31)
l10n_ch/report/bvr.mako (+45/-2)
l10n_ch/report/report_webkit_html.mako (+1/-1)
l10n_ch/report/report_webkit_html.py (+132/-78)
l10n_ch/report/report_webkit_html_view.xml (+51/-49)
l10n_ch/sterchi_chart/account.xml (+2/-2)
l10n_ch/sterchi_chart/fiscal_position.xml (+1/-1)
l10n_ch/test/l10n_ch_dta.yml (+221/-0)
l10n_ch/test/l10n_ch_v11.yml (+161/-0)
l10n_ch/test/l10n_ch_v11_part.yml (+292/-0)
l10n_ch/test/test.v11 (+2/-0)
l10n_ch/test/test_part_1.v11 (+2/-0)
l10n_ch/test/test_part_2.v11 (+2/-0)
l10n_ch/wizard/__init__.py (+3/-2)
l10n_ch/wizard/bvr_import.py (+7/-6)
l10n_ch/wizard/create_dta.py (+35/-27)
l10n_ch/wizard/create_dta_view.xml (+1/-16)
l10n_ch/wizard/unicode2ascii.py (+592/-0)
To merge this branch: bzr merge lp:~camptocamp/openobject-addons/6.0-fix-l10n_ch-20110914
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+75354@code.launchpad.net

This proposal supersedes a proposal from 2011-09-14.

Description of the change

Multiple fix, improvments and adds to l10n_ch from Camptocamp swiss localization

To post a comment you must log in.
Revision history for this message
xrg (xrg) wrote : Posted in a previous version of this proposal

From the very first quick look I had at the diff:

=== ....
=== modified file 'l10n_ch/sample/README' (properties changed: -x to +x)
=== modified file 'l10n_ch/sample/sample.dta' (properties changed: -x to +x)
=== modified file 'l10n_ch/sample/sample.v11' (properties changed: -x to +x)
=== modified file 'l10n_ch/sample/zvr_besrtechdok_fr.pdf' (properties changed: -
x to +x)
.... etc.

Please, do not turn on the executable bit on data files. It produces errors
when trying to package OpenERP.

Also, if you are including files from other python projects, please be prepared
to answer:
 - are these files just standalone, or part of any other python "library"? In
the second case, why not call this library instead of copying (bundling) the
file?
 - what is the copyright of the files? License, distribution policy?

--
Say NO to spam and viruses. Stop using Microsoft Windows!

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote : Posted in a previous version of this proposal

Thanks for the warning, I updated the branch by reverting those unwanted chmod changes.

Unmerged revisions

4823. By Yannick Vaucher @ Camptocamp

[FIX] revert chmod -x

4822. By Yannick Vaucher @ Camptocamp

[MRG] from c2c l10n_ch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'l10n_ch/__openerp__.py'
2--- l10n_ch/__openerp__.py 2011-02-09 08:59:05 +0000
3+++ l10n_ch/__openerp__.py 2011-09-14 14:11:28 +0000
4@@ -61,8 +61,8 @@
5
6
7 """,
8- "version" : "6.0",
9- "author" : "Camptocamp SA",
10+ "version" : "6.1",
11+ "author" : "Camptocamp",
12 "category" : "Localization/Account Charts",
13 "website": "http://www.camptocamp.com",
14
15@@ -84,10 +84,10 @@
16 ],
17 "demo_xml" : [
18 "demo/demo.xml",
19+ "demo/dta_demo.xml",
20 ],
21 "update_xml" : [
22 "wizard.xml",
23- "dta_view.xml",
24 "wizard/bvr_import_view.xml",
25 "wizard/create_dta_view.xml",
26 "company_view.xml",
27@@ -98,6 +98,9 @@
28 ],
29 'test' : [
30 'test/l10n_ch_report.yml',
31+ 'test/l10n_ch_dta.yml',
32+ 'test/l10n_ch_v11.yml',
33+ 'test/l10n_ch_v11_part.yml',
34 ],
35 "active": False,
36 "installable": True,
37
38=== removed file 'l10n_ch/account_move_line.py'
39--- l10n_ch/account_move_line.py 2011-01-14 12:41:54 +0000
40+++ l10n_ch/account_move_line.py 1970-01-01 00:00:00 +0000
41@@ -1,87 +0,0 @@
42-# -*- coding: utf-8 -*-
43-#
44-# account_move_line.py
45-# l10n_ch
46-#
47-# Created by Nicolas Bessi based on Credric Krier contribution
48-#
49-# Copyright (c) 2009 CamptoCamp. All rights reserved.
50-##############################################################################
51-#
52-# WARNING: This program as such is intended to be used by professional
53-# programmers who take the whole responsability of assessing all potential
54-# consequences resulting from its eventual inadequacies and bugs
55-# End users who are looking for a ready-to-use solution with commercial
56-# garantees and support are strongly adviced to contract a Free Software
57-# Service Company
58-#
59-# This program is Free Software; you can redistribute it and/or
60-# modify it under the terms of the GNU General Public License
61-# as published by the Free Software Foundation; either version 2
62-# of the License, or (at your option) any later version.
63-#
64-# This program is distributed in the hope that it will be useful,
65-# but WITHOUT ANY WARRANTY; without even the implied warranty of
66-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67-# GNU General Public License for more details.
68-#
69-# You should have received a copy of the GNU General Public License
70-# along with this program; if not, write to the Free Software
71-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
72-#
73-##############################################################################
74-
75-from osv import fields, osv
76-# -*- encoding: utf-8 -*-
77-##############################################################################
78-#
79-# Author: Nicolas Bessi. Copyright Camptocamp SA
80-# Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
81-#
82-# This program is free software: you can redistribute it and/or modify
83-# it under the terms of the GNU Affero General Public License as
84-# published by the Free Software Foundation, either version 3 of the
85-# License, or (at your option) any later version.
86-#
87-# This program is distributed in the hope that it will be useful,
88-# but WITHOUT ANY WARRANTY; without even the implied warranty of
89-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90-# GNU Affero General Public License for more details.
91-#
92-# You should have received a copy of the GNU Affero General Public License
93-# along with this program. If not, see <http://www.gnu.org/licenses/>.
94-#
95-##############################################################################
96-
97-class AccountMoveLine(osv.osv):
98- """ Inherit account.move.line in order to add a custom link
99- between supplier invoice line and bank. The original link
100- was defined in account_payment between line """
101-
102- _inherit = 'account.move.line'
103-
104- def line2bank(self, cr, uid, ids, payment_type='manual', context=None):
105- """add a link to account.move.line in order to link
106- supplier invoice line and bank. The original link
107- was defined in account_payment"""
108- payment_mode_obj = self.pool.get('payment.mode')
109- line2bank = {}
110- if not ids:
111- return {}
112- bank_type = payment_mode_obj.suitable_bank_types(cr, uid, payment_type,
113- context=context)
114- for line in self.browse(cr, uid, ids, context=context):
115- if line.invoice and line.invoice.partner_bank_id:
116- line2bank[line.id] = line.invoice.partner_bank_id.id
117- elif line.partner_id:
118- for bank in line.partner_id.bank_ids:
119- if bank.state in bank_type:
120- line2bank[line.id] = bank.id
121- break
122- if line.id not in line2bank and line.partner_id.bank_ids:
123- line2bank[line.id] = line.partner_id.bank_ids[0].id
124- return line2bank
125-
126-AccountMoveLine()
127-
128-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
129
130=== modified file 'l10n_ch/bank.py'
131--- l10n_ch/bank.py 2011-01-14 12:41:54 +0000
132+++ l10n_ch/bank.py 2011-09-14 14:11:28 +0000
133@@ -33,15 +33,36 @@
134
135 Bank()
136
137-class bvr_checkbox(osv.osv):
138- """ Add function to generate function """
139+
140+class ResPartnerBank(osv.osv):
141 _inherit = "res.partner.bank"
142-
143+
144 _columns = {
145- 'print_bank' : fields.boolean('Print Bank on BVR'),
146- 'print_account' : fields.boolean('Print Account Number on BVR'),
147- }
148-
149-bvr_checkbox()
150-
151-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
152+ 'name': fields.char('Description', size=128, required=True),
153+ 'post_number': fields.char('Post number', size=64),
154+ 'bvr_adherent_num': fields.char('BVR adherent number', size=11),
155+ 'dta_code': fields.char('DTA code', size=5),
156+ 'print_bank': fields.boolean('Print Bank on BVR'),
157+ 'print_account': fields.boolean('Print Account Number on BVR'),
158+ 'my_bank': fields.boolean('Print BVR ?', help="Check to print BVR invoices"),
159+ }
160+
161+ def name_get(self, cursor, uid, ids, context=None):
162+ if not len(ids):
163+ return []
164+ bank_type_obj = self.pool.get('res.partner.bank.type')
165+
166+ type_ids = bank_type_obj.search(cursor, uid, [])
167+ bank_type_names = {}
168+ for bank_type in bank_type_obj.browse(cursor, uid, type_ids,
169+ context=context):
170+ bank_type_names[bank_type.code] = bank_type.name
171+ res = []
172+ for r in self.read(cursor, uid, ids, ['name','state'], context):
173+ res.append((r['id'], r['name']+' : '+bank_type_names.get(r['state'], '')))
174+ return res
175+
176+ _sql_constraints = [('bvr_adherent_uniq', 'unique (bvr_adherent_num)',
177+ 'The BVR adherent number must be unique !')]
178+
179+ResPartnerBank()
180
181=== modified file 'l10n_ch/bank_view.xml'
182--- l10n_ch/bank_view.xml 2011-01-14 00:11:01 +0000
183+++ l10n_ch/bank_view.xml 2011-09-14 14:11:28 +0000
184@@ -24,31 +24,194 @@
185 </field>
186 </field>
187 </record>
188-
189- <record model="ir.ui.view" id="l10nch_view_res_partner_bank">
190- <field name="name">res.partner_bank.form</field>
191- <field name="model">res.partner.bank</field>
192- <field name="type">form</field>
193- <field name="inherit_id" ref="base.view_partner_bank_form"/>
194- <field name="arch" type="xml">
195- <field name="country_id" position="after">
196- <field name="print_bank"/>
197- <field name="print_account"/>
198- </field>
199- </field>
200- </record>
201- <record model="ir.ui.view" id="l10nch_view_res_partner_bank">
202- <field name="name">res.partner_partner_bank.form</field>
203- <field name="model">res.partner</field>
204- <field name="type">form</field>
205- <field name="inherit_id" ref="account.view_partner_property_form"/>
206- <field name="arch" type="xml">
207- <field name="bank" position="after">
208- <newline />
209- <field name="print_bank"/>
210- <field name="print_account"/>
211- </field>
212- </field>
213- </record>
214+ <!-- res.partner.bank in res partner form-->
215+
216+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f1">
217+ <field name="name">res.partner_bank.form.hide.f1</field>
218+ <field name="model">res.partner</field>
219+ <field name="type">form</field>
220+ <field name="sequence" eval="9" /> <!-- we do this to be called before base iban view -->
221+ <field name="inherit_id" ref="account.view_partner_property_form"/>
222+ <field name="arch" type="xml">
223+ <field name="acc_number" position="replace">
224+ </field>
225+ </field>
226+ </record>
227+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f2">
228+ <field name="name">res.partner_bank.form.hide.f2</field>
229+ <field name="model">res.partner</field>
230+ <field name="type">form</field>
231+ <field name="inherit_id" ref="account.view_partner_property_form"/>
232+ <field name="arch" type="xml">
233+ <field name="bank" position="replace">
234+ </field>
235+ </field>
236+ </record>
237+
238+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_add_groups">
239+ <field name="name">res.partner_bank.form.hide.f2</field>
240+ <field name="model">res.partner</field>
241+ <field name="type">form</field>
242+ <field name="sequence" eval="10" /> <!-- we do this to be called before base iban view -->
243+ <field name="inherit_id" ref="account.view_partner_property_form"/>
244+ <field name="arch" type="xml">
245+ <field name="state" position="after">
246+ <newline/>
247+ <separator colspan="4" string="Account infos"/>
248+ <group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
249+ <field name="acc_number"/>
250+ <field name="dta_code"/>
251+ <newline/>
252+ </group>
253+ <newline/>
254+ <group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
255+ <field name="post_number"/>
256+ <newline/>
257+ </group>
258+ <separator colspan="4" string="financial institute infos"/>
259+ <field name="my_bank"/>
260+ <group string="BVR print options" colspan="4" attrs="{'invisible': [('my_bank','!=', True)]}" >
261+ <field name="bvr_adherent_num"/>
262+ <field name="print_bank"/>
263+ <field name="print_account"/>
264+ <newline/>
265+ </group>
266+ <field name="bank" />
267+ </field>
268+ </field>
269+ </record>
270+
271+
272+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f4">
273+ <field name="name">res.partner_bank.form.hide.f1</field>
274+ <field name="model">res.partner</field>
275+ <field name="type">form</field>
276+ <field name="sequence" eval="9" /> <!-- we do this to be called before base iban view -->
277+ <field name="inherit_id" ref="base.view_partner_bank_form"/>
278+ <field name="arch" type="xml">
279+ <field name="acc_number" position="replace">
280+ </field>
281+ </field>
282+ </record>
283+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f5">
284+ <field name="name">res.partner_bank.form.hide.f2</field>
285+ <field name="model">res.partner</field>
286+ <field name="type">form</field>
287+ <field name="inherit_id" ref="base.view_partner_bank_form"/>
288+ <field name="arch" type="xml">
289+ <field name="bank" position="replace">
290+ </field>
291+ </field>
292+ </record>
293+
294+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_add_groups2">
295+ <field name="name">res.partner_bank.form.hide.f2</field>
296+ <field name="model">res.partner</field>
297+ <field name="type">form</field>
298+ <field name="sequence" eval="10" /> <!-- we do this to be called before base iban view -->
299+ <field name="inherit_id" ref="base.view_partner_bank_form"/>
300+ <field name="arch" type="xml">
301+ <field name="state" position="after">
302+ <newline/>
303+ <separator colspan="4" string="Account infos"/>
304+ <group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
305+ <field name="acc_number"/>
306+ <field name="dta_code"/>
307+ <newline/>
308+ </group>
309+ <newline/>
310+ <group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
311+ <field name="post_number"/>
312+ <newline/>
313+ <field name="my_bank"/>
314+ <group string="BVR print options" colspan="4" attrs="{'invisible': [('my_bank','!=', True)]}" >
315+ <field name="bvr_adherent_num"/>
316+ <field name="print_bank"/>
317+ <field name="print_account"/>
318+ <newline/>
319+ </group>
320+ </group>
321+ <separator colspan="4" string="Financial institute infos"/>
322+ </field>
323+ </field>
324+ </record>
325+
326+ <!-- res.partner.bank base form-->
327+
328+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_acc_number_hide_frominvoice">
329+ <field name="name">res.partner_bank.form.hide.acc_number.frominvoice</field>
330+ <field name="model">res.partner.bank</field>
331+ <field name="type">form</field>
332+ <field name="sequence" eval="9" /> <!-- we do this to be called before base iban view -->
333+ <field name="inherit_id" ref="base_iban.view_partner_bank_iban_form"/>
334+ <field name="arch" type="xml">
335+ <field name="acc_number" position="replace">
336+ </field>
337+ </field>
338+ </record>
339+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_bank_frominvoice2">
340+ <field name="name">res.partner_bank.form.hide.bank.frominvoice</field>
341+ <field name="model">res.partner.bank</field>
342+ <field name="type">form</field>
343+ <field name="sequence" eval="9" /> <!-- we do this to be called before base iban view -->
344+ <field name="inherit_id" ref="base_iban.view_partner_bank_iban_form"/>
345+ <field name="arch" type="xml">
346+ <field name="bank" position="replace">
347+ </field>
348+ </field>
349+ </record>
350+
351+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_bank_frominvoice3">
352+ <field name="name">res.partner_bank.form.hide.bank.frominvoice</field>
353+ <field name="model">res.partner.bank</field>
354+ <field name="type">form</field>
355+ <field name="sequence" eval="16" /> <!-- we do this to be called before base iban view -->
356+ <field name="inherit_id" ref="base_iban.view_partner_bank_iban_form"/>
357+ <field name="arch" type="xml">
358+ <field name="iban" position="replace">
359+ </field>
360+ </field>
361+ </record>
362+
363+
364+ <record model="ir.ui.view" id="l10nch_view_res_partner_bank_from_invoice">
365+ <field name="name">res.partner_bank.form.hide.frominvoice</field>
366+ <field name="model">res.partner.bank</field>
367+ <field name="type">form</field>
368+ <field name="sequence" eval="10" /> <!-- we do this to be called before base iban view -->
369+ <field name="inherit_id" ref="base_iban.view_partner_bank_iban_form"/>
370+ <field name="arch" type="xml">
371+ <field name="state" position="after">
372+ <newline/>
373+ <separator colspan="4" string="Account infos"/>
374+ <group string="IBAN account info" colspan="4" attrs="{'invisible': [('state','not in', ['iban'])]}" >
375+ <field name="iban"/>
376+ <newline/>
377+ </group>
378+
379+ <group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
380+ <field name="acc_number"/>
381+ <field name="dta_code"/>
382+ <newline/>
383+ </group>
384+ <newline/>
385+ <group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
386+ <field name="post_number"/>
387+ <newline/>
388+ <field name="my_bank"/>
389+ <group string="BVR print options" colspan="4" attrs="{'invisible': [('my_bank','!=', True)]}" >
390+ <field name="bvr_adherent_num"/>
391+ <field name="print_bank"/>
392+ <field name="print_account"/>
393+ <newline/>
394+ </group>
395+ </group>
396+ <field name="bank" />
397+ </field>
398+ </field>
399+ </record>
400+
401+
402+
403 </data>
404-</openerp>
405+</openerp>
406\ No newline at end of file
407
408=== modified file 'l10n_ch/company.py'
409--- l10n_ch/company.py 2011-02-09 08:59:05 +0000
410+++ l10n_ch/company.py 2011-09-14 14:11:28 +0000
411@@ -33,6 +33,16 @@
412 'bvr_delta_vert': fields.float('BVR Vert. Delta (mm)',
413 help='vert. delta in mm 1.2 will print the bvr 1.2mm lower, negative value is possible'),
414
415+ 'bvr_scan_line_vert': fields.float('BVR vert. position for scan line (mm)',
416+ help='Vert. position in mm for scan line'),
417+
418+ 'bvr_scan_line_horz': fields.float('BVR horiz. position for scan line(mm)',
419+ help='Horiz. position in mm for scan line'),
420+
421+ 'bvr_scan_line_font_size': fields.float('BVR scan line font size (pt)'),
422+
423+ 'bvr_scan_line_letter_spacing':fields.float('BVR scan line letter spacing'),
424+
425 'bvr_background': fields.boolean('Insert BVR background ?'),
426
427 'bvr_only': fields.boolean('Separated BVR only ?',
428@@ -41,6 +51,13 @@
429 'invoice_only': fields.boolean('Invoice only (Do not use with bvr only)?',
430 help='Print only the invoice without BVR'),
431 }
432+
433+ _defaults = {
434+ 'bvr_scan_line_vert': lambda *a: 232,
435+ 'bvr_scan_line_horz': lambda *a: 72,
436+ 'bvr_scan_line_font_size': lambda *a: 12,
437+ 'bvr_scan_line_letter_spacing': lambda *a: 0,
438+ }
439
440 res_company()
441
442
443=== modified file 'l10n_ch/company_view.xml'
444--- l10n_ch/company_view.xml 2011-01-14 12:41:54 +0000
445+++ l10n_ch/company_view.xml 2011-09-14 14:11:28 +0000
446@@ -8,13 +8,21 @@
447 <field name="inherit_id" ref="base.view_company_form"/>
448 <field name="arch" type="xml">
449 <field name="rml_footer2" position="after">
450- <field name="bvr_delta_horz"/>
451- <field name="bvr_delta_vert"/>
452- <field name="bvr_background"/>
453- <field name="bvr_only"/>
454- <field name="invoice_only"/>
455+ <newline/>
456+ <group string="BVR data" colspan="4">
457+ <field name="bvr_delta_horz"/>
458+ <field name="bvr_delta_vert"/>
459+ <field name="bvr_scan_line_vert"/>
460+ <field name="bvr_scan_line_horz"/>
461+ <field name="bvr_scan_line_font_size"/>
462+ <field name="bvr_scan_line_letter_spacing"/>
463+ <field name="bvr_background"/>
464+ <field name="bvr_only"/>
465+ <field name="invoice_only"/>
466+ </group>
467+ <newline/>
468 </field>
469 </field>
470 </record>
471 </data>
472-</openerp>
473+</openerp>
474\ No newline at end of file
475
476=== modified file 'l10n_ch/demo/demo.xml'
477--- l10n_ch/demo/demo.xml 2011-02-09 08:59:05 +0000
478+++ l10n_ch/demo/demo.xml 2011-09-14 14:11:28 +0000
479@@ -15,8 +15,6 @@
480 <field name="bank" ref="main_bank"/>
481 <field name="iban">CH9100767000S00023455</field>
482 <field name="bvr_adherent_num">0000000</field>
483-
484-
485 </record>
486
487 <record id="bank" model="res.partner">
488
489=== removed file 'l10n_ch/dta.py'
490--- l10n_ch/dta.py 2011-01-14 12:41:54 +0000
491+++ l10n_ch/dta.py 1970-01-01 00:00:00 +0000
492@@ -1,85 +0,0 @@
493-# -*- encoding: utf-8 -*-
494-##############################################################################
495-#
496-# Author: Nicolas Bessi. Copyright Camptocamp SA
497-# Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
498-#
499-# This program is free software: you can redistribute it and/or modify
500-# it under the terms of the GNU Affero General Public License as
501-# published by the Free Software Foundation, either version 3 of the
502-# License, or (at your option) any later version.
503-#
504-# This program is distributed in the hope that it will be useful,
505-# but WITHOUT ANY WARRANTY; without even the implied warranty of
506-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
507-# GNU Affero General Public License for more details.
508-#
509-# You should have received a copy of the GNU Affero General Public License
510-# along with this program. If not, see <http://www.gnu.org/licenses/>.
511-#
512-##############################################################################
513-
514-import time
515-from osv import osv, fields
516-
517-class account_dta(osv.osv):
518- """class that implements bank DTA File format,
519- used to transfert bulk batch payment instruction to a bank"""
520- _name = "account.dta"
521- _description = "DTA History"
522- _columns = {
523- ### name of the file
524- 'name': fields.binary('DTA file', readonly=True),
525- ### list of dta line linked to the dta order
526- 'dta_line_ids': fields.one2many('account.dta.line','dta_id','DTA lines', readonly=True),
527- ## textual notes
528- 'note': fields.text('Creation log', readonly=True,
529- help="Displays the problem during dta generation"),
530- ### bank how will execute DTA order
531- 'bank': fields.many2one('res.partner.bank','Bank', readonly=True,select=True,
532- help="Bank how will execute DTA order"),
533- ### date of DTA order generation
534- 'date': fields.date('Creation Date', readonly=True,select=True,
535- help="Date of DTA order generation"),
536- ### user how generate the DTA order
537- 'user_id': fields.many2one('res.users','User', readonly=True, select=True),
538- }
539-account_dta()
540-
541-class account_dta_line(osv.osv):
542- """Class that represent a DTA order line,
543- each line corressponds to a payment instruction"""
544- _name = "account.dta.line"
545- _description = "DTA line"
546- _columns = {
547- ### name of the line
548- 'name' : fields.many2one('account.invoice','Invoice', required=True, size=256),
549- ### partner how will receive payments
550- 'partner_id' : fields.many2one('res.partner','Partner',
551- help="Partenr to pay"),
552- ### due date of the payment
553- 'due_date' : fields.date('Due date'),
554- ### date of the supplier invoice to pay
555- 'invoice_date' : fields.date('Invoice date'),
556- ### cash discount date
557- 'cashdisc_date' : fields.date('Cash Discount date'),
558- ### amount effectively paied on this line
559- 'amount_to_pay' : fields.float('Amount to pay',
560- help="Amount effectively paid"),
561- ### amount that was on the supplier invoice
562- 'amount_invoice': fields.float('Invoiced Amount',
563- help="Amount to pay base on the supplier invoice"),
564- ### Cash discount amount
565- 'amount_cashdisc': fields.float('Cash Discount Amount'),
566- ### Linke to the main dta order
567- 'dta_id': fields.many2one('account.dta','Associated DTA', required=True, ondelete='cascade'),
568- ### state of the invoice Drat, Cancel, Done
569- 'state' : fields.selection([('draft','Draft'),('cancel','Error'),('done','Paid')],'State')
570- }
571- _defaults = {
572- 'state' : lambda *a :'draft',
573- }
574-
575-account_dta_line()
576-
577-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
578\ No newline at end of file
579
580=== modified file 'l10n_ch/dta_data.xml'
581--- l10n_ch/dta_data.xml 2011-05-25 11:51:33 +0000
582+++ l10n_ch/dta_data.xml 2011-09-14 14:11:28 +0000
583@@ -30,33 +30,27 @@
584 <field name="code">dta_company</field>
585 </record>
586
587- <record model="res.partner.bank.type" id="dta_iban">
588- <field name="name">DTA-IBAN</field>
589- <field name="code">dta_iban</field>
590- </record>
591-
592 <record model="res.partner.bank.type" id="bvrbank">
593- <field name="name">DTA-BVRBANK</field>
594+ <field name="name">BVR Bank</field>
595 <field name="code">bvrbank</field>
596 </record>
597
598 <record model="res.partner.bank.type" id="bvrpost">
599- <field name="name">DTA-BVRPOST</field>
600+ <field name="name">BVR Post</field>
601 <field name="code">bvrpost</field>
602 </record>
603
604 <record model="res.partner.bank.type" id="bvpost">
605- <field name="name">DTA-BVPOST</field>
606+ <field name="name">BV Post</field>
607 <field name="code">bvpost</field>
608 </record>
609
610 <record model="res.partner.bank.type" id="bvbank">
611- <field name="name">DTA-BVBANK</field>
612+ <field name="name">BV Bank</field>
613 <field name="code">bvbank</field>
614 </record>
615
616
617-
618 <!-- Adjust the fields attributes for dta_company-->
619 <record model="res.partner.bank.type.field" id="iban_field">
620 <field name="name">iban</field>
621@@ -64,22 +58,13 @@
622 <field name="required" eval="True"/>
623 <field name="readonly" eval="False"/>
624 </record>
625-
626-
627- <!-- Adjust the fields attributes for dta_iban-->
628- <record model="res.partner.bank.type.field" id="iban_field_iban">
629+
630+ <record model="res.partner.bank.type.field" id="iban_field_bvr_bank">
631 <field name="name">iban</field>
632- <field name="bank_type_id" ref="dta_iban"/>
633- <field name="required" eval="True"/>
634- <field name="readonly" eval="False"/>
635- </record>
636- <record model="res.partner.bank.type.field" id="bank_field_iban">
637- <field name="name">bank</field>
638- <field name="bank_type_id" ref="dta_iban"/>
639- <field name="required" eval="True"/>
640- <field name="readonly" eval="False"/>
641- </record>
642-
643+ <field name="bank_type_id" ref="bvrbank"/>
644+ <field name="required" eval="False"/>
645+ <field name="readonly" eval="False"/>
646+ </record>
647
648 <!-- Adjust the fields attributes for bvrbank-->
649 <record model="res.partner.bank.type.field" id="bank_field_bvrbank">
650@@ -139,4 +124,4 @@
651 </record>
652
653 </data>
654-</openerp>
655\ No newline at end of file
656+</openerp>
657
658=== removed file 'l10n_ch/dta_view.xml'
659--- l10n_ch/dta_view.xml 2011-02-09 08:59:05 +0000
660+++ l10n_ch/dta_view.xml 1970-01-01 00:00:00 +0000
661@@ -1,37 +0,0 @@
662-<?xml version="1.0"?>
663-<openerp>
664- <data>
665-
666- <!-- Inherit both bank view -->
667- <record model="ir.ui.view" id="view_partner_bank_form">
668- <field name="name">partner - bank inherit</field>
669- <field name="model">res.partner</field>
670- <field name="type">form</field>
671- <field name="inherit_id" ref="base.view_partner_form"/>
672- <field name="arch" type="xml">
673- <field name="acc_number" position="after">
674- <newline/>
675- <field name="bvr_adherent_num"/>
676- <field name="post_number"/>
677- <field name="dta_code"/>
678- </field>
679- </field>
680- </record>
681-
682- <record model="ir.ui.view" id="view_partner_bank_form2">
683- <field name="name">partner - bank inherit</field>
684- <field name="model">res.partner.bank</field>
685- <field name="type">form</field>
686- <field name="inherit_id" ref="base.view_partner_bank_form"/>
687- <field name="arch" type="xml">
688- <field name="acc_number" position="after">
689- <newline/>
690- <field name="bvr_adherent_num"/>
691- <field name="post_number"/>
692- <field name="dta_code"/>
693- </field>
694- </field>
695- </record>
696-
697- </data>
698-</openerp>
699
700=== modified file 'l10n_ch/invoice.py'
701--- l10n_ch/invoice.py 2011-02-09 08:59:05 +0000
702+++ l10n_ch/invoice.py 2011-09-14 14:11:28 +0000
703@@ -84,7 +84,7 @@
704 ## @param user res.user.id that is currently loged
705 ## @parma ids invoices id
706 ## @return a boolean True if valid False if invalid
707- def _check_bvr(self, cr, uid, ids):
708+ def _check_bvr(self, cr, uid, ids, context=None):
709 """
710 Function to validate a bvr reference like :
711 0100054150009>132000000000000000000000014+ 1300132412>
712@@ -111,7 +111,7 @@
713 ## @param user res.user.id that is currently loged
714 ## @parma ids invoices id
715 ## @return a boolean True if valid False if invalid
716- def _check_reference_type(self, cursor, user, ids):
717+ def _check_reference_type(self, cursor, user, ids, context=None):
718 """Check the customer invoice reference type depending
719 on the BVR reference type and the invoice partner bank type"""
720 for invoice in self.browse(cursor, user, ids):
721@@ -120,7 +120,7 @@
722 invoice.partner_bank_id.state in \
723 ('bvrbank', 'bvrpost') and \
724 invoice.reference_type != 'bvr':
725- return False
726+ return False
727 return True
728
729 _constraints = [
730@@ -143,7 +143,7 @@
731 def onchange_partner_id(self, cr, uid, ids, type, partner_id,
732 date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
733 """ Function that is call when the partner of the invoice is changed
734- it will retriev and set the good bank partner bank"""
735+ it will retrieve and set the good bank partner bank"""
736 res = super(account_invoice, self).onchange_partner_id(
737 cr,
738 uid,
739
740=== modified file 'l10n_ch/journal_data.xml'
741--- l10n_ch/journal_data.xml 2011-05-25 11:51:33 +0000
742+++ l10n_ch/journal_data.xml 2011-09-14 14:11:28 +0000
743@@ -15,7 +15,7 @@
744 <record id="bank_journal" model="account.journal">
745 <field name="name">Banque CHF</field>
746 <field name="code">BCHF</field>
747- <field name="type">cash</field>
748+ <field name="type">bank</field>
749 <field name="view_id" ref="account.account_journal_bank_view"/>
750 <field name="sequence_id" ref="account.sequence_journal"/>
751 <field name="user_id" ref="base.user_root"/>
752@@ -26,7 +26,7 @@
753 <record id="bank_euro_journal" model="account.journal">
754 <field name="name">Banque EUR</field>
755 <field name="code">BEUR</field>
756- <field name="type">cash</field>
757+ <field name="type">bank</field>
758 <field name="view_id" ref="account.account_journal_bank_view"/>
759 <field name="sequence_id" ref="account.sequence_journal"/>
760 <field name="user_id" ref="base.user_root"/>
761
762=== modified file 'l10n_ch/partner.py'
763--- l10n_ch/partner.py 2011-02-09 08:59:05 +0000
764+++ l10n_ch/partner.py 2011-09-14 14:11:28 +0000
765@@ -30,35 +30,4 @@
766 }
767
768 res_partner()
769-
770-class res_partner_bank(osv.osv):
771- _inherit = "res.partner.bank"
772- _columns = {
773- 'name': fields.char('Description', size=128, required=True),
774- 'post_number': fields.char('Post number', size=64),
775- 'bvr_adherent_num': fields.char('BVR adherent number', size=11),
776- 'dta_code': fields.char('DTA code', size=5),
777- }
778-
779- def name_get(self, cr, uid, ids, context=None):
780- if not len(ids):
781- return []
782- bank_type_obj = self.pool.get('res.partner.bank.type')
783-
784- type_ids = bank_type_obj.search(cr, uid, [])
785- bank_type_names = {}
786- for bank_type in bank_type_obj.browse(cr, uid, type_ids,
787- context=context):
788- bank_type_names[bank_type.code] = bank_type.name
789- res = []
790- for r in self.read(cr, uid, ids, ['name','state'], context):
791- res.append((r['id'], r['name']+' : '+bank_type_names[r['state']]))
792- return res
793-
794- _sql_constraints = [
795- ('bvr_adherent_uniq', 'unique (bvr_adherent_num)', 'The BVR adherent number must be unique !')
796- ]
797-
798-res_partner_bank()
799-
800 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
801\ No newline at end of file
802
803=== modified file 'l10n_ch/report/bvr.mako'
804--- l10n_ch/report/bvr.mako 2011-02-09 08:59:05 +0000
805+++ l10n_ch/report/bvr.mako 2011-09-14 14:11:28 +0000
806@@ -7,6 +7,17 @@
807 font-weight: normal;
808 src: url(${police_absolute_path('ocrbb.ttf')}) format("truetype");
809 }
810+ .ocrbb{
811+ text-align:right;
812+ font-family:bvrocrb;
813+ font-size:${str(company.bvr_scan_line_font_size or '0.0').replace(',','.')}pt;
814+ position:absolute;top:${str(company.bvr_scan_line_vert or '0.0').replace(',','.')}mm;
815+ left:${str(company.bvr_scan_line_horz or '0.0').replace(',','.')}mm;
816+ z-index:4;
817+ letter-spacing:str(company.bvr_scan_line_letter_spacing or '0.0').replace(',','.')
818+ }
819+ ${css}
820+ </style>
821 </style>
822
823 </head>
824@@ -87,9 +98,41 @@
825
826 }
827 </script>
828- ${_check(objects)}
829 %for inv in objects :
830 <% setLang(inv.partner_id.lang) %>
831+ <!--adresses + info block -->
832+ <table class="dest_address" style="position:absolute;top:6mm;left:15mm">
833+ <tr><td ><b>${inv.partner_id.title.name or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
834+ <tr><td>${inv.address_invoice_id.street or ''|entity}</td></tr>
835+ <tr><td>${inv.address_invoice_id.street2 or ''|entity}</td></tr>
836+ <tr><td>${inv.address_invoice_id.zip or ''|entity} ${inv.address_invoice_id.city or ''|entity}</td></tr>
837+ %if inv.address_invoice_id.country_id :
838+ <tr><td>${inv.address_invoice_id.country_id.name or ''|entity} </td></tr>
839+ %endif
840+ %if inv.address_invoice_id.phone :
841+ <tr><td>${_("Tel") |entity}: ${inv.address_invoice_id.phone|entity}</td></tr>
842+ %endif
843+ %if inv.address_invoice_id.fax :
844+ <tr><td>${_("Fax") |entity}: ${inv.address_invoice_id.fax|entity}</td></tr>
845+ %endif
846+ %if inv.address_invoice_id.email :
847+ <tr><td>${_("E-mail") |entity}: ${inv.address_invoice_id.email|entity}</td></tr>
848+ %endif
849+ %if inv.partner_id.vat :
850+ <tr><td>${_("VAT") |entity}: ${inv.partner_id.vat|entity}</td></tr>
851+ %endif
852+ </table>
853+
854+ <div style="position:absolute;top:60mm; left:20mm">
855+ ${_('Invoice')} - ${inv.number or ''|entity}
856+ <br/>
857+ <br/>
858+ ${_('Here is the BVR to allow you to pay the invoice %s - %s') % (inv.name or '', inv.number or '',)}
859+ <br/>
860+ ${_('Regards')}
861+ </div>
862+
863+ <div colspan="2" class="ocrbb">${mod10r('01'+str('%.2f' % inv.amount_total).replace('.','').rjust(10,'0'))}&gt;${_get_ref(inv)}+${inv.partner_bank_id.post_number.split('-')[0]+(str(inv.partner_bank_id.post_number.split('-')[1])).rjust(6,'0')+inv.partner_bank_id.post_number.split('-')[2]}&gt;</div>
864 <div id="cont_${inv.id}" style="padding-left:20mm;padding-top:0;padding-bottom:10;height:180mm">
865 <!-- Your communication message here -->
866 </div>
867@@ -103,7 +146,7 @@
868 <tr style="height:8.4666667mm;vertical-align:bottom;padding-bottom:0"> <td><table style="width:100%" CELLPADDING="0" CELLSPACING="0"><td style="width:4mm"></td><td style="width:40mm;text-align: right" >${_space(('%.2f' % inv.amount_total)[:-3], 1)}</td><td style="width:6mm"></td><td style="width:10mm;text-align: right">${ _space(('%.2f' % inv.amount_total)[-2:], 1)}</td><td style="width:3mm;text-align: right"></td></table></td><td><table style="width:100%" CELLPADDING="0" CELLSPACING="0"><td style="width:4mm"></td><td style="width:40mm;text-align: right" >${_space(('%.2f' % inv.amount_total)[:-3], 1)}</td><td style="width:6mm"></td><td style="width:10mm;text-align: right">${ _space(('%.2f' % inv.amount_total)[-2:], 1)}</td><td style="width:3mm;text-align: right"></td></table></td><td></td></tr>
869 <tr style="height:21.166667mm"><td></td><td></td><td></td></tr>
870 <tr style="height:8.4666667mm"> <td></td><td></td><td></td></tr>
871- <tr style="height:21.166667mm;vertical-align:top"><td></td><td colspan="2" style="text-align:right;padding-right:0.3in;font-family:bvrocrb;font-size:12pt">${mod10r('01'+str('%.2f' % inv.amount_total).replace('.','').rjust(10,'0'))}&gt;${_get_ref(inv)}+${inv.partner_bank_id.post_number.split('-')[0]+(str(inv.partner_bank_id.post_number.split('-')[1])).rjust(6,'0')+inv.partner_bank_id.post_number.split('-')[2]}&gt;</td></tr>
872+ <tr style="height:21.166667mm;vertical-align:top"><td></td><td></td></tr>
873 </table>
874 %endfor
875 </body>
876
877=== modified file 'l10n_ch/report/report_webkit_html.mako'
878--- l10n_ch/report/report_webkit_html.mako 2011-02-09 08:59:05 +0000
879+++ l10n_ch/report/report_webkit_html.mako 2011-09-14 14:11:28 +0000
880@@ -9,7 +9,7 @@
881 <% setLang(inv.partner_id.lang) %>
882 <div id="inv_cont_${inv.id}" style="padding-left:20mm;padding-top:0;padding-bottom:10;border-width:0px;border-style:solid">
883 <table class="dest_address">
884- <tr><td ><b>${inv.partner_id.title or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
885+ <tr><td ><b>${inv.partner_id.title.name or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
886 <tr><td>${inv.address_invoice_id.street or ''|entity}</td></tr>
887 <tr><td>${inv.address_invoice_id.street2 or ''|entity}</td></tr>
888 <tr><td>${inv.address_invoice_id.zip or ''|entity} ${inv.address_invoice_id.city or ''|entity}</td></tr>
889
890=== modified file 'l10n_ch/report/report_webkit_html.py'
891--- l10n_ch/report/report_webkit_html.py 2011-02-09 08:59:05 +0000
892+++ l10n_ch/report/report_webkit_html.py 2011-09-14 14:11:28 +0000
893@@ -33,7 +33,9 @@
894 import pooler
895 from tools.config import config
896 from mako.template import Template
897+from mako import exceptions
898 from tools.translate import _
899+from osv.osv import except_osv
900
901
902 class l10n_ch_report_webkit_html(report_sxw.rml_parse):
903@@ -41,16 +43,15 @@
904 super(l10n_ch_report_webkit_html, self).__init__(cr, uid, name, context=context)
905 self.localcontext.update({
906 'time': time,
907- 'cr':cr,
908+ 'cr': cr,
909 'uid': uid,
910 'user':self.pool.get("res.users").browse(cr, uid, uid),
911 'mod10r': mod10r,
912 '_space': self._space,
913 '_get_ref': self._get_ref,
914 'comma_me': self.comma_me,
915- 'police_absolute_path' : self.police_absolute_path,
916- 'bvr_absolute_path':self.bvr_absolute_path,
917- '_check' : self._check,
918+ 'police_absolute_path': self.police_absolute_path,
919+ 'bvr_absolute_path': self.bvr_absolute_path,
920 'headheight': self.headheight
921 })
922
923@@ -58,15 +59,22 @@
924 _compile_comma_me = re.compile("^(-?\d+)(\d{3})")
925 _compile_check_bvr = re.compile('[0-9][0-9]-[0-9]{3,6}-[0-9]')
926 _compile_check_bvr_add_num = re.compile('[0-9]*$')
927-
928+
929+ def set_context(self, objects, data, ids, report_type=None):
930+ user = self.pool.get('res.users').browse(self.cr, self.uid, self.uid)
931+ company = user.company_id
932+ if not company.invoice_only:
933+ self._check(ids)
934+ return super(l10n_ch_report_webkit_html, self).set_context(objects, data, ids, report_type=report_type)
935+
936 def police_absolute_path(self, inner_path) :
937 """Will get the ocrb police absolute path"""
938- path = addons.get_module_resource(os.path.join('l10n_ch','report',inner_path))
939+ path = addons.get_module_resource(os.path.join('l10n_ch', 'report', inner_path))
940 return path
941
942 def bvr_absolute_path(self) :
943 """Will get the ocrb police absolute path"""
944- path = addons.get_module_resource(os.path.join('l10n_ch','report','bvr1.jpg'))
945+ path = addons.get_module_resource(os.path.join('l10n_ch', 'report', 'bvr1.jpg'))
946 return path
947
948 def headheight(self):
949@@ -76,7 +84,7 @@
950
951 def comma_me(self, amount):
952 """Fast swiss number formatting"""
953- if type(amount) is float :
954+ if isinstance(amount, float):
955 amount = str('%.2f'%amount)
956 else :
957 amount = str(amount)
958@@ -88,14 +96,15 @@
959 return self.comma_me(new)
960
961 def _space(self, nbr, nbrspc=5):
962- """Spaces * 5"""
963- res = ''
964- for i in range(len(nbr)):
965- res = res + nbr[i]
966- if not (i-1) % nbrspc:
967- res = res + ' '
968- return res
969+ """Spaces * 5.
970
971+ Example:
972+ >>> self._space('123456789012345')
973+ '12 34567 89012 345'
974+ """
975+ return ''.join([' '[(i - 2) % nbrspc:] + c for i, c in enumerate(nbr)])
976+
977+
978 def _get_ref(self, inv):
979 """Retrieve ESR/BVR reference form invoice in order to print it"""
980 res = ''
981@@ -106,39 +115,77 @@
982 invoice_number = self._compile_get_ref.sub('', inv.number)
983 return mod10r(res + invoice_number.rjust(26-len(res), '0'))
984
985- def _check(self, invoices):
986+ def _check(self, invoice_ids):
987 """Check if the invoice is ready to be printed"""
988+ if not invoice_ids:
989+ invoice_ids = []
990 cursor = self.cr
991 pool = self.pool
992 invoice_obj = pool.get('account.invoice')
993- ids = [x.id for x in invoices]
994+ ids = invoice_ids
995 for invoice in invoice_obj.browse(cursor, self.uid, ids):
996 if not invoice.partner_bank_id:
997- raise wizard.except_wizard(_('UserError'),
998+ raise except_osv(_('UserError'),
999 _('No bank specified on invoice:\n' + \
1000 invoice_obj.name_get(cursor, self.uid, [invoice.id],
1001 context={})[0][1]))
1002 if not self._compile_check_bvr.match(
1003 invoice.partner_bank_id.post_number or ''):
1004- raise wizard.except_wizard(_('UserError'),
1005- _("Your bank BVR number should be of the form 0X-XXX-X! " +
1006- 'Please check your company ' +
1007- 'information for the invoice:\n' +
1008- invoice_obj.name_get(cursor, self.uid, [invoice.id],
1009- context={})[0][1]))
1010+ raise except_osv(_('UserError'),
1011+ _('Your bank BVR number should be of the form 0X-XXX-X! ' +
1012+ 'Please check your company ' +
1013+ 'information for the invoice:\n' +
1014+ invoice_obj.name_get(cursor, self.uid, [invoice.id],
1015+ context={})[0][1]))
1016 if invoice.partner_bank_id.bvr_adherent_num \
1017 and not self._compile_check_bvr_add_num.match(
1018 invoice.partner_bank_id.bvr_adherent_num):
1019- raise wizard.except_wizard('UserError',
1020- 'Your bank BVR adherent number must contain exactly seven' +
1021- 'digits!\nPlease check your company ' +
1022- 'information for the invoice:\n' +
1023- invoice_obj.name_get(cursor, self.uid, [invoice.id],
1024- context={})[0][1])
1025- return ""
1026+ raise except_osv(_('UserError'),
1027+ _('Your bank BVR adherent number must contain exactly seven' +
1028+ 'digits!\nPlease check your company ' +
1029+ 'information for the invoice:\n' +
1030+ invoice_obj.name_get(cursor, self.uid, [invoice.id],
1031+ context={})[0][1]))
1032+ return ''
1033
1034 class BVRWebKitParser(webkit_report.WebKitParser):
1035
1036+ def setLang(self, lang):
1037+ if not lang:
1038+ lang = 'en_US'
1039+ self.localcontext['lang'] = lang
1040+
1041+ def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False):
1042+ """format using the know cursor, language from localcontext"""
1043+ if digits is None:
1044+ digits = self.parser_instance.get_digits(value)
1045+ if isinstance(value, (str, unicode)) and not value:
1046+ return ''
1047+ pool_lang = self.pool.get('res.lang')
1048+ lang = self.localcontext['lang']
1049+
1050+ lang_ids = pool_lang.search(self.parser_instance.cr, self.parser_instance.uid, [('code','=',lang)])[0]
1051+ lang_obj = pool_lang.browse(self.parser_instance.cr, self.parser_instance.uid, lang_ids)
1052+
1053+ if date or date_time:
1054+ if not str(value):
1055+ return ''
1056+
1057+ date_format = lang_obj.date_format
1058+ parse_format = '%Y-%m-%d'
1059+ if date_time:
1060+ value=value.split('.')[0]
1061+ date_format = date_format + " " + lang_obj.time_format
1062+ parse_format = '%Y-%m-%d %H:%M:%S'
1063+ if not isinstance(value, time.struct_time):
1064+ return time.strftime(date_format, time.strptime(value, parse_format))
1065+
1066+ else:
1067+ date = datetime(*value.timetuple()[:6])
1068+ return date.strftime(date_format)
1069+
1070+ return lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
1071+
1072 def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
1073 """generate the PDF"""
1074 self.parser_instance = self.parser(
1075@@ -190,74 +237,81 @@
1076 <body style="border:0; margin: 0;" onload="subst()">
1077 </body>
1078 </html>"""
1079+ self.parser_instance.localcontext.update({'setLang':self.setLang})
1080+ self.parser_instance.localcontext.update({'formatLang':self.formatLang})
1081 css = report_xml.webkit_header.css
1082 if not css :
1083 css = ''
1084 user = self.pool.get('res.users').browse(cursor, uid, uid)
1085- company= user.company_id
1086+ company = user.company_id
1087 parse_template = template
1088 #default_filters=['unicode', 'entity'] can be used to set global filter
1089- body_mako_tpl = Template(parse_template ,input_encoding='utf-8')
1090+ body_mako_tpl = Template(parse_template ,input_encoding='utf-8', output_encoding='utf-8')
1091 #BVR specific
1092 bvr_path = addons.get_module_resource(os.path.join('l10n_ch','report','bvr.mako'))
1093- body_bvr_tpl = Template(file(bvr_path).read(), input_encoding='utf-8')
1094+ body_bvr_tpl = Template(file(bvr_path).read(), input_encoding='utf-8', output_encoding='utf-8')
1095
1096 helper = report_helper.WebKitHelper(cursor, uid, report_xml.id, context)
1097 ##BVR Specific
1098 htmls = []
1099 for obj in objs :
1100-
1101 self.parser_instance.localcontext['objects'] = [obj]
1102 if not company.bvr_only:
1103- html = body_mako_tpl.render(
1104- helper=helper,
1105- css=css,
1106- _=self.translate_call,
1107- **self.parser_instance.localcontext
1108- )
1109+ try:
1110+ html = body_mako_tpl.render(
1111+ helper=helper,
1112+ css=css,
1113+ _=self.translate_call,
1114+ **self.parser_instance.localcontext
1115+ )
1116+ except Exception, e:
1117+ raise Exception(exceptions.text_error_template().render())
1118 htmls.append(html)
1119 if not company.invoice_only:
1120- bvr = body_bvr_tpl.render(
1121- helper=helper,
1122- css=css,
1123- _=self.translate_call,
1124- **self.parser_instance.localcontext
1125+ try:
1126+ bvr = body_bvr_tpl.render(
1127+ helper=helper,
1128+ css=css,
1129+ _=self.translate_call,
1130+ **self.parser_instance.localcontext
1131+ )
1132+ except Exception, e:
1133+ raise Exception(exceptions.text_error_template().render())
1134+ htmls.append(bvr)
1135+ head_mako_tpl = Template(header, input_encoding='utf-8', output_encoding='utf-8')
1136+ try:
1137+ head = head_mako_tpl.render(
1138+ helper=helper,
1139+ css=css,
1140+ _debug=False,
1141+ _=self.translate_call,
1142+ **self.parser_instance.localcontext
1143 )
1144- htmls.append(bvr)
1145- head_mako_tpl = Template(header, input_encoding='utf-8')
1146- head = head_mako_tpl.render(
1147- company=company,
1148- time=time,
1149- helper=helper,
1150- css=css,
1151- formatLang=self.parser_instance.formatLang,
1152- setLang=self.parser_instance.setLang,
1153- _debug=False
1154- )
1155+ except Exception, e:
1156+ raise Exception(exceptions.text_error_template().render())
1157 foot = False
1158 if footer and company.invoice_only :
1159- foot_mako_tpl = Template(footer ,input_encoding='utf-8')
1160- foot = foot_mako_tpl.render(
1161- company=company,
1162- time=time,
1163- helper=helper,
1164- css=css,
1165- formatLang=self.parser_instance.formatLang,
1166- setLang=self.parser_instance.setLang,
1167- _=self.translate_call,
1168-
1169- )
1170+ foot_mako_tpl = Template(footer, input_encoding='utf-8', output_encoding='utf-8')
1171+ try:
1172+ foot = foot_mako_tpl.render(
1173+ helper=helper,
1174+ css=css,
1175+ _=self.translate_call,
1176+ **self.parser_instance.localcontext
1177+ )
1178+ except Exception, e:
1179+ raise Exception(exceptions.text_error_template().render())
1180 if report_xml.webkit_debug :
1181- deb = head_mako_tpl.render(
1182- company=company,
1183- time=time,
1184- helper=helper,
1185- css=css,
1186- _debug=html,
1187- formatLang=self.parser_instance.formatLang,
1188- setLang=self.parser_instance.setLang,
1189- _=self.translate_call,
1190- )
1191+ try:
1192+ deb = head_mako_tpl.render(
1193+ helper=helper,
1194+ css=css,
1195+ _debug=html,
1196+ _=self.translate_call,
1197+ **self.parser_instance.localcontext
1198+ )
1199+ except Exception, e:
1200+ raise Exception(exceptions.text_error_template().render())
1201 return (deb, 'html')
1202 bin = self.get_lib(cursor, uid, company.id)
1203 pdf = self.generate_pdf(bin, report_xml, head, foot, htmls)
1204
1205=== modified file 'l10n_ch/report/report_webkit_html_view.xml'
1206--- l10n_ch/report/report_webkit_html_view.xml 2011-02-09 08:59:05 +0000
1207+++ l10n_ch/report/report_webkit_html_view.xml 2011-09-14 14:11:28 +0000
1208@@ -5,55 +5,57 @@
1209 <field name="orientation">Portrait</field>
1210 <field name="format">A4</field>
1211 <field name="html"><![CDATA[<html>
1212- <head>
1213- <script>
1214- function subst() {
1215- var vars={};
1216- var x=document.location.search.substring(1).split('&');
1217- for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
1218- var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
1219- for(var i in x) {
1220- var y = document.getElementsByClassName(x[i]);
1221- for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
1222- }
1223- }
1224- </script>
1225- <style type="text/css">
1226- ${css}
1227- </style>
1228- </head>
1229- <body style="border:0; margin: 0;" onload="subst()">
1230- <table class="header" style="border-bottom: 0px solid black; width: 100%;padding-left:20mm">
1231- <tr style="vertical-align:top" >
1232- <td>${helper.embed_logo_by_name('camptocamp_logo', width=64)}</td>
1233- <td style="text-align:right">
1234- <table style="border-top: 0px solid black; width: 100%;height:100%">
1235- <tr style="vertical-align:top">
1236- <td style="text-align:right;font-size:12" width="80%"><span class="page"/></td><td style="text-align:left;font-size:12;"> / <span class="topage"/></td>
1237- </tr>
1238- </table> </td>
1239- </tr>
1240- <tr>
1241- <td><br/></td>
1242- <td style="text-align:right"> </td>
1243- </tr>
1244- <tr>
1245- <td>${company.partner_id.name |entity}</td>
1246- <td/>
1247- </tr>
1248- <tr>
1249- <td >${company.partner_id.address and company.partner_id.address[0].street or ''|entity}</td>
1250- <td/>
1251- </tr>
1252- <tr>
1253- <td>Phone: ${company.partner_id.address and company.partner_id.address[0].phone or ''|entity} </td>
1254- <td/>
1255- </tr>
1256- <tr>
1257- <td>Mail: <a href="mailto:${company.partner_id.address and company.partner_id.address[0].email or ''|entity}">${company.partner_id.address and company.partner_id.address[0].email or ''|entity}</a><br/></td>
1258- </tr>
1259- </table> ${_debug or ''} <br/></body>
1260- </html>]]>
1261+ <head>
1262+ <script>
1263+ function subst() {
1264+ var vars={};
1265+ var x=document.location.search.substring(1).split('&');
1266+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
1267+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
1268+ for(var i in x) {
1269+ var y = document.getElementsByClassName(x[i]);
1270+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
1271+ }
1272+ }
1273+ </script>
1274+ <style type="text/css">
1275+ ${css}
1276+ </style>
1277+ </head>
1278+ <!-- <tr style="vertical-align:top">
1279+ <td style="text-align:right;font-size:12" ><span class="page"/></td><td style="text-align:left;font-size:12;"> / <span class="topage"/></td>
1280+ </tr> style="text-align:right"-->
1281+ <body style="border:0; margin: 0;" onload="subst()">
1282+ <table style="border-bottom: 1px solid black; width: 90%;padding-left:0mm;margin-left:5%">
1283+ <tr style="vertical-align:top" >
1284+ <td>${helper.embed_logo_by_name('camptocamp_logo', width=128)}</td>
1285+ <td >
1286+
1287+ <table style="border-top: 0px solid black; width: 100%;height:100%;;padding-left:4mm; margin-left:2%" class="dest_address">
1288+ <tr>
1289+ <td><b>${company.partner_id.name |entity}</b></td><td></td><td></td>
1290+ </tr>
1291+ <tr>
1292+ <td>${company.partner_id.address and company.partner_id.address[0].street or ''|entity}</td><td>${_("phone")}:</td><td>${company.partner_id.address and company.partner_id.address[0].phone or ''|entity} </td><td></td>
1293+ </tr>
1294+ <tr>
1295+ <td>${company.partner_id.address and company.partner_id.address[0].street2 or ''|entity}</td><td>${_('Fax')}:</td><td>${company.partner_id.address and company.partner_id.address[0].fax or ''|entity} </td><td></td>
1296+ </tr>
1297+ <tr>
1298+ <td>${company.partner_id.address and company.partner_id.address[0].zip or ''|entity} ${company.partner_id.address and company.partner_id.address[0].city or ''|entity}</td><td>${_('e-mail')}:</td><td><a href="mailto:${company.partner_id.address and company.partner_id.address[0].email or ''|entity}">${company.partner_id.address and company.partner_id.address[0].email or ''|entity}</a></td><td></td>
1299+ </tr>
1300+ <tr>
1301+ <td>${company.partner_id.address and company.partner_id.address[0].country_id.name or ''|entity}</td><td></td><td style="text-align:right;font-size:12" ><span class="page"/></td><td style="text-align:left;font-size:12;"> / <span class="topage"/></td>
1302+ </tr>
1303+ </table>
1304+ </td>
1305+ </tr>
1306+ </table>
1307+ <br/>
1308+ ${_debug or ''}
1309+ <br/>
1310+ </body>
1311+</html>]]>
1312 </field>
1313 <field eval="45" name="margin_top"/>
1314 <field eval="0.01" name="margin_bottom"/>
1315
1316=== modified file 'l10n_ch/sterchi_chart/account.xml'
1317--- l10n_ch/sterchi_chart/account.xml 2011-02-09 08:59:05 +0000
1318+++ l10n_ch/sterchi_chart/account.xml 2011-09-14 14:11:28 +0000
1319@@ -11773,10 +11773,10 @@
1320 <field name="parent_id" eval="False"/>
1321 </record>
1322 <record id="l10nch_chart_template" model="account.chart.template">
1323- <field name="name">Swiss PCG</field>
1324+ <field name="name">Plan comptable STERCHI</field>
1325 <field name="account_root_id" ref="ch_minimal_0"/>
1326 <field name="tax_code_root_id" ref="vat_code_chart_root"/>
1327- <field name="bank_account_view_id" ref="ch_3400"/>
1328+ <field name="bank_account_view_id" ref="ch_102_0"/>
1329 <field name="property_account_receivable" ref="ch_1100"/>
1330 <field name="property_account_payable" ref="ch_2000"/>
1331 <field name="property_account_expense_categ" ref="ch_4200"/>
1332
1333=== modified file 'l10n_ch/sterchi_chart/fiscal_position.xml'
1334--- l10n_ch/sterchi_chart/fiscal_position.xml 2011-05-25 11:51:33 +0000
1335+++ l10n_ch/sterchi_chart/fiscal_position.xml 2011-09-14 14:11:28 +0000
1336@@ -115,4 +115,4 @@
1337 <field name="tax_dest_id" ref="vat_XO" />
1338 </record>
1339 </data>
1340-</openerp>
1341\ No newline at end of file
1342+</openerp>
1343
1344=== added file 'l10n_ch/test/l10n_ch_dta.yml'
1345--- l10n_ch/test/l10n_ch_dta.yml 1970-01-01 00:00:00 +0000
1346+++ l10n_ch/test/l10n_ch_dta.yml 2011-09-14 14:11:28 +0000
1347@@ -0,0 +1,221 @@
1348+-
1349+ In order to test DTA generation I make an invoice and create the DTA from it.
1350+-
1351+ I create an invoice on 1st January for 7000 EUR
1352+ ###########################
1353+ # Creating 1 invoice #
1354+###########################
1355+-
1356+ !record {model: account.invoice, id: dta_account_invoice}:
1357+ company_id: base.main_company
1358+ journal_id: account.bank_journal
1359+ currency_id: base.EUR
1360+ account_id: account.a_pay
1361+ type : in_invoice
1362+ partner_id: base.res_partner_agrolait
1363+ address_contact_id: base.res_partner_address_8
1364+ address_invoice_id: base.res_partner_address_8
1365+ reference_type: bvr
1366+ reference: 111111111111111111111111111111
1367+ date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
1368+ period_id: account.period_1
1369+ #invoice_line:
1370+ partner_bank_id: main_partner_bank
1371+ check_total : 7000
1372+-
1373+ I add an invoice line
1374+-
1375+ !record {model: account.invoice.line, id: dta_invoice_line}:
1376+ account_id: account.a_expense
1377+ name: '[PC1] Basic PC'
1378+ price_unit: 700.0
1379+ quantity: 10.0
1380+ product_id: product.product_product_pc1
1381+ uos_id: product.product_uom_unit
1382+ invoice_id: dta_account_invoice
1383+
1384+
1385+-
1386+ I Validate invoice by clicking on Validate button
1387+-
1388+ !workflow {model: account.invoice, action: invoice_open, ref: dta_account_invoice}
1389+
1390+-
1391+ I create my payment order to pay my invoice
1392+ ###########################
1393+ # Doing payment order #
1394+###########################
1395+-
1396+ !record {model: payment.order, id: dta_payment_order}:
1397+ #date_created
1398+ #date_done
1399+ date_prefered: due
1400+ #date_scheduled
1401+ #line_ids:
1402+ mode: l10n_ch.payment_mode_dta
1403+ #reference
1404+ state: draft
1405+ total: 7000
1406+ #user_id
1407+-
1408+ I add a payment line to my payment order
1409+-
1410+ !record {model: payment.line, id: dta_pay_line}:
1411+ amount: 7000
1412+ amount_currency: 7000
1413+ bank_id: l10n_ch.agro_bank
1414+ #bank_statement_line_id
1415+ communication: "111111111111111111111111111111"
1416+ #communication2
1417+ company_currency: base.EUR
1418+ #create_date
1419+ currency: base.EUR
1420+ #date
1421+ #info_owner
1422+ #info_partner
1423+ #ml_date_created
1424+ #ml_inv_ref
1425+ #ml_maturity_date
1426+ move_line_id: !ref {model: account.move.line, search: "[('ref','=','111111111111111111111111111111')]"}
1427+ #name (reference)
1428+ order_id: dta_payment_order
1429+ partner_id: base.res_partner_agrolait
1430+ state: normal
1431+
1432+-
1433+ I generate a DTA file by using the wizard "Create DTA" for my payment order
1434+-
1435+ !python {model: create.dta.wizard}: |
1436+ import base64
1437+ wiz_id = self.create(cr,uid,[])
1438+ wiz = self.browse(cr, uid, wiz_id)
1439+ pay_order_id = ref("dta_payment_order")
1440+ #set the payment order as the active id
1441+ context['active_ids'] = [pay_order_id]
1442+ context['active_id'] = pay_order_id
1443+ result = wiz.create_dta(context=context)
1444+ assert result, "No result returned"
1445+
1446+ data = wiz.read(['dta_file'])
1447+ dta_file = base64.decodestring(data[0]['dta_file'] or '')
1448+ assert dta_file, "File is empty"
1449+
1450+ #check that file starts with 1st segment characters "01"
1451+ assert dta_file[:2] == "01", "File is not a DTA file"
1452+
1453+ payment_obj = self.pool.get('payment.order')
1454+ payment_obj.set_done(cr, uid, [ref('dta_payment_order')], context)
1455+ #force state in open state (confirmed)
1456+ payment_obj.write(cr, uid, [ref('dta_payment_order')], {'state': 'open'})
1457+
1458+-
1459+ I check the execution date is today
1460+-
1461+ !assert {model: payment.order, id: dta_payment_order}:
1462+ - date_done == datetime.now().date().strftime('%Y-%m-%d')
1463+
1464+-
1465+ I check my payment order state is Confirmed
1466+-
1467+ !assert {model: payment.order, id: dta_payment_order, string: state is done}:
1468+ - state == 'open'
1469+
1470+-
1471+ I create a Bank Statment in order to confirm the payment line
1472+-
1473+ !record {model: account.bank.statement, id: dta_bank_statement}:
1474+ #account_id:
1475+ #balance_end:
1476+ #balance_end_cash:
1477+ #balance_end_real:
1478+ #balance_start:
1479+ #closing_date:
1480+ #company_id:
1481+ #currency:
1482+ date: !eval "'%s-01-01' %(datetime.now().year)"
1483+ #ending_details_ids:
1484+ journal_id: account.bank_journal
1485+ #line_ids:
1486+ #move_line_ids
1487+ name: "/"
1488+ period_id: account.period_1
1489+ #starting_details_ids
1490+ state: draft
1491+ #total_entry_encoding
1492+ #user_id
1493+
1494+-
1495+ I import the payment line
1496+-
1497+ !python {model: account.payment.populate.statement}: |
1498+ wiz_id = self.create(cr,uid,[])
1499+ wiz = self.browse(cr, uid, wiz_id)
1500+
1501+ line_obj = self.pool.get('payment.line')
1502+ pay_line_ids = line_obj.search(cr, uid, [('communication','=','111111111111111111111111111111'),('amount','=','7000')])
1503+
1504+ data = { 'lines': [(6, 0, [pay_line_ids[0]])],}
1505+ wiz.write(data)
1506+
1507+ context['active_id'] = ref('dta_bank_statement')
1508+ context['active_ids'] = [ref('dta_bank_statement')]
1509+
1510+ self.populate_statement(cr, uid, [wiz_id], context=context)
1511+
1512+
1513+-
1514+ I check the statement line is created
1515+-
1516+ !assert {model: account.bank.statement, id: dta_bank_statement, string: statement_line_ids is not empty}:
1517+ - line_ids
1518+
1519+-
1520+ I check the voucher line is created
1521+-
1522+ !python {model: account.bank.statement}: |
1523+ statement = self.browse(cr, uid, ref('dta_bank_statement'))
1524+
1525+ assert statement.line_ids[0].voucher_id.line_ids, "Voucher line is missing"
1526+ assert len(statement.line_ids[0].voucher_id.line_ids) == 1, "There are too many voucher lines"
1527+
1528+-
1529+ In order to confirm my bank statement, I enter the closing balance and press on compute button
1530+-
1531+ !python {model: account.bank.statement}: |
1532+ statement = self.browse(cr, uid, ref('dta_bank_statement'))
1533+ statement.write({'balance_end_real': -7000.0})
1534+ self.button_dummy(cr, uid, [ref('dta_bank_statement')], context=context)
1535+ statement = self.browse(cr, uid, ref('dta_bank_statement'))
1536+
1537+-
1538+ I confirm my bank statement
1539+-
1540+ !python {model: account.bank.statement}: |
1541+ self.button_confirm_bank(cr, uid, [ref('dta_bank_statement')], context=context)
1542+
1543+
1544+-
1545+ I check the move lines have been defined
1546+-
1547+ !assert {model: account.bank.statement, id: dta_bank_statement, string: move_line_ids is not empty}:
1548+ - move_line_ids
1549+
1550+
1551+-
1552+ I check bank statement is Closed and balance is -7000
1553+-
1554+ !assert {model: account.bank.statement, id: dta_bank_statement, string: state is Closed and balance is -7000}:
1555+ - state == 'confirm'
1556+ - balance_end == -7000.0
1557+
1558+-
1559+ I check the residual amount of invoice, should be 0 in residual currency and 0 in amount_residual and paid
1560+-
1561+ !python {model: account.invoice}: |
1562+ invoice_id = self.browse(cr, uid, ref("dta_account_invoice"))
1563+ move_line_obj = self.pool.get('account.move.line')
1564+ move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
1565+ move_line = move_line_obj.browse(cr, uid, move_lines[0])
1566+ assert move_line.amount_residual_currency == 0.0, "Residual amount currency is not correct : %.2f" % move_line.amount_residual_currency
1567+ assert move_line.amount_residual == 0.0 , "Residual amount of invoice is not correct : %.2f" % move_line.amount_residual
1568+ assert invoice_id.state == 'paid', "Invoice state is not Paid"
1569\ No newline at end of file
1570
1571=== added file 'l10n_ch/test/l10n_ch_v11.yml'
1572--- l10n_ch/test/l10n_ch_v11.yml 1970-01-01 00:00:00 +0000
1573+++ l10n_ch/test/l10n_ch_v11.yml 2011-09-14 14:11:28 +0000
1574@@ -0,0 +1,161 @@
1575+-
1576+ In order to test the V11 import,
1577+ I will create an invoice with a specified reference that I will reconcile with the moves imported from a V11
1578+-
1579+ I create an invoice ref 1234567
1580+-
1581+ !record {model: account.invoice, id: v11_test_invoice}:
1582+ name: V11 YAML invoice
1583+ number: 1234567
1584+ company_id: base.main_company
1585+ journal_id: account.bank_journal
1586+ currency_id: base.EUR
1587+ account_id: account.a_recv
1588+ type : out_invoice
1589+ partner_id: base.res_partner_agrolait
1590+ address_contact_id: base.res_partner_address_8
1591+ address_invoice_id: base.res_partner_address_8
1592+ reference_type: bvr
1593+ reference: 12345676
1594+ date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
1595+ period_id: account.period_1
1596+ #invoice_line:
1597+ partner_bank_id: main_partner_bank
1598+ check_total : 888.00
1599+
1600+-
1601+ I create an invoice line
1602+-
1603+ !record {model: account.invoice.line, id: v11_test_invoice_line}:
1604+ account_id: account.a_expense
1605+ name: '[PC1] Basic PC'
1606+ price_unit: 888.00
1607+ quantity: 1.0
1608+ product_id: product.product_product_pc1
1609+ uos_id: product.product_uom_unit
1610+ invoice_id: v11_test_invoice
1611+
1612+-
1613+ I Validate invoice by clicking on Validate button
1614+-
1615+ !workflow {model: account.invoice, action: invoice_open, ref: v11_test_invoice}
1616+
1617+-
1618+ I specify the invoice number to fit with my v11
1619+-
1620+ !python {model: account.invoice}: |
1621+ invoice = self.browse(cr, uid, ref('v11_test_invoice'))
1622+ invoice.write({'number': 1234567})
1623+
1624+
1625+-
1626+ I create a bank statement
1627+-
1628+ !record {model: account.bank.statement, id: v11_test_bank_statement}:
1629+ #account_id:
1630+ #balance_end:
1631+ #balance_end_cash:
1632+ #balance_end_real:
1633+ #balance_start:
1634+ #closing_date:
1635+ #company_id:
1636+ #currency:
1637+ date: !eval "'%s-01-01' %(datetime.now().year)"
1638+ #ending_details_ids:
1639+ journal_id: account.bank_journal
1640+ #line_ids:
1641+ #move_line_ids
1642+ name: "/"
1643+ period_id: account.period_1
1644+ #starting_details_ids
1645+ state: draft
1646+ #total_entry_encoding
1647+ #user_id
1648+
1649+-
1650+ I import the V11
1651+-
1652+ !python {model: bvr.import.wizard}: |
1653+ import base64
1654+ import addons
1655+ import os
1656+
1657+ # create our wizard
1658+ wiz_id = self.create(cr,uid,[])
1659+ wiz = self.browse(cr, uid, wiz_id)
1660+
1661+ test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test.v11'))
1662+
1663+ # get our test file to test it
1664+ f_v11 = open(test_file_path)
1665+
1666+ str64_v11 = base64.encodestring(f_v11.read())
1667+
1668+ wiz.write({'file': str64_v11})
1669+
1670+ # set the file in the wizard field
1671+ bank_statement_id = ref('v11_test_bank_statement')
1672+
1673+ context['active_id'] = bank_statement_id
1674+ context['active_ids'] = [bank_statement_id]
1675+ # launch the import
1676+ self.import_bvr(cr, uid, [wiz_id], context=context)
1677+
1678+
1679+-
1680+ I check my bank statement got a statement line
1681+-
1682+ !assert {model: account.bank.statement, id: v11_test_bank_statement, string: statement has 1 and only 1 statement line id}:
1683+ - len(line_ids) == 1
1684+
1685+-
1686+ I check the voucher linked to the statement line contains a line with an amount of 888.00
1687+-
1688+ !python {model: account.bank.statement}: |
1689+ statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
1690+
1691+ voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
1692+
1693+ assert voucher_line_ids, "No voucher line found"
1694+
1695+ voucher_line_amount = voucher_line_ids[0].amount
1696+ assert voucher_line_amount == 888.00, "Amount isn't correct : %d" %(voucher_line_amount)
1697+
1698+-
1699+ I check amount of account voucher is equal to the bank statement line amount
1700+-
1701+ !python {model: account.bank.statement}: |
1702+ statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
1703+
1704+ statement_line_amount = statement.line_ids[0].amount
1705+ voucher_amount = statement.line_ids[0].voucher_id.amount
1706+
1707+ assert statement_line_amount == voucher_amount, "Mismatch of amounts"
1708+
1709+-
1710+ I enter the closing balance and press on compute button
1711+-
1712+ !python {model: account.bank.statement}: |
1713+ statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
1714+ statement.write({'balance_end_real': 888.00})
1715+ self.button_dummy(cr, uid, [ref('v11_test_bank_statement')], context=context)
1716+
1717+-
1718+ I check that the statement Balance is 888.00
1719+-
1720+ !assert {model: account.bank.statement, id: v11_test_bank_statement, string: balance is 888.0}:
1721+ - balance_end == 888.0
1722+
1723+-
1724+ I confirm my bank statement
1725+-
1726+ !python {model: account.bank.statement}: |
1727+ self.button_confirm_bank(cr, uid, [ref('v11_test_bank_statement')], context=context)
1728+
1729+-
1730+ I check my invoice is paid, reconciled and has no residual
1731+-
1732+ !assert {model: account.invoice, id: v11_test_invoice, string: 'invoice is paid, reconciled and has no residual'}:
1733+ - state == "paid"
1734+ - reconciled
1735+ - residual == 0.0
1736\ No newline at end of file
1737
1738=== added file 'l10n_ch/test/l10n_ch_v11_part.yml'
1739--- l10n_ch/test/l10n_ch_v11_part.yml 1970-01-01 00:00:00 +0000
1740+++ l10n_ch/test/l10n_ch_v11_part.yml 2011-09-14 14:11:28 +0000
1741@@ -0,0 +1,292 @@
1742+-
1743+ In order to test the V11 import,
1744+ I will create an invoice with a specified reference that I will partialy reconcile with a 1st V11
1745+ And then I will complete the reconcile with a second V11
1746+-
1747+ I create an invoice ref 2000999 of EUR 250.00
1748+-
1749+ !record {model: account.invoice, id: v11_part_test_invoice}:
1750+ name: V11 YAML invoice
1751+ number: 2000999
1752+ company_id: base.main_company
1753+ journal_id: account.bank_journal
1754+ currency_id: base.EUR
1755+ account_id: account.a_recv
1756+ type : out_invoice
1757+ partner_id: base.res_partner_agrolait
1758+ address_contact_id: base.res_partner_address_8
1759+ address_invoice_id: base.res_partner_address_8
1760+ reference_type: bvr
1761+ reference: 20009997
1762+ date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
1763+ period_id: account.period_1
1764+ #invoice_line:
1765+ partner_bank_id: main_partner_bank
1766+ check_total : 250.00
1767+
1768+-
1769+ I create an invoice line
1770+-
1771+ !record {model: account.invoice.line, id: v11_part_test_invoice_line}:
1772+ account_id: account.a_expense
1773+ name: '[PC1] Basic PC'
1774+ price_unit: 250.00
1775+ quantity: 1.0
1776+ product_id: product.product_product_pc1
1777+ uos_id: product.product_uom_unit
1778+ invoice_id: v11_part_test_invoice
1779+
1780+-
1781+ I Validate invoice by clicking on Validate button
1782+-
1783+ !workflow {model: account.invoice, action: invoice_open, ref: v11_part_test_invoice}
1784+
1785+-
1786+ I specify the invoice number to fit with my v11
1787+-
1788+ !python {model: account.invoice}: |
1789+ invoice = self.browse(cr, uid, ref('v11_part_test_invoice'))
1790+ invoice.write({'number': 2000999})
1791+
1792+
1793+-
1794+ I create a 1st bank statement
1795+ #########################################
1796+ # Creating 1st bank statement #
1797+#########################################
1798+-
1799+ !record {model: account.bank.statement, id: v11_part_test_bank_statement_1}:
1800+ #account_id:
1801+ #balance_end:
1802+ #balance_end_cash:
1803+ #balance_end_real:
1804+ #balance_start:
1805+ #closing_date:
1806+ #company_id:
1807+ #currency:
1808+ date: !eval "'%s-01-01' %(datetime.now().year)"
1809+ #ending_details_ids:
1810+ journal_id: account.bank_journal
1811+ #line_ids:
1812+ #move_line_ids
1813+ name: "/"
1814+ period_id: account.period_1
1815+ #starting_details_ids
1816+ state: draft
1817+ #total_entry_encoding
1818+ #user_id
1819+
1820+-
1821+ I import the 1st V11
1822+-
1823+ !python {model: bvr.import.wizard}: |
1824+ import base64
1825+ import addons
1826+ import os
1827+
1828+ # create our wizard
1829+ wiz_id = self.create(cr,uid,[])
1830+ wiz = self.browse(cr, uid, wiz_id)
1831+
1832+ test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test_part_1.v11'))
1833+
1834+ # get our test file to test it
1835+ f_v11 = open(test_file_path)
1836+
1837+ str64_v11 = base64.encodestring(f_v11.read())
1838+
1839+ wiz.write({'file': str64_v11})
1840+
1841+ # set the file in the wizard field
1842+ bank_statement_id = ref('v11_part_test_bank_statement_1')
1843+
1844+ context['active_id'] = bank_statement_id
1845+ context['active_ids'] = [bank_statement_id]
1846+ # launch the import
1847+ self.import_bvr(cr, uid, [wiz_id], context=context)
1848+
1849+
1850+-
1851+ I check my bank statement got a statement line
1852+-
1853+ !assert {model: account.bank.statement, id: v11_part_test_bank_statement_1, string: statement has 1 and only 1 statement line id}:
1854+ - len(line_ids) == 1
1855+
1856+-
1857+ I check the voucher linked to the statement line contains a line with an amount of EUR 150.00
1858+-
1859+ !python {model: account.bank.statement}: |
1860+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
1861+
1862+ voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
1863+
1864+ assert voucher_line_ids, "No voucher line found"
1865+
1866+ voucher_line_amount = voucher_line_ids[0].amount
1867+ assert voucher_line_amount == 150.00, "Amount isn't correct : %d" %(voucher_line_amount)
1868+
1869+-
1870+ I check amount of account voucher is equal to the bank statement line amount
1871+-
1872+ !python {model: account.bank.statement}: |
1873+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
1874+
1875+ statement_line_amount = statement.line_ids[0].amount
1876+ voucher_amount = statement.line_ids[0].voucher_id.amount
1877+
1878+ assert statement_line_amount == voucher_amount, "Mismatch of amounts"
1879+
1880+-
1881+ I enter the closing balance and press on compute button
1882+-
1883+ !python {model: account.bank.statement}: |
1884+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
1885+ statement.write({'balance_end_real': 150.00})
1886+ self.button_dummy(cr, uid, [ref('v11_part_test_bank_statement_1')], context=context)
1887+
1888+-
1889+ I check that the statement Balance is EUR 150.00
1890+-
1891+ !assert {model: account.bank.statement, id: v11_part_test_bank_statement_1, string: balance is 150.0}:
1892+ - balance_end == 150.0
1893+
1894+-
1895+ I confirm my 1st bank statement
1896+-
1897+ !python {model: account.bank.statement}: |
1898+ self.button_confirm_bank(cr, uid, [ref('v11_part_test_bank_statement_1')], context=context)
1899+
1900+
1901+-
1902+ I check that my invoice is partially paid in open state, not reconciled, with a residual amount of EUR 100.0
1903+ #########################################
1904+ # Checking partial result #
1905+#########################################
1906+-
1907+ !assert {model: account.invoice, id: v11_part_test_invoice, string: 'invoice is open, reconciled and has no residual'}:
1908+ - state == "open"
1909+ - not reconciled
1910+ - residual == 100.0
1911+
1912+
1913+
1914+-
1915+ I create a 2nd bank statement
1916+ #########################################
1917+ # Creating 2nd bank statement #
1918+#########################################
1919+-
1920+ !record {model: account.bank.statement, id: v11_part_test_bank_statement_2}:
1921+ #account_id:
1922+ #balance_end:
1923+ #balance_end_cash:
1924+ #balance_end_real:
1925+ #balance_start:
1926+ #closing_date:
1927+ #company_id:
1928+ #currency:
1929+ date: !eval "'%s-01-01' %(datetime.now().year)"
1930+ #ending_details_ids:
1931+ journal_id: account.bank_journal
1932+ #line_ids:
1933+ #move_line_ids
1934+ name: "/"
1935+ period_id: account.period_1
1936+ #starting_details_ids
1937+ state: draft
1938+ #total_entry_encoding
1939+ #user_id
1940+
1941+-
1942+ I import the 2nd V11
1943+-
1944+ !python {model: bvr.import.wizard}: |
1945+ import base64
1946+ import addons
1947+ import os
1948+
1949+ # create our wizard
1950+ wiz_id = self.create(cr,uid,[])
1951+ wiz = self.browse(cr, uid, wiz_id)
1952+
1953+ test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test_part_2.v11'))
1954+
1955+ # get our test file to test it
1956+ f_v11 = open(test_file_path)
1957+
1958+ str64_v11 = base64.encodestring(f_v11.read())
1959+
1960+ wiz.write({'file': str64_v11})
1961+
1962+ # set the file in the wizard field
1963+ bank_statement_id = ref('v11_part_test_bank_statement_2')
1964+
1965+ context['active_id'] = bank_statement_id
1966+ context['active_ids'] = [bank_statement_id]
1967+ # launch the import
1968+ self.import_bvr(cr, uid, [wiz_id], context=context)
1969+
1970+
1971+-
1972+ I check my bank statement got a statement line
1973+-
1974+ !assert {model: account.bank.statement, id: v11_part_test_bank_statement_2, string: statement has 1 and only 1 statement line id}:
1975+ - len(line_ids) == 1
1976+
1977+-
1978+ I check the voucher linked to the statement line contains a line with an amount of EUR 100.00
1979+-
1980+ !python {model: account.bank.statement}: |
1981+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
1982+
1983+ voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
1984+
1985+ assert voucher_line_ids, "No voucher line found"
1986+
1987+ voucher_line_amount = voucher_line_ids[0].amount
1988+ assert voucher_line_amount == 100.00, "Amount isn't correct : %d" %(voucher_line_amount)
1989+
1990+-
1991+ I check amount of account voucher is equal to the bank statement line amount
1992+-
1993+ !python {model: account.bank.statement}: |
1994+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
1995+
1996+ statement_line_amount = statement.line_ids[0].amount
1997+ voucher_amount = statement.line_ids[0].voucher_id.amount
1998+
1999+ assert statement_line_amount == voucher_amount, "Mismatch of amounts"
2000+
2001+
2002+-
2003+ I enter the closing balance and press on compute button
2004+-
2005+ !python {model: account.bank.statement}: |
2006+ statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
2007+ statement.write({'balance_end_real': 100.00})
2008+ self.button_dummy(cr, uid, [ref('v11_part_test_bank_statement_2')], context=context)
2009+
2010+-
2011+ I check that the statement Balance is EUR 100.00
2012+-
2013+ !assert {model: account.bank.statement, id: v11_part_test_bank_statement_2, string: balance is 100.0}:
2014+ - balance_end == 100.0
2015+
2016+-
2017+ I confirm my 2nd bank statement
2018+-
2019+ !python {model: account.bank.statement}: |
2020+ self.button_confirm_bank(cr, uid, [ref('v11_part_test_bank_statement_2')], context=context)
2021+
2022+
2023+
2024+-
2025+ I check my invoice is paid, reconciled and has no residual
2026+ #########################################
2027+ # Checking finale state #
2028+#########################################
2029+-
2030+ !assert {model: account.invoice, id: v11_part_test_invoice, string: 'invoice is paid, reconciled and has no residual'}:
2031+ - state == "paid"
2032+ - reconciled
2033+ - residual == 0.0
2034\ No newline at end of file
2035
2036=== added file 'l10n_ch/test/test.v11'
2037--- l10n_ch/test/test.v11 1970-01-01 00:00:00 +0000
2038+++ l10n_ch/test/test.v11 2011-09-14 14:11:28 +0000
2039@@ -0,0 +1,2 @@
2040+00201012162700000000000000000001234567600000888000001 000111010111010111010100000000010000000000000
2041+999010121627999999999999999999999999999000000088800000000000001110102000000000000000000
2042
2043=== added file 'l10n_ch/test/test_part_1.v11'
2044--- l10n_ch/test/test_part_1.v11 1970-01-01 00:00:00 +0000
2045+++ l10n_ch/test/test_part_1.v11 2011-09-14 14:11:28 +0000
2046@@ -0,0 +1,2 @@
2047+00201012162700000000000000000002000999700000150000001 000111010111010111010100000000010000000000000
2048+999010121627999999999999999999999999999000000015000000000000001110102000000000000000000
2049
2050=== added file 'l10n_ch/test/test_part_2.v11'
2051--- l10n_ch/test/test_part_2.v11 1970-01-01 00:00:00 +0000
2052+++ l10n_ch/test/test_part_2.v11 2011-09-14 14:11:28 +0000
2053@@ -0,0 +1,2 @@
2054+00201012162700000000000000000002000999700000100000001 000111010511010511010500000000010000000000000
2055+999010121627999999999999999999999999999000000010000000000000001110106000000000000000000
2056
2057=== modified file 'l10n_ch/wizard/__init__.py'
2058--- l10n_ch/wizard/__init__.py 2011-01-14 12:41:54 +0000
2059+++ l10n_ch/wizard/__init__.py 2011-09-14 14:11:28 +0000
2060@@ -19,7 +19,8 @@
2061 #
2062 ##############################################################################
2063
2064-import create_dta
2065-import bvr_import
2066+from . import create_dta
2067+from . import bvr_import
2068+from . import unicode2ascii
2069
2070 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2071
2072=== modified file 'l10n_ch/wizard/bvr_import.py'
2073--- l10n_ch/wizard/bvr_import.py 2011-07-04 12:46:51 +0000
2074+++ l10n_ch/wizard/bvr_import.py 2011-09-14 14:11:28 +0000
2075@@ -36,7 +36,9 @@
2076 user_current=user_obj.browse(cursor, user, user)
2077
2078 ##
2079- cursor.execute("SELECT inv.id,inv.number from account_invoice AS inv where inv.company_id = %s" ,(user_current.company_id.id,))
2080+ cursor.execute("SELECT inv.id,inv.number from account_invoice "
2081+ "AS inv where inv.company_id = %s and type='out_invoice'",
2082+ (user_current.company_id.id,))
2083 result_invoice = cursor.fetchall()
2084 REF = re.compile('[^0-9]')
2085 for inv_id,inv_name in result_invoice:
2086@@ -60,7 +62,6 @@
2087 def _import(self, cursor, user, data, context=None):
2088
2089 statement_line_obj = self.pool.get('account.bank.statement.line')
2090-# statement_reconcile_obj = pool.get('account.bank.statement.reconcile')
2091 voucher_obj = self.pool.get('account.voucher')
2092 voucher_line_obj = self.pool.get('account.voucher.line')
2093 move_line_obj = self.pool.get('account.move.line')
2094@@ -167,7 +168,6 @@
2095 # line2reconcile = line.id
2096 account_id = line.account_id.id
2097 break
2098- context.update({'move_line_ids': line_ids})
2099 result = voucher_obj.onchange_partner_id(cursor, user, [], partner_id, journal_id=statement.journal_id.id, price=abs(record['amount']), currency_id= statement.currency.id, ttype='receipt', date=statement.date ,context=context)
2100 voucher_res = { 'type': 'receipt' ,
2101
2102@@ -182,6 +182,7 @@
2103 'period_id': statement.period_id.id
2104 }
2105 voucher_id = voucher_obj.create(cursor, user, voucher_res, context=context)
2106+ context.update({'move_line_ids': line_ids})
2107 values['voucher_id'] = voucher_id
2108 voucher_line_dict = False
2109 if result['value']['line_ids']:
2110@@ -207,7 +208,7 @@
2111 cursor,
2112 user,
2113 [
2114- ('name','=','property_account_receivable'),
2115+ ('name','=',name),
2116 ('company_id','=',statement.company_id.id),
2117 ('res_id', '=', False)
2118 ]
2119@@ -226,9 +227,9 @@
2120 values['partner_id'] = partner_id
2121 statement_line_obj.create(cursor, user, values, context=context)
2122 attachment_obj.create(cursor, user, {
2123- 'name': 'BVR',
2124+ 'name': 'BVR %s'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
2125 'datas': file,
2126- 'datas_fname': 'BVR.txt',
2127+ 'datas_fname': 'BVR %s.txt'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
2128 'res_model': 'account.bank.statement',
2129 'res_id': statement_id,
2130 }, context=context)
2131
2132=== modified file 'l10n_ch/wizard/create_dta.py'
2133--- l10n_ch/wizard/create_dta.py 2011-02-09 08:59:05 +0000
2134+++ l10n_ch/wizard/create_dta.py 2011-09-14 14:11:28 +0000
2135@@ -26,6 +26,7 @@
2136 from osv import osv, fields
2137 import pooler
2138 from tools.translate import _
2139+import unicode2ascii
2140
2141 TRANS=[
2142 (u'é','e'),
2143@@ -38,6 +39,24 @@
2144 (u'ä','a'),
2145 ]
2146
2147+def _u2a(text) :
2148+ """Tries to convert unicode charactere to asci equivalence"""
2149+ if not text : return ""
2150+ txt = ""
2151+ for c in text:
2152+ if ord(c) < 128 :
2153+ txt += c
2154+ elif c in unicode2ascii.EXTRA_LATIN_NAMES :
2155+ txt += unicode2ascii.EXTRA_LATIN_NAMES[c]
2156+ elif c in unicode2ascii.UNI2ASCII_CONVERSIONS :
2157+ txt += unicode2ascii.UNI2ASCII_CONVERSIONS[c]
2158+ elif c in unicode2ascii.EXTRA_CHARACTERS :
2159+ txt += unicode2ascii.EXTRA_CHARACTERS[c]
2160+ elif c in unicode2ascii.FG_HACKS :
2161+ txt += unicode2ascii.FG_HACKS[c]
2162+ else : txt+= "_"
2163+ return txt
2164+
2165 def tr(string_in):
2166 try:
2167 string_in= string_in.decode('utf-8')
2168@@ -339,7 +358,9 @@
2169 if context is None:
2170 context = {}
2171 payment = payment_obj.browse(cr, uid, data['id'], context=context)
2172-
2173+ # if payment.state != 'done':
2174+ # raise osv.except_osv(_('Order not confirmed'),
2175+ # _('Please confirm it'))
2176 if not payment.mode:
2177 raise osv.except_osv(_('Error'),
2178 _('No payment mode'))
2179@@ -374,7 +395,6 @@
2180 raise osv.except_osv(_('Error'),
2181 _('No IBAN for the company bank account.'))
2182
2183- dta_line_obj = pool.get('account.dta.line')
2184 res_partner_bank_obj = pool.get('res.partner.bank')
2185
2186 seq = 1
2187@@ -469,7 +489,7 @@
2188 # si payment structure -> bvr (826)
2189 # si non -> (827)
2190
2191- if elec_pay == 'dta_iban':
2192+ if elec_pay == 'iban':
2193 # If iban => country=country code for space reason
2194 v['comp_country'] = co_addr.country_id and co_addr.country_id.code+'-' or ''
2195 record_type = record_gt836
2196@@ -552,17 +572,17 @@
2197 v['sequence'] = str(seq).rjust(5).replace(' ','0')
2198 if dta :
2199 dta = dta + record_gt890(v).generate()
2200-
2201+ dta_data = _u2a(dta)
2202 dta_data = base64.encodestring(dta)
2203 payment_obj.set_done(cr, uid, [data['id']], context)
2204 attachment_obj.create(cr, uid, {
2205- 'name': 'DTA',
2206+ 'name': 'DTA%s'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
2207 'datas': dta_data,
2208- 'datas_fname': 'DTA.txt',
2209+ 'datas_fname': 'DTA%s.txt'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
2210 'res_model': 'payment.order',
2211 'res_id': data['id'],
2212 }, context=context)
2213- return {'dta': dta_data}
2214+ return dta_data
2215
2216 class create_dta_wizard(osv.osv_memory):
2217 _name="create.dta.wizard"
2218@@ -573,6 +593,11 @@
2219 def create_dta(self, cr, uid, ids, context=None):
2220 if not context:
2221 context = {}
2222+ if isinstance(ids, list):
2223+ req_id = ids[0]
2224+ else:
2225+ req_id = ids
2226+ current = self.browse(cr, uid, req_id, context)
2227 data = {}
2228 active_ids = context.get('active_ids', [])
2229 active_id = context.get('active_id', [])
2230@@ -580,26 +605,9 @@
2231 data['ids'] = active_ids
2232 data['id'] = active_id
2233 dta_file = _create_dta(self, cr, uid, data, context)
2234- context.update({'dta_file':dta_file})
2235- return self.save_dta(cr, uid, ids, context)
2236-
2237- def save_dta(self, cr, uid, ids, context=None):
2238- obj_model = self.pool.get('ir.model.data')
2239- if context is None:
2240- context = {}
2241- model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'), ('name','=','dta_save_view')])
2242- resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
2243- return {
2244- 'view_type': 'form',
2245- 'view_mode': 'form',
2246- 'res_model': 'create.dta.wizard',
2247- 'views': [(resource_id, 'form')],
2248- 'type': 'ir.actions.act_window',
2249- 'target': 'new',
2250- 'context': context,
2251- }
2252-
2253+ current.write({'dta_file': dta_file})
2254+ return True
2255
2256 create_dta_wizard()
2257
2258-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2259\ No newline at end of file
2260+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2261
2262=== modified file 'l10n_ch/wizard/create_dta_view.xml'
2263--- l10n_ch/wizard/create_dta_view.xml 2011-01-14 12:41:54 +0000
2264+++ l10n_ch/wizard/create_dta_view.xml 2011-09-14 14:11:28 +0000
2265@@ -10,6 +10,7 @@
2266 <form string="DTA file creation - Results">
2267 <group width="300" colspan="4">
2268 <separator string="Create DTA" colspan="4"/>
2269+ <field name="dta_file"/>
2270 <group colspan="4">
2271 <button special="cancel" string="Cancel" icon="gtk-cancel" colspan="2"/>
2272 <button name="create_dta" string="Create DTA" type="object" icon="gtk-ok" colspan="2"/>
2273@@ -38,21 +39,5 @@
2274 <field name="key">action</field>
2275 <field name="model">payment.order</field>
2276 </record>
2277-
2278- <!-- Save DTA -->
2279- <record id="dta_save_view" model="ir.ui.view">
2280- <field name="name">Save DTA</field>
2281- <field name="model">create.dta.wizard</field>
2282- <field name="type">form</field>
2283- <field name="arch" type="xml">
2284- <form string="DTA file creation - Results">
2285- <group width="500" colspan="4">
2286- <separator colspan="4" string="Click on 'Save as' to save the DTA file :" />
2287- <field name="dta_file"/>
2288- </group>
2289- </form>
2290- </field>
2291- </record>
2292-
2293 </data>
2294 </openerp>
2295\ No newline at end of file
2296
2297=== added file 'l10n_ch/wizard/unicode2ascii.py'
2298--- l10n_ch/wizard/unicode2ascii.py 1970-01-01 00:00:00 +0000
2299+++ l10n_ch/wizard/unicode2ascii.py 2011-09-14 14:11:28 +0000
2300@@ -0,0 +1,592 @@
2301+# -*- encoding: utf-8 -*-
2302+
2303+"""Convert many unicode characters to ascii characters that are like them.
2304+
2305+I want to collate names, with the property that a last name starting with
2306+O-umlaut will be in with the last name's starting with O. Horrors!
2307+
2308+So I want that many Latin-1 characters have their umlaute's, etc., stripped.
2309+Some of it can be done automatically but some needs to be done by hand, that
2310+I can tell.
2311+"""
2312+__version__='1.0.1'
2313+__author__='Jim Hefferon: ftpmaint at tug.ctan.org'
2314+__date__='2008-July-15'
2315+__notes__="""As sources, used effbot's web site, and
2316+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/251871
2317+and
2318+ man uni2ascii
2319+"""
2320+
2321+import os, os.path, sys, re
2322+import unicodedata
2323+
2324+# These characters that are not done automatically by NFKD, and
2325+# have a name starting with "LATIN". Some of these I found on the interwebs,
2326+# but some I did by eye. Corrections or additions appreciated.
2327+EXTRA_LATIN_NAMES={
2328+ # First are ones I got off the interweb
2329+ u"\N{LATIN CAPITAL LETTER O WITH STROKE}": u"O",
2330+ u"\N{LATIN SMALL LETTER A WITH GRAVE}": u"a",
2331+ u"\N{LATIN SMALL LETTER A WITH ACUTE}": u"a",
2332+ u"\N{LATIN SMALL LETTER A WITH CIRCUMFLEX}": u"a",
2333+ u"\N{LATIN SMALL LETTER A WITH TILDE}": u"a",
2334+ u"\N{LATIN SMALL LETTER A WITH DIAERESIS}": u"ae",
2335+ u"\N{LATIN SMALL LETTER A WITH RING ABOVE}": u"a",
2336+ u"\N{LATIN SMALL LETTER C WITH CEDILLA}": u"c",
2337+ u"\N{LATIN SMALL LETTER E WITH GRAVE}": u"e",
2338+ u"\N{LATIN SMALL LETTER E WITH ACUTE}": u"e",
2339+ u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}": u"e",
2340+ u"\N{LATIN SMALL LETTER E WITH DIAERESIS}": u"e",
2341+ u"\N{LATIN SMALL LETTER I WITH GRAVE}": u"i",
2342+ u"\N{LATIN SMALL LETTER I WITH ACUTE}": u"i",
2343+ u"\N{LATIN SMALL LETTER I WITH CIRCUMFLEX}": u"i",
2344+ u"\N{LATIN SMALL LETTER I WITH DIAERESIS}": u"i",
2345+ u"\N{LATIN SMALL LETTER N WITH TILDE}": u"n",
2346+ u"\N{LATIN SMALL LETTER O WITH GRAVE}": u"o",
2347+ u"\N{LATIN SMALL LETTER O WITH ACUTE}": u"o",
2348+ u"\N{LATIN SMALL LETTER O WITH CIRCUMFLEX}": u"o",
2349+ u"\N{LATIN SMALL LETTER O WITH TILDE}": u"o",
2350+ u"\N{LATIN SMALL LETTER O WITH DIAERESIS}": u"oe",
2351+ u"\N{LATIN SMALL LETTER O WITH STROKE}": u"o",
2352+ u"\N{LATIN SMALL LETTER U WITH GRAVE}": u"u",
2353+ u"\N{LATIN SMALL LETTER U WITH ACUTE}": u"u",
2354+ u"\N{LATIN SMALL LETTER U WITH CIRCUMFLEX}": u"u",
2355+ u"\N{LATIN SMALL LETTER U WITH DIAERESIS}": u"ue",
2356+ u"\N{LATIN SMALL LETTER Y WITH ACUTE}": u"y",
2357+ u"\N{LATIN SMALL LETTER Y WITH DIAERESIS}": u"y",
2358+ u"\N{LATIN SMALL LETTER A WITH MACRON}": u"a",
2359+ u"\N{LATIN SMALL LETTER A WITH BREVE}": u"a",
2360+ u"\N{LATIN SMALL LETTER C WITH ACUTE}": u"c",
2361+ u"\N{LATIN SMALL LETTER C WITH CIRCUMFLEX}": u"c",
2362+ u"\N{LATIN SMALL LETTER E WITH MACRON}": u"e",
2363+ u"\N{LATIN SMALL LETTER E WITH BREVE}": u"e",
2364+ u"\N{LATIN SMALL LETTER G WITH CIRCUMFLEX}": u"g",
2365+ u"\N{LATIN SMALL LETTER G WITH BREVE}": u"g",
2366+ u"\N{LATIN SMALL LETTER G WITH CEDILLA}": u"g",
2367+ u"\N{LATIN SMALL LETTER H WITH CIRCUMFLEX}": u"h",
2368+ u"\N{LATIN SMALL LETTER I WITH TILDE}": u"i",
2369+ u"\N{LATIN SMALL LETTER I WITH MACRON}": u"i",
2370+ u"\N{LATIN SMALL LETTER I WITH BREVE}": u"i",
2371+ u"\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}": u"j",
2372+ u"\N{LATIN SMALL LETTER K WITH CEDILLA}": u"k",
2373+ u"\N{LATIN SMALL LETTER L WITH ACUTE}": u"l",
2374+ u"\N{LATIN SMALL LETTER L WITH CEDILLA}": u"l",
2375+ u"\N{LATIN CAPITAL LETTER L WITH STROKE}": u"L",
2376+ u"\N{LATIN SMALL LETTER L WITH STROKE}": u"l",
2377+ u"\N{LATIN SMALL LETTER N WITH ACUTE}": u"n",
2378+ u"\N{LATIN SMALL LETTER N WITH CEDILLA}": u"n",
2379+ u"\N{LATIN SMALL LETTER O WITH MACRON}": u"o",
2380+ u"\N{LATIN SMALL LETTER O WITH BREVE}": u"o",
2381+ u"\N{LATIN SMALL LETTER R WITH ACUTE}": u"r",
2382+ u"\N{LATIN SMALL LETTER R WITH CEDILLA}": u"r",
2383+ u"\N{LATIN SMALL LETTER S WITH ACUTE}": u"s",
2384+ u"\N{LATIN SMALL LETTER S WITH CIRCUMFLEX}": u"s",
2385+ u"\N{LATIN SMALL LETTER S WITH CEDILLA}": u"s",
2386+ u"\N{LATIN SMALL LETTER T WITH CEDILLA}": u"t",
2387+ u"\N{LATIN SMALL LETTER U WITH TILDE}": u"u",
2388+ u"\N{LATIN SMALL LETTER U WITH MACRON}": u"u",
2389+ u"\N{LATIN SMALL LETTER U WITH BREVE}": u"u",
2390+ u"\N{LATIN SMALL LETTER U WITH RING ABOVE}": u"u",
2391+ u"\N{LATIN SMALL LETTER W WITH CIRCUMFLEX}": u"w",
2392+ u"\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}": u"y",
2393+ u"\N{LATIN SMALL LETTER Z WITH ACUTE}": u"z",
2394+ u"\N{LATIN SMALL LETTER W WITH GRAVE}": u"w",
2395+ u"\N{LATIN SMALL LETTER W WITH ACUTE}": u"w",
2396+ u"\N{LATIN SMALL LETTER W WITH DIAERESIS}": u"w",
2397+ u"\N{LATIN SMALL LETTER Y WITH GRAVE}": u"y",
2398+ # Below are the ones that failed automated conversion
2399+ u'\N{LATIN CAPITAL LETTER AE}': u'AE',
2400+ u'\N{LATIN CAPITAL LETTER ETH}': u'D',
2401+ u"\N{LATIN CAPITAL LETTER A WITH DIAERESIS}": u"Ae",
2402+ u"\N{LATIN CAPITAL LETTER O WITH DIAERESIS}": u"Oe",
2403+ u"\N{LATIN CAPITAL LETTER U WITH DIAERESIS}": u"Ue",
2404+ u'\N{LATIN CAPITAL LETTER O WITH STROKE}': u'O',
2405+ u'\N{LATIN CAPITAL LETTER THORN}': u'TH',
2406+ u'\N{LATIN SMALL LETTER SHARP S}': u'ss',
2407+ u'\N{LATIN SMALL LETTER AE}': u'ae',
2408+ u'\N{LATIN SMALL LETTER ETH}': u'd',
2409+ u'\N{LATIN SMALL LETTER O WITH STROKE}': u'o',
2410+ u'\N{LATIN SMALL LETTER THORN}': 'th',
2411+ u'\N{LATIN CAPITAL LETTER D WITH STROKE}': u'D',
2412+ u'\N{LATIN SMALL LETTER D WITH STROKE}': u'd',
2413+ u'\N{LATIN CAPITAL LETTER H WITH STROKE}': u'H',
2414+ u'\N{LATIN SMALL LETTER H WITH STROKE}': u'h',
2415+ u'\N{LATIN SMALL LETTER DOTLESS I}': u'i',
2416+ u'\N{LATIN SMALL LETTER KRA}': u'q',
2417+ u'\N{LATIN CAPITAL LETTER L WITH STROKE}': u'L',
2418+ u'\N{LATIN SMALL LETTER L WITH STROKE}': u'l',
2419+ u'\N{LATIN CAPITAL LETTER ENG}': u'N',
2420+ u'\N{LATIN SMALL LETTER ENG}': u'n',
2421+ u'\N{LATIN CAPITAL LIGATURE OE}': u'OE',
2422+ u'\N{LATIN SMALL LIGATURE OE}': u'oe',
2423+ u'\N{LATIN CAPITAL LETTER T WITH STROKE}': u'T',
2424+ u'\N{LATIN SMALL LETTER T WITH STROKE}': u't',
2425+ u'\N{LATIN SMALL LETTER B WITH STROKE}': u'b',
2426+ u'\N{LATIN CAPITAL LETTER B WITH HOOK}': u'B',
2427+ u'\N{LATIN CAPITAL LETTER B WITH TOPBAR}': u'B',
2428+ u'\N{LATIN SMALL LETTER B WITH TOPBAR}': u'b',
2429+ # u'\N{LATIN CAPITAL LETTER TONE SIX}': u'', # ?B
2430+ # u'\N{LATIN SMALL LETTER TONE SIX}': u'', # ?b
2431+ u'\N{LATIN CAPITAL LETTER OPEN O}': u'O',
2432+ u'\N{LATIN CAPITAL LETTER C WITH HOOK}': u'C',
2433+ u'\N{LATIN SMALL LETTER C WITH HOOK}': u'c',
2434+ u'\N{LATIN CAPITAL LETTER AFRICAN D}': u'D',
2435+ u'\N{LATIN CAPITAL LETTER D WITH HOOK}': u'D',
2436+ u'\N{LATIN CAPITAL LETTER D WITH TOPBAR}': u'D',
2437+ u'\N{LATIN SMALL LETTER D WITH TOPBAR}': u'd',
2438+ # u'\N{LATIN SMALL LETTER TURNED DELTA}': u'',
2439+ u'\N{LATIN CAPITAL LETTER REVERSED E}': u'E',
2440+ # u'\N{LATIN CAPITAL LETTER SCHWA}': u'',
2441+ u'\N{LATIN CAPITAL LETTER OPEN E}': u'E',
2442+ u'\N{LATIN CAPITAL LETTER F WITH HOOK}': u'F',
2443+ u'\N{LATIN SMALL LETTER F WITH HOOK}': u'f',
2444+ u'\N{LATIN CAPITAL LETTER G WITH HOOK}': u'G',
2445+ # u'\N{LATIN CAPITAL LETTER GAMMA}': u'',
2446+ u'\N{LATIN SMALL LETTER HV}': u'hv',
2447+ u'\N{LATIN CAPITAL LETTER IOTA}': u'i',
2448+ u'\N{LATIN CAPITAL LETTER I WITH STROKE}': u'I',
2449+ u'\N{LATIN CAPITAL LETTER K WITH HOOK}': u'K',
2450+ u'\N{LATIN SMALL LETTER K WITH HOOK}': u'k',
2451+ u'\N{LATIN SMALL LETTER L WITH BAR}': u'l',
2452+ # u'\N{LATIN SMALL LETTER LAMBDA WITH STROKE}': u'',
2453+ # u'\N{LATIN CAPITAL LETTER TURNED M}': u'',
2454+ u'\N{LATIN CAPITAL LETTER N WITH LEFT HOOK}': u'N',
2455+ u'\N{LATIN SMALL LETTER N WITH LONG RIGHT LEG}': u'N',
2456+ u'\N{LATIN CAPITAL LETTER O WITH MIDDLE TILDE}': u'O',
2457+ u'\N{LATIN CAPITAL LETTER OI}': u'OI',
2458+ u'\N{LATIN SMALL LETTER OI}': u'oi',
2459+ u'\N{LATIN CAPITAL LETTER P WITH HOOK}': u'P',
2460+ u'\N{LATIN SMALL LETTER P WITH HOOK}': u'p',
2461+ # u'\N{LATIN LETTER YR}': u'',
2462+ # u'\N{LATIN CAPITAL LETTER TONE TWO}': u'',
2463+ # u'\N{LATIN SMALL LETTER TONE TWO}': u'',
2464+ u'\N{LATIN CAPITAL LETTER ESH}': u'SH',
2465+ # u'\N{LATIN LETTER REVERSED ESH LOOP}': u'',
2466+ u'\N{LATIN SMALL LETTER T WITH PALATAL HOOK}': u't',
2467+ u'\N{LATIN CAPITAL LETTER T WITH HOOK}': u'T',
2468+ u'\N{LATIN SMALL LETTER T WITH HOOK}': u't',
2469+ u'\N{LATIN CAPITAL LETTER T WITH RETROFLEX HOOK}': u'T',
2470+ # u'\N{LATIN CAPITAL LETTER UPSILON}': u'',
2471+ u'\N{LATIN CAPITAL LETTER V WITH HOOK}': u'V',
2472+ u'\N{LATIN CAPITAL LETTER Y WITH HOOK}': u'Y',
2473+ u'\N{LATIN SMALL LETTER Y WITH HOOK}': u'y',
2474+ u'\N{LATIN CAPITAL LETTER Z WITH STROKE}': u'Z',
2475+ u'\N{LATIN SMALL LETTER Z WITH STROKE}': u'z',
2476+ u'\N{LATIN CAPITAL LETTER EZH}': u'S',
2477+ # u'\N{LATIN CAPITAL LETTER EZH REVERSED}': u'',
2478+ # u'\N{LATIN SMALL LETTER EZH REVERSED}': u'',
2479+ u'\N{LATIN SMALL LETTER EZH WITH TAIL}': u's',
2480+ # u'\N{LATIN LETTER TWO WITH STROKE}': u'',
2481+ # u'\N{LATIN CAPITAL LETTER TONE FIVE}': u'',
2482+ # u'\N{LATIN SMALL LETTER TONE FIVE}': u'',
2483+ # u'\N{LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE}': u'',
2484+ u'\N{LATIN LETTER WYNN}': u'w',
2485+ # u'\N{LATIN LETTER DENTAL CLICK}': u'',
2486+ # u'\N{LATIN LETTER LATERAL CLICK}': u'',
2487+ # u'\N{LATIN LETTER ALVEOLAR CLICK}': u'',
2488+ # u'\N{LATIN LETTER RETROFLEX CLICK}': u'',
2489+ # u'\N{LATIN SMALL LETTER TURNED E}': u'',
2490+ u'\N{LATIN CAPITAL LETTER AE WITH MACRON}': u'AE',
2491+ u'\N{LATIN SMALL LETTER AE WITH MACRON}': u'ae',
2492+ u'\N{LATIN CAPITAL LETTER G WITH STROKE}': u'G',
2493+ u'\N{LATIN SMALL LETTER G WITH STROKE}': u'g',
2494+ u'\N{LATIN CAPITAL LETTER EZH WITH CARON}': u'S',
2495+ u'\N{LATIN SMALL LETTER EZH WITH CARON}': u's',
2496+ u'\N{LATIN CAPITAL LETTER HWAIR}': u'HW',
2497+ u'\N{LATIN CAPITAL LETTER WYNN}': u'W',
2498+ u'\N{LATIN CAPITAL LETTER AE WITH ACUTE}': u'AE',
2499+ u'\N{LATIN SMALL LETTER AE WITH ACUTE}': u'AE',
2500+ u'\N{LATIN CAPITAL LETTER O WITH STROKE AND ACUTE}': u'O',
2501+ u'\N{LATIN SMALL LETTER O WITH STROKE AND ACUTE}': u'o',
2502+ u'\N{LATIN CAPITAL LETTER YOGH}': u'J',
2503+ u'\N{LATIN SMALL LETTER YOGH}': u'j',
2504+ u'\N{LATIN CAPITAL LETTER N WITH LONG RIGHT LEG}': u'N',
2505+ u'\N{LATIN SMALL LETTER D WITH CURL}': u'd',
2506+ u'\N{LATIN CAPITAL LETTER OU}': u'OU',
2507+ u'\N{LATIN SMALL LETTER OU}': u'ou',
2508+ u'\N{LATIN CAPITAL LETTER Z WITH HOOK}': u'Z',
2509+ u'\N{LATIN SMALL LETTER Z WITH HOOK}': u'z',
2510+ u'\N{LATIN SMALL LETTER L WITH CURL}': u'l',
2511+ u'\N{LATIN SMALL LETTER N WITH CURL}': u'n',
2512+ u'\N{LATIN SMALL LETTER T WITH CURL}': u't',
2513+ u'\N{LATIN SMALL LETTER DOTLESS J}': u'j',
2514+ u'\N{LATIN SMALL LETTER DB DIGRAPH}': u'db',
2515+ u'\N{LATIN SMALL LETTER QP DIGRAPH}': u'qp',
2516+ u'\N{LATIN CAPITAL LETTER A WITH STROKE}': u'A',
2517+ u'\N{LATIN CAPITAL LETTER C WITH STROKE}': u'C',
2518+ u'\N{LATIN SMALL LETTER C WITH STROKE}': u'C',
2519+ u'\N{LATIN CAPITAL LETTER L WITH BAR}': u'L',
2520+ u'\N{LATIN CAPITAL LETTER T WITH DIAGONAL STROKE}': u'T',
2521+ u'\N{LATIN SMALL LETTER S WITH SWASH TAIL}': u'S',
2522+ u'\N{LATIN SMALL LETTER Z WITH SWASH TAIL}': u'Z',
2523+ # u'\N{LATIN CAPITAL LETTER GLOTTAL STOP}': u'',
2524+ # u'\N{LATIN SMALL LETTER TURNED A}': u'',
2525+ # u'\N{LATIN SMALL LETTER ALPHA}': u'',
2526+ # u'\N{LATIN SMALL LETTER TURNED ALPHA}': u'',
2527+ u'\N{LATIN SMALL LETTER B WITH HOOK}': u'b',
2528+ u'\N{LATIN SMALL LETTER OPEN O}': u'o',
2529+ u'\N{LATIN SMALL LETTER C WITH CURL}': u'c',
2530+ u'\N{LATIN SMALL LETTER D WITH TAIL}': u'd',
2531+ u'\N{LATIN SMALL LETTER D WITH HOOK}': u'd',
2532+ # u'\N{LATIN SMALL LETTER REVERSED E}': u'',
2533+ # u'\N{LATIN SMALL LETTER SCHWA}': u'',
2534+ # u'\N{LATIN SMALL LETTER SCHWA WITH HOOK}': u'',
2535+ u'\N{LATIN SMALL LETTER OPEN E}': u'e',
2536+ # u'\N{LATIN SMALL LETTER REVERSED OPEN E}': u'',
2537+ # u'\N{LATIN SMALL LETTER REVERSED OPEN E WITH HOOK}': u'',
2538+ # u'\N{LATIN SMALL LETTER CLOSED REVERSED OPEN E}': u'',
2539+ u'\N{LATIN SMALL LETTER DOTLESS J WITH STROKE}': u'j',
2540+ u'\N{LATIN SMALL LETTER G WITH HOOK}': u'g',
2541+ u'\N{LATIN SMALL LETTER SCRIPT G}': u'g',
2542+ u'\N{LATIN LETTER SMALL CAPITAL G}': u'G',
2543+ # u'\N{LATIN SMALL LETTER GAMMA}': u'',
2544+ # u'\N{LATIN SMALL LETTER RAMS HORN}': u'',
2545+ # u'\N{LATIN SMALL LETTER TURNED H}': u'',
2546+ u'\N{LATIN SMALL LETTER H WITH HOOK}': u'h',
2547+ u'\N{LATIN SMALL LETTER HENG WITH HOOK}': u'h',
2548+ u'\N{LATIN SMALL LETTER I WITH STROKE}': u'i',
2549+ # u'\N{LATIN SMALL LETTER IOTA}': u'',
2550+ u'\N{LATIN LETTER SMALL CAPITAL I}': u'I',
2551+ u'\N{LATIN SMALL LETTER L WITH MIDDLE TILDE}': u'L',
2552+ u'\N{LATIN SMALL LETTER L WITH BELT}': u'L',
2553+ u'\N{LATIN SMALL LETTER L WITH RETROFLEX HOOK}': u'L',
2554+ # u'\N{LATIN SMALL LETTER LEZH}': u'',
2555+ # u'\N{LATIN SMALL LETTER TURNED M}': u'',
2556+ # u'\N{LATIN SMALL LETTER TURNED M WITH LONG LEG}': u'',
2557+ u'\N{LATIN SMALL LETTER M WITH HOOK}': u'm',
2558+ u'\N{LATIN SMALL LETTER N WITH LEFT HOOK}': u'n',
2559+ u'\N{LATIN SMALL LETTER N WITH RETROFLEX HOOK}': u'n',
2560+ u'\N{LATIN LETTER SMALL CAPITAL N}': u'N',
2561+ u'\N{LATIN SMALL LETTER BARRED O}': u'o',
2562+ u'\N{LATIN LETTER SMALL CAPITAL OE}': u'OE',
2563+ # u'\N{LATIN SMALL LETTER CLOSED OMEGA}': u'',
2564+ # u'\N{LATIN SMALL LETTER PHI}': u'',
2565+ # u'\N{LATIN SMALL LETTER TURNED R}': u'',
2566+ # u'\N{LATIN SMALL LETTER TURNED R WITH LONG LEG}': u'',
2567+ # u'\N{LATIN SMALL LETTER TURNED R WITH HOOK}': u'',
2568+ u'\N{LATIN SMALL LETTER R WITH LONG LEG}': u'r',
2569+ u'\N{LATIN SMALL LETTER R WITH TAIL}': u'r',
2570+ u'\N{LATIN SMALL LETTER R WITH FISHHOOK}': u'r',
2571+ # u'\N{LATIN SMALL LETTER REVERSED R WITH FISHHOOK}': u'',
2572+ u'\N{LATIN LETTER SMALL CAPITAL R}': u'R',
2573+ # u'\N{LATIN LETTER SMALL CAPITAL INVERTED R}': u'',
2574+ u'\N{LATIN SMALL LETTER S WITH HOOK}': u's',
2575+ u'\N{LATIN SMALL LETTER ESH}': u'sh',
2576+ u'\N{LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK}': u'j',
2577+ # u'\N{LATIN SMALL LETTER SQUAT REVERSED ESH}': u'',
2578+ u'\N{LATIN SMALL LETTER ESH WITH CURL}': u'sh',
2579+ # u'\N{LATIN SMALL LETTER TURNED T}': u'',
2580+ u'\N{LATIN SMALL LETTER T WITH RETROFLEX HOOK}': u't',
2581+ u'\N{LATIN SMALL LETTER U BAR}': u'u',
2582+ # u'\N{LATIN SMALL LETTER UPSILON}': u'',
2583+ u'\N{LATIN SMALL LETTER V WITH HOOK}': u'v',
2584+ # u'\N{LATIN SMALL LETTER TURNED V}': u'',
2585+ # u'\N{LATIN SMALL LETTER TURNED W}': u'',
2586+ # u'\N{LATIN SMALL LETTER TURNED Y}': u'',
2587+ u'\N{LATIN LETTER SMALL CAPITAL Y}': u'Y',
2588+ u'\N{LATIN SMALL LETTER Z WITH RETROFLEX HOOK}': u'z',
2589+ u'\N{LATIN SMALL LETTER Z WITH CURL}': u'z',
2590+ u'\N{LATIN SMALL LETTER EZH}': u's',
2591+ u'\N{LATIN SMALL LETTER EZH WITH CURL}': u's',
2592+ # u'\N{LATIN LETTER GLOTTAL STOP}': u'',
2593+ # u'\N{LATIN LETTER PHARYNGEAL VOICED FRICATIVE}': u'',
2594+ # u'\N{LATIN LETTER INVERTED GLOTTAL STOP}': u'',
2595+ u'\N{LATIN LETTER STRETCHED C}': u'c',
2596+ # u'\N{LATIN LETTER BILABIAL CLICK}': u'',
2597+ u'\N{LATIN LETTER SMALL CAPITAL B}': u'B',
2598+ u'\N{LATIN SMALL LETTER CLOSED OPEN E}': u'e',
2599+ u'\N{LATIN LETTER SMALL CAPITAL G WITH HOOK}': u'G',
2600+ u'\N{LATIN LETTER SMALL CAPITAL H}': u'H',
2601+ u'\N{LATIN SMALL LETTER J WITH CROSSED-TAIL}': u'j',
2602+ # u'\N{LATIN SMALL LETTER TURNED K}': u'',
2603+ u'\N{LATIN LETTER SMALL CAPITAL L}': u'L',
2604+ u'\N{LATIN SMALL LETTER Q WITH HOOK}': u'q',
2605+ # u'\N{LATIN LETTER GLOTTAL STOP WITH STROKE}': u'',
2606+ # u'\N{LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE}': u'',
2607+ # u'\N{LATIN SMALL LETTER DZ DIGRAPH}': u'',
2608+ # u'\N{LATIN SMALL LETTER DEZH DIGRAPH}': u'',
2609+ # u'\N{LATIN SMALL LETTER DZ DIGRAPH WITH CURL}': u'',
2610+ # u'\N{LATIN SMALL LETTER TS DIGRAPH}': u'',
2611+ # u'\N{LATIN SMALL LETTER TESH DIGRAPH}': u'',
2612+ # u'\N{LATIN SMALL LETTER TC DIGRAPH WITH CURL}': u'',
2613+ # u'\N{LATIN SMALL LETTER FENG DIGRAPH}': u'',
2614+ # u'\N{LATIN SMALL LETTER LS DIGRAPH}': u'',
2615+ # u'\N{LATIN SMALL LETTER LZ DIGRAPH}': u'',
2616+ # u'\N{LATIN LETTER BILABIAL PERCUSSIVE}': u'',
2617+ # u'\N{LATIN LETTER BIDENTAL PERCUSSIVE}': u'',
2618+ # u'\N{LATIN SMALL LETTER TURNED H WITH FISHHOOK}': u'',
2619+ # u'\N{LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL}': u'',
2620+ u'\N{LATIN LETTER SMALL CAPITAL A}': u'A',
2621+ u'\N{LATIN LETTER SMALL CAPITAL AE}': u'AE',
2622+ # u'\N{LATIN SMALL LETTER TURNED AE}': u'',
2623+ u'\N{LATIN LETTER SMALL CAPITAL BARRED B}': u'B',
2624+ u'\N{LATIN LETTER SMALL CAPITAL C}': u'C',
2625+ u'\N{LATIN LETTER SMALL CAPITAL D}': u'D',
2626+ u'\N{LATIN LETTER SMALL CAPITAL ETH}': u'D',
2627+ u'\N{LATIN LETTER SMALL CAPITAL E}': u'E',
2628+ # u'\N{LATIN SMALL LETTER TURNED OPEN E}': u'',
2629+ # u'\N{LATIN SMALL LETTER TURNED I}': u'',
2630+ u'\N{LATIN LETTER SMALL CAPITAL J}': u'J',
2631+ u'\N{LATIN LETTER SMALL CAPITAL K}': u'K',
2632+ u'\N{LATIN LETTER SMALL CAPITAL L WITH STROKE}': u'L',
2633+ u'\N{LATIN LETTER SMALL CAPITAL M}': u'M',
2634+ # u'\N{LATIN LETTER SMALL CAPITAL REVERSED N}': u'',
2635+ u'\N{LATIN LETTER SMALL CAPITAL O}': u'O',
2636+ u'\N{LATIN LETTER SMALL CAPITAL OPEN O}': u'O',
2637+ # u'\N{LATIN SMALL LETTER SIDEWAYS O}': u'',
2638+ # u'\N{LATIN SMALL LETTER SIDEWAYS OPEN O}': u'',
2639+ # u'\N{LATIN SMALL LETTER SIDEWAYS O WITH STROKE}': u'',
2640+ # u'\N{LATIN SMALL LETTER TURNED OE}': u'',
2641+ u'\N{LATIN LETTER SMALL CAPITAL OU}': u'OU',
2642+ # u'\N{LATIN SMALL LETTER TOP HALF O}': u'',
2643+ # u'\N{LATIN SMALL LETTER BOTTOM HALF O}': u'',
2644+ u'\N{LATIN LETTER SMALL CAPITAL P}': u'P',
2645+ # u'\N{LATIN LETTER SMALL CAPITAL REVERSED R}': u'',
2646+ # u'\N{LATIN LETTER SMALL CAPITAL TURNED R}': u'',
2647+ u'\N{LATIN LETTER SMALL CAPITAL T}': u'T',
2648+ u'\N{LATIN LETTER SMALL CAPITAL U}': u'U',
2649+ # u'\N{LATIN SMALL LETTER SIDEWAYS U}': u'',
2650+ # u'\N{LATIN SMALL LETTER SIDEWAYS DIAERESIZED U}': u'',
2651+ # u'\N{LATIN SMALL LETTER SIDEWAYS TURNED M}': u'',
2652+ u'\N{LATIN LETTER SMALL CAPITAL V}': u'V',
2653+ u'\N{LATIN LETTER SMALL CAPITAL W}': u'W',
2654+ u'\N{LATIN LETTER SMALL CAPITAL Z}': u'',
2655+ u'\N{LATIN LETTER SMALL CAPITAL EZH}': u'S',
2656+ # u'\N{LATIN LETTER VOICED LARYNGEAL SPIRANT}': u'',
2657+ # u'\N{LATIN LETTER AIN}': u'',
2658+ u'\N{LATIN SMALL LETTER UE}': u'ue',
2659+ u'\N{LATIN SMALL LETTER B WITH MIDDLE TILDE}': u'b',
2660+ u'\N{LATIN SMALL LETTER D WITH MIDDLE TILDE}': u'd',
2661+ u'\N{LATIN SMALL LETTER F WITH MIDDLE TILDE}': u'f',
2662+ u'\N{LATIN SMALL LETTER M WITH MIDDLE TILDE}': u'm',
2663+ u'\N{LATIN SMALL LETTER N WITH MIDDLE TILDE}': u'n',
2664+ u'\N{LATIN SMALL LETTER P WITH MIDDLE TILDE}': u'p',
2665+ u'\N{LATIN SMALL LETTER R WITH MIDDLE TILDE}': u'r',
2666+ u'\N{LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE}': u'r',
2667+ u'\N{LATIN SMALL LETTER S WITH MIDDLE TILDE}': u's',
2668+ u'\N{LATIN SMALL LETTER T WITH MIDDLE TILDE}': u't',
2669+ u'\N{LATIN SMALL LETTER Z WITH MIDDLE TILDE}': u'z',
2670+ # u'\N{LATIN SMALL LETTER TURNED G}': u'',
2671+ # u'\N{LATIN SMALL LETTER INSULAR G}': u'',
2672+ u'\N{LATIN SMALL LETTER TH WITH STRIKETHROUGH}': u'th',
2673+ u'\N{LATIN SMALL CAPITAL LETTER I WITH STROKE}': u'I',
2674+ # u'\N{LATIN SMALL LETTER IOTA WITH STROKE}': u'',
2675+ u'\N{LATIN SMALL LETTER P WITH STROKE}': u'p',
2676+ u'\N{LATIN SMALL CAPITAL LETTER U WITH STROKE}': u'U',
2677+ # u'\N{LATIN SMALL LETTER UPSILON WITH STROKE}': u'',
2678+ u'\N{LATIN SMALL LETTER B WITH PALATAL HOOK}': u'b',
2679+ u'\N{LATIN SMALL LETTER D WITH PALATAL HOOK}': u'd',
2680+ u'\N{LATIN SMALL LETTER F WITH PALATAL HOOK}': u'f',
2681+ u'\N{LATIN SMALL LETTER G WITH PALATAL HOOK}': u'g',
2682+ u'\N{LATIN SMALL LETTER K WITH PALATAL HOOK}': u'k',
2683+ u'\N{LATIN SMALL LETTER L WITH PALATAL HOOK}': u'l',
2684+ u'\N{LATIN SMALL LETTER M WITH PALATAL HOOK}': u'm',
2685+ u'\N{LATIN SMALL LETTER N WITH PALATAL HOOK}': u'n',
2686+ u'\N{LATIN SMALL LETTER P WITH PALATAL HOOK}': u'p',
2687+ u'\N{LATIN SMALL LETTER R WITH PALATAL HOOK}': u'r',
2688+ u'\N{LATIN SMALL LETTER S WITH PALATAL HOOK}': u's',
2689+ u'\N{LATIN SMALL LETTER ESH WITH PALATAL HOOK}': u'sh',
2690+ u'\N{LATIN SMALL LETTER V WITH PALATAL HOOK}': u'v',
2691+ u'\N{LATIN SMALL LETTER X WITH PALATAL HOOK}': u'x',
2692+ u'\N{LATIN SMALL LETTER Z WITH PALATAL HOOK}': u'z',
2693+ u'\N{LATIN SMALL LETTER A WITH RETROFLEX HOOK}': u'a',
2694+ # u'\N{LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK}': u'',
2695+ u'\N{LATIN SMALL LETTER D WITH HOOK AND TAIL}': u'd',
2696+ u'\N{LATIN SMALL LETTER E WITH RETROFLEX HOOK}': u'e',
2697+ u'\N{LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK}': u'e',
2698+ u'\N{LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK}': u'e',
2699+ # u'\N{LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK}': u'',
2700+ u'\N{LATIN SMALL LETTER I WITH RETROFLEX HOOK}': u'i',
2701+ u'\N{LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK}': u'o',
2702+ u'\N{LATIN SMALL LETTER ESH WITH RETROFLEX HOOK}': u'sh',
2703+ u'\N{LATIN SMALL LETTER U WITH RETROFLEX HOOK}': u'u',
2704+ u'\N{LATIN SMALL LETTER EZH WITH RETROFLEX HOOK}': u's',
2705+ # u'\N{LATIN SUBSCRIPT SMALL LETTER SCHWA}': u'',
2706+ # u'\N{LATIN CROSS}': u''
2707+ }
2708+
2709+# Additional ones; see "man uni2ascii"
2710+UNI2ASCII_CONVERSIONS={
2711+ u'\N{NO-BREAK SPACE}': u' ',
2712+ u'\N{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'"',
2713+ u'\N{SOFT HYPHEN}': u'', # Controversial: see http://www.cs.tut.fi/~jkorpela/shy.html
2714+ u'\N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'"',
2715+ u'\N{ETHIOPIC WORDSPACE}': u' ',
2716+ u'\N{OGHAM SPACE MARK}': u' ',
2717+ u'\N{EN QUAD}': u' ',
2718+ u'\N{EM QUAD}': u' ',
2719+ u'\N{EN SPACE}': u' ',
2720+ u'\N{EM SPACE}': u' ',
2721+ u'\N{THREE-PER-EM SPACE}': u' ',
2722+ u'\N{FOUR-PER-EM SPACE}': u' ',
2723+ u'\N{SIX-PER-EM SPACE}': u' ',
2724+ u'\N{FIGURE SPACE}': u' ',
2725+ u'\N{PUNCTUATION SPACE}': u' ',
2726+ u'\N{THIN SPACE}': u' ',
2727+ u'\N{HAIR SPACE}': u' ',
2728+ u'\N{ZERO WIDTH SPACE}': u' ',
2729+ u'\N{ZERO WIDTH NO-BREAK SPACE}': u' ',
2730+ u'\N{HYPHEN}': u'-',
2731+ u'\N{NON-BREAKING HYPHEN}': u'-',
2732+ u'\N{FIGURE DASH}': u'-',
2733+ u'\N{EN DASH}': u'-',
2734+ u'\N{EM DASH}': u'-',
2735+ u'\N{LEFT SINGLE QUOTATION MARK}': u'`',
2736+ u'\N{RIGHT SINGLE QUOTATION MARK}': u"'",
2737+ u'\N{SINGLE LOW-9 QUOTATION MARK}': u'`',
2738+ u'\N{SINGLE HIGH-REVERSED-9 QUOTATION MARK}': u'`',
2739+ u'\N{LEFT DOUBLE QUOTATION MARK}': u'"',
2740+ u'\N{RIGHT DOUBLE QUOTATION MARK}': u'"',
2741+ u'\N{DOUBLE LOW-9 QUOTATION MARK}': u'"',
2742+ u'\N{DOUBLE HIGH-REVERSED-9 QUOTATION MARK}': u'"',
2743+ u'\N{SINGLE LEFT-POINTING ANGLE QUOTATION MARK}': u'`',
2744+ u'\N{SINGLE RIGHT-POINTING ANGLE QUOTATION MARK}': u"'",
2745+ u'\N{LOW ASTERISK}': u'*',
2746+ u'\N{MINUS SIGN}': u'-',
2747+ u'\N{ASTERISK OPERATOR}': u'*',
2748+ u'\N{BOX DRAWINGS LIGHT HORIZONTAL}': u'-',
2749+ u'\N{BOX DRAWINGS HEAVY HORIZONTAL}': u'-',
2750+ u'\N{BOX DRAWINGS LIGHT VERTICAL}': u'|',
2751+ u'\N{BOX DRAWINGS HEAVY VERTICAL}': u'|',
2752+ u'\N{HEAVY ASTERISK}': u'*',
2753+ u'\N{HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT}': u'"',
2754+ u'\N{HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT}': u'"',
2755+ u'\N{IDEOGRAPHIC SPACE}': u' ',
2756+ u'\N{SMALL AMPERSAND}': u'&',
2757+ u'\N{SMALL ASTERISK}': u'*',
2758+ u'\N{SMALL PLUS SIGN}': u'+',
2759+ u'\N{CENT SIGN}': u'cent',
2760+ u'\N{POUND SIGN}': u'pound',
2761+ u'\N{YEN SIGN}': u'yen',
2762+ u'\N{COPYRIGHT SIGN}': u'(c)',
2763+ u'\N{REGISTERED SIGN}': u'(R)',
2764+ u'\N{VULGAR FRACTION ONE QUARTER}': u'1/4',
2765+ u'\N{VULGAR FRACTION ONE HALF}': u'1/2',
2766+ u'\N{VULGAR FRACTION THREE QUARTERS}': u'3/4',
2767+ # u'\N{CAPITAL LETTER ASH}': u'AE',
2768+ u'\N{LATIN SMALL LETTER SHARP S}': u'ss',
2769+ # u'\N{SMALL LETTER ASH}': u'ae',
2770+ u'\N{LATIN CAPITAL LIGATURE IJ}': u'IJ',
2771+ u'\N{LATIN SMALL LIGATURE IJ}': u'ij',
2772+ u'\N{LATIN CAPITAL LIGATURE OE}': u'OE',
2773+ u'\N{LATIN SMALL LIGATURE oe}': u'oe',
2774+ u'\N{LATIN CAPITAL LETTER DZ}': u'DZ',
2775+ u'\N{LATIN CAPITAL LETTER DZ WITH CARON}': u'DZ',
2776+ u'\N{LATIN CAPITAL LETTER D WITH SMALL LETTER Z}': u'Dz',
2777+ u'\N{LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON}': u'Dz',
2778+ u'\N{LATIN SMALL LETTER DZ}': u'dz',
2779+ u'\N{LATIN SMALL LETTER TS DIGRAPH}': u'ts',
2780+ u'\N{HORIZONTAL ELLIPSIS}': u'...',
2781+ u'\N{MIDLINE HORIZONTAL ELLIPSIS}': u'...',
2782+ u'\N{LEFTWARDS ARROW}': u'<-',
2783+ u'\N{RIGHTWARDS ARROW}': u'->',
2784+ u'\N{LEFTWARDS DOUBLE ARROW}': u'<=',
2785+ u'\N{RIGHTWARDS DOUBLE ARROW}': u'=>',
2786+ }
2787+
2788+# More from "man uni2ascii", in a different category.
2789+EXTRA_CHARACTERS={
2790+ u'\N{ACUTE ACCENT}': u"'",
2791+ u'\N{BROKEN BAR}': u'|',
2792+ # u'\N{CEDILLA}': u'{cedilla}',
2793+ u'\N{CENT SIGN}': u' cents ',
2794+ u'\N{COPYRIGHT SIGN}': u'(C)',
2795+ u'\N{CURRENCY SIGN}': u' currency ',
2796+ u'\N{DEGREE SIGN}': u' degrees ',
2797+ # u'\N{DIAERESIS}': u'{umlaut}',
2798+ u'\N{DIVISION SIGN}': u'/',
2799+ # u'\N{FEMININE ORDINAL INDICATOR}': u'{^a}',
2800+ u'\N{INVERTED EXCLAMATION MARK}': u'!',
2801+ u'\N{INVERTED QUESTION MARK}': u'?',
2802+ # wrong? u'\N{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'<<',
2803+ u'\N{MACRON}': u'_',
2804+ # u'\N{MASCULINE ORDINAL INDICATOR}': u'{^o}',
2805+ u'\N{MICRO SIGN}': u'micro',
2806+ u'\N{MIDDLE DOT}': u'*',
2807+ u'\N{MULTIPLICATION SIGN}': u'*',
2808+ u'\N{NOT SIGN}': u'not',
2809+ u'\N{PILCROW SIGN}': u'paragraph',
2810+ u'\N{PLUS-MINUS SIGN}': u'+/-',
2811+ u'\N{POUND SIGN}': u'pound',
2812+ u'\N{REGISTERED SIGN}': u'(R)',
2813+ # wrong? u'\N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'>>',
2814+ u'\N{SECTION SIGN}': u'section',
2815+ u'\N{SOFT HYPHEN}': u'',
2816+ u'\N{SUPERSCRIPT ONE}': u'^1',
2817+ u'\N{SUPERSCRIPT THREE}': u'^3',
2818+ u'\N{SUPERSCRIPT TWO}': u'^2',
2819+ u'\N{VULGAR FRACTION ONE HALF}': u'1/2',
2820+ u'\N{VULGAR FRACTION ONE QUARTER}': u'1/4',
2821+ u'\N{VULGAR FRACTION THREE QUARTERS}': u'3/4',
2822+ u'\N{YEN SIGN}': u'yen'
2823+}
2824+FG_HACKS={
2825+ u'\u0082': u'', # "break permitted here" symbol
2826+ u'\u2022': u'*', # Bullet
2827+}
2828+
2829+
2830+def build_dictionary():
2831+ 'Return the translation dictionary.'
2832+ d = dict()
2833+ # First do what can be done automatically
2834+ for i in range(0xffff):
2835+ u=unichr(i)
2836+ try:
2837+ n=unicodedata.name(u)
2838+ if n.startswith('LATIN '):
2839+ k=unicodedata.normalize('NFKD', u).encode('ASCII', 'ignore')
2840+ if k: d[i]=unicode(k) # i=ord(u)
2841+ except ValueError: pass
2842+ # Next, add some by-hand ones (overlap possible, so order matters)
2843+ for m in [EXTRA_LATIN_NAMES,EXTRA_CHARACTERS,UNI2ASCII_CONVERSIONS,FG_HACKS]:
2844+ for i in m:
2845+ try: d[ord(i)]=unicode(m[i])
2846+ except Exception, err: pass
2847+ return d
2848+
2849+
2850+
2851+udict = build_dictionary()
2852+convert = lambda s: s.translate(udict)
2853+
2854+def coroutine(func):
2855+ def start(*argz, **kwz):
2856+ cr = func(*argz, **kwz)
2857+ cr.next()
2858+ return cr
2859+ return start
2860+
2861+@coroutine
2862+def co_filter(drain, in_enc='utf-8', out_enc='ascii'):
2863+ bs = None
2864+ while True:
2865+ chunk = (yield bs)
2866+ bs = drain(convert(unicode(chunk)).encode('utf-8'))
2867+
2868+def uc_filter(sin, sout, bs=8192, in_enc='utf-8', out_enc='ascii'):
2869+ sout = co_filter(sout.write, in_enc, out_enc)
2870+ while True:
2871+ dta = sin.read(bs)
2872+ if not dta: break
2873+ else: sout.send(dta)
2874+
2875+
2876+if __name__ == '__main__':
2877+ from optparse import OptionParser
2878+ parser = OptionParser(usage='%prog [options]',
2879+ description='utf8 stdin -> ascii stdout')
2880+ parser.add_option('-s', '--src-enc',
2881+ action='store', type='str', dest='src_enc', metavar='ENC', default='utf-8',
2882+ help='source encoding (utf-8)')
2883+ parser.add_option('-d', '--dst-enc',
2884+ action='store', type='str', dest='dst_enc', metavar='ENC', default='ascii',
2885+ help='destination encoding (ascii)')
2886+ parser.add_option('-c', '--chunk',
2887+ action='store', type='int', dest='bs', metavar='BYTES', default=8192,
2888+ help='read/write in chunks of a given size (8192)')
2889+ optz, argz = parser.parse_args()
2890+ if argz: parser.error('Only stdin -> stdout conversion suported')
2891+
2892+ uc_filter(sys.stdin, sys.stdout, bs=optz.bs, in_enc=optz.src_enc, out_enc=optz.dst_enc)