Cancelar facturas con xml firmado
This commit is contained in:
parent
f958227f56
commit
9e50033b9f
|
@ -371,7 +371,7 @@ class Finkok(object):
|
|||
if os.path.isfile(file_xml):
|
||||
root = etree.parse(file_xml).getroot()
|
||||
else:
|
||||
root = etree.fromstring(file_xml)
|
||||
root = etree.fromstring(file_xml.encode())
|
||||
|
||||
xml = etree.tostring(root)
|
||||
|
||||
|
@ -385,8 +385,12 @@ class Finkok(object):
|
|||
'store_pending': True,
|
||||
}
|
||||
|
||||
result = client.service.cancel_signature(**args)
|
||||
return result
|
||||
try:
|
||||
result = client.service.cancel_signature(**args)
|
||||
return result
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
def get_acuse(self, rfc, uuids, type_acuse='C'):
|
||||
for u in uuids:
|
||||
|
|
|
@ -33,7 +33,8 @@ from dateutil import parser
|
|||
|
||||
from .helper import CaseInsensitiveDict, NumLet, SendMail, TemplateInvoice
|
||||
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT, \
|
||||
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE
|
||||
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE, \
|
||||
PATH_XMLSEC, TEMPLATE_CANCEL
|
||||
|
||||
|
||||
#~ def _get_hash(password):
|
||||
|
@ -1048,6 +1049,52 @@ def get_date(value, next_day=False):
|
|||
return d
|
||||
|
||||
|
||||
def cancel_cfdi(uuid, pk12, rfc, auth):
|
||||
from .pac import Finkok as PAC
|
||||
|
||||
template = read_file(TEMPLATE_CANCEL, 'r')
|
||||
data = {
|
||||
'rfc': rfc,
|
||||
'fecha': datetime.datetime.now().isoformat()[:19],
|
||||
'uuid': str(uuid).upper(),
|
||||
}
|
||||
template = template.format(**data)
|
||||
|
||||
data = {
|
||||
'xmlsec': PATH_XMLSEC,
|
||||
'pk12': _save_temp(pk12),
|
||||
'pass': _get_md5(rfc),
|
||||
'template': _save_temp(template, 'w'),
|
||||
}
|
||||
args = '"{xmlsec}" --sign --pkcs12 "{pk12}" --pwd {pass} ' \
|
||||
'"{template}"'.format(**data)
|
||||
xml_sign = _call(args)
|
||||
|
||||
if DEBUG:
|
||||
auth = {}
|
||||
else:
|
||||
if not auth:
|
||||
msg = 'Sin datos para cancelar'
|
||||
result = {'ok': False, 'error': msg}
|
||||
return result
|
||||
|
||||
msg = 'Factura cancelada correctamente'
|
||||
data = {'ok': True, 'msg': msg, 'row': {'estatus': 'Cancelada'}}
|
||||
pac = PAC(auth)
|
||||
result = pac.cancel_signature(xml_sign)
|
||||
if result:
|
||||
codes = {None: '',
|
||||
'Could not get UUID Text': 'UUID no encontrado'}
|
||||
if not result['CodEstatus'] is None:
|
||||
data['ok'] = False
|
||||
data['msg'] = codes.get(result['CodEstatus'], result['CodEstatus'])
|
||||
else:
|
||||
data['ok'] = False
|
||||
data['msg'] = pac.error
|
||||
|
||||
return data, result
|
||||
|
||||
|
||||
class ImportFacturaLibre(object):
|
||||
|
||||
def __init__(self, path):
|
||||
|
|
|
@ -32,6 +32,9 @@ class StorageEngine(object):
|
|||
def send_email(self, values, session):
|
||||
return main.Facturas.send(values['id'], session['rfc'])
|
||||
|
||||
def _get_cancelinvoice(self, values):
|
||||
return main.Facturas.cancel(values['id'])
|
||||
|
||||
def _get_statussat(self, values):
|
||||
return main.Facturas.get_status_sat(values['id'])
|
||||
|
||||
|
|
|
@ -723,7 +723,7 @@ class Socios(BaseModel):
|
|||
.where((Socios.id==id) & (Socios.es_cliente==True))
|
||||
.dicts()
|
||||
)
|
||||
print (id, row)
|
||||
#~ print (id, row)
|
||||
if len(row):
|
||||
return {'ok': True, 'row': row[0]}
|
||||
return {'ok': False}
|
||||
|
@ -1009,6 +1009,8 @@ class Facturas(BaseModel):
|
|||
notas = TextField(default='')
|
||||
pagada = BooleanField(default=False)
|
||||
cancelada = BooleanField(default=False)
|
||||
fecha_cancelacion = DateTimeField(null=True)
|
||||
acuse = TextField(default='')
|
||||
donativo = BooleanField(default=False)
|
||||
tipo_relacion = TextField(default='')
|
||||
error = TextField(default='')
|
||||
|
@ -1016,6 +1018,25 @@ class Facturas(BaseModel):
|
|||
class Meta:
|
||||
order_by = ('fecha',)
|
||||
|
||||
@classmethod
|
||||
def cancel(cls, id):
|
||||
msg = 'Factura cancelada correctamente'
|
||||
auth = Emisor.get_auth()
|
||||
certificado = Certificado.select()[0]
|
||||
obj = Facturas.get(Facturas.id==id)
|
||||
data, result = util.cancel_cfdi(
|
||||
obj.uuid, certificado.p12, certificado.rfc, auth)
|
||||
if data['ok']:
|
||||
obj.estatus = 'Cancelada'
|
||||
obj.error = ''
|
||||
obj.cancelada = True
|
||||
obj.fecha_cancelacion = result['Fecha']
|
||||
obj.acuse = result['Acuse']
|
||||
else:
|
||||
obj.error = data['msg']
|
||||
obj.save()
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def filter_years(cls):
|
||||
data = [{'id': -1, 'value': 'Todos'}]
|
||||
|
@ -1025,7 +1046,8 @@ class Facturas(BaseModel):
|
|||
.order_by(Facturas.fecha.year)
|
||||
.scalar(as_tuple=True)
|
||||
)
|
||||
data += [{'id': int(row), 'value': int(row)} for row in rows]
|
||||
if not rows is None:
|
||||
data += [{'id': int(row), 'value': int(row)} for row in rows]
|
||||
return tuple(data)
|
||||
|
||||
@classmethod
|
||||
|
@ -1489,7 +1511,7 @@ class Facturas(BaseModel):
|
|||
|
||||
auth = Emisor.get_auth()
|
||||
|
||||
error = False
|
||||
#~ error = False
|
||||
msg = 'Factura timbrada correctamente'
|
||||
result = util.timbra_xml(obj.xml, auth)
|
||||
if result['ok']:
|
||||
|
@ -1498,10 +1520,10 @@ class Facturas(BaseModel):
|
|||
obj.fecha_timbrado = result['fecha']
|
||||
obj.estatus = 'Timbrada'
|
||||
obj.error = ''
|
||||
obj.save()
|
||||
#~ obj.save()
|
||||
row = {'uuid': obj.uuid, 'estatus': 'Timbrada'}
|
||||
else:
|
||||
error = True
|
||||
#~ error = True
|
||||
msg = result['error']
|
||||
obj.estatus = 'Error'
|
||||
obj.error = msg
|
||||
|
|
|
@ -25,6 +25,8 @@ DB_SAT = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'sat.db'))
|
|||
|
||||
IV = 'valores_iniciales.json'
|
||||
INIT_VALUES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', IV))
|
||||
CT = 'cancel_template.xml'
|
||||
TEMPLATE_CANCEL = os.path.abspath(os.path.join(PATH_TEMPLATES, CT))
|
||||
|
||||
PATH_XSLT = os.path.abspath(os.path.join(BASE_DIR, '..', 'xslt'))
|
||||
PATH_BIN = os.path.abspath(os.path.join(BASE_DIR, '..', 'bin'))
|
||||
|
@ -69,9 +71,11 @@ log = Logger(LOG_NAME)
|
|||
|
||||
PATH_XSLTPROC = 'xsltproc'
|
||||
PATH_OPENSSL = 'openssl'
|
||||
PATH_XMLSEC = 'xmlsec1'
|
||||
if 'win' in sys.platform:
|
||||
PATH_XSLTPROC = os.path.join(PATH_BIN, 'xsltproc.exe')
|
||||
PATH_OPENSSL = os.path.join(PATH_BIN, 'openssl.exe')
|
||||
PATH_XMLSEC = os.path.join(PATH_BIN, 'xmlsec.exe')
|
||||
|
||||
|
||||
PRE = {
|
||||
|
|
|
@ -695,7 +695,19 @@ function grid_invoices_click(id, e, node){
|
|||
|
||||
|
||||
function send_cancel(id){
|
||||
show(id)
|
||||
webix.ajax().get('/values/cancelinvoice', {id: id}, function(text, data){
|
||||
var values = data.json()
|
||||
if(values.ok){
|
||||
msg_sucess(values.msg)
|
||||
gi.updateItem(id, values.row)
|
||||
}else{
|
||||
webix.alert({
|
||||
title: 'Error al Cancelar',
|
||||
text: values.msg,
|
||||
type: 'alert-error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function cmd_invoice_cancelar_click(){
|
||||
|
@ -715,6 +727,11 @@ function cmd_invoice_cancelar_click(){
|
|||
return
|
||||
}
|
||||
|
||||
if(row.estatus == 'Cancelada'){
|
||||
msg_error('La factura ya esta cancelada')
|
||||
return
|
||||
}
|
||||
|
||||
msg = '¿Estás seguro de enviar a cancelar esta factura?<BR><BR> \
|
||||
ESTA ACCIÓN NO SE PUEDE DESHACER'
|
||||
webix.confirm({
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Cancelacion RfcEmisor="{rfc}" Fecha="{fecha}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://cancelacfd.sat.gob.mx">
|
||||
<Folios>
|
||||
<UUID>{uuid}</UUID>
|
||||
</Folios>
|
||||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||
<SignedInfo>
|
||||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
|
||||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
|
||||
<Reference URI="">
|
||||
<Transforms>
|
||||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
||||
</Transforms>
|
||||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
|
||||
<DigestValue />
|
||||
</Reference>
|
||||
</SignedInfo>
|
||||
<SignatureValue />
|
||||
<KeyInfo>
|
||||
<X509Data>
|
||||
<X509SubjectName />
|
||||
<X509IssuerSerial />
|
||||
<X509Certificate />
|
||||
</X509Data>
|
||||
<KeyValue />
|
||||
</KeyInfo>
|
||||
</Signature>
|
||||
</Cancelacion>
|
Loading…
Reference in New Issue