343 lines
9.5 KiB
Python
343 lines
9.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
#~ import re
|
|
#~ from xml.etree import ElementTree as ET
|
|
#~ from requests import Request, Session, exceptions
|
|
import datetime
|
|
import hashlib
|
|
import os
|
|
import requests
|
|
import time
|
|
from lxml import etree
|
|
from xml.dom.minidom import parseString
|
|
from xml.sax.saxutils import escape, unescape
|
|
from uuid import UUID
|
|
|
|
from logbook import Logger
|
|
from zeep import Client
|
|
from zeep.plugins import HistoryPlugin
|
|
from zeep.cache import SqliteCache
|
|
from zeep.transports import Transport
|
|
from zeep.exceptions import Fault, TransportError
|
|
from requests.exceptions import ConnectionError
|
|
|
|
|
|
class Finkok(object):
|
|
|
|
def _get_xml(self, uuid):
|
|
if not self._validate_uuid(uuid):
|
|
return ''
|
|
|
|
method = 'util'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
|
|
args = {
|
|
'username': self._auth['USER'],
|
|
'password': self._auth['PASS'],
|
|
'uuid': uuid,
|
|
'taxpayer_id': self.rfc,
|
|
'invoice_type': 'I',
|
|
}
|
|
try:
|
|
result = client.service.get_xml(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
except TransportError as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
if result.error:
|
|
self.error = result.error
|
|
return ''
|
|
|
|
tree = parseString(result.xml)
|
|
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
|
return xml
|
|
|
|
def recupera_xml(self, file_xml='', uuid=''):
|
|
self.error = ''
|
|
if uuid:
|
|
return self._get_xml(uuid)
|
|
|
|
method = 'timbra'
|
|
ok, xml = self._validate_xml(file_xml)
|
|
if not ok:
|
|
return ''
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
try:
|
|
result = client.service.stamped(
|
|
xml, self._auth['user'], self._auth['pass'])
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return self._check_result(method, result)
|
|
|
|
def estatus_xml(self, uuid):
|
|
method = 'timbra'
|
|
if not self._validate_uuid(uuid):
|
|
return ''
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
try:
|
|
result = client.service.query_pending(
|
|
self._auth['USER'], self._auth['PASS'], uuid)
|
|
return result.status
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
def get_acuse(self, rfc, uuids, type_acuse='C'):
|
|
for u in uuids:
|
|
if not self._validate_uuid(u):
|
|
return ''
|
|
|
|
method = 'cancel'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
|
|
args = {
|
|
'username': self._auth['USER'],
|
|
'password': self._auth['PASS'],
|
|
'taxpayer_id': rfc,
|
|
'uuid': '',
|
|
'type': type_acuse,
|
|
}
|
|
try:
|
|
result = []
|
|
for u in uuids:
|
|
args['uuid'] = u
|
|
r = client.service.get_receipt(**args)
|
|
result.append(r)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def estatus_cancel(self, uuids):
|
|
for u in uuids:
|
|
if not self._validate_uuid(u):
|
|
return ''
|
|
|
|
method = 'cancel'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
|
|
args = {
|
|
'username': self._auth['USER'],
|
|
'password': self._auth['PASS'],
|
|
'uuid': '',
|
|
}
|
|
try:
|
|
result = []
|
|
for u in uuids:
|
|
args['uuid'] = u
|
|
r = client.service.query_pending_cancellation(**args)
|
|
result.append(r)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def add_token(self, rfc, email):
|
|
"""Agrega un nuevo token al cliente para timbrado.
|
|
Se requiere cuenta de reseller para usar este método
|
|
|
|
Args:
|
|
rfc (str): El RFC del cliente, ya debe existir
|
|
email (str): El correo del cliente, funciona como USER al timbrar
|
|
|
|
Returns:
|
|
dict
|
|
'username': 'username',
|
|
'status': True or False
|
|
'name': 'name',
|
|
'success': True or False
|
|
'token': 'Token de timbrado',
|
|
'message': None
|
|
"""
|
|
auth = AUTH['RESELLER']
|
|
|
|
method = 'util'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
args = {
|
|
'username': auth['USER'],
|
|
'password': auth['PASS'],
|
|
'name': rfc,
|
|
'token_username': email,
|
|
'taxpayer_id': rfc,
|
|
'status': True,
|
|
}
|
|
try:
|
|
result = client.service.add_token(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def get_date(self):
|
|
method = 'util'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
try:
|
|
result = client.service.datetime(AUTH['USER'], AUTH['PASS'])
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
if result.error:
|
|
self.error = result.error
|
|
return
|
|
|
|
return result.datetime
|
|
|
|
def add_client(self, rfc, type_user=False):
|
|
"""Agrega un nuevo cliente para timbrado.
|
|
Se requiere cuenta de reseller para usar este método
|
|
|
|
Args:
|
|
rfc (str): El RFC del nuevo cliente
|
|
|
|
Kwargs:
|
|
type_user (bool): False == 'P' == Prepago or True == 'O' == On demand
|
|
|
|
Returns:
|
|
dict
|
|
'message':
|
|
'Account Created successfully'
|
|
'Account Already exists'
|
|
'success': True or False
|
|
"""
|
|
auth = AUTH['RESELLER']
|
|
|
|
tu = {False: 'P', True: 'O'}
|
|
method = 'client'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
args = {
|
|
'reseller_username': auth['USER'],
|
|
'reseller_password': auth['PASS'],
|
|
'taxpayer_id': rfc,
|
|
'type_user': tu[type_user],
|
|
'added': datetime.datetime.now().isoformat()[:19],
|
|
}
|
|
try:
|
|
result = client.service.add(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def edit_client(self, rfc, status=True):
|
|
"""
|
|
Se requiere cuenta de reseller para usar este método
|
|
status = 'A' or 'S'
|
|
"""
|
|
auth = AUTH['RESELLER']
|
|
|
|
sv = {False: 'S', True: 'A'}
|
|
method = 'client'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
args = {
|
|
'reseller_username': auth['USER'],
|
|
'reseller_password': auth['PASS'],
|
|
'taxpayer_id': rfc,
|
|
'status': sv[status],
|
|
}
|
|
try:
|
|
result = client.service.edit(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def get_client(self, rfc):
|
|
"""Regresa el estatus del cliente
|
|
.
|
|
Se requiere cuenta de reseller para usar este método
|
|
|
|
Args:
|
|
rfc (str): El RFC del emisor
|
|
|
|
Returns:
|
|
dict
|
|
'message': None,
|
|
'users': {
|
|
'ResellerUser': [
|
|
{
|
|
'status': 'A',
|
|
'counter': 0,
|
|
'taxpayer_id': '',
|
|
'credit': 0
|
|
}
|
|
]
|
|
} or None si no existe
|
|
"""
|
|
auth = AUTH['RESELLER']
|
|
|
|
method = 'client'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
args = {
|
|
'reseller_username': auth['USER'],
|
|
'reseller_password': auth['PASS'],
|
|
'taxpayer_id': rfc,
|
|
}
|
|
|
|
try:
|
|
result = client.service.get(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
except TransportError as e:
|
|
self.errorcancel = str(e)
|
|
return ''
|
|
|
|
return result
|
|
|
|
def assign_client(self, rfc, credit):
|
|
"""Agregar credito a un emisor
|
|
|
|
Se requiere cuenta de reseller para usar este método
|
|
|
|
Args:
|
|
rfc (str): El RFC del emisor, debe existir
|
|
credit (int): Cantidad de folios a agregar
|
|
|
|
Returns:
|
|
dict
|
|
'success': True or False,
|
|
'credit': nuevo credito despues de agregar or None
|
|
'message':
|
|
'Success, added {credit} of credit to {RFC}'
|
|
'RFC no encontrado'
|
|
"""
|
|
auth = AUTH['RESELLER']
|
|
|
|
method = 'client'
|
|
client = Client(
|
|
URL[method], transport=self._transport, plugins=self._plugins)
|
|
args = {
|
|
'username': auth['USER'],
|
|
'password': auth['PASS'],
|
|
'taxpayer_id': rfc,
|
|
'credit': credit,
|
|
}
|
|
try:
|
|
result = client.service.assign(**args)
|
|
except Fault as e:
|
|
self.error = str(e)
|
|
return ''
|
|
|
|
return result
|