l10n_ch improvments
bzr revid: nicolas.bessi@camptocamp.com-20091016112520-ji2oa9krhae9yy0b
This commit is contained in:
parent
df9f5fb23c
commit
ae7912f0c4
|
@ -31,8 +31,8 @@
|
|||
#
|
||||
##############################################################################
|
||||
{
|
||||
"name" : "Switzerland localisation corrected by Camptocamp",
|
||||
"description" : """
|
||||
"name" : "Switzerland localisation corrected by Camptocamp",
|
||||
"description" : """
|
||||
Swiss localisation :
|
||||
- DTA generation for a lot of paiment types
|
||||
- BVR management (number generation, report, etc..)
|
||||
|
@ -43,9 +43,9 @@ You can also add with this module one of the following account plan:
|
|||
- l10n_ch_c2c_pcg
|
||||
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
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)
|
||||
et l'import du relevé de compte depuis la banque de manière automatisée.
|
||||
|
@ -66,45 +66,39 @@ TODO :
|
|||
|
||||
|
||||
""",
|
||||
"version" : "5.0",
|
||||
"author" : "Camptocamp SA",
|
||||
"category" : "Localisation/Europe",
|
||||
"website": "http://www.camptocamp.com",
|
||||
|
||||
"depends" : [
|
||||
"base",
|
||||
"account",
|
||||
"base_vat",
|
||||
"base_iban",
|
||||
"account_payment",
|
||||
"account_tax_include",
|
||||
],
|
||||
"init_xml" : [
|
||||
"dta_data.xml",
|
||||
"vaudtax_data.xml",
|
||||
#these data will soon be part of an other modules but if you want
|
||||
#them now uncomment the two lines
|
||||
#"zip_code_default.xml",
|
||||
#"bank_ch.xml",
|
||||
],
|
||||
"demo_xml" : [
|
||||
"demo/vaudtax_data_demo.xml",
|
||||
],
|
||||
"update_xml" : [
|
||||
"dta_view.xml",
|
||||
"dta_wizard.xml",
|
||||
#this file as been move to the account chart
|
||||
# "account_vat.xml",
|
||||
"bvr_report.xml",
|
||||
"bvr_wizard.xml",
|
||||
"bvr_view.xml",
|
||||
"company_view.xml",
|
||||
"account_invoice.xml",
|
||||
"bank_view.xml",
|
||||
"account_journal_view.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True,
|
||||
"version" : "5.0",
|
||||
"author" : "Camptocamp SA",
|
||||
"category" : "Localisation/Europe",
|
||||
"website": "http://www.camptocamp.com",
|
||||
|
||||
"depends" : [
|
||||
"base",
|
||||
"account",
|
||||
"base_vat",
|
||||
"base_iban",
|
||||
"account_payment",
|
||||
"account_tax_include",
|
||||
],
|
||||
"init_xml" : [
|
||||
"dta_data.xml",
|
||||
"vaudtax_data.xml",
|
||||
],
|
||||
"demo_xml" : [
|
||||
"demo/vaudtax_data_demo.xml",
|
||||
],
|
||||
"update_xml" : [
|
||||
"dta_view.xml",
|
||||
"dta_wizard.xml",
|
||||
"bvr_report.xml",
|
||||
"bvr_wizard.xml",
|
||||
"bvr_view.xml",
|
||||
"company_view.xml",
|
||||
"account_invoice.xml",
|
||||
"bank_view.xml",
|
||||
"account_journal_view.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True,
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -33,39 +33,39 @@
|
|||
from osv import fields, osv
|
||||
|
||||
class AccountMoveLine(osv.osv):
|
||||
""" Inherit account.move.line in order to add a custom link
|
||||
between supplier invoice line and bank. The original link
|
||||
was defined in account_payment between line """
|
||||
""" Inherit account.move.line in order to add a custom link
|
||||
between supplier invoice line and bank. The original link
|
||||
was defined in account_payment between line """
|
||||
|
||||
_inherit = 'account.move.line'
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cr a psycopg cursor
|
||||
## @param uid res.user.id that is currently loged
|
||||
## @param payment_type manual
|
||||
## @parma context a standard dict
|
||||
## @return a dict who has the account move line id as key and the bank id as value
|
||||
def line2bank(self, cr, uid, ids, payment_type='manual', context=None):
|
||||
"""add a link to account.move.line in order to link
|
||||
supplier invoice line and bank. The original link
|
||||
was defined in account_payment"""
|
||||
payment_mode_obj = self.pool.get('payment.mode')
|
||||
line2bank = {}
|
||||
if not ids:
|
||||
return {}
|
||||
bank_type = payment_mode_obj.suitable_bank_types(cr, uid, payment_type,
|
||||
context=context)
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
if line.invoice and line.invoice.partner_bank:
|
||||
line2bank[line.id] = line.invoice.partner_bank.id
|
||||
elif line.partner:
|
||||
for bank in line.partner.bank_ids:
|
||||
if bank.state in bank_type:
|
||||
line2bank[line.id] = bank.id
|
||||
break
|
||||
if line.id not in line2bank and line.partner.bank_ids:
|
||||
line2bank[line.id] = line.partner.bank_ids[0].id
|
||||
return line2bank
|
||||
## @param self The object pointer.
|
||||
## @param cr a psycopg cursor
|
||||
## @param uid res.user.id that is currently loged
|
||||
## @param payment_type manual
|
||||
## @parma context a standard dict
|
||||
## @return a dict who has the account move line id as key and the bank id as value
|
||||
def line2bank(self, cr, uid, ids, payment_type='manual', context=None):
|
||||
"""add a link to account.move.line in order to link
|
||||
supplier invoice line and bank. The original link
|
||||
was defined in account_payment"""
|
||||
payment_mode_obj = self.pool.get('payment.mode')
|
||||
line2bank = {}
|
||||
if not ids:
|
||||
return {}
|
||||
bank_type = payment_mode_obj.suitable_bank_types(cr, uid, payment_type,
|
||||
context=context)
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
if line.invoice and line.invoice.partner_bank:
|
||||
line2bank[line.id] = line.invoice.partner_bank.id
|
||||
elif line.partner_id:
|
||||
for bank in line.partner_id.bank_ids:
|
||||
if bank.state in bank_type:
|
||||
line2bank[line.id] = bank.id
|
||||
break
|
||||
if line.id not in line2bank and line.partner_id.bank_ids:
|
||||
line2bank[line.id] = line.partner_id.bank_ids[0].id
|
||||
return line2bank
|
||||
|
||||
AccountMoveLine()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -33,14 +33,23 @@ from osv import fields, osv
|
|||
|
||||
|
||||
class Bank(osv.osv):
|
||||
"""Inherit res.bank class in order to add swiss specific field"""
|
||||
_inherit = 'res.bank'
|
||||
_columns = {
|
||||
###Swiss unik bank identifier also use in IBAN number
|
||||
'clearing': fields.char('Clearing number', size=64),
|
||||
### city of the bank
|
||||
'city': fields.char('City', size=128, select=1),
|
||||
}
|
||||
"""Inherit res.bank class in order to add swiss specific field"""
|
||||
_inherit = 'res.bank'
|
||||
_columns = {
|
||||
###Swiss unik bank identifier also use in IBAN number
|
||||
'clearing': fields.char('Clearing number', size=64),
|
||||
### city of the bank
|
||||
'city': fields.char('City', size=128, select=1),
|
||||
}
|
||||
|
||||
Bank()
|
||||
|
||||
class bvr_checkbox(osv.osv):
|
||||
""" Add function to generate function """
|
||||
_inherit = "res.partner.bank"
|
||||
_columns = {
|
||||
'printBank' : fields.boolean('Print Bank on BVR'),
|
||||
'printAccount' : fields.boolean('Print Account Number on BVR'),
|
||||
}
|
||||
bvr_checkbox()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -24,5 +24,31 @@
|
|||
</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="printBank" select="2"/>
|
||||
<field name="printAccount" select="2"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="l10nch_view_res_partner_bank">
|
||||
<field name="name">res.partner_partner_bank.form</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="account.view_partner_property_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bank" position="after">
|
||||
<newline />
|
||||
<field name="printBank" select="2"/>
|
||||
<field name="printAccount" select="2"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -34,17 +34,17 @@
|
|||
import netsvc
|
||||
from osv import fields, osv
|
||||
class res_company(osv.osv):
|
||||
"""override company in order to add bvr vertical and
|
||||
Horizontal print delta"""
|
||||
_inherit = "res.company"
|
||||
_columns = {
|
||||
### horiz. delta in mm 1.2 will print the bvz 1.2mm lefter
|
||||
'bvr_delta_horz': fields.float('BVR Horz. Delta (mm)',
|
||||
help='horiz. delta in mm 1.2 will print the bvz 1.2mm lefter'),
|
||||
### vert. delta in mm 1.2 will print the bvz 1.2mm lefter
|
||||
'bvr_delta_vert': fields.float('BVR Vert. Delta (mm)',
|
||||
help='vert. delta in mm 1.2 will print the bvz 1.2mm lefter'),
|
||||
}
|
||||
"""override company in order to add bvr vertical and
|
||||
Horizontal print delta"""
|
||||
_inherit = "res.company"
|
||||
_columns = {
|
||||
### horiz. delta in mm 1.2 will print the bvz 1.2mm lefter
|
||||
'bvr_delta_horz': fields.float('BVR Horz. Delta (mm)',
|
||||
help='horiz. delta in mm 1.2 will print the bvz 1.2mm lefter'),
|
||||
### vert. delta in mm 1.2 will print the bvz 1.2mm lefter
|
||||
'bvr_delta_vert': fields.float('BVR Vert. Delta (mm)',
|
||||
help='vert. delta in mm 1.2 will print the bvz 1.2mm lefter'),
|
||||
}
|
||||
res_company()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -34,62 +34,62 @@ 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="display 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),
|
||||
}
|
||||
"""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="display 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 lin 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',
|
||||
}
|
||||
"""Class that represent a DTA order line,
|
||||
each lin 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()
|
||||
|
||||
|
||||
|
|
|
@ -37,176 +37,176 @@ from mx import DateTime
|
|||
|
||||
|
||||
class account_invoice(osv.osv):
|
||||
"""Inherit account.invoice in order to add bvr
|
||||
printing functionnalites. BVR is a Swiss payment vector"""
|
||||
_inherit = "account.invoice"
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma context a standard dict
|
||||
## @return a list of tuple (name,value)
|
||||
def _get_reference_type(self, cursor, user, context=None):
|
||||
"""Function use by the function field reference_type in order to initalise available
|
||||
BVR Reference Types"""
|
||||
res = super(account_invoice, self)._get_reference_type(cursor, user,
|
||||
context=context)
|
||||
res.append(('bvr', 'BVR'))
|
||||
return res
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma context a standard dict
|
||||
## @param name of the files
|
||||
## @param args a list of diverse argument
|
||||
## @parma context a standard dict
|
||||
## @return a dict (invoice id,amount to pay)
|
||||
def _amount_to_pay(self, cursor, user, ids, name, args, context=None):
|
||||
'''Return the amount still to pay regarding all the payment orders'''
|
||||
if not ids:
|
||||
return {}
|
||||
res = {}
|
||||
for invoice in self.browse(cursor, user, ids, context=context):
|
||||
res[invoice.id] = 0.0
|
||||
if invoice.move_id:
|
||||
for line in invoice.move_id.line_id:
|
||||
if not line.date_maturity or \
|
||||
DateTime.strptime(line.date_maturity, '%Y-%m-%d') \
|
||||
< DateTime.now():
|
||||
res[invoice.id] += line.amount_to_pay
|
||||
return res
|
||||
"""Inherit account.invoice in order to add bvr
|
||||
printing functionnalites. BVR is a Swiss payment vector"""
|
||||
_inherit = "account.invoice"
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma context a standard dict
|
||||
## @return a list of tuple (name,value)
|
||||
def _get_reference_type(self, cursor, user, context=None):
|
||||
"""Function use by the function field reference_type in order to initalise available
|
||||
BVR Reference Types"""
|
||||
res = super(account_invoice, self)._get_reference_type(cursor, user,
|
||||
context=context)
|
||||
res.append(('bvr', 'BVR'))
|
||||
return res
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma context a standard dict
|
||||
## @param name of the files
|
||||
## @param args a list of diverse argument
|
||||
## @parma context a standard dict
|
||||
## @return a dict (invoice id,amount to pay)
|
||||
def _amount_to_pay(self, cursor, user, ids, name, args, context=None):
|
||||
'''Return the amount still to pay regarding all the payment orders'''
|
||||
if not ids:
|
||||
return {}
|
||||
res = {}
|
||||
for invoice in self.browse(cursor, user, ids, context=context):
|
||||
res[invoice.id] = 0.0
|
||||
if invoice.move_id:
|
||||
for line in invoice.move_id.line_id:
|
||||
if not line.date_maturity or \
|
||||
DateTime.strptime(line.date_maturity, '%Y-%m-%d') \
|
||||
< DateTime.now():
|
||||
res[invoice.id] += line.amount_to_pay
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
### BVR reference type BVR or FREE
|
||||
'reference_type': fields.selection(_get_reference_type,
|
||||
'Reference Type', required=True),
|
||||
### Partner bank link between bank and partner id
|
||||
'partner_bank': fields.many2one('res.partner.bank', 'Bank Account',
|
||||
help='The partner bank account to pay\nKeep empty to use the default'
|
||||
),
|
||||
### 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'),
|
||||
}
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @return a boolean True if valid False if invalid
|
||||
def _check_bvr(self, cr, uid, ids):
|
||||
"""
|
||||
Function to validate a bvr reference like :
|
||||
0100054150009>132000000000000000000000014+ 1300132412>
|
||||
The validation is based on l10n_ch
|
||||
"""
|
||||
invoices = self.browse(cr,uid,ids)
|
||||
for invoice in invoices:
|
||||
if invoice.reference_type == 'bvr':
|
||||
if not invoice.reference:
|
||||
return False
|
||||
## I need help for this bug because in this case
|
||||
# <010001000060190> 052550152684006+ 43435>
|
||||
# the reference 052550152684006 do not match modulo 10
|
||||
#
|
||||
if mod10r(invoice.reference[:-1]) != invoice.reference and \
|
||||
len(invoice.reference) == 15:
|
||||
return True
|
||||
#
|
||||
if mod10r(invoice.reference[:-1]) != invoice.reference:
|
||||
return False
|
||||
return True
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @return a boolean True if valid False if invalid
|
||||
def _check_reference_type(self, cursor, user, ids):
|
||||
"""Check the customer invoice reference type depending
|
||||
on the BVR reference type and the invoice partner bank type"""
|
||||
for invoice in self.browse(cursor, user, ids):
|
||||
if invoice.type in 'in_invoice':
|
||||
if invoice.partner_bank and \
|
||||
invoice.partner_bank.state in \
|
||||
('bvrbank', 'bvrpost') and \
|
||||
invoice.reference_type != 'bvr':
|
||||
return False
|
||||
return True
|
||||
_columns = {
|
||||
### BVR reference type BVR or FREE
|
||||
'reference_type': fields.selection(_get_reference_type,
|
||||
'Reference Type', required=True),
|
||||
### Partner bank link between bank and partner id
|
||||
'partner_bank': fields.many2one('res.partner.bank', 'Bank Account',
|
||||
help='The partner bank account to pay\nKeep empty to use the default'
|
||||
),
|
||||
### 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'),
|
||||
}
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @return a boolean True if valid False if invalid
|
||||
def _check_bvr(self, cr, uid, ids):
|
||||
"""
|
||||
Function to validate a bvr reference like :
|
||||
0100054150009>132000000000000000000000014+ 1300132412>
|
||||
The validation is based on l10n_ch
|
||||
"""
|
||||
invoices = self.browse(cr,uid,ids)
|
||||
for invoice in invoices:
|
||||
if invoice.reference_type == 'bvr':
|
||||
if not invoice.reference:
|
||||
return False
|
||||
## I need help for this bug because in this case
|
||||
# <010001000060190> 052550152684006+ 43435>
|
||||
# the reference 052550152684006 do not match modulo 10
|
||||
#
|
||||
if mod10r(invoice.reference[:-1]) != invoice.reference and \
|
||||
len(invoice.reference) == 15:
|
||||
return True
|
||||
#
|
||||
if mod10r(invoice.reference[:-1]) != invoice.reference:
|
||||
return False
|
||||
return True
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @return a boolean True if valid False if invalid
|
||||
def _check_reference_type(self, cursor, user, ids):
|
||||
"""Check the customer invoice reference type depending
|
||||
on the BVR reference type and the invoice partner bank type"""
|
||||
for invoice in self.browse(cursor, user, ids):
|
||||
if invoice.type in 'in_invoice':
|
||||
if invoice.partner_bank and \
|
||||
invoice.partner_bank.state in \
|
||||
('bvrbank', 'bvrpost') and \
|
||||
invoice.reference_type != 'bvr':
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_bvr, 'Error: Invalid Bvr Number (wrong checksum).',
|
||||
['reference']),
|
||||
(_check_reference_type, 'Error: BVR reference is required.',
|
||||
['reference_type']),
|
||||
]
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cr a psycopg cursor
|
||||
## @param uid res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @parma type the invoice type
|
||||
## @param partner_id the partner linked to the invoice
|
||||
## @parma date_invoice date of the invoice
|
||||
## @parma payment_term inoice payment term
|
||||
## @param partner_bank_id the partner linked invoice bank
|
||||
## @return the dict of values with the partner_bank value updated
|
||||
def onchange_partner_id(self, cr, uid, ids, type, partner_id,
|
||||
date_invoice=False, payment_term=False, partner_bank_id=False):
|
||||
""" Function that is call when the partner of the invoice is changed
|
||||
it will retriev 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
|
||||
)
|
||||
bank_id = False
|
||||
if partner_id:
|
||||
p = self.pool.get('res.partner').browse(cr, uid, partner_id)
|
||||
if p.bank_ids:
|
||||
bank_id = p.bank_ids[0].id
|
||||
_constraints = [
|
||||
(_check_bvr, 'Error: Invalid Bvr Number (wrong checksum).',
|
||||
['reference']),
|
||||
(_check_reference_type, 'Error: BVR reference is required.',
|
||||
['reference_type']),
|
||||
]
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cr a psycopg cursor
|
||||
## @param uid res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @parma type the invoice type
|
||||
## @param partner_id the partner linked to the invoice
|
||||
## @parma date_invoice date of the invoice
|
||||
## @parma payment_term inoice payment term
|
||||
## @param partner_bank_id the partner linked invoice bank
|
||||
## @return the dict of values with the partner_bank value updated
|
||||
def onchange_partner_id(self, cr, uid, ids, type, partner_id,
|
||||
date_invoice=False, payment_term=False, partner_bank_id=False):
|
||||
""" Function that is call when the partner of the invoice is changed
|
||||
it will retriev 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
|
||||
)
|
||||
bank_id = False
|
||||
if partner_id:
|
||||
p = self.pool.get('res.partner').browse(cr, uid, partner_id)
|
||||
if p.bank_ids:
|
||||
bank_id = p.bank_ids[0].id
|
||||
|
||||
if type in ('in_invoice', 'in_refund'):
|
||||
res['value']['partner_bank'] = bank_id
|
||||
if type in ('in_invoice', 'in_refund'):
|
||||
res['value']['partner_bank'] = bank_id
|
||||
|
||||
if partner_bank_id != bank_id:
|
||||
to_update = self.onchange_partner_bank(cr, uid, ids, bank_id)
|
||||
res['value'].update(to_update['value'])
|
||||
return res
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @param partner_bank_id the partner linked invoice bank
|
||||
## @return the dict of values with the reference type value updated
|
||||
def onchange_partner_bank(self, cursor, user, ids, partner_bank_id):
|
||||
"""update the reference type depending of the partner bank"""
|
||||
res = {'value': {}}
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
if partner_bank_id:
|
||||
partner_bank = partner_bank_obj.browse(cursor, user, partner_bank_id)
|
||||
if partner_bank.state in ('bvrbank', 'bvrpost'):
|
||||
res['value']['reference_type'] = 'bvr'
|
||||
return res
|
||||
if partner_bank_id != bank_id:
|
||||
to_update = self.onchange_partner_bank(cr, uid, ids, bank_id)
|
||||
res['value'].update(to_update['value'])
|
||||
return res
|
||||
|
||||
## @param self The object pointer.
|
||||
## @param cursor a psycopg cursor
|
||||
## @param user res.user.id that is currently loged
|
||||
## @parma ids invoices id
|
||||
## @param partner_bank_id the partner linked invoice bank
|
||||
## @return the dict of values with the reference type value updated
|
||||
def onchange_partner_bank(self, cursor, user, ids, partner_bank_id):
|
||||
"""update the reference type depending of the partner bank"""
|
||||
res = {'value': {}}
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
if partner_bank_id:
|
||||
partner_bank = partner_bank_obj.browse(cursor, user, partner_bank_id)
|
||||
if partner_bank.state in ('bvrbank', 'bvrpost'):
|
||||
res['value']['reference_type'] = 'bvr'
|
||||
return res
|
||||
|
||||
account_invoice()
|
||||
|
||||
class account_tax_code(osv.osv):
|
||||
"""Inherit account tax code in order
|
||||
to add a Case code"""
|
||||
_name = 'account.tax.code'
|
||||
_inherit = "account.tax.code"
|
||||
_columns = {
|
||||
### The case code of the taxt code
|
||||
'code': fields.char('Case Code', size=512),
|
||||
}
|
||||
"""Inherit account tax code in order
|
||||
to add a Case code"""
|
||||
_name = 'account.tax.code'
|
||||
_inherit = "account.tax.code"
|
||||
_columns = {
|
||||
### The case code of the taxt code
|
||||
'code': fields.char('Case Code', size=512),
|
||||
}
|
||||
account_tax_code()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -34,13 +34,13 @@ import netsvc
|
|||
from osv import fields, osv
|
||||
|
||||
class res_partner(osv.osv):
|
||||
_inherit = 'res.partner'
|
||||
_inherit = 'res.partner'
|
||||
|
||||
_columns = {
|
||||
'ref_companies': fields.one2many('res.company', 'partner_id',
|
||||
'Companies that refers to partner'),
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'ref_companies': fields.one2many('res.company', 'partner_id',
|
||||
'Companies that refers to partner'),
|
||||
}
|
||||
|
||||
|
||||
|
||||
res_partner()
|
||||
|
@ -48,52 +48,50 @@ 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_number': fields.char('BVR account number', size=11),
|
||||
'bvr_adherent_num': fields.char('BVR adherent number', size=11),
|
||||
'dta_code': fields.char('DTA code', size=5),
|
||||
}
|
||||
|
||||
def _default_value(self, cursor, user, field, context=None):
|
||||
if field in ('country_id', 'state_id'):
|
||||
value = False
|
||||
else:
|
||||
value = ''
|
||||
if not context.get('address', False):
|
||||
return value
|
||||
for ham, spam, address in context['address']:
|
||||
if 'type' in address.keys() :
|
||||
if address['type'] == 'default':
|
||||
return address.get(field,False)
|
||||
elif not address['type']:
|
||||
value = address.get(field,False)
|
||||
else :
|
||||
value = False
|
||||
return value
|
||||
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
if not len(ids):
|
||||
return []
|
||||
bank_type_obj = self.pool.get('res.partner.bank.type')
|
||||
_inherit = "res.partner.bank"
|
||||
_columns = {
|
||||
'name': fields.char('Description', size=128, required=True),
|
||||
'post_number': fields.char('Post number', size=64),
|
||||
'bvr_number': fields.char('BVR account number', size=11),
|
||||
'bvr_adherent_num': fields.char('BVR adherent number', size=11),
|
||||
'dta_code': fields.char('DTA code', size=5),
|
||||
}
|
||||
|
||||
# def _default_value(self, cursor, user, field, context=None):
|
||||
# if field in ('country_id', 'state_id'):
|
||||
# value = False
|
||||
# else:
|
||||
# value = ''
|
||||
# if not context.get('address', False):
|
||||
# return value
|
||||
# for ham, spam, address in context['address']:
|
||||
# if 'type' in address.keys() :
|
||||
# if address['type'] == 'default':
|
||||
# return address[field]
|
||||
# elif not address['type']:
|
||||
# value = address[field]
|
||||
# else :
|
||||
# value = False
|
||||
# return value
|
||||
|
||||
|
||||
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 !')
|
||||
]
|
||||
|
||||
|
||||
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:
|
||||
|
|
|
@ -34,11 +34,11 @@ from osv import fields
|
|||
from osv import osv
|
||||
|
||||
class payment_order(osv.osv):
|
||||
_inherit = 'payment.order'
|
||||
_inherit = 'payment.order'
|
||||
|
||||
def get_wizard(self,mode):
|
||||
if mode == 'dta':
|
||||
return 'l10n_ch','wizard_account_dta_create'
|
||||
return super(payment_order,self).get_wizard(mode)
|
||||
def get_wizard(self,mode):
|
||||
if mode == 'dta':
|
||||
return 'l10n_ch','wizard_account_dta_create'
|
||||
return super(payment_order,self).get_wizard(mode)
|
||||
payment_order()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -34,70 +34,92 @@ import time
|
|||
from report import report_sxw
|
||||
from tools import mod10r
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
from mx.DateTime import *
|
||||
|
||||
class account_invoice_bvr(report_sxw.rml_parse):
|
||||
"""Report class that Allows to print BVR payement vector"""
|
||||
def __init__(self, cr, uid, name, context):
|
||||
super(account_invoice_bvr, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'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,
|
||||
'format_date': self._get_and_change_date_format_for_swiss,
|
||||
#'date_invoice':
|
||||
})
|
||||
def _get_and_change_date_format_for_swiss (self,date_to_format):
|
||||
date_formatted=''
|
||||
print date_to_format
|
||||
if date_to_format:
|
||||
date_formatted = strptime(date_to_format,'%Y-%m-%d').strftime('%d.%m.%Y')
|
||||
return date_formatted
|
||||
|
||||
def comma_me(self,amount):
|
||||
if type(amount) is float :
|
||||
amount = str('%.2f'%amount)
|
||||
else :
|
||||
amount = str(amount)
|
||||
orig = amount
|
||||
new = re.sub("^(-?\d+)(\d{3})", "\g<1>'\g<2>", amount)
|
||||
if orig == new:
|
||||
return new
|
||||
else:
|
||||
return self.comma_me(new)
|
||||
"""Report class that Allows to print BVR payement vector"""
|
||||
def __init__(self, cr, uid, name, context):
|
||||
super(account_invoice_bvr, self).__init__(cr, uid, name, context)
|
||||
self.copyocrbfile('addons/l10n_ch/report/ocrbb.ttf')
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'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,
|
||||
'format_date': self._get_and_change_date_format_for_swiss,
|
||||
'police_absolute_path' : self.police_absolute_path,
|
||||
'copyocrbfile': self.copyocrbfile
|
||||
})
|
||||
def _get_and_change_date_format_for_swiss (self,date_to_format):
|
||||
date_formatted=''
|
||||
print date_to_format
|
||||
if date_to_format:
|
||||
date_formatted = strptime(date_to_format,'%Y-%m-%d').strftime('%d.%m.%Y')
|
||||
return date_formatted
|
||||
|
||||
def police_absolute_path(self, inner_path) :
|
||||
path = os.path.join(os.path.dirname(sys.argv[0]), inner_path)
|
||||
return path
|
||||
|
||||
def copyocrbfile(self,file):
|
||||
src = self.police_absolute_path(file)
|
||||
file = os.path.basename(src)
|
||||
dest = os.path.join('/tmp/',file)
|
||||
if not os.path.isfile(dest):
|
||||
try:
|
||||
shutil.copyfile(src,dest)
|
||||
except:
|
||||
"""print ocrbfile was not copy in /tmp/ please
|
||||
copy it manually from l10_ch/report"""
|
||||
|
||||
|
||||
|
||||
def _space(self,nbr, nbrspc=5):
|
||||
res = ''
|
||||
for i in range(len(nbr)):
|
||||
res = res + nbr[i]
|
||||
if not (i-1) % nbrspc:
|
||||
res = res + ' '
|
||||
return res
|
||||
def comma_me(self,amount):
|
||||
if type(amount) is float :
|
||||
amount = str('%.2f'%amount)
|
||||
else :
|
||||
amount = str(amount)
|
||||
orig = amount
|
||||
new = re.sub("^(-?\d+)(\d{3})", "\g<1>'\g<2>", amount)
|
||||
if orig == new:
|
||||
return new
|
||||
else:
|
||||
return self.comma_me(new)
|
||||
|
||||
def _get_ref(self, o):
|
||||
res = ''
|
||||
if o.partner_bank.bvr_adherent_num:
|
||||
res = o.partner_bank.bvr_adherent_num
|
||||
invoice_number = ''
|
||||
if o.number:
|
||||
invoice_number = re.sub('[^0-9]', '0', o.number)
|
||||
return mod10r(res + invoice_number.rjust(26-len(res), '0'))
|
||||
def _space(self,nbr, nbrspc=5):
|
||||
res = ''
|
||||
for i in range(len(nbr)):
|
||||
res = res + nbr[i]
|
||||
if not (i-1) % nbrspc:
|
||||
res = res + ' '
|
||||
return res
|
||||
|
||||
def _get_ref(self, o):
|
||||
res = ''
|
||||
if o.partner_bank.bvr_adherent_num:
|
||||
res = o.partner_bank.bvr_adherent_num
|
||||
invoice_number = ''
|
||||
if o.number:
|
||||
invoice_number = re.sub('[^0-9]', '0', o.number)
|
||||
return mod10r(res + invoice_number.rjust(26-len(res), '0'))
|
||||
|
||||
report_sxw.report_sxw(
|
||||
'report.l10n_ch.bvr',
|
||||
'account.invoice',
|
||||
'addons/l10n_ch/report/bvr.rml',
|
||||
parser=account_invoice_bvr,
|
||||
header=False)
|
||||
'report.l10n_ch.bvr',
|
||||
'account.invoice',
|
||||
'addons/l10n_ch/report/bvr.rml',
|
||||
parser=account_invoice_bvr,
|
||||
header=False)
|
||||
|
||||
report_sxw.report_sxw(
|
||||
'report.l10n_ch.invoice.bvr',
|
||||
'account.invoice',
|
||||
'addons/l10n_ch/report/invoice.rml',
|
||||
parser=account_invoice_bvr,
|
||||
header=False)
|
||||
'report.l10n_ch.invoice.bvr',
|
||||
'account.invoice',
|
||||
'addons/l10n_ch/report/invoice.rml',
|
||||
parser=account_invoice_bvr,
|
||||
header=False)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,40 +1,36 @@
|
|||
<?xml version="1.0"?>
|
||||
<document filename="test.pdf">
|
||||
<docinit>
|
||||
<registerFont fontName="ocrb" fontFile="addons/l10n_ch/report/ocrbb.ttf"/>
|
||||
<registerFont fontFile="/tmp/ocrbb.ttf" expr="{'fontFile':str(police_absolute_path('addons/l10n_ch/report/ocrbb.ttf'))}" fontName="ocrb" />
|
||||
</docinit>
|
||||
<template pageSize="(210.0mm,297.0mm)" title="Test" author="Martin Simon" allowSplitting="20">
|
||||
<pageTemplate id="first">
|
||||
<pageGraphics>
|
||||
<setFont name="Helvetica" size="30"/>
|
||||
<fill color="darkblue"/>
|
||||
<stroke color="darkblue"/>
|
||||
<drawString x="1cm" y="27.8cm">[[ company.partner_id.name ]]</drawString>
|
||||
<lines>1cm 27.7cm 20cm 27.7cm</lines>
|
||||
<!-- You Logo - Change X,Y,Width and Height -->
|
||||
<image x="1.3cm" y="27.6cm" height="40.0" >[[company.logo or removeParentNode('image')]]</image>
|
||||
<setFont name="Helvetica" size="8"/>
|
||||
<fill color="black"/>
|
||||
<stroke color="black"/>
|
||||
<lines>1.3cm 27.7cm 20cm 27.7cm</lines>
|
||||
|
||||
<setFont name="Helvetica" size="10"/>
|
||||
<drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
|
||||
|
||||
<drawString x="1cm" y="27.1cm">[[ company.partner_id.address[0].street ]]</drawString>
|
||||
<drawString x="1cm" y="26.7cm">[[ company.partner_id.address[0].zip ]] [[ company.partner_id.address[0].city ]]</drawString>
|
||||
<drawString x="17cm" y="27.1cm">TVA:</drawString>
|
||||
<drawString x="18cm" y="27.1cm">[[ company.partner_id.vat ]]</drawString>
|
||||
<drawString x="1cm" y="26.2cm">Phone:</drawString>
|
||||
<drawRightString x="7cm" y="26.2cm">[[ company.partner_id.address[0].phone ]]</drawRightString>
|
||||
|
||||
<drawString x="1cm" y="25.8cm">Mail:</drawString>
|
||||
<drawRightString x="7cm" y="25.8cm">[[ company.partner_id.address[0].email ]]</drawRightString>
|
||||
<lines>1cm 25.7cm 7cm 25.7cm</lines>
|
||||
|
||||
</pageGraphics>
|
||||
<drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]] </drawRightString>
|
||||
<drawString x="1.3cm" y="27.2cm">[[ company.partner_id.name ]]</drawString>
|
||||
<drawString x="1.3cm" y="26.8cm">[[ company.partner_id.address and company.partner_id.address[0].street or '' ]]</drawString>
|
||||
<drawString x="1.3cm" y="26.4cm">[[ company.partner_id.address and company.partner_id.address[0].zip or '' ]] [[ company.partner_id.address and company.partner_id.address[0].city or '' ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name or '']]</drawString>
|
||||
<drawString x="1.3cm" y="26.0cm">Phone:</drawString>
|
||||
<drawRightString x="7cm" y="26.0cm">[[ company.partner_id.address and company.partner_id.address[0].phone or '' ]]</drawRightString>
|
||||
<drawString x="1.3cm" y="25.6cm">Mail:</drawString>
|
||||
<drawRightString x="7cm" y="25.6cm">[[ company.partner_id.address and company.partner_id.address[0].email or '' ]]</drawRightString>
|
||||
<lines>1.3cm 25.5cm 7cm 25.5cm</lines>
|
||||
</pageGraphics>
|
||||
|
||||
<frame id="first" x1="24.0" y1="111.5mm" width="190mm" height="142mm" last="1"/>
|
||||
<frame id="Frame1"
|
||||
expr="{'height':str(111+(company.bvr_delta_vert or 0.0))+'mm', 'x1': str((company.bvr_delta_horz or 0.0))+'mm'}"
|
||||
x1="0mm"
|
||||
y1="0mm"
|
||||
y1="-5"
|
||||
width="210mm"
|
||||
height="106mm"/>
|
||||
height="111mm"/>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
|
||||
|
@ -116,6 +112,12 @@
|
|||
-->
|
||||
<illustration width="210mm" height="106mm">
|
||||
<setFont name="Helvetica" size="11"/>
|
||||
<drawString x="2mm" y="93mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.name or '' ]]</drawString>
|
||||
<drawString x="2mm" y="88mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.zip or '']] [[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.city or '']]</drawString>
|
||||
|
||||
<drawString x="62mm" y="93mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.name or '' ]]</drawString>
|
||||
<drawString x="62mm" y="88mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.zip or '']] [[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.city or '']]</drawString>
|
||||
|
||||
<drawString x="2mm" y="78mm"> [[ user.company_id.partner_id.name ]]</drawString>
|
||||
<drawString x="2mm" y="73mm"> [[ user.company_id.partner_id.address[0].street ]]</drawString>
|
||||
<drawString x="2mm" y="68mm"> [[ (user.company_id.partner_id.address[0].street2 or '')]]</drawString>
|
||||
|
@ -145,10 +147,11 @@
|
|||
<drawString x="124mm" y="67mm">[[ _space(_get_ref(o)) ]]</drawString>
|
||||
|
||||
<setFont name="ocrb" size="12"/>
|
||||
|
||||
<drawRightString x="52 mm" y="59.3mm">[[ o.partner_bank and o.partner_bank.printAccount and o.partner_bank.bvr_number or '' ]]</drawRightString>
|
||||
<drawRightString x="112mm" y="59.3mm">[[ o.partner_bank and o.partner_bank.printAccount and o.partner_bank.bvr_number or '' ]]</drawRightString>
|
||||
<drawRightString x="42mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[:-3], 1) + ' ' ]]</drawRightString>
|
||||
<drawRightString x="104mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[:-3], 1) + ' ' ]]</drawRightString>
|
||||
|
||||
<drawRightString x="114 mm" y="59.3mm">[[ o.partner_bank and o.partner_bank.printAccount and o.partner_bank.bvr_number or '' ]]</drawRightString>
|
||||
<drawRightString x="58mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[-2:], 1) + ' ' ]]</drawRightString>
|
||||
<drawRightString x="119mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[-2:], 1) + ' ' ]]</drawRightString>
|
||||
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
<?xml version="1.0"?>
|
||||
<document filename="test.pdf">
|
||||
<docinit>
|
||||
<registerFont fontName="ocrb" fontFile="addons/l10n_ch/report/ocrbb.ttf"/>
|
||||
<registerFont fontFile="/tmp/ocrbb.ttf" expr="{'fontFile':str(police_absolute_path('addons/l10n_ch/report/ocrbb.ttf'))}" fontName="ocrb" />
|
||||
|
||||
</docinit>
|
||||
|
||||
<template pageSize="(210.0mm,297.0mm)" title="Test" author="Martin Simon" allowSplitting="20">
|
||||
<pageTemplate id="first">
|
||||
<pageGraphics>
|
||||
<!--logo-->
|
||||
<setFont name="Helvetica" size="30"/>
|
||||
<fill color="darkblue"/>
|
||||
<stroke color="darkblue"/>
|
||||
<drawString x="1cm" y="27.8cm">[[ company.partner_id.name ]]</drawString>
|
||||
<lines>1cm 27.7cm 20cm 27.7cm</lines>
|
||||
<!-- You Logo - Change X,Y,Width and Height -->
|
||||
<image x="1.3cm" y="27.6cm" height="40.0" >[[company.logo or removeParentNode('image')]]</image>
|
||||
<setFont name="Helvetica" size="8"/>
|
||||
<fill color="black"/>
|
||||
<stroke color="black"/>
|
||||
<lines>1.3cm 27.7cm 20cm 27.7cm</lines>
|
||||
|
||||
<setFont name="Helvetica" size="10"/>
|
||||
<drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
|
||||
<drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
|
||||
|
||||
|
||||
<drawString x="1cm" y="27.1cm">[[ company.partner_id.address and company.partner_id.address[0].street ]]</drawString>
|
||||
<drawString x="1cm" y="26.7cm">[[ company.partner_id.address and company.partner_id.address[0].zip ]] [[ company.partner_id.address and company.partner_id.address[0].city ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name ]]</drawString>
|
||||
<drawString x="17cm" y="27.1cm">TVA:</drawString>
|
||||
<drawString x="18cm" y="27.1cm">[[ company.partner_id.vat ]]</drawString>
|
||||
<drawString x="1cm" y="26.2cm">Phone:</drawString>
|
||||
<drawRightString x="7cm" y="26.2cm">[[ company.partner_id.address and company.partner_id.address[0].phone ]]</drawRightString>
|
||||
<drawString x="1cm" y="25.8cm">Mail:</drawString>
|
||||
<drawRightString x="7cm" y="25.8cm">[[ company.partner_id.address and company.partner_id.address[0].email ]]</drawRightString>
|
||||
<lines>1cm 25.7cm 7cm 25.7cm</lines>
|
||||
</pageGraphics>
|
||||
<!-- end of header -->
|
||||
<drawString x="1.3cm" y="27.2cm">[[ company.partner_id.name ]]</drawString>
|
||||
<drawString x="1.3cm" y="26.8cm">[[ company.partner_id.address and company.partner_id.address[0].street or '' ]]</drawString>
|
||||
<drawString x="1.3cm" y="26.4cm">[[ company.partner_id.address and company.partner_id.address[0].zip or '' ]] [[ company.partner_id.address and company.partner_id.address[0].city or '' ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name or '']]</drawString>
|
||||
<drawString x="1.3cm" y="26.0cm">Phone:</drawString>
|
||||
<drawRightString x="7cm" y="26.0cm">[[ company.partner_id.address and company.partner_id.address[0].phone or '' ]]</drawRightString>
|
||||
<drawString x="1.3cm" y="25.6cm">Mail:</drawString>
|
||||
<drawRightString x="7cm" y="25.6cm">[[ company.partner_id.address and company.partner_id.address[0].email or '' ]]</drawRightString>
|
||||
<lines>1.3cm 25.5cm 7cm 25.5cm</lines>
|
||||
<drawCentredString x="10.5cm" y="0.8cm">Contact : [[ user.name ]] - Page: <pageNumber/></drawCentredString>
|
||||
</pageGraphics> <!-- end of header -->
|
||||
<frame id="first" x1="24.0" y1="111.5mm" width="190mm" height="142mm" last="1"/>
|
||||
<frame id="Frame1"
|
||||
expr="{'height':str(111+(company.bvr_delta_vert or 0.0))+'mm', 'x1': str((company.bvr_delta_horz or 0.0))+'mm'}"
|
||||
x1="0mm"
|
||||
y1="0mm"
|
||||
y1="-5"
|
||||
width="210mm"
|
||||
height="106mm"/>
|
||||
height="111mm"/>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<!-- begin of core -->
|
||||
|
@ -189,7 +188,7 @@
|
|||
</para>
|
||||
<para style="P21">
|
||||
<font face="Helvetica">Invoice Date: </font>
|
||||
<font face="Helvetica">[[format_date(o.date_invoice)]]</font>
|
||||
<font face="Helvetica">[[ o.date_invoice and format_date(o.date_invoice) or '']]</font>
|
||||
</para>
|
||||
<para style="P21">
|
||||
<font face="Helvetica">Remarque:</font>
|
||||
|
@ -248,19 +247,18 @@
|
|||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
<blockTable colWidths="28.0,499.0" style="Table4">
|
||||
<blockTable colWidths="28.0, 499.0" style="Table4">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="P16">[[ repeatIn((l.note and l.note.splitlines()) or [], 'note') ]]</para>
|
||||
<para style="P9">[[ note or removeParentNode('blockTable') ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="P9">[[ note or removeParentNode('table') ]]</para>
|
||||
<xpre style="P16">[[ l.note ]]</xpre>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
</section>
|
||||
<para style="P18">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<blockTable colWidths="215.0,313.0" style="Table5">
|
||||
<tr>
|
||||
|
@ -328,6 +326,11 @@
|
|||
-->
|
||||
<illustration width="210mm" height="106mm">
|
||||
<setFont name="Helvetica" size="11"/>
|
||||
<drawString x="2mm" y="93mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.name or '' ]]</drawString>
|
||||
<drawString x="2mm" y="88mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.zip or '']] [[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.city or '']]</drawString>
|
||||
|
||||
<drawString x="62mm" y="93mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.name or '' ]]</drawString>
|
||||
<drawString x="62mm" y="88mm">[[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.zip or '']] [[ o.partner_bank and o.partner_bank.printBank and o.partner_bank.bank and o.partner_bank.bank.city or '']]</drawString>
|
||||
<drawString x="2mm" y="78mm"> [[user.company_id.name]]</drawString>
|
||||
<drawString x="2mm" y="73mm"> [[ user.company_id.partner_id.address[0].street ]]</drawString>
|
||||
<drawString x="2mm" y="68mm"> [[ (user.company_id.partner_id.address[0].street2 or '')]]</drawString>
|
||||
|
@ -354,10 +357,12 @@
|
|||
|
||||
|
||||
<setFont name="ocrb" size="11"/>
|
||||
|
||||
<drawString x="124mm" y="67mm">[[ _space(_get_ref(o)) ]]</drawString>
|
||||
|
||||
<setFont name="ocrb" size="12"/>
|
||||
|
||||
<drawRightString x="52 mm" y="59.3mm">[[ o.partner_bank and o.partner_bank.printAccount and o.partner_bank.bvr_number or '' ]]</drawRightString>
|
||||
<drawRightString x="112mm" y="59.3mm">[[ o.partner_bank and o.partner_bank.printAccount and o.partner_bank.bvr_number or '' ]]</drawRightString>
|
||||
<drawRightString x="42mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[:-3], 1) + ' ' ]]</drawRightString>
|
||||
<drawRightString x="104mm" y="50mm">[[ _space(('%.2f' % o.amount_total)[:-3], 1) + ' ' ]]</drawRightString>
|
||||
|
||||
|
@ -375,4 +380,4 @@
|
|||
</illustration>
|
||||
|
||||
</story>
|
||||
</document>
|
||||
</document>
|
|
@ -1,342 +0,0 @@
|
|||
|
||||
|
||||
#!/usr/bin/python
|
||||
#coding: latin-1
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c):
|
||||
#
|
||||
# 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
|
||||
# 2005 Fabien Pinckaers, TINY SPRL. (http://tiny.be)
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contact a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# This program is Free Software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Tiny SXW2RML - The Tiny ERP's report engine
|
||||
|
||||
Tiny SXW2RMLis part of the Tiny report project.
|
||||
Tiny Report is a module that allows you to render high quality PDF document
|
||||
from an OpenOffice template (.sxw) and any relationnal database.
|
||||
|
||||
The whole source code is distributed under the terms of the
|
||||
GNU Public Licence.
|
||||
|
||||
(c) 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
|
||||
(c) 2005-TODAY, Fabien Pinckaers - Tiny sprl
|
||||
"""
|
||||
__version__ = '0.9'
|
||||
|
||||
|
||||
import re
|
||||
import string
|
||||
import os
|
||||
import time
|
||||
import zipfile
|
||||
import xml.dom.minidom
|
||||
from reportlab.lib.units import toLength
|
||||
import optparse
|
||||
|
||||
parser = optparse.OptionParser(
|
||||
version="Tiny Report v%s" % __version__,
|
||||
usage = 'tiny_sxw2rml.py [options] file.sxw')
|
||||
parser.add_option("-v", "--verbose", default=False, dest="verbose", help="enable basic debugging")
|
||||
parser.add_option("-o", "--output", dest="output", default='.', help="directory of image output")
|
||||
(opt, args) = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.error("incorrect number of arguments")
|
||||
|
||||
class DomApiGeneral:
|
||||
"""General DOM API utilities."""
|
||||
def __init__(self,content_string="",file=""):
|
||||
self.content_string = content_string
|
||||
self.re_digits = re.compile(r"(.*?\d)(pt|cm|mm|inch|in)")
|
||||
|
||||
def _unitTuple(self,string):
|
||||
"""Split values and units to a tuple."""
|
||||
temp = self.re_digits.findall(string)
|
||||
if not temp:
|
||||
return (string,"")
|
||||
else:
|
||||
return (temp[0])
|
||||
|
||||
def stringPercentToFloat(self,string):
|
||||
temp = string.replace("""%""","")
|
||||
return float(temp)/100
|
||||
|
||||
def findChildrenByName(self,parent,name,attr_dict={}):
|
||||
"""Helper functions. Does not work recursively.
|
||||
Optional: also test for certain attribute/value pairs."""
|
||||
children = []
|
||||
for c in parent.childNodes:
|
||||
if c.nodeType == c.ELEMENT_NODE and c.nodeName == name:
|
||||
children.append(c)
|
||||
if attr_dict == {}:
|
||||
return children
|
||||
else:
|
||||
return self._selectForAttributes(nodelist=children,attr_dict=attr_dict)
|
||||
|
||||
def _selectForAttributes(self,nodelist,attr_dict):
|
||||
"Helper function."""
|
||||
selected_nodes = []
|
||||
for n in nodelist:
|
||||
check = 1
|
||||
for a in attr_dict.keys():
|
||||
if n.getAttribute(a) != attr_dict[a]:
|
||||
# at least one incorrect attribute value?
|
||||
check = 0
|
||||
if check:
|
||||
selected_nodes.append(n)
|
||||
return selected_nodes
|
||||
|
||||
def _stringToTuple(self,s):
|
||||
"""Helper function."""
|
||||
try:
|
||||
temp = string.split(s,",")
|
||||
return int(temp[0]),int(temp[1])
|
||||
except:
|
||||
return None
|
||||
|
||||
def _tupleToString(self,t):
|
||||
try:
|
||||
return self.openOfficeStringUtf8("%s,%s" % (t[0],t[1]))
|
||||
except:
|
||||
return None
|
||||
|
||||
def _lengthToFloat(self,value):
|
||||
v = value
|
||||
if not self.re_digits.search(v):
|
||||
return v
|
||||
try:
|
||||
if v[-4:] == "inch":
|
||||
# OO files use "inch" instead of "in" in Reportlab units
|
||||
v = v[:-2]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
c = round(toLength(v))
|
||||
return c
|
||||
except:
|
||||
return v
|
||||
|
||||
def openOfficeStringUtf8(self,string):
|
||||
if type(string) == unicode:
|
||||
return string.encode("utf-8")
|
||||
tempstring = unicode(string,"cp1252").encode("utf-8")
|
||||
return tempstring
|
||||
|
||||
class DomApi(DomApiGeneral):
|
||||
"""This class provides a DOM-API for XML-Files from an SXW-Archive."""
|
||||
def __init__(self,xml_content,xml_styles):
|
||||
DomApiGeneral.__init__(self)
|
||||
self.content_dom = xml.dom.minidom.parseString(xml_content)
|
||||
self.styles_dom = xml.dom.minidom.parseString(xml_styles)
|
||||
body = self.content_dom.getElementsByTagName("office:body")
|
||||
self.body = body and body[0]
|
||||
|
||||
# TODO:
|
||||
self.style_dict = {}
|
||||
self.style_properties_dict = {}
|
||||
|
||||
# ******** always use the following order:
|
||||
self.buildStyleDict()
|
||||
self.buildStylePropertiesDict()
|
||||
|
||||
self.page_master = self.styles_dom.getElementsByTagName("style:page-master")[0]
|
||||
self.document = self.content_dom.getElementsByTagName("office:document-content")[0]
|
||||
|
||||
def buildStylePropertiesDict(self):
|
||||
for s in self.style_dict.keys():
|
||||
self.style_properties_dict[s] = self.getStylePropertiesDict(s)
|
||||
|
||||
def updateWithPercents(self,dict,updatedict):
|
||||
"""Sometimes you find values like "115%" in the style hierarchy."""
|
||||
if not updatedict:
|
||||
# no style hierarchies for this style? =>
|
||||
return
|
||||
new_updatedict = copy.copy(updatedict)
|
||||
for u in new_updatedict.keys():
|
||||
try:
|
||||
if new_updatedict[u].find("""%""") != -1 and dict.has_key(u):
|
||||
number = float(self.re_digits.search(dict[u]).group(1))
|
||||
unit = self.re_digits.search(dict[u]).group(2)
|
||||
new_number = self.stringPercentToFloat(new_updatedict[u]) * number
|
||||
if unit == "pt":
|
||||
new_number = int(new_number)
|
||||
# no floats allowed for "pt"
|
||||
# OOo just takes the int, does not round (try it out!)
|
||||
new_updatedict[u] = "%s%s" % (new_number,unit)
|
||||
else:
|
||||
dict[u] = new_updatedict[u]
|
||||
except:
|
||||
dict[u] = new_updatedict[u]
|
||||
dict.update(new_updatedict)
|
||||
|
||||
def normalizeStyleProperties(self):
|
||||
"""Transfer all style:style-properties attributes from the
|
||||
self.style_properties_hierarchical dict to the automatic-styles
|
||||
from content.xml. Use this function to preprocess content.xml for
|
||||
XSLT transformations etc.Do not try to implement this function
|
||||
with XSlT - believe me, it's a terrible task..."""
|
||||
styles_styles = self.styles_dom.getElementsByTagName("style:style")
|
||||
automatic_styles = self.content_dom.getElementsByTagName("office:automatic-styles")[0]
|
||||
for s in styles_styles:
|
||||
automatic_styles.appendChild(s.cloneNode(deep=1))
|
||||
content_styles = self.content_dom.getElementsByTagName("style:style")
|
||||
# these are the content_styles with styles_styles added!!!
|
||||
for s in content_styles:
|
||||
c = self.findChildrenByName(s,"style:properties")
|
||||
if c == []:
|
||||
# some derived automatic styles do not have "style:properties":
|
||||
temp = self.content_dom.createElement("style:properties")
|
||||
s.appendChild(temp)
|
||||
c = self.findChildrenByName(s,"style:properties")
|
||||
c = c[0]
|
||||
dict = self.style_properties_dict[(s.getAttribute("style:name")).encode("latin-1")] or {}
|
||||
for attribute in dict.keys():
|
||||
c.setAttribute(self.openOfficeStringUtf8(attribute),self.openOfficeStringUtf8(dict[attribute]))
|
||||
|
||||
def transferStylesXml(self):
|
||||
"""Transfer certain sub-trees from styles.xml to the normalized content.xml
|
||||
(see above). It is not necessary to do this - for example - with paragraph styles.
|
||||
the "normalized" style properties contain all information needed for
|
||||
further processing."""
|
||||
# TODO: What about table styles etc.?
|
||||
page_master = self.page_master
|
||||
outline_styles = self.styles_dom.getElementsByTagName("text:outline-style")
|
||||
t = self.content_dom.createElement("transferredfromstylesxml")
|
||||
self.document.insertBefore(t,self.body)
|
||||
t_new = self.body.previousSibling
|
||||
try:
|
||||
t_new.appendChild(page_master.cloneNode(deep=1))
|
||||
t_new.appendChild(outline_styles[0].cloneNode(deep=1))
|
||||
except:
|
||||
pass
|
||||
|
||||
def normalizeLength(self):
|
||||
"""Normalize all lengthes to floats (i.e: 1 inch = 72).
|
||||
Always use this after "normalizeContent" and "transferStyles"!"""
|
||||
# TODO: The complex attributes of table cell styles are not transferred yet.
|
||||
#all_styles = self.content_dom.getElementsByTagName("style:properties")
|
||||
#all_styles += self.content_dom.getElementsByTagName("draw:image")
|
||||
all_styles = self.content_dom.getElementsByTagName("*")
|
||||
for s in all_styles:
|
||||
for x in s._attrs.keys():
|
||||
v = s.getAttribute(x)
|
||||
s.setAttribute(x,"%s" % self._lengthToFloat(v))
|
||||
# convert float to string first!
|
||||
|
||||
def normalizeTableColumns(self):
|
||||
"""Handle this strange table:number-columns-repeated attribute."""
|
||||
columns = self.content_dom.getElementsByTagName("table:table-column")
|
||||
for c in columns:
|
||||
if c.hasAttribute("table:number-columns-repeated"):
|
||||
number = int(c.getAttribute("table:number-columns-repeated"))
|
||||
c.removeAttribute("table:number-columns-repeated")
|
||||
for i in range(number-1):
|
||||
(c.parentNode).insertBefore(c.cloneNode(deep=1),c)
|
||||
|
||||
def buildStyleDict(self):
|
||||
"""Store all style:style-nodes from content.xml and styles.xml in self.style_dict.
|
||||
Caution: in this dict the nodes from two dom apis are merged!"""
|
||||
for st in (self.styles_dom,self.content_dom):
|
||||
for s in st.getElementsByTagName("style:style"):
|
||||
name = s.getAttribute("style:name").encode("latin-1")
|
||||
self.style_dict[name] = s
|
||||
return True
|
||||
|
||||
def toxml(self):
|
||||
return self.content_dom.toxml(encoding="utf-8")
|
||||
|
||||
def getStylePropertiesDict(self,style_name):
|
||||
res = {}
|
||||
|
||||
if self.style_dict[style_name].hasAttribute("style:parent-style-name"):
|
||||
parent = self.style_dict[style_name].getAttribute("style:parent-style-name").encode("latin-1")
|
||||
res = self.getStylePropertiesDict(parent)
|
||||
|
||||
childs = self.style_dict[style_name].childNodes
|
||||
for c in childs:
|
||||
if c.nodeType == c.ELEMENT_NODE and c.nodeName == "style:properties":
|
||||
for attr in c._attrs.keys():
|
||||
res[attr] = c.getAttribute(attr).encode("latin-1")
|
||||
return res
|
||||
|
||||
class PyOpenOffice(object):
|
||||
"""This is the main class which provides all functionality."""
|
||||
def __init__(self, path='.'):
|
||||
self.path = path
|
||||
|
||||
def oo_read(self,fname):
|
||||
z = zipfile.ZipFile(fname,"r")
|
||||
content = z.read('content.xml')
|
||||
style = z.read('styles.xml')
|
||||
all = z.namelist()
|
||||
for a in all:
|
||||
if a[:9]=='Pictures/' and len(a)>10:
|
||||
pic_content = z.read(a)
|
||||
f=open(os.path.join(self.path, os.path.basename(a)),"wb")
|
||||
f.write(pic_content)
|
||||
f.close()
|
||||
z.close()
|
||||
return content,style
|
||||
|
||||
def oo_replace(self,content):
|
||||
regex = [
|
||||
(r"<para[^>]*/>", ""),
|
||||
#(r"<text:ordered-list.*?>(.*?)</text:ordered-list>", "$1"),
|
||||
#(r"<text:unordered-list.*?>(.*?)</text:unordered-list>", "$1"),
|
||||
(r"<para(.*)>(.*?)<text:line-break[^>]*/>", "<para$1>$2</para><para$1>"),
|
||||
]
|
||||
for key,val in regex:
|
||||
content = re.sub(key, val, content)
|
||||
return content
|
||||
|
||||
def unpackNormalize(self,sourcefile):
|
||||
c,s = self.oo_read(sourcefile)
|
||||
c = self.oo_replace(c)
|
||||
dom = DomApi(c,s)
|
||||
dom.normalizeStyleProperties()
|
||||
dom.transferStylesXml()
|
||||
dom.normalizeLength()
|
||||
dom.normalizeTableColumns()
|
||||
new_c = dom.toxml()
|
||||
return new_c
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import libxslt
|
||||
import libxml2
|
||||
|
||||
f = sys.argv[1]
|
||||
tool = PyOpenOffice(opt.output)
|
||||
res = tool.unpackNormalize(f)
|
||||
styledoc = libxml2.parseFile('normalized_oo2rml.xsl')
|
||||
style = libxslt.parseStylesheetDoc(styledoc)
|
||||
doc = libxml2.parseMemory(res,len(res))
|
||||
result = style.applyStylesheet(doc, None)
|
||||
xml = style.saveResultToString(result)
|
||||
print xml
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -39,215 +39,215 @@ from tools.translate import _
|
|||
|
||||
ASK_FORM = """<?xml version="1.0"?>
|
||||
<form string="BVR Import">
|
||||
<field name="file"/>
|
||||
<field name="file"/>
|
||||
</form>"""
|
||||
|
||||
ASK_FIELDS = {
|
||||
'file': {
|
||||
'string': 'BVR file',
|
||||
'type': 'binary',
|
||||
'required': True,
|
||||
},
|
||||
'file': {
|
||||
'string': 'BVR file',
|
||||
'type': 'binary',
|
||||
'required': True,
|
||||
},
|
||||
}
|
||||
|
||||
def _reconstruct_invoice_ref(cursor, user, reference, context):
|
||||
###
|
||||
id_invoice = False
|
||||
# On fait d'abord une recherche sur toutes les factures
|
||||
# we now searhc for company
|
||||
user_obj=pooler.get_pool(cursor.dbname).get('res.users')
|
||||
user_current=user_obj.browse(cursor, user, user)
|
||||
|
||||
##
|
||||
|
||||
cursor.execute("SELECT inv.id,inv.number from account_invoice AS inv where inv.company_id = " + str(user_current.company_id.id))
|
||||
result_invoice = cursor.fetchall()
|
||||
|
||||
for inv_id,inv_name in result_invoice:
|
||||
inv_name = re.sub('[^0-9]', '0', str(inv_name))
|
||||
if inv_name == reference:
|
||||
id_invoice = inv_id
|
||||
break
|
||||
if id_invoice:
|
||||
cursor.execute('SELECT l.id ' \
|
||||
'FROM account_move_line l, account_invoice i ' \
|
||||
'WHERE l.move_id = i.move_id AND l.reconcile_id is NULL ' \
|
||||
'AND i.id in (' + ','.join([str(x) for x in [id_invoice]]) + ')')
|
||||
inv_line = []
|
||||
for id_line in cursor.fetchall():
|
||||
inv_line.append(id_line[0])
|
||||
return inv_line
|
||||
else:
|
||||
return []
|
||||
return True
|
||||
###
|
||||
id_invoice = False
|
||||
# On fait d'abord une recherche sur toutes les factures
|
||||
# we now searhc for company
|
||||
user_obj=pooler.get_pool(cursor.dbname).get('res.users')
|
||||
user_current=user_obj.browse(cursor, user, user)
|
||||
|
||||
##
|
||||
|
||||
cursor.execute("SELECT inv.id,inv.number from account_invoice AS inv where inv.company_id = " + str(user_current.company_id.id))
|
||||
result_invoice = cursor.fetchall()
|
||||
|
||||
for inv_id,inv_name in result_invoice:
|
||||
inv_name = re.sub('[^0-9]', '0', str(inv_name))
|
||||
if inv_name == reference:
|
||||
id_invoice = inv_id
|
||||
break
|
||||
if id_invoice:
|
||||
cursor.execute('SELECT l.id ' \
|
||||
'FROM account_move_line l, account_invoice i ' \
|
||||
'WHERE l.move_id = i.move_id AND l.reconcile_id is NULL ' \
|
||||
'AND i.id in (' + ','.join([str(x) for x in [id_invoice]]) + ')')
|
||||
inv_line = []
|
||||
for id_line in cursor.fetchall():
|
||||
inv_line.append(id_line[0])
|
||||
return inv_line
|
||||
else:
|
||||
return []
|
||||
return True
|
||||
def _import(obj, cursor, user, data, context):
|
||||
|
||||
pool = pooler.get_pool(cursor.dbname)
|
||||
statement_line_obj = pool.get('account.bank.statement.line')
|
||||
statement_reconcile_obj = pool.get('account.bank.statement.reconcile')
|
||||
move_line_obj = pool.get('account.move.line')
|
||||
property_obj = pool.get('ir.property')
|
||||
model_fields_obj = pool.get('ir.model.fields')
|
||||
attachment_obj = pool.get('ir.attachment')
|
||||
file = data['form']['file']
|
||||
statement_id = data['id']
|
||||
pool = pooler.get_pool(cursor.dbname)
|
||||
statement_line_obj = pool.get('account.bank.statement.line')
|
||||
statement_reconcile_obj = pool.get('account.bank.statement.reconcile')
|
||||
move_line_obj = pool.get('account.move.line')
|
||||
property_obj = pool.get('ir.property')
|
||||
model_fields_obj = pool.get('ir.model.fields')
|
||||
attachment_obj = pool.get('ir.attachment')
|
||||
file = data['form']['file']
|
||||
statement_id = data['id']
|
||||
|
||||
records = []
|
||||
total_amount = 0
|
||||
total_cost = 0
|
||||
find_total = False
|
||||
records = []
|
||||
total_amount = 0
|
||||
total_cost = 0
|
||||
find_total = False
|
||||
|
||||
for lines in base64.decodestring(file).split("\n"):
|
||||
# Manage files without carriage return
|
||||
while lines:
|
||||
(line, lines) = (lines[:128], lines[128:])
|
||||
record = {}
|
||||
for lines in base64.decodestring(file).split("\n"):
|
||||
# Manage files without carriage return
|
||||
while lines:
|
||||
(line, lines) = (lines[:128], lines[128:])
|
||||
record = {}
|
||||
|
||||
if line[0:3] in ('999', '995'):
|
||||
if find_total:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Too much total record found!'))
|
||||
find_total = True
|
||||
if lines:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Record found after total record!'))
|
||||
amount = float(line[39:49]) + (float(line[49:51]) / 100)
|
||||
cost = float(line[69:76]) + (float(line[76:78]) / 100)
|
||||
if line[2] == '5':
|
||||
amount *= -1
|
||||
cost *= -1
|
||||
if line[0:3] in ('999', '995'):
|
||||
if find_total:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Too much total record found!'))
|
||||
find_total = True
|
||||
if lines:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Record found after total record!'))
|
||||
amount = float(line[39:49]) + (float(line[49:51]) / 100)
|
||||
cost = float(line[69:76]) + (float(line[76:78]) / 100)
|
||||
if line[2] == '5':
|
||||
amount *= -1
|
||||
cost *= -1
|
||||
|
||||
if round(amount - total_amount, 2) >= 0.01 \
|
||||
or round(cost - total_cost, 2) >= 0.01:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Total record different from the computed!'))
|
||||
if int(line[51:63]) != len(records):
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Number record different from the computed!'))
|
||||
else:
|
||||
record = {
|
||||
'reference': line[12:39],
|
||||
'amount': float(line[39:47]) + (float(line[47:49]) / 100),
|
||||
'date': time.strftime('%Y-%m-%d',
|
||||
time.strptime(line[65:71], '%y%m%d')),
|
||||
'cost': float(line[96:98]) + (float(line[98:100]) / 100),
|
||||
}
|
||||
if round(amount - total_amount, 2) >= 0.01 \
|
||||
or round(cost - total_cost, 2) >= 0.01:
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Total record different from the computed!'))
|
||||
if int(line[51:63]) != len(records):
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Number record different from the computed!'))
|
||||
else:
|
||||
record = {
|
||||
'reference': line[12:39],
|
||||
'amount': float(line[39:47]) + (float(line[47:49]) / 100),
|
||||
'date': time.strftime('%Y-%m-%d',
|
||||
time.strptime(line[65:71], '%y%m%d')),
|
||||
'cost': float(line[96:98]) + (float(line[98:100]) / 100),
|
||||
}
|
||||
|
||||
if record['reference'] != mod10r(record['reference'][:-1]):
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Recursive mod10 is invalid for reference: %s') % \
|
||||
record['reference'])
|
||||
if record['reference'] != mod10r(record['reference'][:-1]):
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('Recursive mod10 is invalid for reference: %s') % \
|
||||
record['reference'])
|
||||
|
||||
if line[2] == '5':
|
||||
record['amount'] *= -1
|
||||
record['cost'] *= -1
|
||||
total_amount += record['amount']
|
||||
total_cost += record['cost']
|
||||
records.append(record)
|
||||
if line[2] == '5':
|
||||
record['amount'] *= -1
|
||||
record['cost'] *= -1
|
||||
total_amount += record['amount']
|
||||
total_cost += record['cost']
|
||||
records.append(record)
|
||||
|
||||
model_fields_ids = model_fields_obj.search(cursor, user, [
|
||||
('name', 'in', ['property_account_receivable', 'property_account_payable']),
|
||||
('model', '=', 'res.partner'),
|
||||
], context=context)
|
||||
property_ids = property_obj.search(cursor, user, [
|
||||
('fields_id', 'in', model_fields_ids),
|
||||
('res_id', '=', False),
|
||||
], context=context)
|
||||
model_fields_ids = model_fields_obj.search(cursor, user, [
|
||||
('name', 'in', ['property_account_receivable', 'property_account_payable']),
|
||||
('model', '=', 'res.partner'),
|
||||
], context=context)
|
||||
property_ids = property_obj.search(cursor, user, [
|
||||
('fields_id', 'in', model_fields_ids),
|
||||
('res_id', '=', False),
|
||||
], context=context)
|
||||
|
||||
account_receivable = False
|
||||
account_payable = False
|
||||
for property in property_obj.browse(cursor, user, property_ids, context=context):
|
||||
if property.fields_id.name == 'property_account_receivable':
|
||||
account_receivable = int(property.value.split(',')[1])
|
||||
elif property.fields_id.name == 'property_account_payable':
|
||||
account_payable = int(property.value.split(',')[1])
|
||||
account_receivable = False
|
||||
account_payable = False
|
||||
for property in property_obj.browse(cursor, user, property_ids, context=context):
|
||||
if property.fields_id.name == 'property_account_receivable':
|
||||
account_receivable = int(property.value.split(',')[1])
|
||||
elif property.fields_id.name == 'property_account_payable':
|
||||
account_payable = int(property.value.split(',')[1])
|
||||
|
||||
for record in records:
|
||||
# Remove the 11 first char because it can be adherent number
|
||||
# TODO check if 11 is the right number
|
||||
reference = record['reference'][11:-1].lstrip('0')
|
||||
values = {
|
||||
'name': 'IN '+ reference,
|
||||
'date': record['date'],
|
||||
'amount': record['amount'],
|
||||
'ref': reference,
|
||||
'type': (record['amount'] >= 0 and 'customer') or 'supplier',
|
||||
'statement_id': statement_id,
|
||||
}
|
||||
line_ids = move_line_obj.search(cursor, user, [
|
||||
('ref', 'like', reference),
|
||||
('reconcile_id', '=', False),
|
||||
('account_id.type', 'in', ['receivable', 'payable']),
|
||||
], order='date desc', context=context)
|
||||
if not line_ids:
|
||||
line_ids = _reconstruct_invoice_ref(cursor,user,reference,None)
|
||||
|
||||
line2reconcile = False
|
||||
partner_id = False
|
||||
account_id = False
|
||||
for line in move_line_obj.browse(cursor, user, line_ids, context=context):
|
||||
if line.partner_id.id:
|
||||
partner_id = line.partner_id.id
|
||||
if record['amount'] >= 0:
|
||||
if round(record['amount'] - line.debit, 2) < 0.01:
|
||||
line2reconcile = line.id
|
||||
account_id = line.account_id.id
|
||||
break
|
||||
else:
|
||||
if round(line.credit + record['amount'], 2) < 0.01:
|
||||
line2reconcile = line.id
|
||||
account_id = line.account_id.id
|
||||
break
|
||||
if not account_id:
|
||||
if record['amount'] >= 0:
|
||||
account_id = account_receivable
|
||||
else:
|
||||
account_id = account_payable
|
||||
if not account_id :
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('The properties account payable account receivable'))
|
||||
values['account_id'] = account_id
|
||||
values['partner_id'] = partner_id
|
||||
for record in records:
|
||||
# Remove the 11 first char because it can be adherent number
|
||||
# TODO check if 11 is the right number
|
||||
reference = record['reference'][11:-1].lstrip('0')
|
||||
values = {
|
||||
'name': 'IN '+ reference,
|
||||
'date': record['date'],
|
||||
'amount': record['amount'],
|
||||
'ref': reference,
|
||||
'type': (record['amount'] >= 0 and 'customer') or 'supplier',
|
||||
'statement_id': statement_id,
|
||||
}
|
||||
line_ids = move_line_obj.search(cursor, user, [
|
||||
('ref', 'like', reference),
|
||||
('reconcile_id', '=', False),
|
||||
('account_id.type', 'in', ['receivable', 'payable']),
|
||||
], order='date desc', context=context)
|
||||
if not line_ids:
|
||||
line_ids = _reconstruct_invoice_ref(cursor,user,reference,None)
|
||||
|
||||
line2reconcile = False
|
||||
partner_id = False
|
||||
account_id = False
|
||||
for line in move_line_obj.browse(cursor, user, line_ids, context=context):
|
||||
if line.partner_id.id:
|
||||
partner_id = line.partner_id.id
|
||||
if record['amount'] >= 0:
|
||||
if round(record['amount'] - line.debit, 2) < 0.01:
|
||||
line2reconcile = line.id
|
||||
account_id = line.account_id.id
|
||||
break
|
||||
else:
|
||||
if round(line.credit + record['amount'], 2) < 0.01:
|
||||
line2reconcile = line.id
|
||||
account_id = line.account_id.id
|
||||
break
|
||||
if not account_id:
|
||||
if record['amount'] >= 0:
|
||||
account_id = account_receivable
|
||||
else:
|
||||
account_id = account_payable
|
||||
if not account_id :
|
||||
raise wizard.except_wizard(_('Error'),
|
||||
_('The properties account payable account receivable'))
|
||||
values['account_id'] = account_id
|
||||
values['partner_id'] = partner_id
|
||||
|
||||
if line2reconcile:
|
||||
values['reconcile_id'] = statement_reconcile_obj.create(cursor, user, {
|
||||
'line_ids': [(6, 0, [line2reconcile])],
|
||||
}, context=context)
|
||||
if line2reconcile:
|
||||
values['reconcile_id'] = statement_reconcile_obj.create(cursor, user, {
|
||||
'line_ids': [(6, 0, [line2reconcile])],
|
||||
}, context=context)
|
||||
|
||||
statement_line_obj.create(cursor, user, values, context=context)
|
||||
attachment_obj.create(cursor, user, {
|
||||
'name': 'BVR',
|
||||
'datas': file,
|
||||
'datas_fname': 'BVR.txt',
|
||||
'res_model': 'account.bank.statement',
|
||||
'res_id': statement_id,
|
||||
}, context=context)
|
||||
return {}
|
||||
statement_line_obj.create(cursor, user, values, context=context)
|
||||
attachment_obj.create(cursor, user, {
|
||||
'name': 'BVR',
|
||||
'datas': file,
|
||||
'datas_fname': 'BVR.txt',
|
||||
'res_model': 'account.bank.statement',
|
||||
'res_id': statement_id,
|
||||
}, context=context)
|
||||
return {}
|
||||
|
||||
|
||||
class BVRImport(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type': 'form',
|
||||
'arch': ASK_FORM,
|
||||
'fields': ASK_FIELDS,
|
||||
'state': [
|
||||
('end', 'Cancel', 'gtk-cancel'),
|
||||
('import', 'Import', 'gtk-ok', True),
|
||||
],
|
||||
},
|
||||
},
|
||||
'import': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type': 'action',
|
||||
'action': _import,
|
||||
'state': 'end',
|
||||
},
|
||||
},
|
||||
}
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type': 'form',
|
||||
'arch': ASK_FORM,
|
||||
'fields': ASK_FIELDS,
|
||||
'state': [
|
||||
('end', 'Cancel', 'gtk-cancel'),
|
||||
('import', 'Import', 'gtk-ok', True),
|
||||
],
|
||||
},
|
||||
},
|
||||
'import': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type': 'action',
|
||||
'action': _import,
|
||||
'state': 'end',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
BVRImport('l10n_ch.bvr_import')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue