diff --git a/.gitignore b/.gitignore index bee4090c..5b5a0dad 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ coverage.xml /.python-version prueba-cert.pem + +htmlcov/ diff --git a/requirements.txt b/requirements.txt index faafd01b..951971cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,5 +10,5 @@ newrelic==6.2.0.156 pandas==1.2.4 python-hosts==1.0.1 sentry-sdk==1.14.0 -stpmex==3.11.2 +stpmex==3.13.1 importlib-metadata==4.13.0 diff --git a/speid/commands/spei.py b/speid/commands/spei.py index 59c4eede..8ab8b191 100644 --- a/speid/commands/spei.py +++ b/speid/commands/spei.py @@ -4,23 +4,21 @@ import pytz from mongoengine import DoesNotExist from stpmex.business_days import get_next_business_day -from stpmex.types import Estado as StpEstado from speid import app from speid.helpers.callback_helper import set_status_transaction -from speid.helpers.transaction_helper import process_incoming_transaction +from speid.helpers.transaction_helper import ( + process_incoming_transaction, + stp_model_to_dict, +) from speid.models import Event, Transaction +from speid.models.transaction import ( + REFUNDS_PAYMENTS_TYPES, + STP_VALID_DEPOSITS_STATUSES, +) from speid.processors import stpmex_client from speid.types import Estado, EventType -ESTADOS_DEPOSITOS_VALIDOS = { - StpEstado.confirmada, - StpEstado.liquidada, - StpEstado.traspaso_liquidado, -} - -TIPOS_PAGO_DEVOLUCION = {0, 16, 17, 18, 23, 24} - @app.cli.group('speid') def speid_group(): @@ -87,11 +85,11 @@ def reconciliate_deposits( # Se ignora los tipos pago devolución debido a que # el estado de estas operaciones se envían # al webhook `POST /orden_events` - if recibida.tipoPago in TIPOS_PAGO_DEVOLUCION: + if recibida.tipoPago in REFUNDS_PAYMENTS_TYPES: no_procesadas.append(recibida.claveRastreo) continue - if recibida.estado not in ESTADOS_DEPOSITOS_VALIDOS: + if recibida.estado not in STP_VALID_DEPOSITS_STATUSES: no_procesadas.append(recibida.claveRastreo) continue @@ -105,27 +103,7 @@ def reconciliate_deposits( # hace una conversión del modelo de respuesta de # la función `consulta_recibidas` al modelo del evento que envía # STP por el webhook en `POST /ordenes` - stp_request = dict( - Clave=recibida.idEF, - FechaOperacion=recibida.fechaOperacion.strftime('%Y%m%d'), - InstitucionOrdenante=recibida.institucionContraparte, - InstitucionBeneficiaria=recibida.institucionOperante, - ClaveRastreo=recibida.claveRastreo, - Monto=recibida.monto, - NombreOrdenante=recibida.nombreOrdenante, - TipoCuentaOrdenante=recibida.tipoCuentaOrdenante, - CuentaOrdenante=recibida.cuentaOrdenante, - RFCCurpOrdenante=recibida.rfcCurpOrdenante, - NombreBeneficiario=recibida.nombreBeneficiario, - TipoCuentaBeneficiario=recibida.tipoCuentaBeneficiario, - CuentaBeneficiario=recibida.cuentaBeneficiario, - RFCCurpBeneficiario=getattr( - recibida, 'rfcCurpBeneficiario', 'NA' - ), - ConceptoPago=recibida.conceptoPago, - ReferenciaNumerica=recibida.referenciaNumerica, - Empresa=recibida.empresa, - ) + stp_request = stp_model_to_dict(recibida) click.echo(f'Depósito procesado: {recibida.claveRastreo}') process_incoming_transaction(stp_request) else: diff --git a/speid/exc.py b/speid/exc.py index c5736e17..325dc52b 100644 --- a/speid/exc.py +++ b/speid/exc.py @@ -1,3 +1,6 @@ +from dataclasses import dataclass + + class OrderNotFoundException(ReferenceError): pass @@ -16,3 +19,13 @@ class ScheduleError(Exception): """ pass + + +@dataclass +class TransactionNeedManualReviewError(Exception): + """ + when a person should review the transaction status manually + """ + + speid_id: str + error: str diff --git a/speid/helpers/transaction_helper.py b/speid/helpers/transaction_helper.py index 24066a81..61c3ec9a 100644 --- a/speid/helpers/transaction_helper.py +++ b/speid/helpers/transaction_helper.py @@ -1,4 +1,5 @@ import os +from typing import Dict from mongoengine import NotUniqueError from sentry_sdk import capture_exception, capture_message @@ -40,3 +41,25 @@ def process_incoming_transaction(incoming_transaction: dict) -> dict: transaction.save() capture_exception(e) return r + + +def stp_model_to_dict(model) -> Dict: + return dict( + Clave=model.idEF, + FechaOperacion=model.fechaOperacion.strftime('%Y%m%d'), + InstitucionOrdenante=model.institucionContraparte, + InstitucionBeneficiaria=model.institucionOperante, + ClaveRastreo=model.claveRastreo, + Monto=model.monto, + NombreOrdenante=model.nombreOrdenante, + TipoCuentaOrdenante=model.tipoCuentaOrdenante, + CuentaOrdenante=model.cuentaOrdenante, + RFCCurpOrdenante=model.rfcCurpOrdenante, + NombreBeneficiario=model.nombreBeneficiario, + TipoCuentaBeneficiario=model.tipoCuentaBeneficiario, + CuentaBeneficiario=model.cuentaBeneficiario, + RFCCurpBeneficiario=getattr(model, 'rfcCurpBeneficiario', 'NA'), + ConceptoPago=model.conceptoPago, + ReferenciaNumerica=model.referenciaNumerica, + Empresa=model.empresa, + ) diff --git a/speid/models/transaction.py b/speid/models/transaction.py index a8bd9308..3efef571 100644 --- a/speid/models/transaction.py +++ b/speid/models/transaction.py @@ -1,5 +1,5 @@ +import datetime as dt import os -from datetime import datetime from enum import Enum from typing import Optional @@ -16,12 +16,12 @@ ) from sentry_sdk import capture_exception from stpmex.business_days import get_next_business_day -from stpmex.exc import NoEntityFound, StpmexException +from stpmex.exc import EmptyResultsError, StpmexException from stpmex.resources import Orden from stpmex.types import Estado as STPEstado from speid import STP_EMPRESA -from speid.exc import MalformedOrderException +from speid.exc import MalformedOrderException, TransactionNeedManualReviewError from speid.helpers import callback_helper from speid.processors import stpmex_client from speid.types import Estado, EventType, TipoTransaccion @@ -42,17 +42,32 @@ os.getenv('SKIP_VALIDATION_PRIOR_SEND_ORDER', 'false').lower() == 'true' ) -STP_FAILED_STATUSES = [ +STP_FAILED_TRANSFERS_STATUSES = { STPEstado.traspaso_cancelado, STPEstado.cancelada, STPEstado.cancelada_adapter, STPEstado.cancelada_rechazada, -] + STPEstado.devuelta, +} + +STP_SUCCEDED_TRANSFERS_STATUSES = { + STPEstado.liquidada, + STPEstado.traspaso_liquidado, +} + + +STP_VALID_DEPOSITS_STATUSES = { + STPEstado.confirmada, + STPEstado.liquidada, + STPEstado.traspaso_liquidado, +} + +REFUNDS_PAYMENTS_TYPES = {0, 16, 17, 18, 23, 24} @handler(signals.pre_save) def pre_save_transaction(sender, document): - date = document.fecha_operacion or datetime.today() + date = document.fecha_operacion or dt.datetime.today() document.compound_key = ( f'{document.clave_rastreo}:{date.strftime("%Y%m%d")}' ) @@ -130,6 +145,18 @@ class Transaction(Document, BaseModel): ] } + @property + def created_at_cdmx(self) -> dt.datetime: + utc_created_at = self.created_at.replace(tzinfo=pytz.utc) + return utc_created_at.astimezone(pytz.timezone('America/Mexico_City')) + + @property + def created_at_fecha_operacion(self) -> dt.date: + # STP doesn't return `fecha_operacion` on withdrawal creation, but we + # can calculate it. + assert self.tipo is TipoTransaccion.retiro + return get_next_business_day(self.created_at_cdmx) + def set_state(self, state: Estado): from ..tasks.transactions import send_transaction_status @@ -162,39 +189,41 @@ def is_valid_account(self) -> bool: pass return is_valid - def fetch_stp_status(self) -> Optional[STPEstado]: - # checa status en stp - estado = None - try: - stp_order = stpmex_client.ordenes.consulta_clave_rastreo( - claveRastreo=self.clave_rastreo, - institucionOperante=self.institucion_ordenante, - fechaOperacion=get_next_business_day(self.created_at), - ) - estado = stp_order.estado - except NoEntityFound: - ... - return estado - - def is_current_working_day(self) -> bool: - # checks if transaction was made in the current working day - local = self.created_at.replace(tzinfo=pytz.utc) - local = local.astimezone(pytz.timezone('America/Mexico_City')) - return get_next_business_day(local) == datetime.utcnow().date() - - def fail_if_not_found_stp(self) -> None: - # if transaction is not found in stp, or has a failed status, - # return to origin. Only checking for curent working day - if not self.is_current_working_day(): - return + def fetch_stp_status(self) -> STPEstado: + stp_order = stpmex_client.ordenes_v2.consulta_clave_rastreo_enviada( + clave_rastreo=self.clave_rastreo, + fecha_operacion=self.created_at_fecha_operacion, + ) + return stp_order.estado + + def update_stp_status(self) -> None: try: - estado = self.fetch_stp_status() + status: Optional[STPEstado] = self.fetch_stp_status() + except EmptyResultsError: + status = None except StpmexException as ex: capture_exception(ex) + return + + if not status: + raise TransactionNeedManualReviewError( + self.speid_id, + f'Can not retrieve transaction stp_id: {self.stp_id}', + ) + elif status in STP_FAILED_TRANSFERS_STATUSES: + self.set_state(Estado.failed) + self.save() + elif status in STP_SUCCEDED_TRANSFERS_STATUSES: + self.set_state(Estado.succeeded) + self.save() + elif status is STPEstado.autorizada: + return else: - if not estado or estado in STP_FAILED_STATUSES: - self.set_state(Estado.failed) - self.save() + # Cualquier otro caso se debe revisar manualmente y aplicar + # el fix correspondiente + raise TransactionNeedManualReviewError( + self.speid_id, f'Unhandled stp status: {status}' + ) def create_order(self) -> Orden: # Validate account has already been created diff --git a/speid/tasks/orders.py b/speid/tasks/orders.py index 82ad6d2e..90ba45a9 100644 --- a/speid/tasks/orders.py +++ b/speid/tasks/orders.py @@ -20,6 +20,7 @@ MalformedOrderException, ResendSuccessOrderException, ScheduleError, + TransactionNeedManualReviewError, ) from speid.helpers.task_helpers import time_in_range from speid.models import Event, Transaction @@ -52,7 +53,11 @@ def retry_timeout(attempts: int) -> int: def send_order(self, order_val: dict): try: execute(order_val) - except (MalformedOrderException, ResendSuccessOrderException) as exc: + except ( + MalformedOrderException, + ResendSuccessOrderException, + TransactionNeedManualReviewError, + ) as exc: capture_exception(exc) except ScheduleError: self.retry(countdown=STP_COUNTDOWN) @@ -93,30 +98,43 @@ def execute(order_val: dict): transaction.save() pass except AssertionError: + # Se hace un reenvío del estado de la transferencia + # transaction.set_state(Estado.succeeded) # Para evitar que se vuelva a mandar o regresar se manda la excepción raise ResendSuccessOrderException() + # Estas validaciones aplican para transferencias existentes que + # pudieron haber fallado o han sido enviadas a STP + if transaction.estado in [Estado.failed, Estado.error]: + transaction.set_state(Estado.failed) + return + + # Revisa el estado de una transferencia si ya tiene asignado stp_id o ha + # pasado más de 2 hrs. + now = datetime.utcnow() + if transaction.stp_id or (now - transaction.created_at) > timedelta( + hours=2 + ): + transaction.update_stp_status() + return + + # A partir de aquí son validaciones para transferencias nuevas if transaction.monto > MAX_AMOUNT: transaction.events.append(Event(type=EventType.error)) transaction.save() raise MalformedOrderException() - now = datetime.utcnow() - # Return transaction after 2 hours of creation - if (now - transaction.created_at) > timedelta(hours=2): - transaction.fail_if_not_found_stp() - else: - try: - transaction.create_order() - except ( - AccountDoesNotExist, - BankCodeClabeMismatch, - InvalidAccountType, - InvalidAmount, - InvalidInstitution, - InvalidTrackingKey, - PldRejected, - ValidationError, - ): - transaction.set_state(Estado.failed) - transaction.save() + try: + transaction.create_order() + except ( + AccountDoesNotExist, + BankCodeClabeMismatch, + InvalidAccountType, + InvalidAmount, + InvalidInstitution, + InvalidTrackingKey, + PldRejected, + ValidationError, + ): + transaction.set_state(Estado.failed) + transaction.save() diff --git a/speid/tasks/transactions.py b/speid/tasks/transactions.py index fc33015c..c9af929c 100644 --- a/speid/tasks/transactions.py +++ b/speid/tasks/transactions.py @@ -1,16 +1,32 @@ -from typing import List +import datetime as dt +from typing import Dict, List import cep import pytz from celery.exceptions import MaxRetriesExceededError from cep.exc import CepError, MaxRequestError from mongoengine import DoesNotExist -from stpmex.business_days import current_cdmx_time_zone +from stpmex.business_days import ( + current_cdmx_time_zone, + get_next_business_day, + get_prior_business_day, +) +from stpmex.exc import EmptyResultsError, InvalidFutureDateError from speid.helpers import callback_helper +from speid.helpers.transaction_helper import ( + process_incoming_transaction, + stp_model_to_dict, +) from speid.models import Account, Event, Transaction +from speid.models.transaction import ( + REFUNDS_PAYMENTS_TYPES, + STP_VALID_DEPOSITS_STATUSES, +) +from speid.processors import stpmex_client from speid.tasks import celery -from speid.types import Estado, EventType +from speid.types import Estado, EventType, TipoTransaccion +from speid.validations.queries import DepositStatusQuery CURP_LENGTH = 18 RFC_LENGTH = 13 @@ -125,3 +141,48 @@ def send_transaction_status(self, transaction_id: str, state: str) -> None: callback_helper.set_status_transaction( transaction.speid_id, state, curp, rfc, nombre_beneficiario ) + + +@celery.task +def check_deposits_status(deposit: Dict) -> None: + req = DepositStatusQuery(**deposit) + transactions = Transaction.objects( + clave_rastreo=req.clave_rastreo, + cuenta_beneficiario=req.cuenta_beneficiario, + tipo=TipoTransaccion.deposito, + ).all() + + if transactions: + retry_incoming_transactions.apply_async( + ([t.speid_id for t in transactions],) + ) + return + + # Si no existe en los registros se obtiene de STP y se intenta con 3 fechas + # operativas próximas a la fecha que el cliente nos proporcionó + fechas_operacion = [ + get_next_business_day(req.fecha_operacion), + get_prior_business_day(req.fecha_operacion), + get_next_business_day(req.fecha_operacion + dt.timedelta(days=1)), + ] + + for fecha_operacion in fechas_operacion: + try: + recibida = ( + stpmex_client.ordenes_v2.consulta_clave_rastreo_recibida( + clave_rastreo=req.clave_rastreo, + fecha_operacion=fecha_operacion, + ) + ) + except (InvalidFutureDateError, EmptyResultsError): + continue + else: + if ( + recibida.tipoPago in REFUNDS_PAYMENTS_TYPES + or recibida.estado not in STP_VALID_DEPOSITS_STATUSES + ): + return + + stp_request = stp_model_to_dict(recibida) + process_incoming_transaction(stp_request) + return diff --git a/speid/validations/queries.py b/speid/validations/queries.py new file mode 100644 index 00000000..66f16b0e --- /dev/null +++ b/speid/validations/queries.py @@ -0,0 +1,10 @@ +import datetime as dt + +from clabe import Clabe +from pydantic import BaseModel + + +class DepositStatusQuery(BaseModel): + clave_rastreo: str + cuenta_beneficiario: Clabe + fecha_operacion: dt.date diff --git a/tests/commands/test_spei.py b/tests/commands/test_spei.py index 70ecaa8e..a8dfe013 100644 --- a/tests/commands/test_spei.py +++ b/tests/commands/test_spei.py @@ -5,12 +5,12 @@ import requests_mock from freezegun import freeze_time -from speid.commands.spei import ( - ESTADOS_DEPOSITOS_VALIDOS, - TIPOS_PAGO_DEVOLUCION, - speid_group, -) +from speid.commands.spei import speid_group from speid.models import Transaction +from speid.models.transaction import ( + REFUNDS_PAYMENTS_TYPES, + STP_VALID_DEPOSITS_STATUSES, +) from speid.types import Estado, EventType from speid.validations import StpTransaction @@ -149,7 +149,6 @@ def test_reconciliate_deposits_historic(runner): ).all() assert len(deposits_db) == 1 - Transaction.drop_collection() @freeze_time("2023-08-27") # 2023-08-26 18:00 UTC-6 @@ -175,8 +174,8 @@ def test_reconciliate_deposits_current_fecha_operacion(runner): valid_deposits = [ d for d in deposits - if d['estado'] in ESTADOS_DEPOSITOS_VALIDOS - and d['tipoPago'] not in TIPOS_PAGO_DEVOLUCION + if d['estado'] in STP_VALID_DEPOSITS_STATUSES + and d['tipoPago'] not in REFUNDS_PAYMENTS_TYPES ] with requests_mock.mock() as m: @@ -199,7 +198,6 @@ def test_reconciliate_deposits_current_fecha_operacion(runner): assert not any( d.clave_rastreo == devolucion['claveRastreo'] for d in deposits_db ) - Transaction.drop_collection() @freeze_time("2023-08-26 01:00:00") # 2023-08-25 19:00 UTC-6 @@ -249,8 +247,8 @@ def test_reconciliate_deposits_ignores_duplicated(runner): valid_deposits = [ d for d in deposits - if d['estado'] in ESTADOS_DEPOSITOS_VALIDOS - and d['tipoPago'] not in TIPOS_PAGO_DEVOLUCION + if d['estado'] in STP_VALID_DEPOSITS_STATUSES + and d['tipoPago'] not in REFUNDS_PAYMENTS_TYPES ] with requests_mock.mock() as m: @@ -270,4 +268,3 @@ def test_reconciliate_deposits_ignores_duplicated(runner): ).all() assert len(deposits_db) == len(valid_deposits) - Transaction.drop_collection() diff --git a/tests/conftest.py b/tests/conftest.py index ca4ac0a5..77f9a93f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,6 +15,13 @@ SEND_STATUS_TRANSACTION_TASK = os.environ['SEND_STATUS_TRANSACTION_TASK'] +@pytest.fixture +def client(): + app.testing = True + client = app.test_client() + return client + + @pytest.fixture def runner(): runner = FlaskCliRunner(app) @@ -23,8 +30,8 @@ def runner(): @pytest.fixture def mock_callback_queue(): - with patch.object(Celery, 'send_task', return_value=None): - yield + with patch.object(Celery, 'send_task', return_value=None) as mock: + yield mock @pytest.fixture(scope='module') @@ -57,6 +64,29 @@ def outcome_transaction() -> Generator[Transaction, None, None]: transaction.delete() +@pytest.fixture +def default_income_transaction(): + return dict( + Clave=2456303, + FechaOperacion=20210618, + InstitucionOrdenante=40012, + InstitucionBeneficiaria=90646, + ClaveRastreo="PRUEBATAMIZI1", + Monto=100.0, + NombreOrdenante="BANCO", + TipoCuentaOrdenante=40, + CuentaOrdenante="846180000500000008", + RFCCurpOrdenante="ND", + NombreBeneficiario="TAMIZI", + TipoCuentaBeneficiario=40, + CuentaBeneficiario="646180157000000004", + RFCCurpBeneficiario="ND", + ConceptoPago="PRUEBA", + ReferenciaNumerica=2423, + Empresa="TAMIZI", + ) + + @pytest.fixture def physical_account(): # Pongo los import aquí porque de otra forma no puedo hacer tests del @@ -82,6 +112,29 @@ def physical_account(): account.delete() +@pytest.fixture +def second_physical_account(): + from speid.models import PhysicalAccount + from speid.types import Estado + + account = PhysicalAccount( + estado=Estado.succeeded, + nombre='Juan', + apellido_paterno='Perez', + apellido_materno='Perez', + cuenta='646180157018613700', + rfc_curp='PEPJ800101HCSPRL02', + telefono='5544332211', + fecha_nacimiento=dt.date(1980, 1, 1), + pais_nacimiento='MX', + ) + account.save() + + yield account + + account.delete() + + @pytest.fixture def moral_account(): # Pongo los import aquí porque de otra forma no puedo hacer tests del @@ -148,3 +201,9 @@ def orden_pago(outcome_transaction): usuario='foo', ) ) + + +@pytest.fixture(autouse=True) +def cleanup_transactions(): + yield + Transaction.drop_collection() diff --git a/tests/tasks/cassettes/test_check_existing_deposit.yaml b/tests/tasks/cassettes/test_check_existing_deposit.yaml new file mode 100644 index 00000000..2486fb04 --- /dev/null +++ b/tests/tasks/cassettes/test_check_existing_deposit.yaml @@ -0,0 +1,42 @@ +interactions: +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "Test162467872", "tipoOrden": "R", + "fechaOperacion": "20230828", "firma": "SgmhFe+ySNKghFsLscumsJmjME2Fd+grVr1qaS+q9z2Av1RF2QV88WJ51vArFI/nTWBjtmuEvfgQfU2oIY6kv2JS16M85EPLbIJPMZnKYktWBl4hMjJIxlf8OogUI8uuZsQ8PHbwPlZLayjFeOmJnP6PLxI0c9re+HF5ieRVpFQ="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '287' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":13864373,"claveRastreo":"Test162467872","conceptoPago":"Pago + de prueba","cuentaBeneficiario":"646180157018877012","cuentaOrdenante":"646580103500000006","empresa":"TAMIZI","estado":"TLQ","fechaOperacion":20230828,"institucionContraparte":90646,"institucionOperante":90646,"medioEntrega":3,"monto":0.01,"nombreBeneficiario":"Beneficiario","nombreOrdenante":"CONESA","nombreCep":null,"rfcCep":"TCU200828RX8","sello":null,"rfcCurpBeneficiario":"ND","referenciaNumerica":1234567,"rfcCurpOrdenante":"ACO841030SU7","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1693246820537,"tsLiquidacion":1693246825244,"causaDevolucion":null,"urlCEP":"https://www.banxico.org.mx/cep/go?i=90646&s=20210302&d=Htx%2FNVOdUKgiu8uqML7PX3qzuFfKM8i71Qzhdi3vcyy64uMK96Sw3UAVErWMcTMIfsBqHMPiYv5%2FpWbscHEU3w%3D%3D"}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 17:11:13 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_check_not_existing_deposit.yaml b/tests/tasks/cassettes/test_check_not_existing_deposit.yaml new file mode 100644 index 00000000..329e2af1 --- /dev/null +++ b/tests/tasks/cassettes/test_check_not_existing_deposit.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "FOOBARBAZ", "tipoOrden": "R", "fechaOperacion": + "20230828", "firma": "qQI8DzXf3W4s6zkEiQMZ0sZRbncyjgBih4T6qZ6rE2I5LKh7RWcRZsjPtW2DcwZBQRfZA5Z3jcg/mbL7hmA6n6UQvCwQR7pPoOBEoC7y1A1V+NV2nfGYq5oqIfdvI+HqzG61qeyu/HplTinZZJ3pYZPWn6HDbKhlNy+spb82EmY="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '283' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":6,"mensaje":"No se encontraron datos relacionados"}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 17:13:34 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 400 + message: Bad Request +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "FOOBARBAZ", "tipoOrden": "R", "fechaOperacion": + "20230825", "firma": "oGkIkyhYHi9SQ/84ebQOp04EWkA3snpWlVVncKlFNgJp8xBnuYv8LsOM+nRVkcMxe0Zpi9Cx6h/QiZnHbTWesCg2Z2zGez6S8+EsT982B78Ens4ofyBoITx9CWcqpMkvH7dDFCy4fW9FbHQB5/nnume0EipXOheK6x4QUMFpn1M="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '283' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":6,"mensaje":"No se encontraron datos relacionados"}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 17:13:35 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 400 + message: Bad Request +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "FOOBARBAZ", "tipoOrden": "R", "fechaOperacion": + "20230829", "firma": "QcQNbps5QRotUTOANg6Sqg0n3vh8bv7dTZP9ViQCK6zax9myXbAVuc8fKWgAlR96gIZtW2IM9OrXCdciamGGS96WkA4xOb7TPKasWctAtWIW8hdO57BTlQW5Iy/q0sGeVxGPHLbVriHNyE6DXRB08Za8HD8neot2xIZi2puJq2k="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '283' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":6,"mensaje":"No se encontraron datos relacionados"}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 17:13:36 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/tasks/cassettes/test_check_refunded_deposit.yaml b/tests/tasks/cassettes/test_check_refunded_deposit.yaml new file mode 100644 index 00000000..caec73b5 --- /dev/null +++ b/tests/tasks/cassettes/test_check_refunded_deposit.yaml @@ -0,0 +1,42 @@ +interactions: +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "Test162467872", "tipoOrden": "R", + "fechaOperacion": "20230828", "firma": "SgmhFe+ySNKghFsLscumsJmjME2Fd+grVr1qaS+q9z2Av1RF2QV88WJ51vArFI/nTWBjtmuEvfgQfU2oIY6kv2JS16M85EPLbIJPMZnKYktWBl4hMjJIxlf8OogUI8uuZsQ8PHbwPlZLayjFeOmJnP6PLxI0c9re+HF5ieRVpFQ="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '287' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":13864373,"claveRastreo":"Test162467872","conceptoPago":"Pago + de prueba","cuentaBeneficiario":"646180157018877012","cuentaOrdenante":"646580103500000006","empresa":"TAMIZI","estado":"TCL","fechaOperacion":20230828,"institucionContraparte":90646,"institucionOperante":90646,"medioEntrega":3,"monto":0.01,"nombreBeneficiario":"Beneficiario","nombreOrdenante":"CONESA","nombreCep":null,"rfcCep":"TCU200828RX8","sello":null,"rfcCurpBeneficiario":"ND","referenciaNumerica":1234567,"rfcCurpOrdenante":"ACO841030SU7","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1693246820537,"tsLiquidacion":1693246825244,"causaDevolucion":null,"urlCEP":"https://www.banxico.org.mx/cep/go?i=90646&s=20210302&d=Htx%2FNVOdUKgiu8uqML7PX3qzuFfKM8i71Qzhdi3vcyy64uMK96Sw3UAVErWMcTMIfsBqHMPiYv5%2FpWbscHEU3w%3D%3D"}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 17:49:37 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_fail_transaction_with_no_stp.yaml b/tests/tasks/cassettes/test_fail_transaction_with_no_stp.yaml index e9d33caf..8d78b954 100644 --- a/tests/tasks/cassettes/test_fail_transaction_with_no_stp.yaml +++ b/tests/tasks/cassettes/test_fail_transaction_with_no_stp.yaml @@ -1,7 +1,7 @@ interactions: - request: - body: '{"empresa": "TAMIZI", "claveRastreo": "CRINEXISTENTE", "institucionOperante": - 90646, "fechaOperacion": "20221020", "firma": "InMoA+mGcOV+z5qgKphy0lmjaeCtMpL+ns2cqbvePvJSW9//gC5bxOyUyDMeT1O6ENBCxsr9IBi22gW5p91cDxEnwC3pq1EuOXcez28dPp3pRpB93laOs3ANsaG6Q583QKbriBa1yXcT8iz1gTxqKn6OE2mFeZzFok+oINKiobY="}' + body: '{"empresa": "TAMIZI", "claveRastreo": "CRINEXISTENTE", "tipoOrden": "E", + "firma": "stqK+F6CMAImkTymhpJ2bd0JuKmjrTN6e3oSOul5us03DojeS86Eg05+jlOzfOm9xHn8sk3oqQ1kRS2Utj79pjp+BcldOCx+8yqapUIkTeTH4D2UB3e1sCc0RmJhpi4FDHVUScjAJzckZ0tX/+kHuChykxHVWWtybbxc8ihW/ic="}' headers: Accept: - '*/*' @@ -10,29 +10,32 @@ interactions: Connection: - keep-alive Content-Length: - - '299' + - '257' Content-Type: - application/json User-Agent: - - stpmex-python/3.9.1 + - stpmex-python/3.12.0 method: POST - uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/consOrdEnvRastreo + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden response: body: - string: '{"resultado":{"descripcionError":"Firma invalida No entity found for - query","id":0}}' + string: '{"estado":6,"mensaje":"No se encontraron datos relacionados"}' headers: - Content-Length: - - '84' + Connection: + - keep-alive Content-Type: - application/json Date: - - Thu, 20 Oct 2022 16:17:52 GMT - X-ORACLE-DMS-ECID: - - caf9e530-1d86-4f58-82ee-095674dc8b9c-00002ce6 - X-ORACLE-DMS-RID: - - '0' + - Wed, 25 Oct 2023 20:19:26 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers status: - code: 200 - message: OK + code: 400 + message: Bad Request version: 1 diff --git a/tests/tasks/cassettes/test_fail_transaction_with_stp_failed.yaml b/tests/tasks/cassettes/test_fail_transaction_with_stp_failed.yaml deleted file mode 100644 index 460ab5c1..00000000 --- a/tests/tasks/cassettes/test_fail_transaction_with_stp_failed.yaml +++ /dev/null @@ -1,80 +0,0 @@ -interactions: -- request: - body: '{"monto": 10.3, "conceptoPago": "PRUEBA 2", "cuentaBeneficiario": "072691004495711499", - "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": - "646180157082332965", "nombreOrdenante": "BANCO", "institucionOperante": "90646", - "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1666282229", - "referenciaNumerica": 4969905, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": - "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": - "iPruOlfR2VKQ+FN7pGlibGZF6uXv1Uskv0+53xpMg7rMyVzWWvO2M66vmAAuqX4/tl5ViX+BSDFP/sBNJAPDTvgRESwd10/iQ18b1uPn1MR6FZZ6pr4LNrVgqTZNC9PWFf/2N62TFzv4mXBdMJWfhzevqhimxD9xfJoO99f+XOQ=", - "empresa": "TAMIZI"}' - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '711' - Content-Type: - - application/json - User-Agent: - - stpmex-python/3.9.1 - method: PUT - uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra - response: - body: - string: '{"resultado":{"id":3471094}}' - headers: - Content-Length: - - '28' - Content-Type: - - application/json - Date: - - Thu, 20 Oct 2022 16:10:29 GMT - X-ORACLE-DMS-ECID: - - caf9e530-1d86-4f58-82ee-095674dc8b9c-00002cd7 - X-ORACLE-DMS-RID: - - '0' - status: - code: 200 - message: OK -- request: - body: '{"empresa": "TAMIZI", "claveRastreo": "CR1666282229", "institucionOperante": - 90646, "fechaOperacion": "20221020", "firma": "B+BcBLgNBtpCZ52nfJxxkkkmIbuXBBoCFXFJ77IU7dE6NEdRHwtbQNan77M59T79LCUnsziHVNEUp18HLW41fQdJI+imq6vzkxbpRM6GXpLbPDkOL4szGsB/gst6+CvEEq1A5+wP4APVGDyb5wBQFarZd5thTll9TEBM1mPbXQ4="}' - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '298' - Content-Type: - - application/json - User-Agent: - - stpmex-python/3.9.1 - method: POST - uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/consOrdEnvRastreo - response: - body: - string: '{"resultado":{"id":1,"ordenPago":{"clavePago":"","claveRastreo":"CR1666282229","conceptoPago":"PRUEBA - 2","conceptoPago2":"","cuentaBeneficiario":"072691004495711499","cuentaBeneficiario2":"","cuentaOrdenante":"646180157082332965","empresa":"TAMIZI","estado":"TCL","fechaOperacion":20221020,"folioOrigen":"CR1666282229","idCliente":"CR1666282229","idEF":3471094,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.30,"nombreBeneficiario":"Pablo - Sanchez","nombreBeneficiario2":"","nombreOrdenante":"Manuel Avalos Tovar","prioridad":1,"referenciaCobranza":"","referenciaNumerica":4969905,"rfcCurpBeneficiario":"ND","rfcCurpBeneficiario2":"","rfcCurpOrdenante":"AATM970329HDFVVN05","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"topologia":"V","tsCaptura":1666282229919,"usuario":"tamizi"}}}' - headers: - Content-Length: - - '840' - Content-Type: - - application/json - Date: - - Thu, 20 Oct 2022 16:10:30 GMT - X-ORACLE-DMS-ECID: - - caf9e530-1d86-4f58-82ee-095674dc8b9c-00002cd8 - X-ORACLE-DMS-RID: - - '0' - status: - code: 200 - message: OK -version: 1 diff --git a/tests/tasks/cassettes/test_fail_transaction_with_stp_succeeded.yaml b/tests/tasks/cassettes/test_fail_transaction_with_stp_succeeded.yaml index 58cbc3c0..af4562e8 100644 --- a/tests/tasks/cassettes/test_fail_transaction_with_stp_succeeded.yaml +++ b/tests/tasks/cassettes/test_fail_transaction_with_stp_succeeded.yaml @@ -1,12 +1,12 @@ interactions: - request: - body: '{"monto": 10.2, "conceptoPago": "PRUEBA", "cuentaBeneficiario": "072691004495711499", + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 7789", "cuentaBeneficiario": "072691004495711499", "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": - "646180157082332965", "nombreOrdenante": "BANCO", "institucionOperante": "90646", - "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1666281944", - "referenciaNumerica": 3463971, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698264838", + "referenciaNumerica": 7236417, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": - "y5oD/k6CfEIiF19rZGyRfaWCg5iakqocivqUG0r3xLDRexa1ANyliS6f8A8yvcGR+ZD67W2gKltJDVoXUq3BwIbySsCQf/cqU7+eO5qeg0B+4/K1R0jiEgK0EhKvGHzL9205cbnhto1QPVWe4CTNp1i8Je9RPF6KMr7X8vfURdc=", + "EFo1uzrhRol2FDsdyXLqEF221ChcHjKd9QEr0wsjtwilSoYzOzuzD66iI9Z5EzwbohJYH4/iQOLM0/G4BgEMjBrFn7yS7tYz3IhuDdVHcksFgkWucwMBjKqmgEHX9dmPlDV3bzTI8+KKWKGp8MY+n6/CnTdUTY4A4sOg27R6JPQ=", "empresa": "TAMIZI"}' headers: Accept: @@ -16,33 +16,33 @@ interactions: Connection: - keep-alive Content-Length: - - '709' + - '714' Content-Type: - application/json User-Agent: - - stpmex-python/3.9.1 + - stpmex-python/3.12.0 method: PUT uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra response: body: - string: '{"resultado":{"id":3471091}}' + string: '{"resultado":{"id":21785011}}' headers: Content-Length: - - '28' + - '29' Content-Type: - application/json Date: - - Thu, 20 Oct 2022 16:05:45 GMT + - Wed, 25 Oct 2023 20:13:58 GMT X-ORACLE-DMS-ECID: - - caf9e530-1d86-4f58-82ee-095674dc8b9c-00002cc2 + - bc722c26-d789-4f18-88dc-059072b5d031-000036ae X-ORACLE-DMS-RID: - '0' status: code: 200 message: OK - request: - body: '{"empresa": "TAMIZI", "claveRastreo": "CR1666281944", "institucionOperante": - 90646, "fechaOperacion": "20221020", "firma": "zFz/OYlOmDa8HofzlcjNXIPgxSPKOVmunV62AVIxsmHRxY5kPCVHvsTjra2shPnrsNSMlxHifVSKAy35qNzW8VqMJmSPa5vnN6sFq9Kt5s4QBztFRXsV2TByhg1w4GwmLm90On1GtTo0ZnMF1XF3+y5kMoEAJg/Fpn5XkCu+I5E="}' + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698264838", "tipoOrden": "E", + "firma": "lVJ6zR1Hctsl41ifQAvTWW8HFlde9bgCmF1zZiIzru1Zi0/gdHW7aMKkZD24TEl5V3/saAPFoSHzgoDaI8MvP+FUj/Eml6nncXoshD9/EuiheBY3HYsYtgJmkmIxdSX096Kqk4cQAbU4ouCIyyJNYH3O7RxTY4atmbsbM7I+E5g="}' headers: Accept: - '*/*' @@ -51,28 +51,33 @@ interactions: Connection: - keep-alive Content-Length: - - '298' + - '256' Content-Type: - application/json User-Agent: - - stpmex-python/3.9.1 + - stpmex-python/3.12.0 method: POST - uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/consOrdEnvRastreo + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden response: body: - string: '{"resultado":{"id":1,"ordenPago":{"clavePago":"","claveRastreo":"CR1666281944","conceptoPago":"PRUEBA","conceptoPago2":"","cuentaBeneficiario":"072691004495711499","cuentaBeneficiario2":"","cuentaOrdenante":"646180157082332965","empresa":"TAMIZI","estado":"A","fechaOperacion":20221020,"folioOrigen":"CR1666281944","idCliente":"CR1666281944","idEF":3471091,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.20,"nombreBeneficiario":"Pablo - Sanchez","nombreBeneficiario2":"","nombreOrdenante":"Manuel Avalos Tovar","prioridad":1,"referenciaCobranza":"","referenciaNumerica":3463971,"rfcCurpBeneficiario":"ND","rfcCurpBeneficiario2":"","rfcCurpOrdenante":"AATM970329HDFVVN05","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"topologia":"V","tsCaptura":1666281945447,"usuario":"tamizi"}}}' + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21785011,"claveRastreo":"CR1698264838","conceptoPago":"PRUEBA + 7789","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"LQ","fechaOperacion":20231025,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"vIDTWhXOZ1FC8HdteHCXctGW0a/UcI1p4wib73BpR1FmOhytO8toxzp3hWqb3pthm6YcZRD+CzD/W5ARkuBPUA==","rfcCurpBeneficiario":"ND","referenciaNumerica":7236417,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698264838951,"tsLiquidacion":1698264842784,"causaDevolucion":null,"urlCEP":"https://www.banxico.org.mx/cep/go?i=90646&s=20210302&d=CoI8uNTMT%2FRKK9Pg2eqKMmPySbMjchOypQh%2FHOQQyJOfTU9JCK1K2HkHtFsDFOkfdRNawGb9mCeIfcrE7f23Kw%3D%3D"}}' headers: - Content-Length: - - '838' + Connection: + - keep-alive Content-Type: - application/json Date: - - Thu, 20 Oct 2022 16:05:45 GMT - X-ORACLE-DMS-ECID: - - caf9e530-1d86-4f58-82ee-095674dc8b9c-00002cc3 - X-ORACLE-DMS-RID: - - '0' + - Wed, 25 Oct 2023 20:14:04 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers status: code: 200 message: OK diff --git a/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698096580-failed].yaml b/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698096580-failed].yaml new file mode 100644 index 00000000..dfe37436 --- /dev/null +++ b/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698096580-failed].yaml @@ -0,0 +1,43 @@ +interactions: +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698096580", "tipoOrden": "E", + "fechaOperacion": "20231023", "firma": "iFPQsrznw187U3jav3pCFaKU7Qesb2HUaVTTwIWOeAmmi+ujPLaoqqvRuwJr/ORzbT6mWeDNcU+c745uzNoW3AC8dWp8DljHQSP9oN0bMEzVyLxLF5ju88Zt9XuHhbhrdax42C5YL0wectEm/3axX9eXPlc2YRyFIfKMjhUcomA="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '286' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21776485,"claveRastreo":"CR1698096580","conceptoPago":"PRUEBA + 1485","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"D","fechaOperacion":20231023,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"JfWdH7zgqd30axI1ihVdXYa3UPLDBRBsYjj3bPjDYWcrGBKRFkAVHmRxic9uYr6x04CeLddlThZ2ICIZdfRzpA==","rfcCurpBeneficiario":"ND","referenciaNumerica":2658438,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698096580763,"tsLiquidacion":1698096586371,"causaDevolucion":1,"urlCEP":null}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:29:37 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698101998-failed].yaml b/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698101998-failed].yaml new file mode 100644 index 00000000..6dbd8051 --- /dev/null +++ b/tests/tasks/cassettes/test_retrieve_transfer_status_when_stp_id_is_not_none[CR1698101998-failed].yaml @@ -0,0 +1,43 @@ +interactions: +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698101998", "tipoOrden": "E", + "fechaOperacion": "20231023", "firma": "lpbvPqSsR8DTnILaN2yiB3pe3PSZtahyRtMoSQ2h0PzKRiEvxwaUxEijJf/orNy4WZ5JEcYtNZrurk5MHAHDYZkU/NTDg8kw7odn7uDiUFeO+7HnhlgB9aJj/BkdZ0SUZSVwWxYLdRFwelMK3iuoRn1zmcYAgiTDprvQlwAavps="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '286' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21776654,"claveRastreo":"CR1698101998","conceptoPago":"PRUEBA + 5409","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"CN","fechaOperacion":20231023,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"611Aw1PJw9A1XN10jVUsh8RgSmfcUX5OPpM+0JGe/DJY7BraV+1zoEUIjhoqY/mIrdLcF7S6+ZEpUMRekDnJnQ==","rfcCurpBeneficiario":"ND","referenciaNumerica":2403350,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698101999159,"tsLiquidacion":null,"causaDevolucion":null,"urlCEP":null}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:29:40 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_fail_transaction_not_working_day.yaml b/tests/tasks/cassettes/test_retry_transfer_already_failed.yaml similarity index 61% rename from tests/tasks/cassettes/test_fail_transaction_not_working_day.yaml rename to tests/tasks/cassettes/test_retry_transfer_already_failed.yaml index 87373df0..18a413e1 100644 --- a/tests/tasks/cassettes/test_fail_transaction_not_working_day.yaml +++ b/tests/tasks/cassettes/test_retry_transfer_already_failed.yaml @@ -1,12 +1,12 @@ interactions: - request: - body: '{"monto": 10.0, "conceptoPago": "PRUEBA 9524", "cuentaBeneficiario": "072691004495711499", + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 8070", "cuentaBeneficiario": "072691004495711499", "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": - "646180157082332965", "nombreOrdenante": "BANCO", "institucionOperante": "90646", - "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1667947295", - "referenciaNumerica": 9813989, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698366540", + "referenciaNumerica": 9486455, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": - "Ycjv5bE2NWQ6jJAtcddaKGRmZJBAk2EICyBLDO5we9YFYcj5ymjIB2RMUcxgPe5g2MPs5UhOBVAGHf223Eu/P4IJsaMg7GwKdv0e6hJsXKvlfEJgljuwgYKzoDjDtjTmfOw9yiKUgm1h0xnvvd/OXkdMJ9AM+a/zJpTxxAPfM+E=", + "dEzSpoMpp+WvzgoYtXcruMMdK0Q/qqsUkwnh8vwOFXaph5e8BitET8Y/HWDa9xfODsNA4u7ChxA19fYhEZVF2FNtDlMb7hv7HgOKda/vHWwWcYtKo9/oUIndnCZecb0+BGgLOqCgOOdp4y9qndDj2bMs/jK27kLYtPrt7nmCt4U=", "empresa": "TAMIZI"}' headers: Accept: @@ -20,21 +20,21 @@ interactions: Content-Type: - application/json User-Agent: - - stpmex-python/3.9.3.dev0 + - stpmex-python/3.13.0 method: PUT uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra response: body: - string: '{"resultado":{"id":4476052}}' + string: '{"resultado":{"id":21787417}}' headers: Content-Length: - - '28' + - '29' Content-Type: - application/json Date: - - Tue, 08 Nov 2022 22:41:36 GMT + - Fri, 27 Oct 2023 00:29:01 GMT X-ORACLE-DMS-ECID: - - d26d7b05-0759-4d96-b1fc-1060b5c5f50e-00002692 + - bc722c26-d789-4f18-88dc-059072b5d031-0001617e X-ORACLE-DMS-RID: - '0' status: diff --git a/tests/tasks/cassettes/test_retry_transfers_submitted.yaml b/tests/tasks/cassettes/test_retry_transfers_submitted.yaml new file mode 100644 index 00000000..4af3d033 --- /dev/null +++ b/tests/tasks/cassettes/test_retry_transfers_submitted.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 7808", "cuentaBeneficiario": "072691004495711499", + "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698262324", + "referenciaNumerica": 4605443, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": + "goEuc+OwioYLqj9W+1z9qFW076EGzIkLxicej/U6Ks2FFZBau4BuYwi6I9xsnyDHaJ/r8oMZybnWdmj9HIrc/i7LUgo6+V+5K7+7iD/2vkc/vhK0aSms5zgKNSm7EsMgDGtFGNwiniqwPUzw8YtVEZUnmkNtuJKYvBO5WMYQ9Pw=", + "empresa": "TAMIZI"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '714' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: PUT + uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra + response: + body: + string: '{"resultado":{"id":21784922}}' + headers: + Content-Length: + - '29' + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:32:05 GMT + X-ORACLE-DMS-ECID: + - bc722c26-d789-4f18-88dc-059072b5d031-000035ac + X-ORACLE-DMS-RID: + - '0' + status: + code: 200 + message: OK +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698262324", "tipoOrden": "E", + "firma": "ngOZMGoxii5wen5IxT/xRiPUo1g0M1BMpk7dn/9s2S+7hMS9+KHEiPU9qgr4NYaWuUJhvvnV8TrZaLW0oQOngIAeK6fHogCfbREWGfLGPdROuDJVfgwbknOlnChaiy1weOGT8+VNV9NsioIGP8aqf+uLvMWfdUj4JBK4cZHtKek="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '256' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21784922,"claveRastreo":"CR1698262324","conceptoPago":"PRUEBA + 7808","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"A","fechaOperacion":20231025,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"NujPKbKrWGoLYXpZPWCdIDY7PdGHw1OeUWUnjUE1d7nvJE4jqVajHhdiUAans7nGjqA4GjvxkXja2D4PZ3ym7Q==","rfcCurpBeneficiario":"ND","referenciaNumerica":4605443,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698262325261,"tsLiquidacion":null,"causaDevolucion":null,"urlCEP":null}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:32:06 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_not_found_in_api.yaml b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_not_found_in_api.yaml new file mode 100644 index 00000000..6df0aff7 --- /dev/null +++ b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_not_found_in_api.yaml @@ -0,0 +1,43 @@ +interactions: +- request: + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 8060", "cuentaBeneficiario": "072691004495711499", + "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698363753", + "referenciaNumerica": 8409977, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": + "WQ10pllVAc1vE7SK/yKJx9CFfOOPVzlcPfepVO998T69wDI+qNo4uWjd8CuxbF74zFd2F3oH5G6MgDKbdVNGgUifVZSSUNS8IeSQ5edymahP6b+NmBX0idmdJpVzrhWpxf1+9FqUgrBK8gYYEqjeIf+sYntj+4q5TspjuUnebgk=", + "empresa": "TAMIZI"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '714' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.13.0 + method: PUT + uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra + response: + body: + string: '{"resultado":{"id":21787172}}' + headers: + Content-Length: + - '29' + Content-Type: + - application/json + Date: + - Thu, 26 Oct 2023 23:42:34 GMT + X-ORACLE-DMS-ECID: + - bc722c26-d789-4f18-88dc-059072b5d031-00016096 + X-ORACLE-DMS-RID: + - '0' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_unhandled_status.yaml b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_unhandled_status.yaml new file mode 100644 index 00000000..5c9191e3 --- /dev/null +++ b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_but_unhandled_status.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 7243", "cuentaBeneficiario": "072691004495711499", + "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698365494", + "referenciaNumerica": 6224447, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": + "uWRUIURdRE75pP1XXTdFRNchxN+w537JYmqZvL/2+GjujhkL3z9tqxb5I48ZUbAnsT8F9Waur9gOR25ARbCCkYO6JbsObUVgNwDW5WQhl3I1O8G6W3PMX77m6k+ZXnbdx0ynBYrQfHquIKETl5RPiWx52w9xfZWhaVG9rQg8vNE=", + "empresa": "TAMIZI"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '714' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.13.0 + method: PUT + uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra + response: + body: + string: '{"resultado":{"id":21787203}}' + headers: + Content-Length: + - '29' + Content-Type: + - application/json + Date: + - Fri, 27 Oct 2023 00:11:36 GMT + X-ORACLE-DMS-ECID: + - bc722c26-d789-4f18-88dc-059072b5d031-00016134 + X-ORACLE-DMS-RID: + - '0' + status: + code: 200 + message: OK +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698365494", "tipoOrden": "E", + "fechaOperacion": "20231027", "firma": "wzk7xxPDg9sHF04wXGMGALdr+7RSb6TQWm7ALO49Wx/kBGIXLfWzqzriifIhyrfNeJk5AyDYcm2uTCU2a4gKicjpXHuyyiEzQzx3tVkI7Vk5gTvY66Zn4uOE7OwaqbElc4an6uIosYNkoqtX+QPBs3y8MGFqIQjr42mbQBPSkDk="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '286' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.13.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21787203,"claveRastreo":"CR1698365494","conceptoPago":"PRUEBA + 7243","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"L","fechaOperacion":20231027,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"ezdNCEax5YmpqHVNYFny4Ddd0PAXvyUqItMsUy8S7BMoQgoP4+AHGmaLqPsoLDjFadZF/fqTaJqI8kKCeQCPJg==","rfcCurpBeneficiario":"ND","referenciaNumerica":6224447,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698365496834,"tsLiquidacion":null,"causaDevolucion":null,"urlCEP":null}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 27 Oct 2023 00:11:44 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_retry_transfers_with_stp_id_succeeded.yaml b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_succeeded.yaml new file mode 100644 index 00000000..00facb73 --- /dev/null +++ b/tests/tasks/cassettes/test_retry_transfers_with_stp_id_succeeded.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 9032", "cuentaBeneficiario": "072691004495711499", + "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698261906", + "referenciaNumerica": 4188700, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": + "hOhmHGKSp3daMLWm3bjachIeeNiMsLKSHZqOxaYAbAq4aeOUvNPHZ/qA/fzaVbUULdqHVHsmJeo0viwtPLlHmjosLZIGXwyCI1hmMjLpK/cBQstqEVVJcemUsebp7NURqYSjs1xkKPdtlRbGfDDir1fzWGZPpu3QNdsGT6sR2pE=", + "empresa": "TAMIZI"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '714' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: PUT + uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra + response: + body: + string: '{"resultado":{"id":21784919}}' + headers: + Content-Length: + - '29' + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:25:07 GMT + X-ORACLE-DMS-ECID: + - bc722c26-d789-4f18-88dc-059072b5d031-00003569 + X-ORACLE-DMS-RID: + - '0' + status: + code: 200 + message: OK +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698261906", "tipoOrden": "E", + "firma": "tjVc2F6HTsEd4FR75nxDeXvfo7dZ9m029JdDEAr2doU9th1o2ljJMsZ83jHmyAHU1SD9LQuiFRGpLRHxxbeS8HQjqP6K+4q6py0Ez9l4lu4gQjn7xUfzMDX9SvJxGNgeMW/93kr/yCoB1ymj9pD1S5kTDdrHALO90+aw3+d3tjE="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '256' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.12.0 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":0,"mensaje":"Datos consultados correctamente","respuesta":{"idEF":21784919,"claveRastreo":"CR1698261906","conceptoPago":"PRUEBA + 9032","cuentaBeneficiario":"072691004495711499","cuentaOrdenante":"646180157018613700","empresa":"TAMIZI","estado":"LQ","fechaOperacion":20231025,"institucionContraparte":40072,"institucionOperante":90646,"medioEntrega":3,"monto":10.00,"nombreBeneficiario":"Pablo + Sanchez","nombreOrdenante":"JUAN PEREZ PEREZ","nombreCep":null,"rfcCep":null,"sello":"w8jt79r1A3xyToW1XTDXhgo6hWnHzjo96PI+kDOg0KkLuIX2AB69kDXMoJK+Bpahr9WCu8zmJdyQAWRP5ZV3jg==","rfcCurpBeneficiario":"ND","referenciaNumerica":4188700,"rfcCurpOrdenante":"PEPJ800101HCSPRL02","tipoCuentaBeneficiario":40,"tipoCuentaOrdenante":40,"tipoPago":1,"tsCaptura":1698261907433,"tsLiquidacion":null,"causaDevolucion":null,"urlCEP":null}}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Wed, 25 Oct 2023 19:25:08 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 200 + message: OK +version: 1 diff --git a/tests/tasks/cassettes/test_transaction_submitted_but_not_found_in_stp.yaml b/tests/tasks/cassettes/test_transaction_submitted_but_not_found_in_stp.yaml new file mode 100644 index 00000000..9ed151df --- /dev/null +++ b/tests/tasks/cassettes/test_transaction_submitted_but_not_found_in_stp.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: '{"monto": 10.0, "conceptoPago": "PRUEBA 67", "cuentaBeneficiario": "072691004495711499", + "nombreBeneficiario": "Pablo Sanchez", "institucionContraparte": "40072", "cuentaOrdenante": + "646180157018613700", "nombreOrdenante": "BANCO", "institucionOperante": "90646", + "tipoCuentaBeneficiario": 40, "tipoCuentaOrdenante": 40, "claveRastreo": "CR1698792478", + "referenciaNumerica": 5055033, "rfcCurpBeneficiario": "ND", "rfcCurpOrdenante": + "ND", "prioridad": 1, "medioEntrega": 3, "tipoPago": 1, "topologia": "T", "firma": + "zsZmhH6RPQak/cSuWajEFW/pFOp675+9dfdokxQC9FaVRe2AZvEdlUhhLzdxhGoLJ9GM6J34qWYI12Qphk94PAYIGb60wFSyBqBaYEw2iKlMk1p+V4uXVFyx5kjBufXdkztTovIW5xRc8ZFC4qNsBCpCrxgu74O4tO0TGhvpU0g=", + "empresa": "TAMIZI"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '712' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.13.1 + method: PUT + uri: https://demo.stpmex.com:7024/speiws/rest/ordenPago/registra + response: + body: + string: '{"resultado":{"id":21803106}}' + headers: + Content-Length: + - '29' + Content-Type: + - application/json + Date: + - Tue, 31 Oct 2023 22:47:58 GMT + X-ORACLE-DMS-ECID: + - b7682f19-20a2-42e8-b319-67c390954dd5-0000136f + X-ORACLE-DMS-RID: + - '0' + status: + code: 200 + message: OK +- request: + body: '{"empresa": "TAMIZI", "claveRastreo": "CR1698792478", "tipoOrden": "E", + "fechaOperacion": "20231030", "firma": "R/lQ3YqRG7AGkNNE7CMt6oHHyD0/FvrUvB8byv29oXiJv+K7oXgaiMuMMHpyALfH5wcf09h+Y5C1YwU98FdumWWaTod0nx/kzoRCe76QQkrNFZ/DEADdxZ4laB6b8e8IGkmYWnVo+nPn5bCrEEPi1Wr0412ouBFJTnyjPmG8ps0="}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '286' + Content-Type: + - application/json + User-Agent: + - stpmex-python/3.13.1 + method: POST + uri: https://efws-dev.stpmex.com/efws/API/consultaOrden + response: + body: + string: '{"estado":6,"mensaje":"No se encontraron datos relacionados"}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Tue, 31 Oct 2023 22:48:00 GMT + Server: + - nginx + Transfer-Encoding: + - chunked + Vary: + - Origin + - Access-Control-Request-Method + - Access-Control-Request-Headers + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/tasks/test_orders.py b/tests/tasks/test_orders.py index c97a3d21..d231a76d 100644 --- a/tests/tasks/test_orders.py +++ b/tests/tasks/test_orders.py @@ -4,7 +4,6 @@ from unittest.mock import MagicMock, patch import pytest -import vcr from freezegun import freeze_time from stpmex.exc import ( AccountDoesNotExist, @@ -21,11 +20,11 @@ MalformedOrderException, ResendSuccessOrderException, ScheduleError, + TransactionNeedManualReviewError, ) from speid.models import Transaction from speid.tasks.orders import execute, retry_timeout, send_order from speid.types import Estado, EventType, TipoTransaccion -from speid.validations import factory @pytest.fixture @@ -62,7 +61,6 @@ def test_worker_with_incorrect_version( transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.error - transaction.delete() def test_worker_without_version(default_internal_request, mock_callback_queue): @@ -73,7 +71,6 @@ def test_worker_without_version(default_internal_request, mock_callback_queue): transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.error - transaction.delete() def test_malformed_order_worker(order, mock_callback_queue): @@ -83,7 +80,6 @@ def test_malformed_order_worker(order, mock_callback_queue): transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.error - transaction.delete() @pytest.mark.vcr @@ -95,7 +91,6 @@ def test_create_order_debit_card(order, physical_account): assert transaction.estado is Estado.submitted assert transaction.events[-1].type is EventType.completed assert transaction.tipo is TipoTransaccion.retiro - transaction.delete() @pytest.mark.vcr @@ -107,7 +102,6 @@ def test_worker_with_version_2(order, physical_account): assert transaction.estado is Estado.submitted assert transaction.events[-1].type is EventType.completed assert transaction.tipo is TipoTransaccion.retiro - transaction.delete() @pytest.mark.vcr @@ -123,8 +117,6 @@ def test_ignore_invalid_account_type( send_order(order) mock_retry.assert_not_called() mock_capture_exception.assert_not_called() - transaction = Transaction.objects.order_by('-created_at').first() - transaction.delete() @patch('speid.tasks.orders.capture_exception') @@ -141,8 +133,6 @@ def test_ignore_transfers_to_blocked_banks( send_order(order) mock_retry.assert_not_called() mock_capture_exception.assert_not_called() - transaction = Transaction.objects.order_by('-created_at').first() - transaction.delete() @patch('speid.tasks.orders.capture_exception') @@ -154,9 +144,6 @@ def test_malformed_order_exception( mock_capture_exception.assert_called_once() - transaction = Transaction.objects.order_by('-created_at').first() - transaction.delete() - @patch('speid.tasks.orders.execute', side_effect=Exception()) @patch('speid.tasks.orders.capture_exception') @@ -169,14 +156,23 @@ def test_retry_on_unexpected_exception( mock_capture_exception.assert_called_once() +@patch( + 'speid.tasks.orders.execute', + side_effect=TransactionNeedManualReviewError('sp1', 'error'), +) +@patch('speid.tasks.orders.capture_exception') +def test_doesnt_retry_on_manual_review_exception( + mock_capture_exception: MagicMock, _, order +): + send_order(order) + mock_capture_exception.assert_called_once() + + def test_hold_max_amount(order): order['monto'] = 102000000 with pytest.raises(MalformedOrderException): execute(order) - transaction = Transaction.objects.order_by('-created_at').first() - transaction.delete() - @patch('speid.tasks.orders.capture_exception') @patch('speid.tasks.orders.send_order.retry') @@ -191,7 +187,6 @@ def test_stp_schedule_limit( mock_capture_exception.assert_called_once() -@vcr.use_cassette('tests/tasks/cassettes/test_resend_not_success_order.yaml') @pytest.mark.parametrize( 'exc', [ @@ -215,15 +210,6 @@ def test_resend_not_success_order(exc, order, mock_callback_queue): transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.failed - # Ejecuta nuevamente la misma orden - execute(order) - - transaction.reload() - assert transaction.events[-2].type is EventType.retry - assert transaction.estado is Estado.submitted - - transaction.delete() - @pytest.mark.vcr def test_resend_success_order(order): @@ -235,82 +221,54 @@ def test_resend_success_order(order): # Ejecuta nuevamente la misma orden with pytest.raises(ResendSuccessOrderException): execute(order) - transaction.delete() @pytest.mark.vcr() -@freeze_time('2022-11-08 10:00:00') -def test_fail_transaction_with_stp_succeeded(order, mock_callback_queue): +@freeze_time('2023-10-25 14:00:00') +def test_fail_transaction_with_stp_succeeded( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta execute(order) transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.submitted # changing time to 4 hours ago so transaction fails in the next step transaction.created_at = datetime.utcnow() - timedelta(hours=4) + # Simulate that we lost `stp_id` for any reason + transaction.stp_id = None transaction.save() # executing again so time assert fails execute(order) - # status didn't change because transaction was succesful in STP + # status didn't change because transaction was 'Autorizada' in STP assert transaction.estado is Estado.submitted - transaction.delete() @pytest.mark.vcr() -@freeze_time('2022-11-08 10:00:00') -def test_fail_transaction_with_stp_failed(order, mock_callback_queue): +@freeze_time('2023-10-31 14:00:00') +def test_transaction_submitted_but_not_found_in_stp( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta execute(order) transaction = Transaction.objects.order_by('-created_at').first() assert transaction.estado is Estado.submitted - # changing time to 4 hours ago so transaction fails in the next step - transaction.created_at = datetime.utcnow() - timedelta(hours=4) + # simulate that we cannot retrieve transfer data just by changing + # created_at so the original fecha_operacion changes + transaction.created_at = transaction.created_at - dt.timedelta(days=1) transaction.save() - # executing again so time assert fails - execute(order) - # status changed because transaction was failed in STP - transaction.reload() - assert transaction.estado is Estado.failed - transaction.delete() - - -@pytest.mark.vcr() -@freeze_time('2022-11-08 10:00:00') -def test_fail_transaction_with_no_stp(order, mock_callback_queue): - # new transaction so next `execute` - # finds something to send to STP - input = factory.create(order['version'], **order) - transaction = input.transform() - transaction.clave_rastreo = 'CRINEXISTENTE' - transaction.created_at = datetime.utcnow() - timedelta(hours=4) - transaction.save() - - # sending to stp - execute(order) + with pytest.raises(TransactionNeedManualReviewError): + execute(order) + # status didn't change because transaction was 'Autorizada' in STP transaction.reload() - # status changed to failed because order was not found in stp - assert transaction.estado is Estado.failed - transaction.delete() - - -@pytest.mark.vcr() -def test_fail_transaction_not_working_day(order, mock_callback_queue): - execute(order) - transaction = Transaction.objects.order_by('-created_at').first() - assert transaction.estado is Estado.submitted - # changing time to 2 days ago so transaction fails in the next step - transaction.created_at = dt.datetime(2023, 1, 1) - transaction.save() - assert not transaction.is_current_working_day() - # executing again so time assert fails - execute(order) - # status didn't change because transaction was succesful in STP assert transaction.estado is Estado.submitted - transaction.delete() @pytest.mark.vcr @freeze_time('2022-11-08 10:00:00') def test_unexpected_stp_error(order, mock_callback_queue): with patch( - 'speid.models.transaction.stpmex_client.ordenes.consulta_clave_rastreo' + 'speid.models.transaction.stpmex_client.ordenes_v2.' + 'consulta_clave_rastreo_enviada' ) as consulta_mock, patch( 'speid.models.transaction.capture_exception' ) as capture_mock: @@ -322,7 +280,154 @@ def test_unexpected_stp_error(order, mock_callback_queue): assert transaction.estado is Estado.submitted # changing time so it fails assertion transaction.created_at = datetime.utcnow() - timedelta(hours=4) + transaction.stp_id = None transaction.save() # executing again so time assert fails execute(order) capture_mock.assert_called_once() + + +@pytest.mark.vcr +def test_retry_transfers_with_stp_id_succeeded( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta + + execute(order) + + transaction = Transaction.objects.order_by('-created_at').first() + assert transaction.estado is Estado.submitted + + with patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + execute(order) + + transaction.reload() + assert transaction.estado is Estado.succeeded + mock_registra.assert_not_called() + + +@pytest.mark.vcr +def test_retry_transfers_submitted( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta + execute(order) + + transaction = Transaction.objects.order_by('-created_at').first() + assert transaction.estado is Estado.submitted + + with patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + + execute(order) + + transaction.reload() + assert transaction.estado is Estado.submitted + mock_registra.assert_not_called() + + +@pytest.mark.parametrize( + 'clave_rastreo,speid_estado', + [ + ('CR1698096580', Estado.failed), # STP status = Estado.devuelta + ('CR1698101998', Estado.failed), # STP status = Estado.cancelada + ], +) +@pytest.mark.vcr +def test_retrieve_transfer_status_when_stp_id_is_not_none( + outcome_transaction, + second_physical_account, + order, + clave_rastreo, + speid_estado, + mock_callback_queue, +): + # Transfers that we are passing in the parameter `clave_rastreo` + # were created on 2023-10-23 23:41 UTC time (fecha_operacion=2023-10-23). + # STP WS changes the status to `cancelada` or `devuelta` after + # a few minutes. That's why we cannot create the transfer and then + # retrieve the status in the same cassette. + + outcome_transaction.created_at = dt.datetime(2023, 10, 23, 23, 41) + outcome_transaction.cuenta_ordenante = second_physical_account.cuenta + outcome_transaction.clave_rastreo = clave_rastreo + outcome_transaction.save() + + order['cuenta_ordenante'] = second_physical_account.cuenta + order['speid_id'] = outcome_transaction.speid_id + + with patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + execute(order) + + transfer = Transaction.objects.get(clave_rastreo=clave_rastreo) + assert transfer.estado is speid_estado + mock_registra.assert_not_called() + + +@pytest.mark.vcr +def test_retry_transfers_with_stp_id_but_not_found_in_api( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta + execute(order) + + transaction = Transaction.objects.order_by('-created_at').first() + assert transaction.estado is Estado.submitted + + with patch( + 'speid.models.transaction.Transaction.fetch_stp_status', + return_value=None, + ), patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + with pytest.raises(TransactionNeedManualReviewError): + execute(order) + + transaction.reload() + assert transaction.estado is Estado.submitted + mock_registra.assert_not_called() + + +@pytest.mark.vcr +def test_retry_transfers_with_stp_id_but_unhandled_status( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta + execute(order) + + transaction = Transaction.objects.order_by('-created_at').first() + assert transaction.estado is Estado.submitted + + with patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + with pytest.raises(TransactionNeedManualReviewError): + execute(order) + + transaction.reload() + assert transaction.estado is Estado.submitted + mock_registra.assert_not_called() + + +@pytest.mark.vcr +def test_retry_transfer_already_failed( + order, second_physical_account, mock_callback_queue +): + order['cuenta_ordenante'] = second_physical_account.cuenta + execute(order) + + transaction = Transaction.objects.order_by('-created_at').first() + # Changing to error state so we can simulate a failed trx + transaction.estado = Estado.error + transaction.save() + with patch( + 'speid.models.transaction.stpmex_client.ordenes.registra' + ) as mock_registra: + execute(order) + + mock_registra.assert_not_called() diff --git a/tests/tasks/test_transactions.py b/tests/tasks/test_transactions.py index b695c26e..5d8e5e68 100644 --- a/tests/tasks/test_transactions.py +++ b/tests/tasks/test_transactions.py @@ -4,9 +4,11 @@ import pytest from celery.exceptions import MaxRetriesExceededError, Retry from cep.exc import CepError, MaxRequestError +from mongoengine import DoesNotExist from speid.models import Transaction from speid.tasks.transactions import ( + check_deposits_status, process_outgoing_transactions, retry_incoming_transactions, send_transaction_status, @@ -410,3 +412,75 @@ def test_send_transaction_not_restricted_accounts_persona_fisica( nombre_beneficiario=None, ), ) + + +@patch('celery.Celery.send_task') +@pytest.mark.vcr +def test_check_existing_deposit(mock_send_task) -> None: + req = dict( + clave_rastreo='Test162467872', + cuenta_beneficiario='646180157018877012', + fecha_operacion='2023-08-28', + ) + check_deposits_status(req) + transaction = Transaction.objects.get(clave_rastreo=req['clave_rastreo']) + assert transaction + assert transaction.cuenta_beneficiario == req['cuenta_beneficiario'] + assert transaction.fecha_operacion.date() == dt.date.fromisoformat( + req['fecha_operacion'] + ) + assert transaction.estado is Estado.succeeded + mock_send_task.assert_called_once() + + +@patch('celery.Celery.send_task') +@pytest.mark.vcr +def test_check_not_existing_deposit(mock_send_task) -> None: + req = dict( + clave_rastreo='FOOBARBAZ', + cuenta_beneficiario='646180157018877012', + fecha_operacion='2023-08-28', + ) + check_deposits_status(req) + with pytest.raises(DoesNotExist): + Transaction.objects.get(clave_rastreo=req['clave_rastreo']) + mock_send_task.assert_not_called() + + +@patch('celery.Celery.send_task') +@pytest.mark.vcr +def test_check_refunded_deposit(mock_send_task): + req = dict( + clave_rastreo='Test162467872', + cuenta_beneficiario='646180157018877012', + fecha_operacion='2023-08-28', + ) + check_deposits_status(req) + with pytest.raises(DoesNotExist): + Transaction.objects.get(clave_rastreo=req['clave_rastreo']) + mock_send_task.assert_not_called() + + +@patch('celery.Celery.send_task') +@patch('speid.tasks.transactions.process_incoming_transaction') +def test_retry_incoming_transaction( + mock_process_incoming_transaction, + mock_send_task, + default_income_transaction, + client, +): + resp = client.post('/ordenes', json=default_income_transaction) + assert resp.status_code == 201 + fecha_operacion = str(default_income_transaction['FechaOperacion']) + + req = dict( + clave_rastreo=default_income_transaction['ClaveRastreo'], + cuenta_beneficiario=default_income_transaction['CuentaBeneficiario'], + fecha_operacion=( + f'{fecha_operacion[0:4]}-' + f'{fecha_operacion[4:6]}-{fecha_operacion[6:]}' + ), + ) + check_deposits_status(req) + mock_process_incoming_transaction.assert_not_called() + mock_send_task.assert_called() diff --git a/tests/views/conftest.py b/tests/views/conftest.py index f0156f65..75e69458 100644 --- a/tests/views/conftest.py +++ b/tests/views/conftest.py @@ -1,14 +1,5 @@ import pytest -from speid import app - - -@pytest.fixture -def client(): - app.testing = True - client = app.test_client() - return client - @pytest.fixture def default_blocked_transaction(): @@ -54,26 +45,3 @@ def default_blocked_incoming_transaction(): ReferenciaNumerica=2423, Empresa="TAMIZI", ) - - -@pytest.fixture -def default_income_transaction(): - return dict( - Clave=2456303, - FechaOperacion=20180618, - InstitucionOrdenante=40012, - InstitucionBeneficiaria=90646, - ClaveRastreo="PRUEBATAMIZI1", - Monto=100.0, - NombreOrdenante="BANCO", - TipoCuentaOrdenante=40, - CuentaOrdenante="846180000500000008", - RFCCurpOrdenante="ND", - NombreBeneficiario="TAMIZI", - TipoCuentaBeneficiario=40, - CuentaBeneficiario="646180157000000004", - RFCCurpBeneficiario="ND", - ConceptoPago="PRUEBA", - ReferenciaNumerica=2423, - Empresa="TAMIZI", - )