[MRG] from c2c l10n_ch

bzr revid: yannick.vaucher@camptocamp.com-20110916143255-7btktl8u1u23cwn0
This commit is contained in:
Yannick Vaucher 2011-09-16 16:32:55 +02:00
parent e1012285a3
commit 2b142c0a31
33 changed files with 2377 additions and 974 deletions

View File

@ -2,7 +2,7 @@
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
# Donors: Hasa SA, Open Net SA and Prisme Solutions Informatique SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -21,10 +21,8 @@
{
"name" : "Switzerland - localization with 2011 taxes",
"description" : """
Swiss localisation.
===================
"description" : """
Swiss localisation :
- DTA generation for a lot of payment types
- BVR management (number generation, report, etc..)
- Import account move from the bank file (like v11 etc..)
@ -33,9 +31,11 @@ Swiss localisation.
You can also add ZIP and bank completion with:
- l10n_ch_zip
- l10n_ch_bank
Author: Camptocamp SA
Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
Author: Camptocamp SA
Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
------------------------------------------------------------------------
Module incluant la localisation Suisse de TinyERP revu et corrigé par Camptocamp. Cette nouvelle version
comprend la gestion et l'émissionde BVR, le paiement électronique via DTA (pour les banques, le système postal est en développement)
@ -47,10 +47,11 @@ Par ailleurs, conjointement à ce module, nous proposons la complétion NPA:
Vous pouvez ajouter la completion des banques et des NPA avec with:
- l10n_ch_zip
- l10n_ch_bank
Auteur: Camptocamp SA
Donateurs: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
--------------------------------------------------------------------------
TODO :
- Implement bvr import partial reconciliation
- Replace wizard by osv_memory when possible
@ -60,8 +61,8 @@ TODO :
""",
"version" : "6.0",
"author" : "Camptocamp SA",
"version" : "6.1",
"author" : "Camptocamp",
"category" : "Finance",
"website": "http://www.camptocamp.com",
@ -83,10 +84,10 @@ TODO :
],
"demo_xml" : [
"demo/demo.xml",
"demo/dta_demo.xml",
],
"update_xml" : [
"wizard.xml",
"dta_view.xml",
"wizard/bvr_import_view.xml",
"wizard/create_dta_view.xml",
"company_view.xml",
@ -97,6 +98,9 @@ TODO :
],
'test' : [
'test/l10n_ch_report.yml',
'test/l10n_ch_dta.yml',
'test/l10n_ch_v11.yml',
'test/l10n_ch_v11_part.yml',
],
"active": False,
"installable": True,

View File

@ -32,13 +32,13 @@ class WizardMultiChartsAccounts(osv.osv_memory):
'sale_tax': False,
'purchase_tax':False
}
def execute(self, cr, uid, ids, context=None):
"""Override of code in order to be able to link journal with account in XML"""
res = super(WizardMultiChartsAccounts, self).execute(cr, uid, ids, context)
path = addons.get_module_resource(os.path.join('l10n_ch','sterchi_chart','account_journal_rel.xml'))
tools.convert_xml_import(cr, 'l10n_ch', path, idref=None, mode='init', noupdate=True, report=None)
return res
WizardMultiChartsAccounts()
WizardMultiChartsAccounts()

View File

@ -19,12 +19,15 @@
#
##############################################################################
from tools.translate import _
from osv import fields, osv
class Bank(osv.osv):
"""Inherit res.bank class in order to add swiss specific field"""
_inherit = 'res.bank'
_columns = {
### Internal reference
'code': fields.char('Code', size=64),
###Swiss unik bank identifier also use in IBAN number
'clearing': fields.char('Clearing number', size=64),
### city of the bank
@ -33,15 +36,113 @@ class Bank(osv.osv):
Bank()
class bvr_checkbox(osv.osv):
""" Add function to generate function """
class ResPartnerBank(osv.osv):
_inherit = "res.partner.bank"
_columns = {
'print_bank' : fields.boolean('Print Bank on BVR'),
'print_account' : fields.boolean('Print Account Number on BVR'),
}
'name': fields.char('Description', size=128, required=True),
'post_number': fields.char('Post number', size=64),
'bvr_adherent_num': fields.char('BVR adherent number', size=11),
'dta_code': fields.char('DTA code', size=5),
'print_bank': fields.boolean('Print Bank on BVR'),
'print_account': fields.boolean('Print Account Number on BVR'),
'acc_number': fields.char('Account/IBAN Number', size=64),
}
bvr_checkbox()
def name_get(self, cursor, uid, ids, context=None):
if not len(ids):
return []
bank_type_obj = self.pool.get('res.partner.bank.type')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
type_ids = bank_type_obj.search(cursor, uid, [])
bank_type_names = {}
for bank_type in bank_type_obj.browse(cursor, uid, type_ids,
context=context):
bank_type_names[bank_type.code] = bank_type.name
res = []
for r in self.read(cursor, uid, ids, ['name','state'], context):
res.append((r['id'], r['name']+' : '+bank_type_names.get(r['state'], '')))
return res
def post_write(self, cr, uid, ids, context={}):
""" Override of post_write method.
In Switzerland with post accounts you can either have a postal account
with a required bank number (BVR Bank) or a postal number alone (BV Post, BVR Post).
So acc_number is not always mandatory and postal and bank number are not the same field """
obj_acc = self.pool.get('account.account')
obj_data = self.pool.get('ir.model.data')
for bank in self.browse(cr, uid, ids, context):
if bank.company_id and not bank.journal_id:
# Find the code and parent of the bank account to create
dig = 6
current_num = 1
ids = obj_acc.search(cr, uid, [('type','=','liquidity')], context=context)
# No liquidity account exists, no template available
if not ids: continue
ref_acc_bank_temp = obj_acc.browse(cr, uid, ids[0], context=context)
ref_acc_bank = ref_acc_bank_temp.parent_id
while True:
new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num)
ids = obj_acc.search(cr, uid, [('code', '=', new_code), ('company_id', '=', bank.company_id.id)])
if not ids:
break
current_num += 1
# Here is the test
if not bank.acc_number:
number = bank.post_number
else:
number = bank.acc_number
acc = {
'name': (bank.bank_name or '')+' '+ number,
'currency_id': bank.company_id.currency_id.id,
'code': new_code,
'type': 'liquidity',
'user_type': ref_acc_bank_temp.user_type.id,
'reconcile': False,
'parent_id': ref_acc_bank.id,
'company_id': bank.company_id.id,
}
acc_bank_id = obj_acc.create(cr,uid,acc,context=context)
# Get the journal view id
data_id = obj_data.search(cr, uid, [('model','=','account.journal.view'), ('name','=','account_journal_bank_view')])
data = obj_data.browse(cr, uid, data_id[0], context=context)
view_id_cash = data.res_id
jour_obj = self.pool.get('account.journal')
new_code = 1
while True:
code = _('BNK')+str(new_code)
ids = jour_obj.search(cr, uid, [('code','=',code)], context=context)
if not ids:
break
new_code += 1
#create the bank journal
vals_journal = {
'name': (bank.bank_name or '')+' '+number,
'code': code,
'type': 'bank',
'company_id': bank.company_id.id,
'analytic_journal_id': False,
'currency_id': False,
'default_credit_account_id': acc_bank_id,
'default_debit_account_id': acc_bank_id,
'view_id': view_id_cash
}
journal_id = jour_obj.create(cr, uid, vals_journal, context=context)
self.write(cr, uid, [bank.id], {'journal_id': journal_id}, context=context)
return True
_sql_constraints = [('bvr_adherent_uniq', 'unique (bvr_adherent_num)',
'The BVR adherent number must be unique !')]
ResPartnerBank()

View File

@ -1,54 +1,184 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- res.bank base form-->
<record model="ir.ui.view" id="view_res_bank_form">
<field name="name">res.bank.form</field>
<field name="model">res.bank</field>
<field name="type">form</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="base.view_res_bank_form"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="code"/>
</field>
<field name="bic" position="after">
<field name="clearing"/>
</field>
</field>
</record>
<!-- res.bank base tree-->
<record model="ir.ui.view" id="l10nch_view_res_bank_tree">
<field name="name">res.bank.tree</field>
<field name="model">res.bank</field>
<field name="type">tree</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="base.view_res_bank_tree"/>
<field name="arch" type="xml">
<field name="code" position="after">
<field name="name" position="after">
<field name="code" select="1"/>
<field name="clearing" select="1"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank">
<field name="name">res.partner_bank.form</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<field name="country_id" position="after">
<field name="print_bank"/>
<field name="print_account"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank">
<field name="name">res.partner_partner_bank.form</field>
<!-- res.partner.bank in res partner form-->
<!-- Partner -> Bank Details -->
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f1">
<field name="name">res.partner_bank.form.hide.f1</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="bank" position="after">
<newline />
<field name="print_bank"/>
<field name="print_account"/>
<field name="acc_number" position="replace">
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_f2">
<field name="name">res.partner_bank.form.hide.f2</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="bank" position="replace">
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_add_groups">
<field name="name">res.partner_bank.form.hide.f2</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="sequence" eval="10" />
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="state" position="after">
<newline/>
<separator colspan="4" string="Account infos"/>
<group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
<field name="acc_number" string="Account/IBAN Number" attrs="{'required': [('state','not in',['bvpost','bvrpost'])]}"/>
<field name="dta_code"/>
<newline/>
</group>
<newline/>
<group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
<field name="post_number" attrs="{'required': [('state','in',['bvpost','bvrpost','bvrbank'])]}"/>
<newline/>
</group>
<separator colspan="4" string="Financial institute infos"/>
<field name="bank" />
</field>
</field>
</record>
<!-- res.partner.bank base form-->
<!-- Sales -> Configuration -> Address Book -> Bank accounts -->
<!-- Invoice -> Bank account -->
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_acc_number_hide_frominvoice">
<field name="name">res.partner_bank.form.hide.acc_number.frominvoice</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<field name="acc_number" position="replace">
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_hide_bank_frominvoice2">
<field name="name">res.partner_bank.form.hide.bank.frominvoice</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="sequence" eval="9" />
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<field name="bank" position="replace">
</field>
</field>
</record>
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_from_invoice">
<field name="name">res.partner_bank.form.hide.frominvoice</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="sequence" eval="10"/>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<field name="state" position="after">
<newline/>
<separator colspan="4" string="Account infos"/>
<newline/>
<group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
<field name="acc_number" string="Account/IBAN Number" attrs="{'required': [('state','not in',['bvpost','bvrpost'])]}"/>
<field name="dta_code"/>
<newline/>
</group>
<newline/>
<group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
<field name="post_number" attrs="{'required': [('state','in',['bvpost','bvrpost','bvrbank'])]}"/>
<newline/>
</group>
<separator colspan="4" string="Financial institute infos"/>
<group string="BVR print options" colspan="4" attrs="{'invisible': [('company_id','=',False)]}" >
<field name="bvr_adherent_num"/>
<field name="print_bank"/>
<field name="print_account"/>
<newline/>
</group>
<newline/>
<field name="bank" />
</field>
</field>
</record>
<!-- res.partner form bank list-->
<!-- Adding Type and bank name -->
<record id="l10nch_view_partner_bank_details_list" model="ir.ui.view">
<field name="name">res.partner.form.bank_details.list</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='bank_ids']/tree/field[@name='acc_number']" position="before">
<field name="state" />
<field name="bank" />
</xpath>
</field>
</record>
<!-- res.partner form bank list-->
<!-- Adding Type and bank name -->
<record id="l10nch_view_partner_bank_invoice_tree" model="ir.ui.view">
<field name="name">res.partner.bank.tree.from_invoice</field>
<field name="model">res.partner.bank</field>
<field name="inherit_id" ref="base.view_partner_bank_tree"/>
<field name="type">tree</field>
<field name="arch" type="xml">
<field name="acc_number" position="before">
<field name="state" />
<field name="bank" />
</field>
</field>
</record>
</data>
</openerp>

View File

@ -29,19 +29,36 @@ class res_company(osv.osv):
_columns = {
'bvr_delta_horz': fields.float('BVR Horz. Delta (mm)',
help='horiz. delta in mm 1.2 will print the bvr 1.2mm lefter, negative value is possible'),
'bvr_delta_vert': fields.float('BVR Vert. Delta (mm)',
help='vert. delta in mm 1.2 will print the bvr 1.2mm lower, negative value is possible'),
'bvr_scan_line_vert': fields.float('BVR vert. position for scan line (mm)',
help='Vert. position in mm for scan line'),
'bvr_scan_line_horz': fields.float('BVR horiz. position for scan line(mm)',
help='Horiz. position in mm for scan line'),
'bvr_scan_line_font_size': fields.float('BVR scan line font size (pt)'),
'bvr_scan_line_letter_spacing':fields.float('BVR scan line letter spacing'),
'bvr_background': fields.boolean('Insert BVR background ?'),
'bvr_only': fields.boolean('Separated BVR only ?',
help='Print only the BVR separated page'),
'invoice_only': fields.boolean('Invoice only (Do not use with bvr only)?',
help='Print only the invoice without BVR'),
}
_defaults = {
'bvr_scan_line_vert': lambda *a: 232,
'bvr_scan_line_horz': lambda *a: 72,
'bvr_scan_line_font_size': lambda *a: 12,
'bvr_scan_line_letter_spacing': lambda *a: 0,
}
res_company()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -8,13 +8,21 @@
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="rml_footer2" position="after">
<field name="bvr_delta_horz"/>
<field name="bvr_delta_vert"/>
<field name="bvr_background"/>
<field name="bvr_only"/>
<field name="invoice_only"/>
<newline/>
<group string="BVR data" colspan="4">
<field name="bvr_delta_horz"/>
<field name="bvr_delta_vert"/>
<field name="bvr_scan_line_vert"/>
<field name="bvr_scan_line_horz"/>
<field name="bvr_scan_line_font_size"/>
<field name="bvr_scan_line_letter_spacing"/>
<field name="bvr_background"/>
<field name="bvr_only"/>
<field name="invoice_only"/>
</group>
<newline/>
</field>
</field>
</record>
</data>
</openerp>
</openerp>

View File

@ -13,10 +13,8 @@
<field name="state">bvrbank</field>
<field name="post_number">11-1234-1</field>
<field name="bank" ref="main_bank"/>
<field name="iban">CH9100767000S00023455</field>
<!-- <field name="iban">CH9100767000S00023455</field> -->
<field name="bvr_adherent_num">0000000</field>
</record>
<record id="bank" model="res.partner">
@ -24,7 +22,6 @@
<field name="ref">banq</field>
<field name="name">Banque</field>
<field name="category_id" model="res.partner.category" search="[('name','=','Partenaire')]"/>
<field name="address" eval="[]"/>
</record>
<record id="res_partner_address_bank1" model="res.partner.address">
@ -48,7 +45,6 @@
<field name="website">http://camptocamp.com</field>
<field name="name">ProLibre</field>
<field name="category_id" model="res.partner.category" search="[('name','=','Partenaire')]"/>
<field name="address" eval="[]"/>
</record>
<record id="camptocamp" model="res.partner">
@ -58,7 +54,6 @@
<field name="website">http://camptocamp.com</field>
<field name="name">camptocamp SA</field>
<field name="category_id" model="res.partner.category" search="[('name','=','Partenaire')]"/>
<field name="address" eval="[]"/>
</record>
<!--
Resource: res.partner.address

View File

@ -14,17 +14,18 @@
<field name="state">bvrbank</field>
<field name="post_number">234567</field>
<field name="bank" ref="partner_bank"/>
<field name="iban">CH9100767000S00023455</field>
<!-- <field name="iban">CH9100767000S00023455</field> -->
</record>
<record model="res.partner.bank" id="main_bank">
<field name="name">My bank</field>
<field name="acc_number">123456</field>
<field name="iban">123456</field>
<!-- <field name="acc_number">123456</field> -->
<!-- <field name="iban">123456</field> -->
<field name="partner_id" ref="base.main_partner"/>
<field name="state">dta_company</field>
<field name="bank" ref="partner_bank"/>
<field name="iban">CH9100767000S00023455</field>
<!-- <field name="iban">CH9100767000S00023455</field> -->
<field name="acc_number">CH9100767000S00023455</field>
</record>
<record model="account.invoice" id="v11_invoice">

View File

@ -1,85 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
from osv import osv, fields
class account_dta(osv.osv):
"""class that implements bank DTA File format,
used to transfert bulk batch payment instruction to a bank"""
_name = "account.dta"
_description = "DTA History"
_columns = {
### name of the file
'name': fields.binary('DTA file', readonly=True),
### list of dta line linked to the dta order
'dta_line_ids': fields.one2many('account.dta.line','dta_id','DTA lines', readonly=True),
## textual notes
'note': fields.text('Creation log', readonly=True,
help="Displays the problem during dta generation"),
### bank how will execute DTA order
'bank': fields.many2one('res.partner.bank','Bank', readonly=True,select=True,
help="Bank how will execute DTA order"),
### date of DTA order generation
'date': fields.date('Creation Date', readonly=True,select=True,
help="Date of DTA order generation"),
### user how generate the DTA order
'user_id': fields.many2one('res.users','User', readonly=True, select=True),
}
account_dta()
class account_dta_line(osv.osv):
"""Class that represent a DTA order line,
each line corressponds to a payment instruction"""
_name = "account.dta.line"
_description = "DTA line"
_columns = {
### name of the line
'name' : fields.many2one('account.invoice','Invoice', required=True, size=256),
### partner how will receive payments
'partner_id' : fields.many2one('res.partner','Partner',
help="Partenr to pay"),
### due date of the payment
'due_date' : fields.date('Due date'),
### date of the supplier invoice to pay
'invoice_date' : fields.date('Invoice date'),
### cash discount date
'cashdisc_date' : fields.date('Cash Discount date'),
### amount effectively paied on this line
'amount_to_pay' : fields.float('Amount to pay',
help="Amount effectively paid"),
### amount that was on the supplier invoice
'amount_invoice': fields.float('Invoiced Amount',
help="Amount to pay base on the supplier invoice"),
### Cash discount amount
'amount_cashdisc': fields.float('Cash Discount Amount'),
### Linke to the main dta order
'dta_id': fields.many2one('account.dta','Associated DTA', required=True, ondelete='cascade'),
### state of the invoice Drat, Cancel, Done
'state' : fields.selection([('draft','Draft'),('cancel','Error'),('done','Paid')],'State')
}
_defaults = {
'state' : lambda *a :'draft',
}
account_dta_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<data noupdate="1">
<!-- Memo :
@ -30,113 +30,25 @@
<field name="code">dta_company</field>
</record>
<record model="res.partner.bank.type" id="dta_iban">
<field name="name">DTA-IBAN</field>
<field name="code">dta_iban</field>
</record>
<record model="res.partner.bank.type" id="bvrbank">
<field name="name">DTA-BVRBANK</field>
<field name="name">BVR Bank</field>
<field name="code">bvrbank</field>
</record>
<record model="res.partner.bank.type" id="bvrpost">
<field name="name">DTA-BVRPOST</field>
<field name="name">BVR Post</field>
<field name="code">bvrpost</field>
</record>
<record model="res.partner.bank.type" id="bvpost">
<field name="name">DTA-BVPOST</field>
<field name="name">BV Post</field>
<field name="code">bvpost</field>
</record>
<record model="res.partner.bank.type" id="bvbank">
<field name="name">DTA-BVBANK</field>
<field name="name">BV Bank</field>
<field name="code">bvbank</field>
</record>
<!-- Adjust the fields attributes for dta_company-->
<record model="res.partner.bank.type.field" id="iban_field">
<field name="name">iban</field>
<field name="bank_type_id" ref="bank_dta"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<!-- Adjust the fields attributes for dta_iban-->
<record model="res.partner.bank.type.field" id="iban_field_iban">
<field name="name">iban</field>
<field name="bank_type_id" ref="dta_iban"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<record model="res.partner.bank.type.field" id="bank_field_iban">
<field name="name">bank</field>
<field name="bank_type_id" ref="dta_iban"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<!-- Adjust the fields attributes for bvrbank-->
<record model="res.partner.bank.type.field" id="bank_field_bvrbank">
<field name="name">bank</field>
<field name="bank_type_id" ref="bvrbank"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<record model="res.partner.bank.type.field" id="bvr_num_field_bvrbank">
<field name="name">post_number</field>
<field name="bank_type_id" ref="bvrbank"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<!-- Adjust the fields attributes for bvrpost-->
<record model="res.partner.bank.type.field" id="bank_field_bvrpost">
<field name="name">bank</field>
<field name="bank_type_id" ref="bvrpost"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<record model="res.partner.bank.type.field" id="bvr_num_field_bvrpost">
<field name="name">post_number</field>
<field name="bank_type_id" ref="bvrpost"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<!-- Adjust the fields attributes for bvpost -->
<record model="res.partner.bank.type.field" id="bank_field_bvpost">
<field name="name">bank</field>
<field name="bank_type_id" ref="bvpost"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<record model="res.partner.bank.type.field" id="post_field_bvpost">
<field name="name">post_number</field>
<field name="bank_type_id" ref="bvpost"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<!-- Adjust the fields attributes for bvbank -->
<record model="res.partner.bank.type.field" id="bank_field_bvbank">
<field name="name">bank</field>
<field name="bank_type_id" ref="bvbank"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
<record model="res.partner.bank.type.field" id="acc_num_field_bvbank">
<field name="name">acc_number</field>
<field name="bank_type_id" ref="bvbank"/>
<field name="required" eval="True"/>
<field name="readonly" eval="False"/>
</record>
</data>
</openerp>
</openerp>

View File

@ -1,37 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Inherit both bank view -->
<record model="ir.ui.view" id="view_partner_bank_form">
<field name="name">partner - bank inherit</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="acc_number" position="after">
<newline/>
<field name="bvr_adherent_num"/>
<field name="post_number"/>
<field name="dta_code"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="view_partner_bank_form2">
<field name="name">partner - bank inherit</field>
<field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml">
<field name="acc_number" position="after">
<newline/>
<field name="bvr_adherent_num"/>
<field name="post_number"/>
<field name="dta_code"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@ -73,7 +73,7 @@ class account_invoice(osv.osv):
help='The partner bank account to pay\nKeep empty to use the default'
),
### Amount to pay
'amount_to_pay': fields.function(_amount_to_pay,
'amount_to_pay': fields.function(_amount_to_pay, method=True,
type='float', string='Amount to be paid',
help='The amount which should be paid at the current date\n' \
'minus the amount which is already in payment order'),
@ -120,7 +120,7 @@ class account_invoice(osv.osv):
invoice.partner_bank_id.state in \
('bvrbank', 'bvrpost') and \
invoice.reference_type != 'bvr':
return False
return False
return True
_constraints = [
@ -143,16 +143,16 @@ class account_invoice(osv.osv):
def onchange_partner_id(self, cr, uid, ids, type, partner_id,
date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
""" Function that is call when the partner of the invoice is changed
it will retriev and set the good bank partner bank"""
it will retrieve and set the good bank partner bank"""
res = super(account_invoice, self).onchange_partner_id(
cr,
uid,
ids,
type,
partner_id,
date_invoice,
payment_term
)
uid,
ids,
type,
partner_id,
date_invoice,
payment_term
)
bank_id = False
if partner_id:
p = self.pool.get('res.partner').browse(cr, uid, partner_id)

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="expenses_journal" model="account.journal">
<field name="name">Journal de frais</field>
@ -15,7 +15,7 @@
<record id="bank_journal" model="account.journal">
<field name="name">Banque CHF</field>
<field name="code">BCHF</field>
<field name="type">cash</field>
<field name="type">bank</field>
<field name="view_id" ref="account.account_journal_bank_view"/>
<field name="sequence_id" ref="account.sequence_journal"/>
<field name="user_id" ref="base.user_root"/>
@ -26,7 +26,7 @@
<record id="bank_euro_journal" model="account.journal">
<field name="name">Banque EUR</field>
<field name="code">BEUR</field>
<field name="type">cash</field>
<field name="type">bank</field>
<field name="view_id" ref="account.account_journal_bank_view"/>
<field name="sequence_id" ref="account.sequence_journal"/>
<field name="user_id" ref="base.user_root"/>

