Skip to content

Commit 0493dab

Browse files
committed
test check deposits
1 parent cb1fdd2 commit 0493dab

11 files changed

+387
-77
lines changed

speid/commands/spei.py

+11-33
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,21 @@
44
import pytz
55
from mongoengine import DoesNotExist
66
from stpmex.business_days import get_next_business_day
7-
from stpmex.types import Estado as StpEstado
87

98
from speid import app
109
from speid.helpers.callback_helper import set_status_transaction
11-
from speid.helpers.transaction_helper import process_incoming_transaction
10+
from speid.helpers.transaction_helper import (
11+
process_incoming_transaction,
12+
stp_model_to_dict,
13+
)
1214
from speid.models import Event, Transaction
15+
from speid.models.transaction import (
16+
REFUNDS_PAYMENTS_TYPES,
17+
STP_VALID_DEPOSITS_STATUSES,
18+
)
1319
from speid.processors import stpmex_client
1420
from speid.types import Estado, EventType
1521

16-
ESTADOS_DEPOSITOS_VALIDOS = {
17-
StpEstado.confirmada,
18-
StpEstado.liquidada,
19-
StpEstado.traspaso_liquidado,
20-
}
21-
22-
TIPOS_PAGO_DEVOLUCION = {0, 16, 17, 18, 23, 24}
23-
2422

