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']
|
||||
TOKEN = ''
|
||||
auth = {
|
||||
'DEBUG': debug,
|
||||
'USER': '',
|
||||
'PASS': TOKEN or PASS,
|
||||
'RESELLER': {'USER': USER, 'PASS': PASS}
|
||||
|
@ -58,6 +59,7 @@ def finkok(debug):
|
|||
PASS = ''
|
||||
TOKEN = '5c9a88da105bff9a8c430cb713f6d35269f51674bdc5963c1501b7316366'
|
||||
auth = {
|
||||
'DEBUG': debug,
|
||||
'USER': USER,
|
||||
'PASS': TOKEN or PASS,
|
||||
'RESELLER': {
|
||||
|
|
|
@ -324,21 +324,16 @@ class Finkok(object):
|
|||
try:
|
||||
result = client.service.query_pending(
|
||||
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
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
def cancel_xml(self, rfc, uuids, path_cer, path_key):
|
||||
for u in uuids:
|
||||
if not self._validate_uuid(u):
|
||||
return ''
|
||||
def cancel_xml(self, rfc, uuid, cer, key):
|
||||
# ~ for u in uuids:
|
||||
# ~ if not self._validate_uuid(u):
|
||||
# ~ return ''
|
||||
|
||||
cer = self._load_file(path_cer)
|
||||
key = self._load_file(path_key)
|
||||
method = 'cancel'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
@ -346,7 +341,7 @@ class Finkok(object):
|
|||
sa = client.get_type('ns0:stringArray')
|
||||
|
||||
args = {
|
||||
'UUIDS': uuid_type(uuids=sa(string=uuids)),
|
||||
'UUIDS': uuid_type(uuids=sa(string=uuid)),
|
||||
'username': self._auth['USER'],
|
||||
'password': self._auth['PASS'],
|
||||
'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_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):
|
||||
|
@ -416,7 +417,7 @@ class Certificado(object):
|
|||
data['hasta'] = hasta.replace(tzinfo=None)
|
||||
return data
|
||||
|
||||
def _get_p12(self, password, rfc):
|
||||
def _get_p12(self, password, rfc, token):
|
||||
tmp_cer = tempfile.mkstemp()[1]
|
||||
tmp_key = tempfile.mkstemp()[1]
|
||||
tmp_p12 = tempfile.mkstemp()[1]
|
||||
|
@ -428,7 +429,7 @@ class Certificado(object):
|
|||
|
||||
args = 'openssl pkcs12 -export -in "{}" -inkey "{}" -name "{}" ' \
|
||||
'-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)
|
||||
|
||||
self._kill(tmp_cer)
|
||||
|
@ -437,7 +438,7 @@ class Certificado(object):
|
|||
|
||||
return data
|
||||
|
||||
def _get_info_key(self, password, rfc):
|
||||
def _get_info_key(self, password, rfc, token):
|
||||
data = {}
|
||||
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:"{}"'
|
||||
|
@ -455,17 +456,23 @@ class Certificado(object):
|
|||
self.error = 'Los archivos no son pareja'
|
||||
return data
|
||||
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:"{}" | ' \
|
||||
'openssl rsa -des3 -passout pass:"{}"'.format(
|
||||
self._path_key, password, _get_md5(rfc))
|
||||
args = "openssl pkcs8 -inform DER -in '{}' -passin pass:'{}' | " \
|
||||
"openssl rsa -des3 -passout pass:'{}'".format(
|
||||
self._path_key, password, token)
|
||||
key_enc = _call(args)
|
||||
|
||||
data['key'] = read_file(self._path_key)
|
||||
data['key_enc'] = key_enc
|
||||
data['p12'] = self._get_p12(password, rfc)
|
||||
data['p12'] = self._get_p12(password, rfc, token)
|
||||
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:
|
||||
self.error = 'Error en las rutas temporales del certificado'
|
||||
return {}
|
||||
|
@ -474,7 +481,7 @@ class Certificado(object):
|
|||
if not data:
|
||||
return {}
|
||||
|
||||
llave = self._get_info_key(password, data['rfc'])
|
||||
llave = self._get_info_key(password, rfc, token)
|
||||
if not llave:
|
||||
return {}
|
||||
|
||||
|
@ -485,9 +492,15 @@ class Certificado(object):
|
|||
return data
|
||||
|
||||
|
||||
def make_xml(data, certificado):
|
||||
def make_xml(data, certificado, auth):
|
||||
from .cfdi_xml import CFDI
|
||||
|
||||
token = _get_md5(certificado.rfc)
|
||||
if USAR_TOKEN:
|
||||
token = auth['PASS']
|
||||
if AUTH['DEBUG']:
|
||||
token = AUTH['PASS']
|
||||
|
||||
if DEBUG:
|
||||
data['emisor']['Rfc'] = certificado.rfc
|
||||
data['emisor']['RegimenFiscal'] = '603'
|
||||
|
@ -501,7 +514,7 @@ def make_xml(data, certificado):
|
|||
'xml': save_temp(xml, 'w'),
|
||||
'openssl': PATH_OPENSSL,
|
||||
'key': save_temp(certificado.key_enc, 'w'),
|
||||
'pass': _get_md5(certificado.rfc)
|
||||
'pass': token,
|
||||
}
|
||||
args = '"{xsltproc}" "{xslt}" "{xml}" | ' \
|
||||
'"{openssl}" dgst -sha256 -sign "{key}" -passin pass:"{pass}" | ' \
|
||||
|
@ -517,13 +530,10 @@ def make_xml(data, certificado):
|
|||
def timbra_xml(xml, auth):
|
||||
from .pac import Finkok as PAC
|
||||
|
||||
if DEBUG:
|
||||
auth = {}
|
||||
else:
|
||||
if not auth:
|
||||
msg = 'Sin datos para timbrar'
|
||||
result = {'ok': True, 'error': msg}
|
||||
return result
|
||||
if not DEBUG and not auth:
|
||||
msg = 'Sin datos para timbrar'
|
||||
result = {'ok': True, 'error': msg}
|
||||
return result
|
||||
|
||||
result = {'ok': True, 'error': ''}
|
||||
pac = PAC(auth)
|
||||
|
@ -1299,9 +1309,46 @@ def upload_file(rfc, opt, file_obj):
|
|||
return {'status': 'error', 'ok': False}
|
||||
|
||||
|
||||
def cancel_cfdi(uuid, pk12, rfc, auth):
|
||||
def cancel_xml(auth, uuid, certificado):
|
||||
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')
|
||||
data = {
|
||||
'rfc': rfc,
|
||||
|
@ -1313,7 +1360,7 @@ def cancel_cfdi(uuid, pk12, rfc, auth):
|
|||
data = {
|
||||
'xmlsec': PATH_XMLSEC,
|
||||
'pk12': save_temp(pk12),
|
||||
'pass': _get_md5(rfc),
|
||||
'pass': token,
|
||||
'template': save_temp(template, 'w'),
|
||||
}
|
||||
args = '"{xmlsec}" --sign --pkcs12 "{pk12}" --pwd {pass} ' \
|
||||
|
|
|
@ -16,7 +16,8 @@ if __name__ == '__main__':
|
|||
|
||||
from controllers import util
|
||||
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}'
|
||||
|
@ -639,7 +640,8 @@ class Certificado(BaseModel):
|
|||
obj = cls.get_(cls)
|
||||
paths = Configuracion.get_({'fields': 'path_cer'})
|
||||
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:
|
||||
msg = 'Certificado guardado correctamente'
|
||||
q = Certificado.update(**data).where(Certificado.id==obj.id)
|
||||
|
@ -2202,11 +2204,34 @@ class Facturas(BaseModel):
|
|||
|
||||
@classmethod
|
||||
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'
|
||||
auth = Emisor.get_auth()
|
||||
certificado = Certificado.select()[0]
|
||||
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)
|
||||
if data['ok']:
|
||||
obj.estatus = 'Cancelada'
|
||||
|
@ -2214,6 +2239,7 @@ class Facturas(BaseModel):
|
|||
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()
|
||||
|
@ -2395,7 +2421,7 @@ class Facturas(BaseModel):
|
|||
return
|
||||
|
||||
@util.run_in_thread
|
||||
def _actualizar_saldo_cliente(self, invoice):
|
||||
def _actualizar_saldo_cliente(self, invoice, cancel=False):
|
||||
if invoice.tipo_comprobante == 'T':
|
||||
return
|
||||
|
||||
|
@ -2406,6 +2432,9 @@ class Facturas(BaseModel):
|
|||
if invoice.tipo_comprobante == 'E':
|
||||
importe *= -1
|
||||
|
||||
if cancel:
|
||||
importe *= -1
|
||||
|
||||
q = (Socios
|
||||
.update(saldo_cliente=Socios.saldo_cliente + importe)
|
||||
.where(Socios.id==invoice.cliente.id)
|
||||
|
@ -2811,7 +2840,7 @@ class Facturas(BaseModel):
|
|||
data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
|
||||
return data
|
||||
|
||||
def _make_xml(self, invoice):
|
||||
def _make_xml(self, invoice, auth):
|
||||
emisor = Emisor.select()[0]
|
||||
certificado = Certificado.select()[0]
|
||||
|
||||
|
@ -3000,7 +3029,7 @@ class Facturas(BaseModel):
|
|||
'donativo': donativo,
|
||||
'complementos': complementos,
|
||||
}
|
||||
return util.make_xml(data, certificado)
|
||||
return util.make_xml(data, certificado, auth)
|
||||
|
||||
@classmethod
|
||||
def get_status_sat(cls, id):
|
||||
|
@ -3047,13 +3076,13 @@ class Facturas(BaseModel):
|
|||
|
||||
@classmethod
|
||||
def timbrar(cls, id):
|
||||
auth = Emisor.get_auth()
|
||||
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.save()
|
||||
|
||||
enviar_correo = util.get_bool(Configuracion.get_('correo_directo'))
|
||||
auth = Emisor.get_auth()
|
||||
|
||||
anticipo = False
|
||||
msg = 'Factura timbrada correctamente'
|
||||
|
|
|
@ -115,4 +115,6 @@ IMPUESTOS = {
|
|||
'CEDULAR': '000',
|
||||
}
|
||||
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',
|
||||
id: 'tab_options',
|
||||
multiview: true,
|
||||
//~ tabbar: {options: [
|
||||
//~ 'Plantillas',
|
||||
//~ 'Otros']},
|
||||
animate: true,
|
||||
cells: [
|
||||
{id: 'Plantillas', rows: options_templates},
|
||||
|
|
Loading…
Reference in New Issue