View File

@ -30,35 +30,4 @@ class res_partner(osv.osv):
}
res_partner()
class res_partner_bank(osv.osv):
_inherit = "res.partner.bank"
_columns = {
'name': fields.char('Description', size=128, required=True),
'post_number': fields.char('Post number', size=64),
'bvr_adherent_num': fields.char('BVR adherent number', size=11),
'dta_code': fields.char('DTA code', size=5),
}
def name_get(self, cr, uid, ids, context=None):
if not len(ids):
return []
bank_type_obj = self.pool.get('res.partner.bank.type')
type_ids = bank_type_obj.search(cr, uid, [])
bank_type_names = {}
for bank_type in bank_type_obj.browse(cr, uid, type_ids,
context=context):
bank_type_names[bank_type.code] = bank_type.name
res = []
for r in self.read(cr, uid, ids, ['name','state'], context):
res.append((r['id'], r['name']+' : '+bank_type_names[r['state']]))
return res
_sql_constraints = [
('bvr_adherent_uniq', 'unique (bvr_adherent_num)', 'The BVR adherent number must be unique !')
]
res_partner_bank()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,6 +7,17 @@
font-weight: normal;
src: url(${police_absolute_path('ocrbb.ttf')}) format("truetype");
}
.ocrbb{
text-align:right;
font-family:bvrocrb;
font-size:${str(company.bvr_scan_line_font_size or '0.0').replace(',','.')}pt;
position:absolute;top:${str(company.bvr_scan_line_vert or '0.0').replace(',','.')}mm;
left:${str(company.bvr_scan_line_horz or '0.0').replace(',','.')}mm;
z-index:4;
letter-spacing:str(company.bvr_scan_line_letter_spacing or '0.0').replace(',','.')
}
${css}
</style>
</style>
</head>
@ -87,9 +98,41 @@
}
</script>
${_check(objects)}
%for inv in objects :
<% setLang(inv.partner_id.lang) %>
<!--adresses + info block -->
<table class="dest_address" style="position:absolute;top:6mm;left:15mm">
<tr><td ><b>${inv.partner_id.title.name or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
<tr><td>${inv.address_invoice_id.street or ''|entity}</td></tr>
<tr><td>${inv.address_invoice_id.street2 or ''|entity}</td></tr>
<tr><td>${inv.address_invoice_id.zip or ''|entity} ${inv.address_invoice_id.city or ''|entity}</td></tr>
%if inv.address_invoice_id.country_id :
<tr><td>${inv.address_invoice_id.country_id.name or ''|entity} </td></tr>
%endif
%if inv.address_invoice_id.phone :
<tr><td>${_("Tel") |entity}: ${inv.address_invoice_id.phone|entity}</td></tr>
%endif
%if inv.address_invoice_id.fax :
<tr><td>${_("Fax") |entity}: ${inv.address_invoice_id.fax|entity}</td></tr>
%endif
%if inv.address_invoice_id.email :
<tr><td>${_("E-mail") |entity}: ${inv.address_invoice_id.email|entity}</td></tr>
%endif
%if inv.partner_id.vat :
<tr><td>${_("VAT") |entity}: ${inv.partner_id.vat|entity}</td></tr>
%endif
</table>
<div style="position:absolute;top:60mm; left:20mm">
${_('Invoice')} - ${inv.number or ''|entity}
<br/>
<br/>
${_('Here is the BVR to allow you to pay the invoice %s - %s') % (inv.name or '', inv.number or '',)}
<br/>
${_('Regards')}
</div>
<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>
<div id="cont_${inv.id}" style="padding-left:20mm;padding-top:0;padding-bottom:10;height:180mm">
<!-- Your communication message here -->
</div>
@ -103,7 +146,7 @@
<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>
<tr style="height:21.166667mm"><td></td><td></td><td></td></tr>
<tr style="height:8.4666667mm"> <td></td><td></td><td></td></tr>
<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>
<tr style="height:21.166667mm;vertical-align:top"><td></td><td></td></tr>
</table>
%endfor
</body>

View File

@ -9,7 +9,7 @@
<% setLang(inv.partner_id.lang) %>
<div id="inv_cont_${inv.id}" style="padding-left:20mm;padding-top:0;padding-bottom:10;border-width:0px;border-style:solid">
<table class="dest_address">
<tr><td ><b>${inv.partner_id.title or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
<tr><td ><b>${inv.partner_id.title.name or ''|entity} ${inv.partner_id.name |entity}</b></td></tr>
<tr><td>${inv.address_invoice_id.street or ''|entity}</td></tr>
<tr><td>${inv.address_invoice_id.street2 or ''|entity}</td></tr>
<tr><td>${inv.address_invoice_id.zip or ''|entity} ${inv.address_invoice_id.city or ''|entity}</td></tr>

View File

@ -33,7 +33,9 @@ import addons
import pooler
from tools.config import config
from mako.template import Template
from mako import exceptions
from tools.translate import _
from osv.osv import except_osv
class l10n_ch_report_webkit_html(report_sxw.rml_parse):
@ -41,16 +43,15 @@ class l10n_ch_report_webkit_html(report_sxw.rml_parse):
super(l10n_ch_report_webkit_html, self).__init__(cr, uid, name, context=context)
self.localcontext.update({
'time': time,
'cr':cr,
'cr': cr,
'uid': uid,
'user':self.pool.get("res.users").browse(cr, uid, uid),
'mod10r': mod10r,
'_space': self._space,
'_get_ref': self._get_ref,
'comma_me': self.comma_me,
'police_absolute_path' : self.police_absolute_path,
'bvr_absolute_path':self.bvr_absolute_path,
'_check' : self._check,
'police_absolute_path': self.police_absolute_path,
'bvr_absolute_path': self.bvr_absolute_path,
'headheight': self.headheight
})
@ -58,15 +59,22 @@ class l10n_ch_report_webkit_html(report_sxw.rml_parse):
_compile_comma_me = re.compile("^(-?\d+)(\d{3})")
_compile_check_bvr = re.compile('[0-9][0-9]-[0-9]{3,6}-[0-9]')
_compile_check_bvr_add_num = re.compile('[0-9]*$')
def set_context(self, objects, data, ids, report_type=None):
user = self.pool.get('res.users').browse(self.cr, self.uid, self.uid)
company = user.company_id
if not company.invoice_only:
self._check(ids)
return super(l10n_ch_report_webkit_html, self).set_context(objects, data, ids, report_type=report_type)
def police_absolute_path(self, inner_path) :
"""Will get the ocrb police absolute path"""
path = addons.get_module_resource(os.path.join('l10n_ch','report',inner_path))
path = addons.get_module_resource(os.path.join('l10n_ch', 'report', inner_path))
return path
def bvr_absolute_path(self) :
"""Will get the ocrb police absolute path"""
path = addons.get_module_resource(os.path.join('l10n_ch','report','bvr1.jpg'))
path = addons.get_module_resource(os.path.join('l10n_ch', 'report', 'bvr1.jpg'))
return path
def headheight(self):
@ -76,7 +84,7 @@ class l10n_ch_report_webkit_html(report_sxw.rml_parse):
def comma_me(self, amount):
"""Fast swiss number formatting"""
if type(amount) is float :
if isinstance(amount, float):
amount = str('%.2f'%amount)
else :
amount = str(amount)
@ -88,14 +96,15 @@ class l10n_ch_report_webkit_html(report_sxw.rml_parse):
return self.comma_me(new)
def _space(self, nbr, nbrspc=5):
"""Spaces * 5"""
res = ''
for i in range(len(nbr)):
res = res + nbr[i]
if not (i-1) % nbrspc:
res = res + ' '
return res
"""Spaces * 5.
Example:
>>> self._space('123456789012345')
'12 34567 89012 345'
"""
return ''.join([' '[(i - 2) % nbrspc:] + c for i, c in enumerate(nbr)])
def _get_ref(self, inv):
"""Retrieve ESR/BVR reference form invoice in order to print it"""
res = ''
@ -106,39 +115,77 @@ class l10n_ch_report_webkit_html(report_sxw.rml_parse):
invoice_number = self._compile_get_ref.sub('', inv.number)
return mod10r(res + invoice_number.rjust(26-len(res), '0'))
def _check(self, invoices):
def _check(self, invoice_ids):
"""Check if the invoice is ready to be printed"""
if not invoice_ids:
invoice_ids = []
cursor = self.cr
pool = self.pool
invoice_obj = pool.get('account.invoice')
ids = [x.id for x in invoices]
ids = invoice_ids
for invoice in invoice_obj.browse(cursor, self.uid, ids):
if not invoice.partner_bank_id:
raise wizard.except_wizard(_('UserError'),
raise except_osv(_('UserError'),
_('No bank specified on invoice:\n' + \
invoice_obj.name_get(cursor, self.uid, [invoice.id],
context={})[0][1]))
if not self._compile_check_bvr.match(
invoice.partner_bank_id.post_number or ''):
raise wizard.except_wizard(_('UserError'),
_("Your bank BVR number should be of the form 0X-XXX-X! " +
'Please check your company ' +
'information for the invoice:\n' +
invoice_obj.name_get(cursor, self.uid, [invoice.id],
context={})[0][1]))
raise except_osv(_('UserError'),
_('Your bank BVR number should be of the form 0X-XXX-X! ' +
'Please check your company ' +
'information for the invoice:\n' +
invoice_obj.name_get(cursor, self.uid, [invoice.id],
context={})[0][1]))
if invoice.partner_bank_id.bvr_adherent_num \
and not self._compile_check_bvr_add_num.match(
invoice.partner_bank_id.bvr_adherent_num):
raise wizard.except_wizard('UserError',
'Your bank BVR adherent number must contain exactly seven' +
'digits!\nPlease check your company ' +
'information for the invoice:\n' +
invoice_obj.name_get(cursor, self.uid, [invoice.id],
context={})[0][1])
return ""
raise except_osv(_('UserError'),
_('Your bank BVR adherent number must contain exactly seven' +
'digits!\nPlease check your company ' +
'information for the invoice:\n' +
invoice_obj.name_get(cursor, self.uid, [invoice.id],
context={})[0][1]))
return ''
class BVRWebKitParser(webkit_report.WebKitParser):
def setLang(self, lang):
if not lang:
lang = 'en_US'
self.localcontext['lang'] = lang
def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False):
"""format using the know cursor, language from localcontext"""
if digits is None:
digits = self.parser_instance.get_digits(value)
if isinstance(value, (str, unicode)) and not value:
return ''
pool_lang = self.pool.get('res.lang')
lang = self.localcontext['lang']
lang_ids = pool_lang.search(self.parser_instance.cr, self.parser_instance.uid, [('code','=',lang)])[0]
lang_obj = pool_lang.browse(self.parser_instance.cr, self.parser_instance.uid, lang_ids)
if date or date_time:
if not str(value):
return ''
date_format = lang_obj.date_format
parse_format = '%Y-%m-%d'
if date_time:
value=value.split('.')[0]
date_format = date_format + " " + lang_obj.time_format
parse_format = '%Y-%m-%d %H:%M:%S'
if not isinstance(value, time.struct_time):
return time.strftime(date_format, time.strptime(value, parse_format))
else:
date = datetime(*value.timetuple()[:6])
return date.strftime(date_format)
return lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
"""generate the PDF"""
self.parser_instance = self.parser(
@ -190,74 +237,81 @@ class BVRWebKitParser(webkit_report.WebKitParser):
<body style="border:0; margin: 0;" onload="subst()">
</body>
</html>"""
self.parser_instance.localcontext.update({'setLang':self.setLang})
self.parser_instance.localcontext.update({'formatLang':self.formatLang})
css = report_xml.webkit_header.css
if not css :
css = ''
user = self.pool.get('res.users').browse(cursor, uid, uid)
company= user.company_id
company = user.company_id
parse_template = template
#default_filters=['unicode', 'entity'] can be used to set global filter
body_mako_tpl = Template(parse_template ,input_encoding='utf-8')
body_mako_tpl = Template(parse_template ,input_encoding='utf-8', output_encoding='utf-8')
#BVR specific
bvr_path = addons.get_module_resource(os.path.join('l10n_ch','report','bvr.mako'))
body_bvr_tpl = Template(file(bvr_path).read(), input_encoding='utf-8')
body_bvr_tpl = Template(file(bvr_path).read(), input_encoding='utf-8', output_encoding='utf-8')
helper = report_helper.WebKitHelper(cursor, uid, report_xml.id, context)
##BVR Specific
htmls = []
for obj in objs :
self.parser_instance.localcontext['objects'] = [obj]
if not company.bvr_only:
html = body_mako_tpl.render(
try:
html = body_mako_tpl.render(
helper=helper,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext
)
except Exception, e:
raise Exception(exceptions.text_error_template().render())
htmls.append(html)
if not company.invoice_only:
try:
bvr = body_bvr_tpl.render(
helper=helper,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext
)
except Exception, e:
raise Exception(exceptions.text_error_template().render())
htmls.append(bvr)
head_mako_tpl = Template(header, input_encoding='utf-8', output_encoding='utf-8')
try:
head = head_mako_tpl.render(
helper=helper,
css=css,
_debug=False,
_=self.translate_call,
**self.parser_instance.localcontext
)
except Exception, e:
raise Exception(exceptions.text_error_template().render())
foot = False
if footer and company.invoice_only :
foot_mako_tpl = Template(footer, input_encoding='utf-8', output_encoding='utf-8')
try:
foot = foot_mako_tpl.render(
helper=helper,
css=css,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext
)
htmls.append(html)
if not company.invoice_only:
bvr = body_bvr_tpl.render(
helper=helper,
css=css,
_=self.translate_call,
**self.parser_instance.localcontext
)
htmls.append(bvr)
head_mako_tpl = Template(header, input_encoding='utf-8')
head = head_mako_tpl.render(
company=company,
time=time,
helper=helper,
css=css,
formatLang=self.parser_instance.formatLang,
setLang=self.parser_instance.setLang,
_debug=False
)
foot = False
if footer and company.invoice_only :
foot_mako_tpl = Template(footer ,input_encoding='utf-8')
foot = foot_mako_tpl.render(
company=company,
time=time,
helper=helper,
css=css,
formatLang=self.parser_instance.formatLang,
setLang=self.parser_instance.setLang,
_=self.translate_call,
)
except Exception, e:
raise Exception(exceptions.text_error_template().render())
if report_xml.webkit_debug :
deb = head_mako_tpl.render(
company=company,
time=time,
helper=helper,
css=css,
_debug=html,
formatLang=self.parser_instance.formatLang,
setLang=self.parser_instance.setLang,
_=self.translate_call,
)
try:
deb = head_mako_tpl.render(
helper=helper,
css=css,
_debug=html,
_=self.translate_call,
**self.parser_instance.localcontext
)
except Exception, e:
raise Exception(exceptions.text_error_template().render())
return (deb, 'html')
bin = self.get_lib(cursor, uid, company.id)
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls)

View File

@ -5,55 +5,57 @@
<field name="orientation">Portrait</field>
<field name="format">A4</field>
<field name="html"><![CDATA[<html>
<head>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
<style type="text/css">
${css}
</style>
</head>
<body style="border:0; margin: 0;" onload="subst()">
<table class="header" style="border-bottom: 0px solid black; width: 100%;padding-left:20mm">
<tr style="vertical-align:top" >
<td>${helper.embed_logo_by_name('camptocamp_logo', width=64)}</td>
<td style="text-align:right">
<table style="border-top: 0px solid black; width: 100%;height:100%">
<tr style="vertical-align:top">
<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>
</tr>
</table> </td>
</tr>
<tr>
<td><br/></td>
<td style="text-align:right"> </td>
</tr>
<tr>
<td>${company.partner_id.name |entity}</td>
<td/>
</tr>
<tr>
<td >${company.partner_id.address and company.partner_id.address[0].street or ''|entity}</td>
<td/>
</tr>
<tr>
<td>Phone: ${company.partner_id.address and company.partner_id.address[0].phone or ''|entity} </td>
<td/>
</tr>
<tr>
<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>
</tr>
</table> ${_debug or ''} <br/></body>
</html>]]>
<head>
<script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script>
<style type="text/css">
${css}
</style>
</head>
<!-- <tr style="vertical-align:top">
<td style="text-align:right;font-size:12" ><span class="page"/></td><td style="text-align:left;font-size:12;"> / <span class="topage"/></td>
</tr> style="text-align:right"-->
<body style="border:0; margin: 0;" onload="subst()">
<table style="border-bottom: 1px solid black; width: 90%;padding-left:0mm;margin-left:5%">
<tr style="vertical-align:top" >
<td>${helper.embed_logo_by_name('camptocamp_logo', width=128)}</td>
<td >
<table style="border-top: 0px solid black; width: 100%;height:100%;;padding-left:4mm; margin-left:2%" class="dest_address">
<tr>
<td><b>${company.partner_id.name |entity}</b></td><td></td><td></td>
</tr>
<tr>
<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>
</tr>
<tr>
<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>
</tr>
<tr>
<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>
</tr>
<tr>
<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>
</tr>
</table>
</td>
</tr>
</table>
<br/>
${_debug or ''}
<br/>
</body>
</html>]]>
</field>
<field eval="45" name="margin_top"/>
<field eval="0.01" name="margin_bottom"/>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<!-- Fiscal Position Templates -->
<record id="fiscal_position_template_import" model="account.fiscal.position.template">
@ -115,4 +115,4 @@
<field name="tax_dest_id" ref="vat_XO" />
</record>
</data>
</openerp>
</openerp>

View File

@ -0,0 +1,221 @@
-
In order to test DTA generation I make an invoice and create the DTA from it.
-
I create an invoice on 1st January for 7000 EUR
###########################
# Creating 1 invoice #
###########################
-
!record {model: account.invoice, id: dta_account_invoice}:
company_id: base.main_company
journal_id: account.bank_journal
currency_id: base.EUR
account_id: account.a_pay
type : in_invoice
partner_id: base.res_partner_agrolait
address_contact_id: base.res_partner_address_8
address_invoice_id: base.res_partner_address_8
reference_type: bvr
reference: 111111111111111111111111111111
date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
period_id: account.period_1
#invoice_line:
partner_bank_id: main_partner_bank
check_total : 7000
-
I add an invoice line
-
!record {model: account.invoice.line, id: dta_invoice_line}:
account_id: account.a_expense
name: '[PC1] Basic PC'
price_unit: 700.0
quantity: 10.0
product_id: product.product_product_pc1
uos_id: product.product_uom_unit
invoice_id: dta_account_invoice
-
I Validate invoice by clicking on Validate button
-
!workflow {model: account.invoice, action: invoice_open, ref: dta_account_invoice}
-
I create my payment order to pay my invoice
###########################
# Doing payment order #
###########################
-
!record {model: payment.order, id: dta_payment_order}:
#date_created
#date_done
date_prefered: due
#date_scheduled
#line_ids:
mode: l10n_ch.payment_mode_dta
#reference
state: draft
total: 7000
#user_id
-
I add a payment line to my payment order
-
!record {model: payment.line, id: dta_pay_line}:
amount: 7000
amount_currency: 7000
bank_id: l10n_ch.agro_bank
#bank_statement_line_id
communication: "111111111111111111111111111111"
#communication2
company_currency: base.EUR
#create_date
currency: base.EUR
#date
#info_owner
#info_partner
#ml_date_created
#ml_inv_ref
#ml_maturity_date
move_line_id: !ref {model: account.move.line, search: "[('ref','=','111111111111111111111111111111')]"}
#name (reference)
order_id: dta_payment_order
partner_id: base.res_partner_agrolait
state: normal
-
I generate a DTA file by using the wizard "Create DTA" for my payment order
-
!python {model: create.dta.wizard}: |
import base64
wiz_id = self.create(cr,uid,[])
wiz = self.browse(cr, uid, wiz_id)
pay_order_id = ref("dta_payment_order")
#set the payment order as the active id
context['active_ids'] = [pay_order_id]
context['active_id'] = pay_order_id
result = wiz.create_dta(context=context)
assert result, "No result returned"
data = wiz.read(['dta_file'])
dta_file = base64.decodestring(data[0]['dta_file'] or '')
assert dta_file, "File is empty"
#check that file starts with 1st segment characters "01"
assert dta_file[:2] == "01", "File is not a DTA file"
payment_obj = self.pool.get('payment.order')
payment_obj.set_done(cr, uid, [ref('dta_payment_order')], context)
#force state in open state (confirmed)
payment_obj.write(cr, uid, [ref('dta_payment_order')], {'state': 'open'})
-
I check the execution date is today
-
!assert {model: payment.order, id: dta_payment_order}:
- date_done == datetime.now().date().strftime('%Y-%m-%d')
-
I check my payment order state is Confirmed
-
!assert {model: payment.order, id: dta_payment_order, string: state is done}:
- state == 'open'
-
I create a Bank Statment in order to confirm the payment line
-
!record {model: account.bank.statement, id: dta_bank_statement}:
#account_id:
#balance_end:
#balance_end_cash:
#balance_end_real:
#balance_start:
#closing_date:
#company_id:
#currency:
date: !eval "'%s-01-01' %(datetime.now().year)"
#ending_details_ids:
journal_id: account.bank_journal
#line_ids:
#move_line_ids
name: "/"
period_id: account.period_1
#starting_details_ids
state: draft
#total_entry_encoding
#user_id
-
I import the payment line
-
!python {model: account.payment.populate.statement}: |
wiz_id = self.create(cr,uid,[])
wiz = self.browse(cr, uid, wiz_id)
line_obj = self.pool.get('payment.line')
pay_line_ids = line_obj.search(cr, uid, [('communication','=','111111111111111111111111111111'),('amount','=','7000')])
data = { 'lines': [(6, 0, [pay_line_ids[0]])],}
wiz.write(data)
context['active_id'] = ref('dta_bank_statement')
context['active_ids'] = [ref('dta_bank_statement')]
self.populate_statement(cr, uid, [wiz_id], context=context)
-
I check the statement line is created
-
!assert {model: account.bank.statement, id: dta_bank_statement, string: statement_line_ids is not empty}:
- line_ids
-
I check the voucher line is created
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('dta_bank_statement'))
assert statement.line_ids[0].voucher_id.line_ids, "Voucher line is missing"
assert len(statement.line_ids[0].voucher_id.line_ids) == 1, "There are too many voucher lines"
-
In order to confirm my bank statement, I enter the closing balance and press on compute button
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('dta_bank_statement'))
statement.write({'balance_end_real': -7000.0})
self.button_dummy(cr, uid, [ref('dta_bank_statement')], context=context)
statement = self.browse(cr, uid, ref('dta_bank_statement'))
-
I confirm my bank statement
-
!python {model: account.bank.statement}: |
self.button_confirm_bank(cr, uid, [ref('dta_bank_statement')], context=context)
-
I check the move lines have been defined
-
!assert {model: account.bank.statement, id: dta_bank_statement, string: move_line_ids is not empty}:
- move_line_ids
-
I check bank statement is Closed and balance is -7000
-
!assert {model: account.bank.statement, id: dta_bank_statement, string: state is Closed and balance is -7000}:
- state == 'confirm'
- balance_end == -7000.0
-
I check the residual amount of invoice, should be 0 in residual currency and 0 in amount_residual and paid
-
!python {model: account.invoice}: |
invoice_id = self.browse(cr, uid, ref("dta_account_invoice"))
move_line_obj = self.pool.get('account.move.line')
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)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert move_line.amount_residual_currency == 0.0, "Residual amount currency is not correct : %.2f" % move_line.amount_residual_currency
assert move_line.amount_residual == 0.0 , "Residual amount of invoice is not correct : %.2f" % move_line.amount_residual
assert invoice_id.state == 'paid', "Invoice state is not Paid"

View File

@ -1,5 +1,5 @@
-
In order to test BVR printing. I create Partner data.
In order to test BVR printing. I create Partner data .
-
!record {model: res.partner.category, id: res_partner_category_bvr}:
name: Customers
@ -57,4 +57,4 @@
!python {model: account.invoice}: |
from tools.test_reports import try_report
company = self.pool.get('res.users').browse(cr, uid, uid).company_id
company.lib_path and try_report(cr, uid, 'report.invoice_web_bvr', [ref('l10n_ch_invoice')]) or 'Webkit lib not set'
company.lib_path and try_report(cr, uid, 'report.invoice_web_bvr', [ref('l10n_ch_invoice')]) or 'Webkit lib not set'

View File

@ -0,0 +1,161 @@
-
In order to test the V11 import,
I will create an invoice with a specified reference that I will reconcile with the moves imported from a V11
-
I create an invoice ref 1234567
-
!record {model: account.invoice, id: v11_test_invoice}:
name: V11 YAML invoice
number: 1234567
company_id: base.main_company
journal_id: account.bank_journal
currency_id: base.EUR
account_id: account.a_recv
type : out_invoice
partner_id: base.res_partner_agrolait
address_contact_id: base.res_partner_address_8
address_invoice_id: base.res_partner_address_8
reference_type: bvr
reference: 12345676
date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
period_id: account.period_1
#invoice_line:
partner_bank_id: main_partner_bank
check_total : 888.00
-
I create an invoice line
-
!record {model: account.invoice.line, id: v11_test_invoice_line}:
account_id: account.a_expense
name: '[PC1] Basic PC'
price_unit: 888.00
quantity: 1.0
product_id: product.product_product_pc1
uos_id: product.product_uom_unit
invoice_id: v11_test_invoice
-
I Validate invoice by clicking on Validate button
-
!workflow {model: account.invoice, action: invoice_open, ref: v11_test_invoice}
-
I specify the invoice number to fit with my v11
-
!python {model: account.invoice}: |
invoice = self.browse(cr, uid, ref('v11_test_invoice'))
invoice.write({'number': 1234567})
-
I create a bank statement
-
!record {model: account.bank.statement, id: v11_test_bank_statement}:
#account_id:
#balance_end:
#balance_end_cash:
#balance_end_real:
#balance_start:
#closing_date:
#company_id:
#currency:
date: !eval "'%s-01-01' %(datetime.now().year)"
#ending_details_ids:
journal_id: account.bank_journal
#line_ids:
#move_line_ids
name: "/"
period_id: account.period_1
#starting_details_ids
state: draft
#total_entry_encoding
#user_id
-
I import the V11
-
!python {model: bvr.import.wizard}: |
import base64
import addons
import os
# create our wizard
wiz_id = self.create(cr,uid,[])
wiz = self.browse(cr, uid, wiz_id)
test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test.v11'))
# get our test file to test it
f_v11 = open(test_file_path)
str64_v11 = base64.encodestring(f_v11.read())
wiz.write({'file': str64_v11})
# set the file in the wizard field
bank_statement_id = ref('v11_test_bank_statement')
context['active_id'] = bank_statement_id
context['active_ids'] = [bank_statement_id]
# launch the import
self.import_bvr(cr, uid, [wiz_id], context=context)
-
I check my bank statement got a statement line
-
!assert {model: account.bank.statement, id: v11_test_bank_statement, string: statement has 1 and only 1 statement line id}:
- len(line_ids) == 1
-
I check the voucher linked to the statement line contains a line with an amount of 888.00
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
assert voucher_line_ids, "No voucher line found"
voucher_line_amount = voucher_line_ids[0].amount
assert voucher_line_amount == 888.00, "Amount isn't correct : %d" %(voucher_line_amount)
-
I check amount of account voucher is equal to the bank statement line amount
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
statement_line_amount = statement.line_ids[0].amount
voucher_amount = statement.line_ids[0].voucher_id.amount
assert statement_line_amount == voucher_amount, "Mismatch of amounts"
-
I enter the closing balance and press on compute button
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_test_bank_statement'))
statement.write({'balance_end_real': 888.00})
self.button_dummy(cr, uid, [ref('v11_test_bank_statement')], context=context)
-
I check that the statement Balance is 888.00
-
!assert {model: account.bank.statement, id: v11_test_bank_statement, string: balance is 888.0}:
- balance_end == 888.0
-
I confirm my bank statement
-
!python {model: account.bank.statement}: |
self.button_confirm_bank(cr, uid, [ref('v11_test_bank_statement')], context=context)
-
I check my invoice is paid, reconciled and has no residual
-
!assert {model: account.invoice, id: v11_test_invoice, string: 'invoice is paid, reconciled and has no residual'}:
- state == "paid"
- reconciled
- residual == 0.0

View File

@ -0,0 +1,292 @@
-
In order to test the V11 import,
I will create an invoice with a specified reference that I will partialy reconcile with a 1st V11
And then I will complete the reconcile with a second V11
-
I create an invoice ref 2000999 of EUR 250.00
-
!record {model: account.invoice, id: v11_part_test_invoice}:
name: V11 YAML invoice
number: 2000999
company_id: base.main_company
journal_id: account.bank_journal
currency_id: base.EUR
account_id: account.a_recv
type : out_invoice
partner_id: base.res_partner_agrolait
address_contact_id: base.res_partner_address_8
address_invoice_id: base.res_partner_address_8
reference_type: bvr
reference: 20009997
date_invoice: !eval "'%s-01-01' %(datetime.now().year)"
period_id: account.period_1
#invoice_line:
partner_bank_id: main_partner_bank
check_total : 250.00
-
I create an invoice line
-
!record {model: account.invoice.line, id: v11_part_test_invoice_line}:
account_id: account.a_expense
name: '[PC1] Basic PC'
price_unit: 250.00
quantity: 1.0
product_id: product.product_product_pc1
uos_id: product.product_uom_unit
invoice_id: v11_part_test_invoice
-
I Validate invoice by clicking on Validate button
-
!workflow {model: account.invoice, action: invoice_open, ref: v11_part_test_invoice}
-
I specify the invoice number to fit with my v11
-
!python {model: account.invoice}: |
invoice = self.browse(cr, uid, ref('v11_part_test_invoice'))
invoice.write({'number': 2000999})
-
I create a 1st bank statement
#########################################
# Creating 1st bank statement #
#########################################
-
!record {model: account.bank.statement, id: v11_part_test_bank_statement_1}:
#account_id:
#balance_end:
#balance_end_cash:
#balance_end_real:
#balance_start:
#closing_date:
#company_id:
#currency:
date: !eval "'%s-01-01' %(datetime.now().year)"
#ending_details_ids:
journal_id: account.bank_journal
#line_ids:
#move_line_ids
name: "/"
period_id: account.period_1
#starting_details_ids
state: draft
#total_entry_encoding
#user_id
-
I import the 1st V11
-
!python {model: bvr.import.wizard}: |
import base64
import addons
import os
# create our wizard
wiz_id = self.create(cr,uid,[])
wiz = self.browse(cr, uid, wiz_id)
test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test_part_1.v11'))
# get our test file to test it
f_v11 = open(test_file_path)
str64_v11 = base64.encodestring(f_v11.read())
wiz.write({'file': str64_v11})
# set the file in the wizard field
bank_statement_id = ref('v11_part_test_bank_statement_1')
context['active_id'] = bank_statement_id
context['active_ids'] = [bank_statement_id]
# launch the import
self.import_bvr(cr, uid, [wiz_id], context=context)
-
I check my bank statement got a statement line
-
!assert {model: account.bank.statement, id: v11_part_test_bank_statement_1, string: statement has 1 and only 1 statement line id}:
- len(line_ids) == 1
-
I check the voucher linked to the statement line contains a line with an amount of EUR 150.00
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
assert voucher_line_ids, "No voucher line found"
voucher_line_amount = voucher_line_ids[0].amount
assert voucher_line_amount == 150.00, "Amount isn't correct : %d" %(voucher_line_amount)
-
I check amount of account voucher is equal to the bank statement line amount
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
statement_line_amount = statement.line_ids[0].amount
voucher_amount = statement.line_ids[0].voucher_id.amount
assert statement_line_amount == voucher_amount, "Mismatch of amounts"
-
I enter the closing balance and press on compute button
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_1'))
statement.write({'balance_end_real': 150.00})
self.button_dummy(cr, uid, [ref('v11_part_test_bank_statement_1')], context=context)
-
I check that the statement Balance is EUR 150.00
-
!assert {model: account.bank.statement, id: v11_part_test_bank_statement_1, string: balance is 150.0}:
- balance_end == 150.0
-
I confirm my 1st bank statement
-
!python {model: account.bank.statement}: |
self.button_confirm_bank(cr, uid, [ref('v11_part_test_bank_statement_1')], context=context)
-
I check that my invoice is partially paid in open state, not reconciled, with a residual amount of EUR 100.0
#########################################
# Checking partial result #
#########################################
-
!assert {model: account.invoice, id: v11_part_test_invoice, string: 'invoice is open, reconciled and has no residual'}:
- state == "open"
- not reconciled
- residual == 100.0
-
I create a 2nd bank statement
#########################################
# Creating 2nd bank statement #
#########################################
-
!record {model: account.bank.statement, id: v11_part_test_bank_statement_2}:
#account_id:
#balance_end:
#balance_end_cash:
#balance_end_real:
#balance_start:
#closing_date:
#company_id:
#currency:
date: !eval "'%s-01-01' %(datetime.now().year)"
#ending_details_ids:
journal_id: account.bank_journal
#line_ids:
#move_line_ids
name: "/"
period_id: account.period_1
#starting_details_ids
state: draft
#total_entry_encoding
#user_id
-
I import the 2nd V11
-
!python {model: bvr.import.wizard}: |
import base64
import addons
import os
# create our wizard
wiz_id = self.create(cr,uid,[])
wiz = self.browse(cr, uid, wiz_id)
test_file_path = addons.get_module_resource(os.path.join('l10n_ch', 'test', 'test_part_2.v11'))
# get our test file to test it
f_v11 = open(test_file_path)
str64_v11 = base64.encodestring(f_v11.read())
wiz.write({'file': str64_v11})
# set the file in the wizard field
bank_statement_id = ref('v11_part_test_bank_statement_2')
context['active_id'] = bank_statement_id
context['active_ids'] = [bank_statement_id]
# launch the import
self.import_bvr(cr, uid, [wiz_id], context=context)
-
I check my bank statement got a statement line
-
!assert {model: account.bank.statement, id: v11_part_test_bank_statement_2, string: statement has 1 and only 1 statement line id}:
- len(line_ids) == 1
-
I check the voucher linked to the statement line contains a line with an amount of EUR 100.00
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
voucher_line_ids = statement.line_ids[0].voucher_id.line_ids
assert voucher_line_ids, "No voucher line found"
voucher_line_amount = voucher_line_ids[0].amount
assert voucher_line_amount == 100.00, "Amount isn't correct : %d" %(voucher_line_amount)
-
I check amount of account voucher is equal to the bank statement line amount
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
statement_line_amount = statement.line_ids[0].amount
voucher_amount = statement.line_ids[0].voucher_id.amount
assert statement_line_amount == voucher_amount, "Mismatch of amounts"
-
I enter the closing balance and press on compute button
-
!python {model: account.bank.statement}: |
statement = self.browse(cr, uid, ref('v11_part_test_bank_statement_2'))
statement.write({'balance_end_real': 100.00})
self.button_dummy(cr, uid, [ref('v11_part_test_bank_statement_2')], context=context)
-
I check that the statement Balance is EUR 100.00
-
!assert {model: account.bank.statement, id: v11_part_test_bank_statement_2, string: balance is 100.0}:
- balance_end == 100.0
-
I confirm my 2nd bank statement
-
!python {model: account.bank.statement}: |
self.button_confirm_bank(cr, uid, [ref('v11_part_test_bank_statement_2')], context=context)
-
I check my invoice is paid, reconciled and has no residual
#########################################
# Checking finale state #
#########################################
-
!assert {model: account.invoice, id: v11_part_test_invoice, string: 'invoice is paid, reconciled and has no residual'}:
- state == "paid"
- reconciled
- residual == 0.0

2
addons/l10n_ch/test/test.v11 Executable file
View File

@ -0,0 +1,2 @@
00201012162700000000000000000001234567600000888000001 000111010111010111010100000000010000000000000
999010121627999999999999999999999999999000000088800000000000001110102000000000000000000

View File

@ -0,0 +1,2 @@
00201012162700000000000000000002000999700000150000001 000111010111010111010100000000010000000000000
999010121627999999999999999999999999999000000015000000000000001110102000000000000000000

View File

@ -0,0 +1,2 @@
00201012162700000000000000000002000999700000100000001 000111010511010511010500000000010000000000000
999010121627999999999999999999999999999000000010000000000000001110106000000000000000000

View File

@ -7,7 +7,6 @@
Accounts/Generate Chart of Accounts from a Chart Template.</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="sequence">4</field>
<field name="category_id" ref="account.category_accounting_configuration"/>
<field name="type">automatic</field>
</record>
</data>

View File

@ -19,7 +19,8 @@
#
##############################################################################
import create_dta
import bvr_import
from . import create_dta
from . import bvr_import
from . import unicode2ascii
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -36,7 +36,9 @@ def _reconstruct_invoice_ref(cursor, user, reference, context=None):
user_current=user_obj.browse(cursor, user, user)
##
cursor.execute("SELECT inv.id,inv.number from account_invoice AS inv where inv.company_id = %s" ,(user_current.company_id.id,))
cursor.execute("SELECT inv.id,inv.number from account_invoice "
"AS inv where inv.company_id = %s and type='out_invoice'",
(user_current.company_id.id,))
result_invoice = cursor.fetchall()
REF = re.compile('[^0-9]')
for inv_id,inv_name in result_invoice:
@ -60,7 +62,6 @@ def _reconstruct_invoice_ref(cursor, user, reference, context=None):
def _import(self, cursor, user, data, context=None):
statement_line_obj = self.pool.get('account.bank.statement.line')
# statement_reconcile_obj = pool.get('account.bank.statement.reconcile')
voucher_obj = self.pool.get('account.voucher')
voucher_line_obj = self.pool.get('account.voucher.line')
move_line_obj = self.pool.get('account.move.line')
@ -167,7 +168,7 @@ def _import(self, cursor, user, data, context=None):
# line2reconcile = line.id
account_id = line.account_id.id
break
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)
result = voucher_obj.onchange_partner_id(cursor, user, [], partner_id, journal_id=statement.journal_id.id, price=abs(record['amount']), voucher_currency_id= statement.currency.id, ttype='receipt', date=statement.date ,context=context)
voucher_res = { 'type': 'receipt' ,
'name': values['name'],
@ -191,8 +192,8 @@ def _import(self, cursor, user, data, context=None):
voucher_line_dict = line_dict
if voucher_line_dict:
voucher_line_dict.update({'voucher_id':voucher_id})
voucher_line_obj.create(cursor, user, voucher_line_dict, context=context)
voucher_line_obj.create(cursor, user, voucher_line_dict, context=context)
if not account_id:
if record['amount'] >= 0:
account_id = account_receivable
@ -204,10 +205,10 @@ def _import(self, cursor, user, data, context=None):
if record['amount'] < 0:
name = "property_account_payable"
prop = property_obj.search(
cursor,
cursor,
user,
[
('name','=','property_account_receivable'),
('name','=',name),
('company_id','=',statement.company_id.id),
('res_id', '=', False)
]
@ -226,9 +227,9 @@ def _import(self, cursor, user, data, context=None):
values['partner_id'] = partner_id
statement_line_obj.create(cursor, user, values, context=context)
attachment_obj.create(cursor, user, {
'name': 'BVR',
'name': 'BVR %s'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
'datas': file,
'datas_fname': 'BVR.txt',
'datas_fname': 'BVR %s.txt'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
'res_model': 'account.bank.statement',
'res_id': statement_id,
}, context=context)

View File

@ -26,6 +26,7 @@ import base64
from osv import osv, fields
import pooler
from tools.translate import _
import unicode2ascii
TRANS=[
(u'é','e'),
@ -38,6 +39,24 @@ TRANS=[
(u'ä','a'),
]
def _u2a(text) :
"""Tries to convert unicode charactere to asci equivalence"""
if not text : return ""
txt = ""
for c in text:
if ord(c) < 128 :
txt += c
elif c in unicode2ascii.EXTRA_LATIN_NAMES :
txt += unicode2ascii.EXTRA_LATIN_NAMES[c]
elif c in unicode2ascii.UNI2ASCII_CONVERSIONS :
txt += unicode2ascii.UNI2ASCII_CONVERSIONS[c]
elif c in unicode2ascii.EXTRA_CHARACTERS :
txt += unicode2ascii.EXTRA_CHARACTERS[c]
elif c in unicode2ascii.FG_HACKS :
txt += unicode2ascii.FG_HACKS[c]
else : txt+= "_"
return txt
def tr(string_in):
try:
string_in= string_in.decode('utf-8')
@ -339,7 +358,9 @@ def _create_dta(obj, cr, uid, data, context=None):
if context is None:
context = {}
payment = payment_obj.browse(cr, uid, data['id'], context=context)
# if payment.state != 'done':
# raise osv.except_osv(_('Order not confirmed'),
# _('Please confirm it'))
if not payment.mode:
raise osv.except_osv(_('Error'),
_('No payment mode'))
@ -365,11 +386,13 @@ def _create_dta(obj, cr, uid, data, context=None):
v['comp_name'] = co_addr.name
v['comp_dta'] = bank.dta_code or '' #XXX not mandatory in pratice
v['comp_bank_number'] = bank.acc_number or ''
if bank.iban:
v['comp_bank_iban'] = bank.iban.replace(' ','') or ''
else:
v['comp_bank_iban'] = ''
# iban and account number are the same field and depends only on the type of account
v['comp_bank_iban'] = v['comp_bank_number'] = bank.acc_number or ''
#if bank.iban:
# v['comp_bank_iban'] = bank.iban.replace(' ','') or ''
#else:
# v['comp_bank_iban'] = ''
if not v['comp_bank_iban']:
raise osv.except_osv(_('Error'),
_('No IBAN for the company bank account.'))
@ -403,7 +426,7 @@ def _create_dta(obj, cr, uid, data, context=None):
'on the partner: %s\n' \
'on line: %s') % (pline.bank_id.state, pline.partner_id.name, pline.name))
v['partner_bank_iban'] = pline.bank_id.iban or False
v['partner_bank_iban'] = pline.bank_id.acc_number or False
v['partner_bank_number'] = pline.bank_id.acc_number \
and pline.bank_id.acc_number.replace('.','').replace('-','') \
or False
@ -468,7 +491,7 @@ def _create_dta(obj, cr, uid, data, context=None):
# si payment structure -> bvr (826)
# si non -> (827)
if elec_pay == 'dta_iban':
if elec_pay == 'iban':
# If iban => country=country code for space reason
v['comp_country'] = co_addr.country_id and co_addr.country_id.code+'-' or ''
record_type = record_gt836
@ -512,13 +535,10 @@ def _create_dta(obj, cr, uid, data, context=None):
elif elec_pay == 'bvbank':
if not v['partner_bank_number'] :
if v['partner_bank_iban'] :
v['partner_bank_number']= v['partner_bank_iban']
else:
raise osv.except_osv(_('Error'), _('You must provide ' \
'a bank number \n' \
'for the partner bank: %s\n' \
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
raise osv.except_osv(_('Error'), _('You must provide ' \
'a bank number \n' \
'for the partner bank: %s\n' \
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
if not v['partner_bank_clearing']:
raise osv.except_osv(_('Error'), _('You must provide ' \
'a Clearing Number\n' \
@ -551,17 +571,17 @@ def _create_dta(obj, cr, uid, data, context=None):
v['sequence'] = str(seq).rjust(5).replace(' ','0')
if dta :
dta = dta + record_gt890(v).generate()
dta_data = _u2a(dta)
dta_data = base64.encodestring(dta)
payment_obj.set_done(cr, uid, [data['id']], context)
attachment_obj.create(cr, uid, {
'name': 'DTA',
'name': 'DTA%s'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
'datas': dta_data,
'datas_fname': 'DTA.txt',
'datas_fname': 'DTA%s.txt'%time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime()),
'res_model': 'payment.order',
'res_id': data['id'],
}, context=context)
return {'dta': dta_data}
return dta_data
class create_dta_wizard(osv.osv_memory):
_name="create.dta.wizard"
@ -572,6 +592,11 @@ class create_dta_wizard(osv.osv_memory):
def create_dta(self, cr, uid, ids, context=None):
if not context:
context = {}
if isinstance(ids, list):
req_id = ids[0]
else:
req_id = ids
current = self.browse(cr, uid, req_id, context)
data = {}
active_ids = context.get('active_ids', [])
active_id = context.get('active_id', [])
@ -579,26 +604,9 @@ class create_dta_wizard(osv.osv_memory):
data['ids'] = active_ids
data['id'] = active_id
dta_file = _create_dta(self, cr, uid, data, context)
context.update({'dta_file':dta_file})
return self.save_dta(cr, uid, ids, context)
def save_dta(self, cr, uid, ids, context=None):
obj_model = self.pool.get('ir.model.data')
if context is None:
context = {}
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'), ('name','=','dta_save_view')])
resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
return {
'view_type': 'form',
'view_mode': 'form',
'res_model': 'create.dta.wizard',
'views': [(resource_id, 'form')],
'type': 'ir.actions.act_window',
'target': 'new',
'context': context,
}
current.write({'dta_file': dta_file})
return True
create_dta_wizard()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -10,6 +10,7 @@
<form string="DTA file creation - Results">
<group width="300" colspan="4">
<separator string="Create DTA" colspan="4"/>
<field name="dta_file"/>
<group colspan="4">
<button special="cancel" string="Cancel" icon="gtk-cancel" colspan="2"/>
<button name="create_dta" string="Create DTA" type="object" icon="gtk-ok" colspan="2"/>
@ -38,21 +39,5 @@
<field name="key">action</field>
<field name="model">payment.order</field>
</record>
<!-- Save DTA -->
<record id="dta_save_view" model="ir.ui.view">
<field name="name">Save DTA</field>
<field name="model">create.dta.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="DTA file creation - Results">
<group width="500" colspan="4">
<separator colspan="4" string="Click on 'Save as' to save the DTA file :" />
<field name="dta_file"/>
</group>
</form>
</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,592 @@
# -*- encoding: utf-8 -*-
"""Convert many unicode characters to ascii characters that are like them.
I want to collate names, with the property that a last name starting with
O-umlaut will be in with the last name's starting with O. Horrors!
So I want that many Latin-1 characters have their umlaute's, etc., stripped.
Some of it can be done automatically but some needs to be done by hand, that
I can tell.
"""
__version__='1.0.1'
__author__='Jim Hefferon: ftpmaint at tug.ctan.org'
__date__='2008-July-15'
__notes__="""As sources, used effbot's web site, and
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/251871
and
man uni2ascii
"""
import os, os.path, sys, re
import unicodedata
# These characters that are not done automatically by NFKD, and
# have a name starting with "LATIN". Some of these I found on the interwebs,
# but some I did by eye. Corrections or additions appreciated.
EXTRA_LATIN_NAMES={
# First are ones I got off the interweb
u"\N{LATIN CAPITAL LETTER O WITH STROKE}": u"O",
u"\N{LATIN SMALL LETTER A WITH GRAVE}": u"a",
u"\N{LATIN SMALL LETTER A WITH ACUTE}": u"a",
u"\N{LATIN SMALL LETTER A WITH CIRCUMFLEX}": u"a",
u"\N{LATIN SMALL LETTER A WITH TILDE}": u"a",
u"\N{LATIN SMALL LETTER A WITH DIAERESIS}": u"ae",
u"\N{LATIN SMALL LETTER A WITH RING ABOVE}": u"a",
u"\N{LATIN SMALL LETTER C WITH CEDILLA}": u"c",
u"\N{LATIN SMALL LETTER E WITH GRAVE}": u"e",
u"\N{LATIN SMALL LETTER E WITH ACUTE}": u"e",
u"\N{LATIN SMALL LETTER E WITH CIRCUMFLEX}": u"e",
u"\N{LATIN SMALL LETTER E WITH DIAERESIS}": u"e",
u"\N{LATIN SMALL LETTER I WITH GRAVE}": u"i",
u"\N{LATIN SMALL LETTER I WITH ACUTE}": u"i",
u"\N{LATIN SMALL LETTER I WITH CIRCUMFLEX}": u"i",
u"\N{LATIN SMALL LETTER I WITH DIAERESIS}": u"i",
u"\N{LATIN SMALL LETTER N WITH TILDE}": u"n",
u"\N{LATIN SMALL LETTER O WITH GRAVE}": u"o",
u"\N{LATIN SMALL LETTER O WITH ACUTE}": u"o",
u"\N{LATIN SMALL LETTER O WITH CIRCUMFLEX}": u"o",
u"\N{LATIN SMALL LETTER O WITH TILDE}": u"o",
u"\N{LATIN SMALL LETTER O WITH DIAERESIS}": u"oe",
u"\N{LATIN SMALL LETTER O WITH STROKE}": u"o",
u"\N{LATIN SMALL LETTER U WITH GRAVE}": u"u",
u"\N{LATIN SMALL LETTER U WITH ACUTE}": u"u",
u"\N{LATIN SMALL LETTER U WITH CIRCUMFLEX}": u"u",
u"\N{LATIN SMALL LETTER U WITH DIAERESIS}": u"ue",
u"\N{LATIN SMALL LETTER Y WITH ACUTE}": u"y",
u"\N{LATIN SMALL LETTER Y WITH DIAERESIS}": u"y",
u"\N{LATIN SMALL LETTER A WITH MACRON}": u"a",
u"\N{LATIN SMALL LETTER A WITH BREVE}": u"a",
u"\N{LATIN SMALL LETTER C WITH ACUTE}": u"c",
u"\N{LATIN SMALL LETTER C WITH CIRCUMFLEX}": u"c",
u"\N{LATIN SMALL LETTER E WITH MACRON}": u"e",
u"\N{LATIN SMALL LETTER E WITH BREVE}": u"e",
u"\N{LATIN SMALL LETTER G WITH CIRCUMFLEX}": u"g",
u"\N{LATIN SMALL LETTER G WITH BREVE}": u"g",
u"\N{LATIN SMALL LETTER G WITH CEDILLA}": u"g",
u"\N{LATIN SMALL LETTER H WITH CIRCUMFLEX}": u"h",
u"\N{LATIN SMALL LETTER I WITH TILDE}": u"i",
u"\N{LATIN SMALL LETTER I WITH MACRON}": u"i",
u"\N{LATIN SMALL LETTER I WITH BREVE}": u"i",
u"\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}": u"j",
u"\N{LATIN SMALL LETTER K WITH CEDILLA}": u"k",
u"\N{LATIN SMALL LETTER L WITH ACUTE}": u"l",
u"\N{LATIN SMALL LETTER L WITH CEDILLA}": u"l",
u"\N{LATIN CAPITAL LETTER L WITH STROKE}": u"L",
u"\N{LATIN SMALL LETTER L WITH STROKE}": u"l",
u"\N{LATIN SMALL LETTER N WITH ACUTE}": u"n",
u"\N{LATIN SMALL LETTER N WITH CEDILLA}": u"n",
u"\N{LATIN SMALL LETTER O WITH MACRON}": u"o",
u"\N{LATIN SMALL LETTER O WITH BREVE}": u"o",
u"\N{LATIN SMALL LETTER R WITH ACUTE}": u"r",
u"\N{LATIN SMALL LETTER R WITH CEDILLA}": u"r",
u"\N{LATIN SMALL LETTER S WITH ACUTE}": u"s",
u"\N{LATIN SMALL LETTER S WITH CIRCUMFLEX}": u"s",
u"\N{LATIN SMALL LETTER S WITH CEDILLA}": u"s",
u"\N{LATIN SMALL LETTER T WITH CEDILLA}": u"t",
u"\N{LATIN SMALL LETTER U WITH TILDE}": u"u",
u"\N{LATIN SMALL LETTER U WITH MACRON}": u"u",
u"\N{LATIN SMALL LETTER U WITH BREVE}": u"u",
u"\N{LATIN SMALL LETTER U WITH RING ABOVE}": u"u",
u"\N{LATIN SMALL LETTER W WITH CIRCUMFLEX}": u"w",
u"\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}": u"y",
u"\N{LATIN SMALL LETTER Z WITH ACUTE}": u"z",
u"\N{LATIN SMALL LETTER W WITH GRAVE}": u"w",
u"\N{LATIN SMALL LETTER W WITH ACUTE}": u"w",
u"\N{LATIN SMALL LETTER W WITH DIAERESIS}": u"w",
u"\N{LATIN SMALL LETTER Y WITH GRAVE}": u"y",
# Below are the ones that failed automated conversion
u'\N{LATIN CAPITAL LETTER AE}': u'AE',
u'\N{LATIN CAPITAL LETTER ETH}': u'D',
u"\N{LATIN CAPITAL LETTER A WITH DIAERESIS}": u"Ae",
u"\N{LATIN CAPITAL LETTER O WITH DIAERESIS}": u"Oe",
u"\N{LATIN CAPITAL LETTER U WITH DIAERESIS}": u"Ue",
u'\N{LATIN CAPITAL LETTER O WITH STROKE}': u'O',
u'\N{LATIN CAPITAL LETTER THORN}': u'TH',
u'\N{LATIN SMALL LETTER SHARP S}': u'ss',
u'\N{LATIN SMALL LETTER AE}': u'ae',
u'\N{LATIN SMALL LETTER ETH}': u'd',
u'\N{LATIN SMALL LETTER O WITH STROKE}': u'o',
u'\N{LATIN SMALL LETTER THORN}': 'th',
u'\N{LATIN CAPITAL LETTER D WITH STROKE}': u'D',
u'\N{LATIN SMALL LETTER D WITH STROKE}': u'd',
u'\N{LATIN CAPITAL LETTER H WITH STROKE}': u'H',
u'\N{LATIN SMALL LETTER H WITH STROKE}': u'h',
u'\N{LATIN SMALL LETTER DOTLESS I}': u'i',
u'\N{LATIN SMALL LETTER KRA}': u'q',
u'\N{LATIN CAPITAL LETTER L WITH STROKE}': u'L',
u'\N{LATIN SMALL LETTER L WITH STROKE}': u'l',
u'\N{LATIN CAPITAL LETTER ENG}': u'N',
u'\N{LATIN SMALL LETTER ENG}': u'n',
u'\N{LATIN CAPITAL LIGATURE OE}': u'OE',
u'\N{LATIN SMALL LIGATURE OE}': u'oe',
u'\N{LATIN CAPITAL LETTER T WITH STROKE}': u'T',
u'\N{LATIN SMALL LETTER T WITH STROKE}': u't',
u'\N{LATIN SMALL LETTER B WITH STROKE}': u'b',
u'\N{LATIN CAPITAL LETTER B WITH HOOK}': u'B',
u'\N{LATIN CAPITAL LETTER B WITH TOPBAR}': u'B',
u'\N{LATIN SMALL LETTER B WITH TOPBAR}': u'b',
# u'\N{LATIN CAPITAL LETTER TONE SIX}': u'', # ?B
# u'\N{LATIN SMALL LETTER TONE SIX}': u'', # ?b
u'\N{LATIN CAPITAL LETTER OPEN O}': u'O',
u'\N{LATIN CAPITAL LETTER C WITH HOOK}': u'C',
u'\N{LATIN SMALL LETTER C WITH HOOK}': u'c',
u'\N{LATIN CAPITAL LETTER AFRICAN D}': u'D',
u'\N{LATIN CAPITAL LETTER D WITH HOOK}': u'D',
u'\N{LATIN CAPITAL LETTER D WITH TOPBAR}': u'D',
u'\N{LATIN SMALL LETTER D WITH TOPBAR}': u'd',
# u'\N{LATIN SMALL LETTER TURNED DELTA}': u'',
u'\N{LATIN CAPITAL LETTER REVERSED E}': u'E',
# u'\N{LATIN CAPITAL LETTER SCHWA}': u'',
u'\N{LATIN CAPITAL LETTER OPEN E}': u'E',
u'\N{LATIN CAPITAL LETTER F WITH HOOK}': u'F',
u'\N{LATIN SMALL LETTER F WITH HOOK}': u'f',
u'\N{LATIN CAPITAL LETTER G WITH HOOK}': u'G',
# u'\N{LATIN CAPITAL LETTER GAMMA}': u'',
u'\N{LATIN SMALL LETTER HV}': u'hv',
u'\N{LATIN CAPITAL LETTER IOTA}': u'i',
u'\N{LATIN CAPITAL LETTER I WITH STROKE}': u'I',
u'\N{LATIN CAPITAL LETTER K WITH HOOK}': u'K',
u'\N{LATIN SMALL LETTER K WITH HOOK}': u'k',
u'\N{LATIN SMALL LETTER L WITH BAR}': u'l',
# u'\N{LATIN SMALL LETTER LAMBDA WITH STROKE}': u'',
# u'\N{LATIN CAPITAL LETTER TURNED M}': u'',
u'\N{LATIN CAPITAL LETTER N WITH LEFT HOOK}': u'N',
u'\N{LATIN SMALL LETTER N WITH LONG RIGHT LEG}': u'N',
u'\N{LATIN CAPITAL LETTER O WITH MIDDLE TILDE}': u'O',
u'\N{LATIN CAPITAL LETTER OI}': u'OI',
u'\N{LATIN SMALL LETTER OI}': u'oi',
u'\N{LATIN CAPITAL LETTER P WITH HOOK}': u'P',
u'\N{LATIN SMALL LETTER P WITH HOOK}': u'p',
# u'\N{LATIN LETTER YR}': u'',
# u'\N{LATIN CAPITAL LETTER TONE TWO}': u'',
# u'\N{LATIN SMALL LETTER TONE TWO}': u'',
u'\N{LATIN CAPITAL LETTER ESH}': u'SH',
# u'\N{LATIN LETTER REVERSED ESH LOOP}': u'',
u'\N{LATIN SMALL LETTER T WITH PALATAL HOOK}': u't',
u'\N{LATIN CAPITAL LETTER T WITH HOOK}': u'T',
u'\N{LATIN SMALL LETTER T WITH HOOK}': u't',
u'\N{LATIN CAPITAL LETTER T WITH RETROFLEX HOOK}': u'T',
# u'\N{LATIN CAPITAL LETTER UPSILON}': u'',
u'\N{LATIN CAPITAL LETTER V WITH HOOK}': u'V',
u'\N{LATIN CAPITAL LETTER Y WITH HOOK}': u'Y',
u'\N{LATIN SMALL LETTER Y WITH HOOK}': u'y',
u'\N{LATIN CAPITAL LETTER Z WITH STROKE}': u'Z',
u'\N{LATIN SMALL LETTER Z WITH STROKE}': u'z',
u'\N{LATIN CAPITAL LETTER EZH}': u'S',
# u'\N{LATIN CAPITAL LETTER EZH REVERSED}': u'',
# u'\N{LATIN SMALL LETTER EZH REVERSED}': u'',
u'\N{LATIN SMALL LETTER EZH WITH TAIL}': u's',
# u'\N{LATIN LETTER TWO WITH STROKE}': u'',
# u'\N{LATIN CAPITAL LETTER TONE FIVE}': u'',
# u'\N{LATIN SMALL LETTER TONE FIVE}': u'',
# u'\N{LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE}': u'',
u'\N{LATIN LETTER WYNN}': u'w',
# u'\N{LATIN LETTER DENTAL CLICK}': u'',
# u'\N{LATIN LETTER LATERAL CLICK}': u'',
# u'\N{LATIN LETTER ALVEOLAR CLICK}': u'',
# u'\N{LATIN LETTER RETROFLEX CLICK}': u'',
# u'\N{LATIN SMALL LETTER TURNED E}': u'',
u'\N{LATIN CAPITAL LETTER AE WITH MACRON}': u'AE',
u'\N{LATIN SMALL LETTER AE WITH MACRON}': u'ae',
u'\N{LATIN CAPITAL LETTER G WITH STROKE}': u'G',
u'\N{LATIN SMALL LETTER G WITH STROKE}': u'g',
u'\N{LATIN CAPITAL LETTER EZH WITH CARON}': u'S',
u'\N{LATIN SMALL LETTER EZH WITH CARON}': u's',
u'\N{LATIN CAPITAL LETTER HWAIR}': u'HW',
u'\N{LATIN CAPITAL LETTER WYNN}': u'W',
u'\N{LATIN CAPITAL LETTER AE WITH ACUTE}': u'AE',
u'\N{LATIN SMALL LETTER AE WITH ACUTE}': u'AE',
u'\N{LATIN CAPITAL LETTER O WITH STROKE AND ACUTE}': u'O',
u'\N{LATIN SMALL LETTER O WITH STROKE AND ACUTE}': u'o',
u'\N{LATIN CAPITAL LETTER YOGH}': u'J',
u'\N{LATIN SMALL LETTER YOGH}': u'j',
u'\N{LATIN CAPITAL LETTER N WITH LONG RIGHT LEG}': u'N',
u'\N{LATIN SMALL LETTER D WITH CURL}': u'd',
u'\N{LATIN CAPITAL LETTER OU}': u'OU',
u'\N{LATIN SMALL LETTER OU}': u'ou',
u'\N{LATIN CAPITAL LETTER Z WITH HOOK}': u'Z',
u'\N{LATIN SMALL LETTER Z WITH HOOK}': u'z',
u'\N{LATIN SMALL LETTER L WITH CURL}': u'l',
u'\N{LATIN SMALL LETTER N WITH CURL}': u'n',
u'\N{LATIN SMALL LETTER T WITH CURL}': u't',
u'\N{LATIN SMALL LETTER DOTLESS J}': u'j',
u'\N{LATIN SMALL LETTER DB DIGRAPH}': u'db',
u'\N{LATIN SMALL LETTER QP DIGRAPH}': u'qp',
u'\N{LATIN CAPITAL LETTER A WITH STROKE}': u'A',
u'\N{LATIN CAPITAL LETTER C WITH STROKE}': u'C',
u'\N{LATIN SMALL LETTER C WITH STROKE}': u'C',
u'\N{LATIN CAPITAL LETTER L WITH BAR}': u'L',
u'\N{LATIN CAPITAL LETTER T WITH DIAGONAL STROKE}': u'T',
u'\N{LATIN SMALL LETTER S WITH SWASH TAIL}': u'S',
u'\N{LATIN SMALL LETTER Z WITH SWASH TAIL}': u'Z',
# u'\N{LATIN CAPITAL LETTER GLOTTAL STOP}': u'',
# u'\N{LATIN SMALL LETTER TURNED A}': u'',
# u'\N{LATIN SMALL LETTER ALPHA}': u'',
# u'\N{LATIN SMALL LETTER TURNED ALPHA}': u'',
u'\N{LATIN SMALL LETTER B WITH HOOK}': u'b',
u'\N{LATIN SMALL LETTER OPEN O}': u'o',
u'\N{LATIN SMALL LETTER C WITH CURL}': u'c',
u'\N{LATIN SMALL LETTER D WITH TAIL}': u'd',
u'\N{LATIN SMALL LETTER D WITH HOOK}': u'd',
# u'\N{LATIN SMALL LETTER REVERSED E}': u'',
# u'\N{LATIN SMALL LETTER SCHWA}': u'',
# u'\N{LATIN SMALL LETTER SCHWA WITH HOOK}': u'',
u'\N{LATIN SMALL LETTER OPEN E}': u'e',
# u'\N{LATIN SMALL LETTER REVERSED OPEN E}': u'',
# u'\N{LATIN SMALL LETTER REVERSED OPEN E WITH HOOK}': u'',
# u'\N{LATIN SMALL LETTER CLOSED REVERSED OPEN E}': u'',
u'\N{LATIN SMALL LETTER DOTLESS J WITH STROKE}': u'j',
u'\N{LATIN SMALL LETTER G WITH HOOK}': u'g',
u'\N{LATIN SMALL LETTER SCRIPT G}': u'g',
u'\N{LATIN LETTER SMALL CAPITAL G}': u'G',
# u'\N{LATIN SMALL LETTER GAMMA}': u'',
# u'\N{LATIN SMALL LETTER RAMS HORN}': u'',
# u'\N{LATIN SMALL LETTER TURNED H}': u'',
u'\N{LATIN SMALL LETTER H WITH HOOK}': u'h',
u'\N{LATIN SMALL LETTER HENG WITH HOOK}': u'h',
u'\N{LATIN SMALL LETTER I WITH STROKE}': u'i',
# u'\N{LATIN SMALL LETTER IOTA}': u'',
u'\N{LATIN LETTER SMALL CAPITAL I}': u'I',
u'\N{LATIN SMALL LETTER L WITH MIDDLE TILDE}': u'L',
u'\N{LATIN SMALL LETTER L WITH BELT}': u'L',
u'\N{LATIN SMALL LETTER L WITH RETROFLEX HOOK}': u'L',
# u'\N{LATIN SMALL LETTER LEZH}': u'',
# u'\N{LATIN SMALL LETTER TURNED M}': u'',
# u'\N{LATIN SMALL LETTER TURNED M WITH LONG LEG}': u'',
u'\N{LATIN SMALL LETTER M WITH HOOK}': u'm',
u'\N{LATIN SMALL LETTER N WITH LEFT HOOK}': u'n',
u'\N{LATIN SMALL LETTER N WITH RETROFLEX HOOK}': u'n',
u'\N{LATIN LETTER SMALL CAPITAL N}': u'N',
u'\N{LATIN SMALL LETTER BARRED O}': u'o',
u'\N{LATIN LETTER SMALL CAPITAL OE}': u'OE',
# u'\N{LATIN SMALL LETTER CLOSED OMEGA}': u'',
# u'\N{LATIN SMALL LETTER PHI}': u'',
# u'\N{LATIN SMALL LETTER TURNED R}': u'',
# u'\N{LATIN SMALL LETTER TURNED R WITH LONG LEG}': u'',
# u'\N{LATIN SMALL LETTER TURNED R WITH HOOK}': u'',
u'\N{LATIN SMALL LETTER R WITH LONG LEG}': u'r',
u'\N{LATIN SMALL LETTER R WITH TAIL}': u'r',
u'\N{LATIN SMALL LETTER R WITH FISHHOOK}': u'r',
# u'\N{LATIN SMALL LETTER REVERSED R WITH FISHHOOK}': u'',
u'\N{LATIN LETTER SMALL CAPITAL R}': u'R',
# u'\N{LATIN LETTER SMALL CAPITAL INVERTED R}': u'',
u'\N{LATIN SMALL LETTER S WITH HOOK}': u's',
u'\N{LATIN SMALL LETTER ESH}': u'sh',
u'\N{LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK}': u'j',
# u'\N{LATIN SMALL LETTER SQUAT REVERSED ESH}': u'',
u'\N{LATIN SMALL LETTER ESH WITH CURL}': u'sh',
# u'\N{LATIN SMALL LETTER TURNED T}': u'',
u'\N{LATIN SMALL LETTER T WITH RETROFLEX HOOK}': u't',
u'\N{LATIN SMALL LETTER U BAR}': u'u',
# u'\N{LATIN SMALL LETTER UPSILON}': u'',
u'\N{LATIN SMALL LETTER V WITH HOOK}': u'v',
# u'\N{LATIN SMALL LETTER TURNED V}': u'',
# u'\N{LATIN SMALL LETTER TURNED W}': u'',
# u'\N{LATIN SMALL LETTER TURNED Y}': u'',
u'\N{LATIN LETTER SMALL CAPITAL Y}': u'Y',
u'\N{LATIN SMALL LETTER Z WITH RETROFLEX HOOK}': u'z',
u'\N{LATIN SMALL LETTER Z WITH CURL}': u'z',
u'\N{LATIN SMALL LETTER EZH}': u's',
u'\N{LATIN SMALL LETTER EZH WITH CURL}': u's',
# u'\N{LATIN LETTER GLOTTAL STOP}': u'',
# u'\N{LATIN LETTER PHARYNGEAL VOICED FRICATIVE}': u'',
# u'\N{LATIN LETTER INVERTED GLOTTAL STOP}': u'',
u'\N{LATIN LETTER STRETCHED C}': u'c',
# u'\N{LATIN LETTER BILABIAL CLICK}': u'',
u'\N{LATIN LETTER SMALL CAPITAL B}': u'B',
u'\N{LATIN SMALL LETTER CLOSED OPEN E}': u'e',
u'\N{LATIN LETTER SMALL CAPITAL G WITH HOOK}': u'G',
u'\N{LATIN LETTER SMALL CAPITAL H}': u'H',
u'\N{LATIN SMALL LETTER J WITH CROSSED-TAIL}': u'j',
# u'\N{LATIN SMALL LETTER TURNED K}': u'',
u'\N{LATIN LETTER SMALL CAPITAL L}': u'L',
u'\N{LATIN SMALL LETTER Q WITH HOOK}': u'q',
# u'\N{LATIN LETTER GLOTTAL STOP WITH STROKE}': u'',
# u'\N{LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE}': u'',
# u'\N{LATIN SMALL LETTER DZ DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER DEZH DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER DZ DIGRAPH WITH CURL}': u'',
# u'\N{LATIN SMALL LETTER TS DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER TESH DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER TC DIGRAPH WITH CURL}': u'',
# u'\N{LATIN SMALL LETTER FENG DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER LS DIGRAPH}': u'',
# u'\N{LATIN SMALL LETTER LZ DIGRAPH}': u'',
# u'\N{LATIN LETTER BILABIAL PERCUSSIVE}': u'',
# u'\N{LATIN LETTER BIDENTAL PERCUSSIVE}': u'',
# u'\N{LATIN SMALL LETTER TURNED H WITH FISHHOOK}': u'',
# u'\N{LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL}': u'',
u'\N{LATIN LETTER SMALL CAPITAL A}': u'A',
u'\N{LATIN LETTER SMALL CAPITAL AE}': u'AE',
# u'\N{LATIN SMALL LETTER TURNED AE}': u'',
u'\N{LATIN LETTER SMALL CAPITAL BARRED B}': u'B',
u'\N{LATIN LETTER SMALL CAPITAL C}': u'C',
u'\N{LATIN LETTER SMALL CAPITAL D}': u'D',
u'\N{LATIN LETTER SMALL CAPITAL ETH}': u'D',
u'\N{LATIN LETTER SMALL CAPITAL E}': u'E',
# u'\N{LATIN SMALL LETTER TURNED OPEN E}': u'',
# u'\N{LATIN SMALL LETTER TURNED I}': u'',
u'\N{LATIN LETTER SMALL CAPITAL J}': u'J',
u'\N{LATIN LETTER SMALL CAPITAL K}': u'K',
u'\N{LATIN LETTER SMALL CAPITAL L WITH STROKE}': u'L',
u'\N{LATIN LETTER SMALL CAPITAL M}': u'M',
# u'\N{LATIN LETTER SMALL CAPITAL REVERSED N}': u'',
u'\N{LATIN LETTER SMALL CAPITAL O}': u'O',
u'\N{LATIN LETTER SMALL CAPITAL OPEN O}': u'O',
# u'\N{LATIN SMALL LETTER SIDEWAYS O}': u'',
# u'\N{LATIN SMALL LETTER SIDEWAYS OPEN O}': u'',
# u'\N{LATIN SMALL LETTER SIDEWAYS O WITH STROKE}': u'',
# u'\N{LATIN SMALL LETTER TURNED OE}': u'',
u'\N{LATIN LETTER SMALL CAPITAL OU}': u'OU',
# u'\N{LATIN SMALL LETTER TOP HALF O}': u'',
# u'\N{LATIN SMALL LETTER BOTTOM HALF O}': u'',
u'\N{LATIN LETTER SMALL CAPITAL P}': u'P',
# u'\N{LATIN LETTER SMALL CAPITAL REVERSED R}': u'',
# u'\N{LATIN LETTER SMALL CAPITAL TURNED R}': u'',
u'\N{LATIN LETTER SMALL CAPITAL T}': u'T',
u'\N{LATIN LETTER SMALL CAPITAL U}': u'U',
# u'\N{LATIN SMALL LETTER SIDEWAYS U}': u'',
# u'\N{LATIN SMALL LETTER SIDEWAYS DIAERESIZED U}': u'',
# u'\N{LATIN SMALL LETTER SIDEWAYS TURNED M}': u'',
u'\N{LATIN LETTER SMALL CAPITAL V}': u'V',
u'\N{LATIN LETTER SMALL CAPITAL W}': u'W',
u'\N{LATIN LETTER SMALL CAPITAL Z}': u'',
u'\N{LATIN LETTER SMALL CAPITAL EZH}': u'S',
# u'\N{LATIN LETTER VOICED LARYNGEAL SPIRANT}': u'',
# u'\N{LATIN LETTER AIN}': u'',
u'\N{LATIN SMALL LETTER UE}': u'ue',
u'\N{LATIN SMALL LETTER B WITH MIDDLE TILDE}': u'b',
u'\N{LATIN SMALL LETTER D WITH MIDDLE TILDE}': u'd',
u'\N{LATIN SMALL LETTER F WITH MIDDLE TILDE}': u'f',
u'\N{LATIN SMALL LETTER M WITH MIDDLE TILDE}': u'm',
u'\N{LATIN SMALL LETTER N WITH MIDDLE TILDE}': u'n',
u'\N{LATIN SMALL LETTER P WITH MIDDLE TILDE}': u'p',
u'\N{LATIN SMALL LETTER R WITH MIDDLE TILDE}': u'r',
u'\N{LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE}': u'r',
u'\N{LATIN SMALL LETTER S WITH MIDDLE TILDE}': u's',
u'\N{LATIN SMALL LETTER T WITH MIDDLE TILDE}': u't',
u'\N{LATIN SMALL LETTER Z WITH MIDDLE TILDE}': u'z',
# u'\N{LATIN SMALL LETTER TURNED G}': u'',
# u'\N{LATIN SMALL LETTER INSULAR G}': u'',
u'\N{LATIN SMALL LETTER TH WITH STRIKETHROUGH}': u'th',
u'\N{LATIN SMALL CAPITAL LETTER I WITH STROKE}': u'I',
# u'\N{LATIN SMALL LETTER IOTA WITH STROKE}': u'',
u'\N{LATIN SMALL LETTER P WITH STROKE}': u'p',
u'\N{LATIN SMALL CAPITAL LETTER U WITH STROKE}': u'U',
# u'\N{LATIN SMALL LETTER UPSILON WITH STROKE}': u'',
u'\N{LATIN SMALL LETTER B WITH PALATAL HOOK}': u'b',
u'\N{LATIN SMALL LETTER D WITH PALATAL HOOK}': u'd',
u'\N{LATIN SMALL LETTER F WITH PALATAL HOOK}': u'f',
u'\N{LATIN SMALL LETTER G WITH PALATAL HOOK}': u'g',
u'\N{LATIN SMALL LETTER K WITH PALATAL HOOK}': u'k',
u'\N{LATIN SMALL LETTER L WITH PALATAL HOOK}': u'l',
u'\N{LATIN SMALL LETTER M WITH PALATAL HOOK}': u'm',
u'\N{LATIN SMALL LETTER N WITH PALATAL HOOK}': u'n',
u'\N{LATIN SMALL LETTER P WITH PALATAL HOOK}': u'p',
u'\N{LATIN SMALL LETTER R WITH PALATAL HOOK}': u'r',
u'\N{LATIN SMALL LETTER S WITH PALATAL HOOK}': u's',
u'\N{LATIN SMALL LETTER ESH WITH PALATAL HOOK}': u'sh',
u'\N{LATIN SMALL LETTER V WITH PALATAL HOOK}': u'v',
u'\N{LATIN SMALL LETTER X WITH PALATAL HOOK}': u'x',
u'\N{LATIN SMALL LETTER Z WITH PALATAL HOOK}': u'z',
u'\N{LATIN SMALL LETTER A WITH RETROFLEX HOOK}': u'a',
# u'\N{LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK}': u'',
u'\N{LATIN SMALL LETTER D WITH HOOK AND TAIL}': u'd',
u'\N{LATIN SMALL LETTER E WITH RETROFLEX HOOK}': u'e',
u'\N{LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK}': u'e',
u'\N{LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK}': u'e',
# u'\N{LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK}': u'',
u'\N{LATIN SMALL LETTER I WITH RETROFLEX HOOK}': u'i',
u'\N{LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK}': u'o',
u'\N{LATIN SMALL LETTER ESH WITH RETROFLEX HOOK}': u'sh',
u'\N{LATIN SMALL LETTER U WITH RETROFLEX HOOK}': u'u',
u'\N{LATIN SMALL LETTER EZH WITH RETROFLEX HOOK}': u's',
# u'\N{LATIN SUBSCRIPT SMALL LETTER SCHWA}': u'',
# u'\N{LATIN CROSS}': u''
}
# Additional ones; see "man uni2ascii"
UNI2ASCII_CONVERSIONS={
u'\N{NO-BREAK SPACE}': u' ',
u'\N{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'"',
u'\N{SOFT HYPHEN}': u'', # Controversial: see http://www.cs.tut.fi/~jkorpela/shy.html
u'\N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'"',
u'\N{ETHIOPIC WORDSPACE}': u' ',
u'\N{OGHAM SPACE MARK}': u' ',
u'\N{EN QUAD}': u' ',
u'\N{EM QUAD}': u' ',
u'\N{EN SPACE}': u' ',
u'\N{EM SPACE}': u' ',
u'\N{THREE-PER-EM SPACE}': u' ',
u'\N{FOUR-PER-EM SPACE}': u' ',
u'\N{SIX-PER-EM SPACE}': u' ',
u'\N{FIGURE SPACE}': u' ',
u'\N{PUNCTUATION SPACE}': u' ',
u'\N{THIN SPACE}': u' ',
u'\N{HAIR SPACE}': u' ',
u'\N{ZERO WIDTH SPACE}': u' ',
u'\N{ZERO WIDTH NO-BREAK SPACE}': u' ',
u'\N{HYPHEN}': u'-',
u'\N{NON-BREAKING HYPHEN}': u'-',
u'\N{FIGURE DASH}': u'-',
u'\N{EN DASH}': u'-',
u'\N{EM DASH}': u'-',
u'\N{LEFT SINGLE QUOTATION MARK}': u'`',
u'\N{RIGHT SINGLE QUOTATION MARK}': u"'",
u'\N{SINGLE LOW-9 QUOTATION MARK}': u'`',
u'\N{SINGLE HIGH-REVERSED-9 QUOTATION MARK}': u'`',
u'\N{LEFT DOUBLE QUOTATION MARK}': u'"',
u'\N{RIGHT DOUBLE QUOTATION MARK}': u'"',
u'\N{DOUBLE LOW-9 QUOTATION MARK}': u'"',
u'\N{DOUBLE HIGH-REVERSED-9 QUOTATION MARK}': u'"',
u'\N{SINGLE LEFT-POINTING ANGLE QUOTATION MARK}': u'`',
u'\N{SINGLE RIGHT-POINTING ANGLE QUOTATION MARK}': u"'",
u'\N{LOW ASTERISK}': u'*',
u'\N{MINUS SIGN}': u'-',
u'\N{ASTERISK OPERATOR}': u'*',
u'\N{BOX DRAWINGS LIGHT HORIZONTAL}': u'-',
u'\N{BOX DRAWINGS HEAVY HORIZONTAL}': u'-',
u'\N{BOX DRAWINGS LIGHT VERTICAL}': u'|',
u'\N{BOX DRAWINGS HEAVY VERTICAL}': u'|',
u'\N{HEAVY ASTERISK}': u'*',
u'\N{HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT}': u'"',
u'\N{HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT}': u'"',
u'\N{IDEOGRAPHIC SPACE}': u' ',
u'\N{SMALL AMPERSAND}': u'&',
u'\N{SMALL ASTERISK}': u'*',
u'\N{SMALL PLUS SIGN}': u'+',
u'\N{CENT SIGN}': u'cent',
u'\N{POUND SIGN}': u'pound',
u'\N{YEN SIGN}': u'yen',
u'\N{COPYRIGHT SIGN}': u'(c)',
u'\N{REGISTERED SIGN}': u'(R)',
u'\N{VULGAR FRACTION ONE QUARTER}': u'1/4',
u'\N{VULGAR FRACTION ONE HALF}': u'1/2',
u'\N{VULGAR FRACTION THREE QUARTERS}': u'3/4',
# u'\N{CAPITAL LETTER ASH}': u'AE',
u'\N{LATIN SMALL LETTER SHARP S}': u'ss',
# u'\N{SMALL LETTER ASH}': u'ae',
u'\N{LATIN CAPITAL LIGATURE IJ}': u'IJ',
u'\N{LATIN SMALL LIGATURE IJ}': u'ij',
u'\N{LATIN CAPITAL LIGATURE OE}': u'OE',
u'\N{LATIN SMALL LIGATURE oe}': u'oe',
u'\N{LATIN CAPITAL LETTER DZ}': u'DZ',
u'\N{LATIN CAPITAL LETTER DZ WITH CARON}': u'DZ',
u'\N{LATIN CAPITAL LETTER D WITH SMALL LETTER Z}': u'Dz',
u'\N{LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON}': u'Dz',
u'\N{LATIN SMALL LETTER DZ}': u'dz',
u'\N{LATIN SMALL LETTER TS DIGRAPH}': u'ts',
u'\N{HORIZONTAL ELLIPSIS}': u'...',
u'\N{MIDLINE HORIZONTAL ELLIPSIS}': u'...',
u'\N{LEFTWARDS ARROW}': u'<-',
u'\N{RIGHTWARDS ARROW}': u'->',
u'\N{LEFTWARDS DOUBLE ARROW}': u'<=',
u'\N{RIGHTWARDS DOUBLE ARROW}': u'=>',
}
# More from "man uni2ascii", in a different category.
EXTRA_CHARACTERS={
u'\N{ACUTE ACCENT}': u"'",
u'\N{BROKEN BAR}': u'|',
# u'\N{CEDILLA}': u'{cedilla}',
u'\N{CENT SIGN}': u' cents ',
u'\N{COPYRIGHT SIGN}': u'(C)',
u'\N{CURRENCY SIGN}': u' currency ',
u'\N{DEGREE SIGN}': u' degrees ',
# u'\N{DIAERESIS}': u'{umlaut}',
u'\N{DIVISION SIGN}': u'/',
# u'\N{FEMININE ORDINAL INDICATOR}': u'{^a}',
u'\N{INVERTED EXCLAMATION MARK}': u'!',
u'\N{INVERTED QUESTION MARK}': u'?',
# wrong? u'\N{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'<<',
u'\N{MACRON}': u'_',
# u'\N{MASCULINE ORDINAL INDICATOR}': u'{^o}',
u'\N{MICRO SIGN}': u'micro',
u'\N{MIDDLE DOT}': u'*',
u'\N{MULTIPLICATION SIGN}': u'*',
u'\N{NOT SIGN}': u'not',
u'\N{PILCROW SIGN}': u'paragraph',
u'\N{PLUS-MINUS SIGN}': u'+/-',
u'\N{POUND SIGN}': u'pound',
u'\N{REGISTERED SIGN}': u'(R)',
# wrong? u'\N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}': u'>>',
u'\N{SECTION SIGN}': u'section',
u'\N{SOFT HYPHEN}': u'',
u'\N{SUPERSCRIPT ONE}': u'^1',
u'\N{SUPERSCRIPT THREE}': u'^3',
u'\N{SUPERSCRIPT TWO}': u'^2',
u'\N{VULGAR FRACTION ONE HALF}': u'1/2',
u'\N{VULGAR FRACTION ONE QUARTER}': u'1/4',
u'\N{VULGAR FRACTION THREE QUARTERS}': u'3/4',
u'\N{YEN SIGN}': u'yen'
}
FG_HACKS={
u'\u0082': u'', # "break permitted here" symbol
u'\u2022': u'*', # Bullet
}
def build_dictionary():
'Return the translation dictionary.'
d = dict()
# First do what can be done automatically
for i in range(0xffff):
u=unichr(i)
try:
n=unicodedata.name(u)
if n.startswith('LATIN '):
k=unicodedata.normalize('NFKD', u).encode('ASCII', 'ignore')
if k: d[i]=unicode(k) # i=ord(u)
except ValueError: pass
# Next, add some by-hand ones (overlap possible, so order matters)
for m in [EXTRA_LATIN_NAMES,EXTRA_CHARACTERS,UNI2ASCII_CONVERSIONS,FG_HACKS]:
for i in m:
try: d[ord(i)]=unicode(m[i])
except Exception, err: pass
return d
udict = build_dictionary()
convert = lambda s: s.translate(udict)
def coroutine(func):
def start(*argz, **kwz):
cr = func(*argz, **kwz)
cr.next()
return cr
return start
@coroutine
def co_filter(drain, in_enc='utf-8', out_enc='ascii'):
bs = None
while True:
chunk = (yield bs)
bs = drain(convert(unicode(chunk)).encode('utf-8'))
def uc_filter(sin, sout, bs=8192, in_enc='utf-8', out_enc='ascii'):
sout = co_filter(sout.write, in_enc, out_enc)
while True:
dta = sin.read(bs)
if not dta: break
else: sout.send(dta)
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser(usage='%prog [options]',
description='utf8 stdin -> ascii stdout')
parser.add_option('-s', '--src-enc',
action='store', type='str', dest='src_enc', metavar='ENC', default='utf-8',
help='source encoding (utf-8)')
parser.add_option('-d', '--dst-enc',
action='store', type='str', dest='dst_enc', metavar='ENC', default='ascii',
help='destination encoding (ascii)')
parser.add_option('-c', '--chunk',
action='store', type='int', dest='bs', metavar='BYTES', default=8192,
help='read/write in chunks of a given size (8192)')
optz, argz = parser.parse_args()
if argz: parser.error('Only stdin -> stdout conversion suported')
uc_filter(sys.stdin, sys.stdout, bs=optz.bs, in_enc=optz.src_enc, out_enc=optz.dst_enc)