1
# -*- encoding: utf-8 -*-
2
##############################################################################
4
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
6
# $Id: account.py 1005 2005-07-25 08:41:42Z nicoe $
8
# WARNING: This program as such is intended to be used by professional
9
# programmers who take the whole responsability of assessing all potential
10
# consequences resulting from its eventual inadequacies and bugs
11
# End users who are looking for a ready-to-use solution with commercial
12
# garantees and support are strongly adviced to contract a Free Software
15
# This program is Free Software; you can redistribute it and/or
16
# modify it under the terms of the GNU General Public License
17
# as published by the Free Software Foundation; either version 2
18
# of the License, or (at your option) any later version.
20
# This program is distributed in the hope that it will be useful,
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
# GNU General Public License for more details.
25
# You should have received a copy of the GNU General Public License
26
# along with this program; if not, write to the Free Software
27
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
##############################################################################
31
from osv import fields, osv
33
from mx.DateTime import *
38
from lxml import etree
40
import codecs, cfdutil
46
class account_invoice(osv.osv):
47
_name = "account.invoice"
48
_inherit = 'account.invoice'
49
_description = 'Invoice'
53
'sign_date':fields.datetime('Sing Date'),
54
'cancel_date':fields.datetime('Cancel Date'),
55
'approved_year':fields.integer('Approved Year'),
56
'approved_number': fields.char('Approved Number', size=32),
57
'certificate': fields.text('Certificate'),
58
'digital_signature': fields.text('Signature'),
59
'cadena':fields.text('Cadena')
60
#'provider_signature': fields.text('Signature Provider'),
61
#'invoice_xml':fields.text('Invoice_Xml'),
65
def copy(self, cr, uid, id, default=None, context=None):
68
default = default.copy()
69
default.update({'state':'draft', 'number':False, 'move_id':False, 'move_name':False, 'cancel_date':False, 'sign_date':False,
70
'approved_year':False, 'approved_number':False, 'certificate':False, 'digital_signature':False, 'cadena':False, 'period_id':False})
71
if 'date_invoice' not in default:
72
default['date_invoice'] = time.strftime('%Y-%m-%d')
73
if 'date_due' not in default:
74
default['date_due'] = False
75
if 'cancel_date' not in default:
76
default['cancel_date'] = False
77
return super(account_invoice, self).copy(cr, uid, id, default, context)
79
def cfdutil_getLineaReporte(self, xml_str_obj, state='False'):
80
return cfdutil.getLineaReporte(xml_str_obj, state)
83
def cfdutil_verifySello(self, cadena, certfname, sello):
84
return cfdutil.verifySello(cadena, certfname, sello)
86
def elimante_double_space(self, data):
87
data = re.sub('[ \t\n\r\f\v]', ' ',data)
88
data = data.strip(' ')
90
data = re.sub(' ', ' ', data)
93
def make_utf(self, data, required=''):
94
if not data and required:
95
raise osv.except_osv(('Error !'), ('Campo %s es Requerido y esta faltando en la captura.'%(required,)))
96
elif data and required:
98
return unicode(self.elimante_double_space(data), 'utf-8')
100
return unicode(self.elimante_double_space(data), 'utf-8')
104
def _period_get(self, cr, uid, ctx={}):
106
ids = self.pool.get('account.period').find(cr, uid, context=ctx)
111
def action_cancel(self, cr, uid, ids, *args):
112
account_move_obj = self.pool.get('account.move')
113
invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids', 'id'])
116
account_move_line_obj = self.pool.get('account.move.line')
117
pay_ids = account_move_line_obj.browse(cr, uid , i['payment_ids'])
118
for move_line in pay_ids:
119
if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids:
120
raise osv.except_osv(_('Error !'), _('You cannot cancel the Invoice which is Partially Paid! You need to unreconcile concerned payment entries!'))
122
reconcile_obj = self.pool.get('account.move.reconcile')
123
line_obj = self.pool.get('account.move.line')
124
move_obj = self.pool.get('account.move')
125
date = time.strftime('%Y-%m-%d')
126
period = self._period_get(cr, uid)
127
inv = self.browse(cr, uid, i['id'])
128
if inv.state in ['draft', 'proforma2', 'cancel']:
129
raise wizard.except_wizard(_('Error !'), _('Can not cancel draft/proforma/cancel invoice.'))
130
if inv.type == 'in_invoice':
131
description = 'Fac. '+inv.reference+' Cancelada'
132
elif inv.type == 'out_invoice':
133
description = 'Fac. '+inv.number+' Cancelada'
135
description = 'Fac. '+inv.number+' Cancelada'
137
raise wizard.except_wizard(_('Data Insufficient !'), _('No Period found on Invoice!'))
138
default={'date':date, 'period_id':period, 'ref':description , 'state':'draft', 'name':'/',}
139
move_obj.button_cancel(cr, uid, [inv.move_id.id,])
140
move_id = move_obj.copy(cr, uid, inv.move_id.id, context={}, default={'date':date, 'period_id':period, 'ref':description })
141
move_obj.post(cr, uid, [inv.move_id.id,])
142
move = move_obj.browse(cr, uid, move_id)
143
move_obj.write(cr, uid, [move_id], {'date':date})
144
for line in move.line_id:
145
line_obj.write(cr, uid, [line.id], {
146
'debit': line.credit,
147
'credit': line.debit,
148
'amount_currency': line.amount_currency and -line.amount_currency or False,
150
}, context={'multireconcile':True})
152
#move_obj.post(self, cr, uid, [move_id])
153
move_obj.post(cr, uid, [move_id])
154
#if inv is paid we unreconcile
155
movelines = inv.move_id.line_id
156
#we unreconcile the lines
157
to_reconcile_ids = {}
158
for line in movelines :
159
#if the account of the line is the as the one in the invoice
161
if line.account_id.id == inv.account_id.id :
162
to_reconcile_ids[line.account_id.id] =[line.id]
163
if type(line.reconcile_id) != osv.orm.browse_null :
164
reconcile_obj.unlink(cr,uid, line.reconcile_id.id)
166
#we match the line to reconcile
167
for tmpline in move.line_id :
168
if tmpline.account_id.id == inv.account_id.id :
169
to_reconcile_ids[tmpline.account_id.id].append(tmpline.id)
170
for account in to_reconcile_ids :
171
line_obj.reconcile(cr, uid, to_reconcile_ids[account],
173
writeoff_period_id=period,
174
writeoff_journal_id=inv.journal_id.id,
175
writeoff_acc_id=inv.account_id.id
177
date_time = now().Format('%Y-%m-%d %H:%M:%S')
178
self.write(cr, uid, inv.id, {'cancel_date':date_time, 'state':'cancel'})
180
#account_move_obj.button_cancel(cr, uid, [i['move_id'][0]])
181
# delete the move this invoice was pointing to
182
# Note that the corresponding move_lines and move_reconciles
183
# will be automatically deleted too
184
#account_move_obj.unlink(cr, uid, [i['move_id'][0]])
187
self.write(cr, uid, ids, {'state':'cancel'})
188
self._log_event(cr, uid, ids,-1.0, 'Cancel Invoice')
189
date_time = now().Format('%Y-%m-%d %H:%M:%S')
190
self.write(cr, uid, ids, {'cancel_date':date_time})
193
def action_cancel_draft(self, cr, uid, ids, *args):
194
for invoice in self.browse(cr, uid, ids):
195
if invoice.type != 'out_invoice':
196
return super(account_invoice, self).action_cancel_draft( cr, uid, ids, *args)
197
self.write(cr, uid, ids, {'cancel_date':False,
200
'approved_number':'',
202
'digital_signature':'',
204
for inv_brw in self.browse(cr, uid, ids):
205
if inv_brw.journal_id.code in ('factura_e' ,'nota_credito_e'):
206
number, prefix = self.get_inv_number(cr, uid, inv_brw)
207
if inv_brw.journal_id.code == 'factura_e':
208
invtype = inv_brw.journal_id.code
210
invtype = inv_brw.type
212
if inv_brw.journal_id.invoice_sequence_id:
213
sid = inv_brw.journal_id.invoice_sequence_id.id
215
seq_code = 'account.invoice.' + invtype
216
cr.execute("SELECT id FROM ir_sequence WHERE code='%s'"%(seq_code))
217
sid = cr.fetchone()[0]
218
sid_brw = self.pool.get('ir.sequence').browse(cr, uid, sid)
219
next_number = sid_brw.number_next
220
number_increment = sid_brw.number_increment
221
if (number + number_increment) == next_number:
222
super(account_invoice, self).action_cancel_draft( cr, uid, ids, *args)
223
move_line_brw = inv_brw.move_id.line_id
224
move_line_ids = [m_line.id for m_line in move_line_brw]
225
query = "SELECT reconcile_id from account_move_line where reconcile_id is not null and id in %s"%(tuple(move_line_ids), )
227
rec_ids = cr.fetchall()
228
rec_ids = [x[0] for x in rec_ids]
229
if len(rec_ids) == 1:
231
query2 = "SELECT id, move_id from account_move_line where reconcile_id = %s"%rec_ids[0]
233
move_ids = cr.fetchall()
234
move_ids = [x[1] for x in move_ids]
235
self.pool.get('account.move.reconcile').unlink(cr, uid, rec_ids)
236
self.pool.get('account.move').button_cancel(cr, uid, move_ids)
237
self.pool.get('account.move').unlink(cr, uid, move_ids)
239
#solo cancela y borra el asiento de la factura ya que no esta conciliado o bien se rompio la conciliacion a mano
240
self.pool.get('account.move').button_cancel(cr, uid, inv_brw.move_id.id)
241
self.pool.get('account.move').unlink(cr, uid, inv_brw.move_id.id)
242
attachment_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_id','in',ids),('res_model','=', self._name)])
243
self.pool.get('ir.attachment').unlink(cr, uid,attachment_ids)
246
raise osv.except_osv(('Warrnig !'), ('This invoice can not be set to draft.'))
248
super(account_invoice, self).action_cancel_draft( cr, uid, ids, *args)
252
def action_number(self, cr, uid, ids, *args):
253
cr.execute('SELECT id, type, number, move_id, reference ' \
254
'FROM account_invoice ' \
255
'WHERE id IN ('+','.join(map(str,ids))+')')
256
for (id, invtype, number, move_id, reference) in cr.fetchall():
258
if self.browse(cr, uid, id).journal_id.code == 'factura_e':
259
invtype = 'factura_e'
260
elif self.browse(cr, uid, id).journal_id.code == 'nota_credito_e':
261
invtype = 'nota_credito_e'
262
number = self.pool.get('ir.sequence').get(cr, uid,
263
'account.invoice.' + invtype)
264
if type in ('in_invoice', 'in_refund'):
267
ref = self._convert_ref(cr, uid, number)
268
cr.execute('UPDATE account_invoice SET number=%s ' \
269
'WHERE id=%d', (number, id))
270
cr.execute('UPDATE account_move_line SET ref=%s ' \
271
'WHERE move_id=%d AND (ref is null OR ref = \'\')',
273
cr.execute('UPDATE account_analytic_line SET ref=%s ' \
274
'FROM account_move_line ' \
275
'WHERE account_move_line.move_id = %d ' \
276
'AND account_analytic_line.move_id = account_move_line.id',
280
def undo_action_number(self, cr, uid, inv_brw , *args):
281
number = inv_brw.number
283
if inv_brw.journal_id.code == 'factura_e':
284
invtype = 'factura_e'
285
elif inv_brw.journal_id.code == 'nota_credito_e':
286
invtype = 'nota_credito_e'
287
cr.execute('lock table ir_sequence')
288
cr.execute("select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where code = 'account.invoice." + invtype + "' and active=True")
289
res = cr.dictfetchone()
291
cr.execute('update ir_sequence set number_next=number_next-number_increment where id=%s and active=True', (res['id'],))
296
def test_open(self, cr, uid, ids, *args):
297
#super(account_invoice, self).action_date_assign( cr, uid, ids, *args)
298
for inv_brw in self.browse(cr, uid, ids):
299
super(account_invoice, self).action_move_create( cr, uid, [inv_brw.id], *args)
300
#super(account_invoice, self).action_number( cr, uid, [inv_brw.id], *args)
301
self.action_number( cr, uid, [inv_brw.id], *args)
302
if (inv_brw.journal_id.code in ('factura_e', 'nota_credito_e')) and (inv_brw.type in ('out_invoice', 'out_refund')):
304
#self.action_number( cr, uid, [inv_brw.id], *args)
305
cfe = self.create_xml(cr, uid, [inv_brw.id], *args)
306
cfe_str = etree.tostring(cfe, pretty_print=True, encoding='utf-8')
307
self.attach_xml(cr, uid, inv_brw.id, cfe_str)
309
#self.undo_action_number( cr, uid, inv_brw , *args)
310
#raise osv.except_osv(('Error !'), ('Error al crear la Factura.'))
313
def attach_xml(self, cr, uid, id, cfe):
314
inv_brw = self.browse(cr, uid, id)
315
self.pool.get('ir.attachment').create(cr, uid, {
316
'name': 'Fact.-' + inv_brw.number,
317
'datas': base64.encodestring(cfe),
318
'datas_fname': inv_brw.number or inv_brw.name + '.xml',
319
'res_model': self._name,
320
'res_id': inv_brw.id,
325
def set_cfe_defaults(self):
326
NS='http://www.w3.org/2001/XMLSchema-instance'
329
schema_location = '{%s}schemaLocation' % NS
330
cfe = etree.Element('Comprobante', attrib={schema_location:"http://www.sat.gob.mx/cfd/2 http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv2.xsd http://www.sat.gob.mx/ecc http://www.sat.gob.mx/sitio_internet/cfd/ecc/ecc.xsd"})
331
cfe.set('xmlns',"http://www.sat.gob.mx/cfd/2")
332
cfe.set('version','2.0')
336
def create_xml(self,cr, uid, ids, context={}):
337
for inv_brw in self.browse(cr, uid, ids):
338
cfe = self.set_cfe_defaults()
339
cfe = self.get_datos_comprobante(cr, uid, inv_brw, cfe, context)
340
emisor = self.get_emisor(cr, uid, inv_brw)
341
receptro = self.get_receptor(cr, uid, inv_brw)
342
conceptos = self.get_conceptos(cr, uid, inv_brw.invoice_line)
343
impuestos = self.get_impuestos(cr, uid, inv_brw.tax_line)
344
addenda = self.get_addenda(cr, uid, inv_brw)
345
#certificado = self.get_certificado(cr, uid, inv_brw)
348
cfe.append(conceptos)
349
cfe.append(impuestos)
351
cadena = cfdutil.getCadenaOriginal(etree.parse(StringIO.StringIO(etree.tostring(cfe))))
352
keyfname = inv_brw.company_id.key
353
sello = cfdutil.getSelloSHA1(cadena, keyfname, inv_brw.company_id.key_phrase)
355
raise osv.except_osv(('Error !'), ('Error al crear el sello.'))
356
cfe.set('sello', sello)
357
self.write(cr, uid, inv_brw.id, {'sign_date':cfe.get('fecha'),
358
'approved_year':int(cfe.get('anoAprobacion')),
359
'approved_number':int(cfe.get('noAprobacion')),
360
'certificate':cfe.get('certificado'),
361
'digital_signature':sello,
363
'date_invoice': cfe.get('fecha').split('T')[0]})
364
#certfname = os.path.join(tools.config['root_path'], 'filestore/%s/%s'%(cr.dbname, inv_brw.company_id.certificate.store_fname))
365
#certfname = os.path.join(tools.config['root_path'], 'ore/%s/%s'%(cr.dbname, inv_brw.company_id.certificate))
366
certfname = inv_brw.company_id.certificate
367
verify = cfdutil.verifySelloSHA1(cadena, certfname, sello)
371
def get_domicilio_fiscal(self, cr, uid, inv_brw):
372
partner_obj = self.pool.get('res.partner')
373
address_obj = self.pool.get('res.partner.address')
374
partner_brw = inv_brw.company_id.partner_id
375
partner_id = inv_brw.company_id.partner_id.id
376
address = etree.Element('Domicilio')
377
#address_obj = self.pool.get('res.partner.address')
378
address = etree.Element('DomicilioFiscal')
379
inovice_addres_id = partner_obj.address_get(cr, uid, [partner_id], ['invoice'])
380
address_brw = address_obj.browse(cr, uid, inovice_addres_id['invoice'])
381
address.set('calle', self.make_utf(address_brw.street, 'Calle Emisior'))
382
address.set('colonia', self.make_utf(address_brw.street2, 'Colonia Emisior'))
383
address.set('municipio',self.make_utf(address_brw.city,'Ciudad Emisior'))
384
address.set('estado', self.make_utf(address_brw.state_id.name, 'Estado Emisior'))
385
address.set('pais',self.make_utf(address_brw.country_id.name, 'Pais Emisior'))
386
address.set('codigoPostal',self.make_utf(address_brw.zip, 'Codigo Postal Emisior'))
389
def get_domicilio_ubicacion(self, cr, uid, inv_brw):
390
partner_obj = self.pool.get('res.partner')
391
address_obj = self.pool.get('res.partner.address')
392
partner_id = inv_brw.partner_id.id
393
address = etree.Element('Domicilio')
394
inovice_addres_id = partner_obj.address_get(cr, uid, [partner_id], ['invoice'])
395
address_brw = address_obj.browse(cr, uid, inovice_addres_id['invoice'])
396
address_brw.street and address.set('calle', self.make_utf(address_brw.street or ''))
397
address_brw.street2 and address.set('colonia', self.make_utf(address_brw.street2 or ''))
398
address_brw.city and address.set('municipio',self.make_utf(address_brw.city or ''))
399
address_brw.state_id and address.set('estado', self.make_utf(address_brw.state_id.name or ''))
400
address_brw.country_id and address.set('pais',self.make_utf(address_brw.country_id.name or 'Pais Emisor'))
401
address_brw.zip and address.set('codigoPostal',self.make_utf(address_brw.zip or ''))
404
def get_emisor(self, cr, uid, inv_brw):
405
partner_brw = inv_brw.company_id.partner_id
406
emisor = etree.Element('Emisor')
407
emisor.append(self.get_domicilio_fiscal(cr, uid, inv_brw))
408
if not partner_brw.vat:
409
raise osv.except_osv(_('No RFC Defined on Emisor Partner!'),_("You must define a RFC for the company !") )
410
emisor.set('rfc',re.sub('[-,._ \t\n\r\f\v]','',partner_brw.vat))
411
emisor.set('nombre',self.make_utf(inv_brw.company_id.name, 'Company Name'))
414
def get_receptor(self,cr, uid, inv_brw):
415
partner_brw = inv_brw.partner_id
416
receptor = etree.Element('Receptor')
417
receptor.append(self.get_domicilio_ubicacion(cr, uid, inv_brw))
418
if not partner_brw.vat:
419
raise osv.except_osv(_('No RFC Defined on Receptor Partner!'),_("You must define a RFC for the Client !") )
420
receptor.set('rfc',re.sub('[-,._ \t\n\r\f\v]','',partner_brw.vat))
421
receptor.set('nombre',self.make_utf(inv_brw.partner_id.name or 'Empresa Receptora'))
424
def get_conceptos(self, cr, uid, lines_brw_lst):
425
conceptos = etree.Element('Conceptos')
426
for line in lines_brw_lst:
427
concept = etree.Element('Concepto')
428
concept.set('cantidad', '%.2f'%(line.quantity))
429
concept.set('descripcion',self.make_utf(line.name, 'Descripcion de Producto'))
430
concept.set('valorUnitario','%.2f'%(line.price_unit))
431
concept.set('importe','%.2f'%(line.price_subtotal))
432
uos = line.uos_id.name
434
concept.set('unidad', uos)
435
conceptos.append(concept)
440
def get_tax(self, cr, uid, tax, tax_type, tax_name):
441
retencion = etree.Element(tax_name)
442
if tax_type == 'retain_iva':
443
retencion.set('impuesto','IVA')
444
tax_pct = round(float(tax.amount) / float(tax.base), 2)
445
retencion.set('tasa', '%.2f'%(tax_pct * 100))
446
elif tax_type == 'retain_isr':
447
retencion.set('impuesto','ISR')
448
tax_pct = round(float(tax.amount) / float(tax.base), 2)
449
retencion.set('tasa', '%.2f'%(tax_pct * 100))
450
if tax_type == 'tax_ieps':
451
retencion.set('impuesto','IEPS')
452
tax_pct = round(float(tax.amount) / float(tax.base), 2)
453
retencion.set('tasa', '%.2f'%(tax_pct * 100))
454
elif tax_type == 'tax_iva':
455
retencion.set('impuesto','IVA')
456
tax_pct = round(float(tax.amount) / float(tax.base), 2)
457
retencion.set('tasa', '%.2f'%(tax_pct * 100))
458
retencion.set('importe', '%.2f'%(abs(tax.amount)))
463
def get_impuestos(self, cr, uid, tax_line):
464
impuestos = etree.Element('Impuestos')
465
traslados = etree.Element('Traslados')
466
retenciones = etree.Element('Retenciones')
467
total_retenciones = 0
470
tax_type = tax.tax_code_id.code
472
if (tax_type == 'retain_iva') or (tax_type == 'retain_isr'):
473
retenciones.append(self.get_tax(cr, uid, tax, tax_type, 'Retencion' ))
474
total_retenciones += tax.amount
475
elif (tax_type == 'tax_iva') or (tax_type == 'tax_ieps'):
476
traslados.append(self.get_tax(cr, uid, tax, tax_type, 'Traslado' ))
477
total_traslados += tax.amount
478
if total_retenciones:
479
impuestos.set('totalImpuestosRetenidos', '%.2f'%(abs(total_retenciones)))
480
impuestos.append(retenciones)
482
impuestos.set('totalImpuestosTrasladados', '%.2f'%(abs(total_traslados)))
483
impuestos.append(traslados)
488
def get_addenda(self,cr, uid, inv_brw):
489
addenda = etree.Element('Addenda')
490
partner_brw = inv_brw.partner_id
491
if not partner_brw.addenda:
493
addenda_brw = partner_brw.addenda
494
addenda_name = etree.Element(addenda_brw.name)
495
for line_brw in addenda_brw.line_ids:
496
value = self.make_utf(str(eval('inv_brw.' + line_brw.default)))
497
addenda_line = etree.Element(line_brw.tag)
498
addenda_line.set(line_brw.tag,value)
499
addenda_name.append(addenda_line)
500
addenda.append(addenda_name)
503
def get_discount(self, cr, uid, inv_brw):
506
def get_payment_form(self, cr, uid, inv_brw):
509
def get_inv_number(self, cr, uid, inv_brw):
511
if inv_brw.journal_id.invoice_sequence_id:
512
prefix = inv_brw.journal_id.invoice_sequence_id.prefix
514
prefix = inv_brw.journal_id.sequence_id.prefix
516
number = int(inv_brw.number[len(prefix):])
518
#number = int(inv_brw.number)
520
number = int(inv_brw.number)
522
sequence_type = 'account.invoice.' + inv_brw.journal_id.code
523
cr.execute("SELECT prefix from ir_sequence where code ='%s'"%(sequence_type))
525
prefix = cr.fetchone()
528
number = int(inv_brw.number.strip(prefix))
529
return number, prefix
532
def get_datos_comprobante(self, cr, uid, inv_brw, cfe, context={}):
533
company_obj = self.pool.get('res.company.folios')
534
if inv_brw.journal_id.invoice_sequence_id:
535
prefix = inv_brw.journal_id.invoice_sequence_id.prefix
537
prefix = inv_brw.journal_id.sequence_id.prefix
539
number = int(inv_brw.number[len(prefix):])
540
cfe.set('serie',prefix)
543
number = int(inv_brw.number)
545
sequence_type = 'account.invoice.' + inv_brw.journal_id.code
546
cr.execute("SELECT prefix from ir_sequence where code ='%s'"%(sequence_type))
548
prefix = cr.fetchone()
551
cfe.set('serie',prefix)
552
number = int(inv_brw.number.strip(prefix))
553
#raise osv.except_osv(_('Error !'),_('The invoice number has to be an integer. Wrong configuratin, check your secuenceses.'))
555
cfe.set('folio',str(int(number)))
556
if context.has_key('date'):
557
cfe.set('fecha',context['date'])
559
cfe.set('fecha',now().strftime('%Y-%m-%dT%H:%M:%S'))
560
cfe.set('anoAprobacion',company_obj.get_folio_info(cr, uid, inv_brw.company_id.id, number, 'approved_year', prefix))
561
cfe.set('formaDePago','Pago en una sola exhibicion')###ahy que poner una forma de pago valida
562
cfe.set('noAprobacion',company_obj.get_folio_info(cr, uid, inv_brw.company_id.id, number, 'approved_number', prefix))
563
cfe.set('condicionesDePago',self.make_utf(inv_brw.payment_term.name, 'Condiciones de Pago'))
565
certfname = inv_brw.company_id.certificate
566
nocert = cfdutil.getNoSerie(certfname)
567
certstr = cfdutil.getCertString(certfname)
568
cfe.set('noCertificado', nocert)
569
cfe.set('certificado', certstr)
570
#cfe.set('noCertificado',inv_brw.company_id.certificate_no)
571
cfe.set('subTotal','%.2f'%(inv_brw.amount_untaxed))
572
cfe.set('total','%.2f'%(inv_brw.amount_total))
573
if inv_brw.type == 'out_invoice':
574
cfe.set('tipoDeComprobante','ingreso')
575
elif inv_brw.type == 'out_refund':
576
cfe.set('tipoDeComprobante','egreso')
577
elif inv_brw.company_id.partner_id.vat == inv_brw.partner_id.vat:
578
cfe.set('tipoDeComprobante','traslado')
579
discount = self.get_discount(cr, uid, inv_brw)
582
cfe.set('descuento',str(discount))
583
payment_form = self.get_payment_form(cr, uid, inv_brw)
585
cfe.set('metodoDePago',payment_form)
595
class account_invoice_addenda(osv.osv):
596
_name = "account.invoice.addenda"
597
_description = "Addenda for the Electronic Invoice"
599
'name': fields.char('Addenda', size=64, required=True),
600
'active': fields.boolean('Active'),
601
'note': fields.text('Description', translate=True),
602
'line_ids': fields.one2many('account.invoice.addenda.lines', 'addenda_id', 'Terms'),
605
'active': lambda *a: 1,
610
account_invoice_addenda()
612
class account_invoice_addenda_lines(osv.osv):
613
_name = "account.invoice.addenda.lines"
614
_description = "Lines of the Electronic Invoice Addenda"
616
def _col_get(self, cr, user, context={}):
618
cols = self.pool.get('account.invoice')._columns
620
result.append( (col, cols[col].string) )
627
'name': fields.char('Field Name', size=64, required=True),
628
'code': fields.char('Code', size=64, required=True),
629
'sequence': fields.integer('Sequence', required=True, help="The sequence field is used to order fields"),
630
'required': fields.boolean('Required'),
631
'relation': fields.many2one('ir.model', 'Relation'),
632
'default': fields.char('Default', size=64),
633
'field': fields.selection(_col_get, 'Field Name', method=True, size=64),
634
'addenda_id': fields.many2one('account.invoice.addenda', 'Addenda', required=True, select=True),
637
'sequence': lambda *a: 5,
642
account_invoice_addenda_lines()