diff --git a/source/finkok/finkok.py b/source/finkok/finkok.py index 534283a..ad576c9 100644 --- a/source/finkok/finkok.py +++ b/source/finkok/finkok.py @@ -237,8 +237,9 @@ class PACFinkok(object): transport=self._transport, plugins=self._plugins) client.set_ns_prefix('can', 'http://facturacion.finkok.com/cancel') # ~ xml = f'\n{xml}' + # ~ xml = f'\n{xml}' args = { - 'xml': base64.b64encode(xml.encode()), + 'xml': xml.encode(), 'username': auth['user'], 'password': auth['pass'], 'store_pending': False, @@ -248,9 +249,115 @@ class PACFinkok(object): log.error(self.error) return '' - return result + folio = result['Folios']['Folio'][0] + status = folio['EstatusUUID'] + if status != '201': + log.debug(f'Cancel status: {status} -') - def client_balance(self, auth, rfc=''): + data = { + 'acuse': result['Acuse'], + 'date': result['Fecha'], + } + return data + + def client_add(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 + True == 'O' == On demand + + Returns: + True or False + + origin PAC + 'message': + 'Account Created successfully' + 'Account Already exists' + 'success': True or False + """ + auth = AUTH['RESELLER'] + tu = {True: 'O', False: 'P'} + + method = 'client' + client = Client( + self.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], + } + + result = self._get_result(client, 'add', args) + if self.error: + return False + + if not result.success: + self.error = result.message + return False + + # ~ PAC success debería ser False + msg = 'Account Already exists' + if result.message == msg: + self.error = msg + return True + + return result.success + + def client_get_token(self, rfc, email): + """Genera 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: + token (str): Es la contraseña para timbrar + + origin PAC + 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( + self.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, + } + + result = self._get_result(client, 'add_token', args) + if self.error: + log.error(self.error) + return '' + + if not result.success: + self.error = result.message + log.error(self.error) + return '' + + return result.token + + def client_balance(self, auth={}, rfc=''): """Regresa los timbres restantes del cliente Se pueden usar las credenciales de relleser o las credenciales del emisor @@ -281,10 +388,10 @@ class PACFinkok(object): log.error(self.error) return '' - success = bool(self.result.users) + success = bool(result.users) if not success: - self.error = self.result.message or 'RFC no existe' + self.error = result.message or 'RFC no existe' return 0 - return self.result.users.ResellerUser[0].credit + return result.users.ResellerUser[0].credit diff --git a/source/finkok/finkok1.py b/source/finkok/finkok1.py index 0bd85a2..72e5e79 100644 --- a/source/finkok/finkok1.py +++ b/source/finkok/finkok1.py @@ -71,99 +71,6 @@ class PACFinkok(object): return data - def client_add(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: - True or False - - origin PAC - 'message': - 'Account Created successfully' - 'Account Already exists' - 'success': True or False - """ - auth = FINKOK['RESELLER'] - tu = {True: 'O', False: 'P'} - - method = 'client' - client = Client( - self.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], - } - - result = self._get_result(client, 'add', args) - if self.error: - return False - - if not result.success: - self.error = result.message - return False - - # ~ PAC success debería ser False - msg = 'Account Already exists' - if result.message == msg: - self.error = msg - return True - - return result.success - - def client_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: - token (str): Es la contraseña para timbrar - - origin PAC - dict - 'username': 'username', - 'status': True or False - 'name': 'name', - 'success': True or False - 'token': 'Token de timbrado', - 'message': None - """ - auth = FINKOK['RESELLER'] - method = 'util' - client = Client( - self.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, - } - - result = self._get_result(client, 'add_token', args) - if self.error: - return '' - - if not result.success: - self.error = result.message - return '' - - return result.token - # ~ Send issue to PAC def client_reset_token(self, email): auth = FINKOK['RESELLER'] diff --git a/source/finkok/finkok2.py b/source/finkok/finkok2.py index 2dbbe61..156f737 100644 --- a/source/finkok/finkok2.py +++ b/source/finkok/finkok2.py @@ -144,44 +144,6 @@ class Finkok(object): 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( @@ -198,44 +160,6 @@ class Finkok(object): 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 @@ -304,39 +228,3 @@ class Finkok(object): 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 diff --git a/source/tests/tests_finkok.py b/source/tests/tests_finkok.py index e8fd036..6a69f70 100644 --- a/source/tests/tests_finkok.py +++ b/source/tests/tests_finkok.py @@ -2,6 +2,8 @@ import base64 import datetime +import random +import string import sys import time import unittest @@ -202,18 +204,69 @@ class TestStamp(unittest.TestCase): template = TEMPLATE_CANCEL.format(**data) sign_xml = cfdi.sign_xml(template) - time.sleep(5) + time.sleep(60) result = self.pac.cancel_xml(sign_xml) self.assertFalse(bool(self.pac.error)) - tree = ET.fromstring(result) - uid = tree.xpath('string(//Acuse/Folios/UUID)') - status = tree.xpath('string(//Acuse/Folios/EstatusUUID)') + tree = ET.fromstring(result['acuse'].encode()) + NS = {'s': 'http://schemas.xmlsoap.org/soap/envelope/'} + path = 'string(//s:Body/*/*/*[1]/*[1])' + cancel_uuid = tree.xpath(path, namespaces=NS) + path = 'string(//s:Body/*/*/*[1]/*[2])' + status = tree.xpath(path, namespaces=NS) - self.assertEqual(cfdi_uuid, uid) + self.assertEqual(cfdi_uuid, cancel_uuid) self.assertEqual(status, expected) +class TestClient(unittest.TestCase): + + def setUp(self): + print(f'In method: {self._testMethodName}') + self.pac = PACFinkok() + + def _get_random_date(self): + cd = datetime.date.today() + sd = datetime.date(1950, 1, 1) + days = random.randint(1, (cd-sd).days) + nd = sd + datetime.timedelta(days=days) + return nd.strftime('%y%m%d') + + def _get_random_rfc(self): + i = ''.join(random.sample(string.ascii_lowercase, 4)) + d = self._get_random_date() + h = uuid.uuid4().hex[:3] + rfc = f'{i}{d}{h}'.upper() + return rfc + + def test_client_add(self): + rfc = self._get_random_rfc() + result = self.pac.client_add(rfc) + self.assertTrue(result) + return + + def test_client_get_token(self): + expected = 60 + rfc = self._get_random_rfc() + result = self.pac.client_add(rfc) + self.assertTrue(result) + + result = self.pac.client_get_token(rfc, f'{rfc}@test.com') + self.assertEqual(len(result), expected) + return + + def test_client_balance(self): + expected = 0 + rfc = self._get_random_rfc() + result = self.pac.client_add(rfc) + self.assertTrue(result) + + result = self.pac.client_balance(rfc=rfc) + self.assertEqual(result, expected) + return + + if __name__ == '__main__': unittest.main() +