2523
@app.cli.group('speid')
2624
def speid_group():
@@ -87,11 +85,11 @@ def reconciliate_deposits(
8785
# Se ignora los tipos pago devolución debido a que
8886
# el estado de estas operaciones se envían
8987
# al webhook `POST /orden_events`
90-
if recibida.tipoPago in TIPOS_PAGO_DEVOLUCION:
88+
if recibida.tipoPago in REFUNDS_PAYMENTS_TYPES:
9189
no_procesadas.append(recibida.claveRastreo)
9290
continue
9391

94-
if recibida.estado not in ESTADOS_DEPOSITOS_VALIDOS:
92+
if recibida.estado not in STP_VALID_DEPOSITS_STATUSES:
9593
no_procesadas.append(recibida.claveRastreo)
9694
continue
9795

@@ -105,27 +103,7 @@ def reconciliate_deposits(
105103
# hace una conversión del modelo de respuesta de
106104
# la función `consulta_recibidas` al modelo del evento que envía
107105
# STP por el webhook en `POST /ordenes`
108-
stp_request = dict(
109-
Clave=recibida.idEF,
110-
FechaOperacion=recibida.fechaOperacion.strftime('%Y%m%d'),
111-
InstitucionOrdenante=recibida.institucionContraparte,
112-
InstitucionBeneficiaria=recibida.institucionOperante,
113-
ClaveRastreo=recibida.claveRastreo,
114-
Monto=recibida.monto,
115-
NombreOrdenante=recibida.nombreOrdenante,
116-
TipoCuentaOrdenante=recibida.tipoCuentaOrdenante,
117-
CuentaOrdenante=recibida.cuentaOrdenante,
118-
RFCCurpOrdenante=recibida.rfcCurpOrdenante,
119-
NombreBeneficiario=recibida.nombreBeneficiario,
120-
TipoCuentaBeneficiario=recibida.tipoCuentaBeneficiario,
121-
CuentaBeneficiario=recibida.cuentaBeneficiario,
122-
RFCCurpBeneficiario=getattr(
123-
recibida, 'rfcCurpBeneficiario', 'NA'
124-
),
125-
ConceptoPago=recibida.conceptoPago,
126-
ReferenciaNumerica=recibida.referenciaNumerica,
127-
Empresa=recibida.empresa,
128-
)
106+
stp_request = stp_model_to_dict(recibida)
129107
click.echo(f'Depósito procesado: {recibida.claveRastreo}')
130108
process_incoming_transaction(stp_request)
131109
else:

speid/helpers/transaction_helper.py

+23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from typing import Dict
23

34
from mongoengine import NotUniqueError
45
from sentry_sdk import capture_exception, capture_message
@@ -40,3 +41,25 @@ def process_incoming_transaction(incoming_transaction: dict) -> dict:
4041
transaction.save()
4142
capture_exception(e)
4243
return r
44+
45+
46+
def stp_model_to_dict(model) -> Dict:
47+
return dict(
48+
Clave=model.idEF,
49+
FechaOperacion=model.fechaOperacion.strftime('%Y%m%d'),
50+
InstitucionOrdenante=model.institucionContraparte,
51+
InstitucionBeneficiaria=model.institucionOperante,
52+
ClaveRastreo=model.claveRastreo,
53+
Monto=model.monto,
54+
NombreOrdenante=model.nombreOrdenante,
55+
TipoCuentaOrdenante=model.tipoCuentaOrdenante,
56+
CuentaOrdenante=model.cuentaOrdenante,
57+
RFCCurpOrdenante=model.rfcCurpOrdenante,
58+
NombreBeneficiario=model.nombreBeneficiario,
59+
TipoCuentaBeneficiario=model.tipoCuentaBeneficiario,
60+
CuentaBeneficiario=model.cuentaBeneficiario,
61+
RFCCurpBeneficiario=getattr(model, 'rfcCurpBeneficiario', 'NA'),
62+
ConceptoPago=model.conceptoPago,
63+
ReferenciaNumerica=model.referenciaNumerica,
64+
Empresa=model.empresa,
65+
)

speid/models/transaction.py

+25-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import datetime as dt
22
import os
33
from enum import Enum
4+
from typing import Optional
45

56
import pytz
67
from mongoengine import (
@@ -41,20 +42,29 @@
4142
os.getenv('SKIP_VALIDATION_PRIOR_SEND_ORDER', 'false').lower() == 'true'
4243
)
4344

44-
STP_FAILED_STATUSES = {
45+
STP_FAILED_TRANSFERS_STATUSES = {
4546
STPEstado.traspaso_cancelado,
4647
STPEstado.cancelada,
4748
STPEstado.cancelada_adapter,
4849
STPEstado.cancelada_rechazada,
4950
STPEstado.devuelta,
5051
}
5152

52-
STP_SUCCEDED_STATUSES = {
53+
STP_SUCCEDED_TRANSFERS_STATUSES = {
5354
STPEstado.liquidada,
5455
STPEstado.traspaso_liquidado,
5556
}
5657

5758

59+
STP_VALID_DEPOSITS_STATUSES = {
60+
STPEstado.confirmada,
61+
STPEstado.liquidada,
62+
STPEstado.traspaso_liquidado,
63+
}
64+
65+
REFUNDS_PAYMENTS_TYPES = {0, 16, 17, 18, 23, 24}
66+
67+
5868
@handler(signals.pre_save)
5969
def pre_save_transaction(sender, document):
6070
date = document.fecha_operacion or dt.datetime.today()
@@ -180,22 +190,25 @@ def is_valid_account(self) -> bool:
180190
return is_valid
181191

182192
def fetch_stp_status(self) -> STPEstado:
183-
fecha_operacion = None
184-
if (
185-
self.created_at_fecha_operacion
186-
< Transaction.current_fecha_operacion()
187-
):
188-
fecha_operacion = self.created_at_fecha_operacion
193+
# fecha_operacion = None
194+
# if (
195+
# self.created_at_fecha_operacion
196+
# < Transaction.current_fecha_operacion()
197+
# ):
198+
# fecha_operacion = self.created_at_fecha_operacion
189199

190200
stp_order = stpmex_client.ordenes_v2.consulta_clave_rastreo_enviada(
191201
clave_rastreo=self.clave_rastreo,
192-
fecha_operacion=fecha_operacion,
202+
fecha_operacion=self.created_at_fecha_operacion
203+
if self.created_at_fecha_operacion
204+
< Transaction.current_fecha_operacion()
205+
else None,
193206
)
194207
return stp_order.estado
195208

196209
def update_stp_status(self) -> None:
197210
try:
198-
status = self.fetch_stp_status()
211+
status: Optional[STPEstado] = self.fetch_stp_status()
199212
except EmptyResultsError:
200213
status = None
201214
except StpmexException as ex:
@@ -207,10 +220,10 @@ def update_stp_status(self) -> None:
207220
elif not self.stp_id and not status:
208221
self.set_state(Estado.failed)
209222
self.save()
210-
elif status in STP_FAILED_STATUSES:
223+
elif status in STP_FAILED_TRANSFERS_STATUSES:
211224
self.set_state(Estado.failed)
212225
self.save()
213-
elif status in STP_SUCCEDED_STATUSES:
226+
elif status in STP_SUCCEDED_TRANSFERS_STATUSES:
214227
self.set_state(Estado.succeeded)
215228
self.save()
216229
elif status is STPEstado.autorizada:

speid/tasks/transactions.py

+62-19
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
1-
from typing import List
1+
import datetime as dt
2+
from typing import Dict, List
23

34
import cep
45
import pytz
56
from celery.exceptions import MaxRetriesExceededError
67
from cep.exc import CepError, MaxRequestError
78
from mongoengine import DoesNotExist
8-
from stpmex.business_days import current_cdmx_time_zone
9+
from pydantic import ValidationError
10+
from stpmex.business_days import (
11+
current_cdmx_time_zone,
12+
get_next_business_day,
13+
get_prior_business_day,
14+
)
15+
from stpmex.exc import EmptyResultsError
916

1017
from speid.helpers import callback_helper
18+
from speid.helpers.transaction_helper import (
19+
process_incoming_transaction,
20+
stp_model_to_dict,
21+
)
1122
from speid.models import Account, Event, Transaction
23+
from speid.models.transaction import (
24+
REFUNDS_PAYMENTS_TYPES,
25+
STP_VALID_DEPOSITS_STATUSES,
26+
)
27+
from speid.processors import stpmex_client
1228
from speid.tasks import celery
1329
from speid.types import Estado, EventType, TipoTransaccion
30+
from speid.validations.queries import DepositStatusQuery
1431

1532
CURP_LENGTH = 18
1633
RFC_LENGTH = 13
@@ -127,25 +144,51 @@ def send_transaction_status(self, transaction_id: str, state: str) -> None:
127144
)
128145

129146

130-
@celery.task(max_retries=GET_RFC_TASK_MAX_RETRIES)
131-
def check_transfer_status(cuenta_ordenante: str, clave_rastreo: str) -> None:
147+
@celery.task
148+
def check_deposits_status(deposit: Dict) -> None:
132149
try:
133-
transaction = Transaction.objects.get(
134-
clave_rastreo=clave_rastreo, cuenta_ordenante=cuenta_ordenante
135-
)
136-
except DoesNotExist:
150+
req = DepositStatusQuery(**deposit)
151+
except ValidationError:
137152
return
138153

139-
if transaction.tipo is not TipoTransaccion.retiro:
140-
return
141-
142-
if transaction.estado in [Estado.succeeded, Estado.failed]:
143-
send_transaction_status.apply_async(
144-
[transaction.id, transaction.estado]
154+
try:
155+
transaction = Transaction.objects.get(
156+
clave_rastreo=req.clave_rastreo,
157+
cuenta_beneficiario=req.cuenta_beneficiario,
158+
tipo=TipoTransaccion.deposito,
145159
)
146-
elif transaction.estado is Estado.error:
147-
send_transaction_status.apply_async([transaction.id, Estado.failed])
148-
elif transaction.estado is Estado.created:
149-
...
150-
elif transaction.estado is Estado.submitted:
160+
except DoesNotExist:
151161
...
162+
else:
163+
retry_incoming_transactions.apply_async(([transaction.speid_id],))
164+
165+
# Si no existe en los registros se obtiene de STP y se intenta con 3 fechas
166+
# operativas próximas a la fecha que el cliente nos proporcionó
167+
fechas_operacion = [
168+
get_next_business_day(req.fecha_deposito),
169+
get_prior_business_day(req.fecha_deposito),
170+
get_next_business_day(req.fecha_deposito + dt.timedelta(days=1)),
171+
]
172+
173+
for fecha_operacion in fechas_operacion:
174+
try:
175+
recibida = (
176+
stpmex_client.ordenes_v2.consulta_clave_rastreo_recibida(
177+
clave_rastreo=req.clave_rastreo,
178+
fecha_operacion=fecha_operacion
179+
if Transaction.current_fecha_operacion() > fecha_operacion
180+
else None,
181+
)
182+
)
183+
except EmptyResultsError:
184+
...
185+
else:
186+
if (
187+
recibida.tipoPago in REFUNDS_PAYMENTS_TYPES
188+
or recibida.estado not in STP_VALID_DEPOSITS_STATUSES
189+
):
190+
return
191+
192+
stp_request = stp_model_to_dict(recibida)
193+
process_incoming_transaction(stp_request)
194+
return

speid/validations/queries.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import datetime as dt
2+
3+
from clabe import Clabe
4+
from pydantic import BaseModel
5+
6+
7+
class DepositStatusQuery(BaseModel):
8+
clave_rastreo: str
9+
cuenta_beneficiario: Clabe
10+
fecha_deposito: dt.date

tests/commands/test_spei.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import requests_mock
66
from freezegun import freeze_time
77

8-
from speid.commands.spei import (
9-
ESTADOS_DEPOSITOS_VALIDOS,
10-
TIPOS_PAGO_DEVOLUCION,
11-
speid_group,
12-
)
8+
from speid.commands.spei import speid_group
139
from speid.models import Transaction
10+
from speid.models.transaction import (
11+
REFUNDS_PAYMENTS_TYPES,
12+
STP_VALID_DEPOSITS_STATUSES,
13+
)
1414
from speid.types import Estado, EventType
1515
from speid.validations import StpTransaction
1616

@@ -149,7 +149,6 @@ def test_reconciliate_deposits_historic(runner):
149149
).all()
150150

151151
assert len(deposits_db) == 1
152-
Transaction.drop_collection()
153152

154153

155154
@freeze_time("2023-08-27") # 2023-08-26 18:00 UTC-6
@@ -175,8 +174,8 @@ def test_reconciliate_deposits_current_fecha_operacion(runner):
175174
valid_deposits = [
176175
d
177176
for d in deposits
178-
if d['estado'] in ESTADOS_DEPOSITOS_VALIDOS
179-
and d['tipoPago'] not in TIPOS_PAGO_DEVOLUCION
177+
if d['estado'] in STP_VALID_DEPOSITS_STATUSES
178+
and d['tipoPago'] not in REFUNDS_PAYMENTS_TYPES
180179
]
181180

182181
with requests_mock.mock() as m:
@@ -199,7 +198,6 @@ def test_reconciliate_deposits_current_fecha_operacion(runner):
199198
assert not any(
200199
d.clave_rastreo == devolucion['claveRastreo'] for d in deposits_db
201200
)
202-
Transaction.drop_collection()
203201

204202

205203
@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):
249247
valid_deposits = [
250248
d
251249
for d in deposits
252-
if d['estado'] in ESTADOS_DEPOSITOS_VALIDOS
253-
and d['tipoPago'] not in TIPOS_PAGO_DEVOLUCION
250+
if d['estado'] in STP_VALID_DEPOSITS_STATUSES
251+
and d['tipoPago'] not in REFUNDS_PAYMENTS_TYPES
254252
]
255253

256254
with requests_mock.mock() as m:
@@ -270,4 +268,3 @@ def test_reconciliate_deposits_ignores_duplicated(runner):
270268
).all()
271269

272270
assert len(deposits_db) == len(valid_deposits)
273-
Transaction.drop_collection()

tests/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,6 @@ def orden_pago(outcome_transaction):
174174

175175

176176
@pytest.fixture(autouse=True)
177-
def cleanup_transfers():
177+
def cleanup_transactions():
178178
yield
179179
Transaction.drop_collection()

0 commit comments

Comments
 (0)