Agregar método alternativo para cancelar
This commit is contained in:
parent
9796ffb6f3
commit
3a10c146d2
|
@ -49,6 +49,7 @@ def finkok(debug):
|
||||||
PASS = FINKOK['PASS']
|
PASS = FINKOK['PASS']
|
||||||
TOKEN = ''
|
TOKEN = ''
|
||||||
auth = {
|
auth = {
|
||||||
|
'DEBUG': debug,
|
||||||
'USER': '',
|
'USER': '',
|
||||||
'PASS': TOKEN or PASS,
|
'PASS': TOKEN or PASS,
|
||||||
'RESELLER': {'USER': USER, 'PASS': PASS}
|
'RESELLER': {'USER': USER, 'PASS': PASS}
|
||||||
|
@ -58,6 +59,7 @@ def finkok(debug):
|
||||||
PASS = ''
|
PASS = ''
|
||||||
TOKEN = '5c9a88da105bff9a8c430cb713f6d35269f51674bdc5963c1501b7316366'
|
TOKEN = '5c9a88da105bff9a8c430cb713f6d35269f51674bdc5963c1501b7316366'
|
||||||
auth = {
|
auth = {
|
||||||
|
'DEBUG': debug,
|
||||||
'USER': USER,
|
'USER': USER,
|
||||||
'PASS': TOKEN or PASS,
|
'PASS': TOKEN or PASS,
|
||||||
'RESELLER': {
|
'RESELLER': {
|
||||||
|
|
|
@ -324,21 +324,16 @@ class Finkok(object):
|
||||||
try:
|
try:
|
||||||
result = client.service.query_pending(
|
result = client.service.query_pending(
|
||||||
self._auth['USER'], self._auth['PASS'], uuid)
|
self._auth['USER'], self._auth['PASS'], uuid)
|
||||||
#~ print (result.date)
|
|
||||||
#~ tree = parseString(unescape(result.xml))
|
|
||||||
#~ response = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
|
||||||
return result.status
|
return result.status
|
||||||
except Fault as e:
|
except Fault as e:
|
||||||
self.error = str(e)
|
self.error = str(e)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def cancel_xml(self, rfc, uuids, path_cer, path_key):
|
def cancel_xml(self, rfc, uuid, cer, key):
|
||||||
for u in uuids:
|
# ~ for u in uuids:
|
||||||
if not self._validate_uuid(u):
|
# ~ if not self._validate_uuid(u):
|
||||||
return ''
|
# ~ return ''
|
||||||
|
|
||||||
cer = self._load_file(path_cer)
|
|
||||||
key = self._load_file(path_key)
|
|
||||||
method = 'cancel'
|
method = 'cancel'
|
||||||
client = Client(
|
client = Client(
|
||||||
URL[method], transport=self._transport, plugins=self._plugins)
|
URL[method], transport=self._transport, plugins=self._plugins)
|
||||||
|
@ -346,7 +341,7 @@ class Finkok(object):
|
||||||
sa = client.get_type('ns0:stringArray')
|
sa = client.get_type('ns0:stringArray')
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
'UUIDS': uuid_type(uuids=sa(string=uuids)),
|
'UUIDS': uuid_type(uuids=sa(string=uuid)),
|
||||||
'username': self._auth['USER'],
|
'username': self._auth['USER'],
|
||||||
'password': self._auth['PASS'],
|
'password': self._auth['PASS'],
|
||||||
'taxpayer_id': rfc,
|
'taxpayer_id': rfc,
|
||||||
|
|
|
@ -41,7 +41,8 @@ from settings import DEBUG, MV, 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, DEFAULT_SAT_PRODUCTO, DECIMALES, DIR_FACTURAS
|
PATH_XMLSEC, TEMPLATE_CANCEL, DEFAULT_SAT_PRODUCTO, DECIMALES, DIR_FACTURAS
|
||||||
|
|
||||||
from settings import SEAFILE_SERVER
|
from settings import SEAFILE_SERVER, USAR_TOKEN
|
||||||
|
from .configpac import AUTH
|
||||||
|
|
||||||
|
|
||||||
def _call(args):
|
def _call(args):
|
||||||
|
@ -416,7 +417,7 @@ class Certificado(object):
|
||||||
data['hasta'] = hasta.replace(tzinfo=None)
|
data['hasta'] = hasta.replace(tzinfo=None)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _get_p12(self, password, rfc):
|
def _get_p12(self, password, rfc, token):
|
||||||
tmp_cer = tempfile.mkstemp()[1]
|
tmp_cer = tempfile.mkstemp()[1]
|
||||||
tmp_key = tempfile.mkstemp()[1]
|
tmp_key = tempfile.mkstemp()[1]
|
||||||
tmp_p12 = tempfile.mkstemp()[1]
|
tmp_p12 = tempfile.mkstemp()[1]
|
||||||
|
@ -428,7 +429,7 @@ class Certificado(object):
|
||||||
|
|
||||||
args = 'openssl pkcs12 -export -in "{}" -inkey "{}" -name "{}" ' \
|
args = 'openssl pkcs12 -export -in "{}" -inkey "{}" -name "{}" ' \
|
||||||
'-passout pass:"{}" -out "{}"'
|
'-passout pass:"{}" -out "{}"'
|
||||||
_call(args.format(tmp_cer, tmp_key, rfc, _get_md5(rfc), tmp_p12))
|
_call(args.format(tmp_cer, tmp_key, rfc, token, tmp_p12))
|
||||||
data = read_file(tmp_p12)
|
data = read_file(tmp_p12)
|
||||||
|
|
||||||
self._kill(tmp_cer)
|
self._kill(tmp_cer)
|
||||||
|
@ -437,7 +438,7 @@ class Certificado(object):
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _get_info_key(self, password, rfc):
|
def _get_info_key(self, password, rfc, token):
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:"{}"'
|
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:"{}"'
|
||||||
|
@ -455,17 +456,23 @@ class Certificado(object):
|
||||||
self.error = 'Los archivos no son pareja'
|
self.error = 'Los archivos no son pareja'
|
||||||
return data
|
return data
|
||||||
|
|
||||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:"{}" | ' \
|
args = "openssl pkcs8 -inform DER -in '{}' -passin pass:'{}' | " \
|
||||||
'openssl rsa -des3 -passout pass:"{}"'.format(
|
"openssl rsa -des3 -passout pass:'{}'".format(
|
||||||
self._path_key, password, _get_md5(rfc))
|
self._path_key, password, token)
|
||||||
key_enc = _call(args)
|
key_enc = _call(args)
|
||||||
|
|
||||||
data['key'] = read_file(self._path_key)
|
data['key'] = read_file(self._path_key)
|
||||||
data['key_enc'] = key_enc
|
data['key_enc'] = key_enc
|
||||||
data['p12'] = self._get_p12(password, rfc)
|
data['p12'] = self._get_p12(password, rfc, token)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def validate(self, password, rfc):
|
def validate(self, password, rfc, auth):
|
||||||
|
token = _get_md5(rfc)
|
||||||
|
if USAR_TOKEN:
|
||||||
|
token = auth['PASS']
|
||||||
|
if AUTH['DEBUG']:
|
||||||
|
token = AUTH['PASS']
|
||||||
|
|
||||||
if not self._path_key or not self._path_cer:
|
if not self._path_key or not self._path_cer:
|
||||||
self.error = 'Error en las rutas temporales del certificado'
|
self.error = 'Error en las rutas temporales del certificado'
|
||||||
return {}
|
return {}
|
||||||
|
@ -474,7 +481,7 @@ class Certificado(object):
|
||||||
if not data:
|
if not data:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
llave = self._get_info_key(password, data['rfc'])
|
llave = self._get_info_key(password, rfc, token)
|
||||||
if not llave:
|
if not llave:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -485,9 +492,15 @@ class Certificado(object):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def make_xml(data, certificado):
|
def make_xml(data, certificado, auth):
|
||||||
from .cfdi_xml import CFDI
|
from .cfdi_xml import CFDI
|
||||||
|
|
||||||
|
token = _get_md5(certificado.rfc)
|
||||||
|
if USAR_TOKEN:
|
||||||
|
token = auth['PASS']
|
||||||
|
if AUTH['DEBUG']:
|
||||||
|
token = AUTH['PASS']
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
data['emisor']['Rfc'] = certificado.rfc
|
data['emisor']['Rfc'] = certificado.rfc
|
||||||
data['emisor']['RegimenFiscal'] = '603'
|
data['emisor']['RegimenFiscal'] = '603'
|
||||||
|
@ -501,7 +514,7 @@ def make_xml(data, certificado):
|
||||||
'xml': save_temp(xml, 'w'),
|
'xml': save_temp(xml, 'w'),
|
||||||
'openssl': PATH_OPENSSL,
|
'openssl': PATH_OPENSSL,
|
||||||
'key': save_temp(certificado.key_enc, 'w'),
|
'key': save_temp(certificado.key_enc, 'w'),
|
||||||
'pass': _get_md5(certificado.rfc)
|
'pass': token,
|
||||||
}
|
}
|
||||||
args = '"{xsltproc}" "{xslt}" "{xml}" | ' \
|
args = '"{xsltproc}" "{xslt}" "{xml}" | ' \
|
||||||
'"{openssl}" dgst -sha256 -sign "{key}" -passin pass:"{pass}" | ' \
|
'"{openssl}" dgst -sha256 -sign "{key}" -passin pass:"{pass}" | ' \
|
||||||
|
@ -517,10 +530,7 @@ def make_xml(data, certificado):
|
||||||
def timbra_xml(xml, auth):
|
def timbra_xml(xml, auth):
|
||||||
from .pac import Finkok as PAC
|
from .pac import Finkok as PAC
|
||||||
|
|
||||||
if DEBUG:
|
if not DEBUG and not auth:
|
||||||
auth = {}
|
|
||||||
else:
|
|
||||||
if not auth:
|
|
||||||
msg = 'Sin datos para timbrar'
|
msg = 'Sin datos para timbrar'
|
||||||
result = {'ok': True, 'error': msg}
|
result = {'ok': True, 'error': msg}
|
||||||
return result
|
return result
|
||||||
|
@ -1299,9 +1309,46 @@ def upload_file(rfc, opt, file_obj):
|
||||||
return {'status': 'error', 'ok': False}
|
return {'status': 'error', 'ok': False}
|
||||||
|
|
||||||
|
|
||||||
def cancel_cfdi(uuid, pk12, rfc, auth):
|
def cancel_xml(auth, uuid, certificado):
|
||||||
from .pac import Finkok as PAC
|
from .pac import Finkok as PAC
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
auth = {}
|
||||||
|
else:
|
||||||
|
if not auth:
|
||||||
|
msg = 'Sin datos para cancelar'
|
||||||
|
data = {'ok': False, 'error': msg}
|
||||||
|
return data, result
|
||||||
|
|
||||||
|
msg = 'Factura cancelada correctamente'
|
||||||
|
data = {'ok': True, 'msg': msg, 'row': {'estatus': 'Cancelada'}}
|
||||||
|
pac = PAC(auth)
|
||||||
|
result = pac.cancel_xml(certificado.rfc, str(uuid).upper(),
|
||||||
|
certificado.cer_pem.encode(), certificado.key_enc.encode())
|
||||||
|
if result:
|
||||||
|
codes = {None: '',
|
||||||
|
'Could not get UUID Text': 'UUID no encontrado',
|
||||||
|
'Invalid Passphrase': 'Contraseña inválida',
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def cancel_signature(uuid, pk12, rfc, auth):
|
||||||
|
from .pac import Finkok as PAC
|
||||||
|
|
||||||
|
token = _get_md5(rfc)
|
||||||
|
if USAR_TOKEN:
|
||||||
|
token = auth['PASS']
|
||||||
|
if AUTH['DEBUG']:
|
||||||
|
token = AUTH['PASS']
|
||||||
|
|
||||||
template = read_file(TEMPLATE_CANCEL, 'r')
|
template = read_file(TEMPLATE_CANCEL, 'r')
|
||||||
data = {
|
data = {
|
||||||
'rfc': rfc,
|
'rfc': rfc,
|
||||||
|
@ -1313,7 +1360,7 @@ def cancel_cfdi(uuid, pk12, rfc, auth):
|
||||||
data = {
|
data = {
|
||||||
'xmlsec': PATH_XMLSEC,
|
'xmlsec': PATH_XMLSEC,
|
||||||
'pk12': save_temp(pk12),
|
'pk12': save_temp(pk12),
|
||||||
'pass': _get_md5(rfc),
|
'pass': token,
|
||||||
'template': save_temp(template, 'w'),
|
'template': save_temp(template, 'w'),
|
||||||
}
|
}
|
||||||
args = '"{xmlsec}" --sign --pkcs12 "{pk12}" --pwd {pass} ' \
|
args = '"{xmlsec}" --sign --pkcs12 "{pk12}" --pwd {pass} ' \
|
||||||
|
|
|
@ -16,7 +16,8 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
from controllers import util
|
from controllers import util
|
||||||
from settings import log, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
|
from settings import log, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
|
||||||
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO
|
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO, \
|
||||||
|
CANCEL_SIGNATURE
|
||||||
|
|
||||||
|
|
||||||
FORMAT = '{0:.2f}'
|
FORMAT = '{0:.2f}'
|
||||||
|
@ -639,7 +640,8 @@ class Certificado(BaseModel):
|
||||||
obj = cls.get_(cls)
|
obj = cls.get_(cls)
|
||||||
paths = Configuracion.get_({'fields': 'path_cer'})
|
paths = Configuracion.get_({'fields': 'path_cer'})
|
||||||
cert = util.Certificado(paths)
|
cert = util.Certificado(paths)
|
||||||
data = cert.validate(values['contra'], session['rfc'])
|
auth = Emisor.get_auth()
|
||||||
|
data = cert.validate(values['contra'], session['rfc'], auth)
|
||||||
if data:
|
if data:
|
||||||
msg = 'Certificado guardado correctamente'
|
msg = 'Certificado guardado correctamente'
|
||||||
q = Certificado.update(**data).where(Certificado.id==obj.id)
|
q = Certificado.update(**data).where(Certificado.id==obj.id)
|
||||||
|
@ -2202,11 +2204,34 @@ class Facturas(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def cancel(cls, id):
|
def cancel(cls, id):
|
||||||
|
if CANCEL_SIGNATURE:
|
||||||
|
return cls._cancel_signature(cls, id)
|
||||||
|
return cls._cancel_xml(cls, id)
|
||||||
|
|
||||||
|
def _cancel_xml(self, id):
|
||||||
msg = 'Factura cancelada correctamente'
|
msg = 'Factura cancelada correctamente'
|
||||||
auth = Emisor.get_auth()
|
auth = Emisor.get_auth()
|
||||||
certificado = Certificado.select()[0]
|
certificado = Certificado.select()[0]
|
||||||
obj = Facturas.get(Facturas.id==id)
|
obj = Facturas.get(Facturas.id==id)
|
||||||
data, result = util.cancel_cfdi(
|
data, result = util.cancel_xml(auth, obj.uuid, certificado)
|
||||||
|
if data['ok']:
|
||||||
|
obj.estatus = 'Cancelada'
|
||||||
|
obj.error = ''
|
||||||
|
obj.cancelada = True
|
||||||
|
obj.fecha_cancelacion = result['Fecha']
|
||||||
|
obj.acuse = result['Acuse']
|
||||||
|
self._actualizar_saldo_cliente(self, obj, True)
|
||||||
|
else:
|
||||||
|
obj.error = data['msg']
|
||||||
|
obj.save()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def _cancel_signature(self, id):
|
||||||
|
msg = 'Factura cancelada correctamente'
|
||||||
|
auth = Emisor.get_auth()
|
||||||
|
certificado = Certificado.select()[0]
|
||||||
|
obj = Facturas.get(Facturas.id==id)
|
||||||
|
data, result = util.cancel_signature(
|
||||||
obj.uuid, certificado.p12, certificado.rfc, auth)
|
obj.uuid, certificado.p12, certificado.rfc, auth)
|
||||||
if data['ok']:
|
if data['ok']:
|
||||||
obj.estatus = 'Cancelada'
|
obj.estatus = 'Cancelada'
|
||||||
|
@ -2214,6 +2239,7 @@ class Facturas(BaseModel):
|
||||||
obj.cancelada = True
|
obj.cancelada = True
|
||||||
obj.fecha_cancelacion = result['Fecha']
|
obj.fecha_cancelacion = result['Fecha']
|
||||||
obj.acuse = result['Acuse']
|
obj.acuse = result['Acuse']
|
||||||
|
self._actualizar_saldo_cliente(self, obj, True)
|
||||||
else:
|
else:
|
||||||
obj.error = data['msg']
|
obj.error = data['msg']
|
||||||
obj.save()
|
obj.save()
|
||||||
|
@ -2395,7 +2421,7 @@ class Facturas(BaseModel):
|
||||||
return
|
return
|
||||||
|
|
||||||
@util.run_in_thread
|
@util.run_in_thread
|
||||||
def _actualizar_saldo_cliente(self, invoice):
|
def _actualizar_saldo_cliente(self, invoice, cancel=False):
|
||||||
if invoice.tipo_comprobante == 'T':
|
if invoice.tipo_comprobante == 'T':
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -2406,6 +2432,9 @@ class Facturas(BaseModel):
|
||||||
if invoice.tipo_comprobante == 'E':
|
if invoice.tipo_comprobante == 'E':
|
||||||
importe *= -1
|
importe *= -1
|
||||||
|
|
||||||
|
if cancel:
|
||||||
|
importe *= -1
|
||||||
|
|
||||||
q = (Socios
|
q = (Socios
|
||||||
.update(saldo_cliente=Socios.saldo_cliente + importe)
|
.update(saldo_cliente=Socios.saldo_cliente + importe)
|
||||||
.where(Socios.id==invoice.cliente.id)
|
.where(Socios.id==invoice.cliente.id)
|
||||||
|
@ -2811,7 +2840,7 @@ class Facturas(BaseModel):
|
||||||
data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
|
data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _make_xml(self, invoice):
|
def _make_xml(self, invoice, auth):
|
||||||
emisor = Emisor.select()[0]
|
emisor = Emisor.select()[0]
|
||||||
certificado = Certificado.select()[0]
|
certificado = Certificado.select()[0]
|
||||||
|
|
||||||
|
@ -3000,7 +3029,7 @@ class Facturas(BaseModel):
|
||||||
'donativo': donativo,
|
'donativo': donativo,
|
||||||
'complementos': complementos,
|
'complementos': complementos,
|
||||||
}
|
}
|
||||||
return util.make_xml(data, certificado)
|
return util.make_xml(data, certificado, auth)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_status_sat(cls, id):
|
def get_status_sat(cls, id):
|
||||||
|
@ -3047,13 +3076,13 @@ class Facturas(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def timbrar(cls, id):
|
def timbrar(cls, id):
|
||||||
|
auth = Emisor.get_auth()
|
||||||
obj = Facturas.get(Facturas.id == id)
|
obj = Facturas.get(Facturas.id == id)
|
||||||
obj.xml = cls._make_xml(cls, obj)
|
obj.xml = cls._make_xml(cls, obj, auth)
|
||||||
obj.estatus = 'Generada'
|
obj.estatus = 'Generada'
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
enviar_correo = util.get_bool(Configuracion.get_('correo_directo'))
|
enviar_correo = util.get_bool(Configuracion.get_('correo_directo'))
|
||||||
auth = Emisor.get_auth()
|
|
||||||
|
|
||||||
anticipo = False
|
anticipo = False
|
||||||
msg = 'Factura timbrada correctamente'
|
msg = 'Factura timbrada correctamente'
|
||||||
|
|
|
@ -116,3 +116,5 @@ IMPUESTOS = {
|
||||||
}
|
}
|
||||||
DEFAULT_SAT_PRODUCTO = '01010101'
|
DEFAULT_SAT_PRODUCTO = '01010101'
|
||||||
DIR_FACTURAS = 'facturas'
|
DIR_FACTURAS = 'facturas'
|
||||||
|
USAR_TOKEN = False
|
||||||
|
CANCEL_SIGNATURE = True
|
|
@ -511,9 +511,6 @@ var tab_options = {
|
||||||
view: 'tabview',
|
view: 'tabview',
|
||||||
id: 'tab_options',
|
id: 'tab_options',
|
||||||
multiview: true,
|
multiview: true,
|
||||||
//~ tabbar: {options: [
|
|
||||||
//~ 'Plantillas',
|
|
||||||
//~ 'Otros']},
|
|
||||||
animate: true,
|
animate: true,
|
||||||
cells: [
|
cells: [
|
||||||
{id: 'Plantillas', rows: options_templates},
|
{id: 'Plantillas', rows: options_templates},
|
||||||
|
|
Loading…
Reference in New Issue