def process_transaction(transaction_id): try: transaction = Transaction.objects.get(id=transaction_id, estado=Estado.submitted) except DoesNotExist: abort(401) order = transaction.get_order() transaction.save() order.monto = order.monto / 100 res = order.registra() if res is not None and res.id > 0: transaction.stp_id = res.id transaction.events.append( Event(type=EventType.completed, metadata=str(res))) transaction.save() return 201, transaction else: transaction.events.append( Event(type=EventType.error, metadata=str(res))) transaction.save() return 400, res
def re_execute_transactions(speid_id): """Retry send a transaction to STP, it takes the values of the event created before """ transaction = Transaction.objects.get(speid_id=speid_id) if transaction is None: raise ValueError('Transaction not found') order = transaction.get_order() transaction.save() order.monto = order.monto / 100 res = order.registra() if res is not None and res.id > 0: transaction.stp_id = res.id transaction.events.append( Event(type=EventType.completed, metadata=str(res))) else: transaction.events.append( Event(type=EventType.error, metadata=str(res))) transaction.save()
def execute(order_val: dict): # Get version version = 0 if "version" in order_val: version = order_val['version'] if time_in_range(START_DOWNTIME, STOP_DOWNTIME, datetime.utcnow().time()): raise ScheduleError transaction = Transaction() try: input = factory.create(version, **order_val) transaction = input.transform() if not clabe.validate_clabe(transaction.cuenta_beneficiario) and ( not luhnmod10.valid(transaction.cuenta_beneficiario)): raise MalformedOrderException() except (MalformedOrderException, TypeError, ValueError): transaction.set_state(Estado.error) transaction.save() raise MalformedOrderException() try: prev_trx = Transaction.objects.get(speid_id=transaction.speid_id) # Si la transacción ya esta como succeeded termina # Puede suceder cuando se corre la misma tarea tiempo después # Y la transacción ya fue confirmada por stp assert prev_trx.estado != Estado.succeeded transaction = prev_trx transaction.events.append(Event(type=EventType.retry)) except DoesNotExist: transaction.events.append(Event(type=EventType.created)) transaction.save() pass except AssertionError: # Para evitar que se vuelva a mandar o regresar se manda la excepción raise ResendSuccessOrderException() if transaction.monto > MAX_AMOUNT: transaction.events.append(Event(type=EventType.error)) transaction.save() raise MalformedOrderException() now = datetime.utcnow() try: # Return transaction after 2 hours of creation assert (now - transaction.created_at) < timedelta(hours=2) transaction.create_order() except ( AssertionError, InvalidAccountType, InvalidAmount, InvalidInstitution, InvalidTrackingKey, PldRejected, ValidationError, ): transaction.set_state(Estado.failed) transaction.save()
def test_event(): received = Event(type=EventType.received) completed = Event(type=EventType.completed) transaction = Transaction(events=[received, completed]) transaction.save() id_trx = transaction.id transaction = Transaction.objects.get(id=id_trx) assert len(transaction.events) == 2 assert transaction.events[0].type == received.type assert transaction.events[1].type == completed.type transaction.delete()
def execute(order_val): # Get version version = 0 if "version" in order_val: version = order_val['version'] transaction = Transaction() try: input = factory.create(version, **order_val) transaction = input.transform() if not clabe.validate_clabe(transaction.cuenta_beneficiario) and ( not luhnmod10.valid(transaction.cuenta_beneficiario)): raise MalformedOrderException() except (MalformedOrderException, TypeError, ValueError): transaction.set_state(Estado.error) transaction.save() raise MalformedOrderException() try: prev_trx = Transaction.objects.get(speid_id=transaction.speid_id) transaction = prev_trx transaction.events.append(Event(type=EventType.retry)) except DoesNotExist: transaction.events.append(Event(type=EventType.created)) pass if transaction.monto > MAX_AMOUNT: transaction.events.append(Event(type=EventType.error)) transaction.save() raise MalformedOrderException() order = transaction.get_order() transaction.save() # Send order to STP order.monto = order.monto / 100 res = order.registra() if res is not None and res.id > 0: transaction.stp_id = res.id transaction.events.append( Event(type=EventType.completed, metadata=str(res))) else: transaction.events.append( Event(type=EventType.error, metadata=str(res))) transaction.save()
def process_outgoing_transactions(self, transactions: list): for request_dic in transactions: try: transaction = Transaction.objects.get( speid_id=request_dic['speid_id']) except DoesNotExist: continue action = request_dic['action'] if action == Estado.succeeded.value: new_estado = Estado.succeeded event_type = EventType.completed elif action == Estado.failed.value: new_estado = Estado.failed event_type = EventType.error else: raise ValueError('Invalid event type') if transaction.estado == new_estado: continue else: transaction.estado = new_estado transaction.set_state(transaction.estado) transaction.events.append( Event(type=event_type, metadata=str('Reversed by recon task'))) transaction.save()
def execute_create_account(account_dict: dict): account_val = AccountValidation(**account_dict) # type: ignore # Look for previous accounts account = account_val.transform() try: previous_account = Account.objects.get(cuenta=account.cuenta) except DoesNotExist: account.events.append(Event(type=EventType.created)) account.save() else: account = previous_account account.events.append(Event(type=EventType.retry)) if account.estado is Estado.succeeded: return account.create_account()
def migrate_from_csv(transactions, events, requests): """ Hace la migración de una base de datos Postgres a MongoDB, los datos deben ser exportados a CSV antes de ser ejecutado, se puede utilizar el archivo scripts/migrate_postgres_mongo.sh para ejecutar la tarea completa :param transactions: Archivo CSV con los datos de las transacciones :param events: Archivo CSV con los eventos relacionados a las transacciones :param requests: Archivo CSV con los requests :return: """ transactions_list = pandas.read_csv( transactions, converters=dict(institucion_ordenante=lambda x: str(x), institucion_beneficiaria=lambda x: str(x), cuenta_ordenante=lambda x: str(x), cuenta_beneficiario=lambda x: str(x))) transactions_list = transactions_list.where( (pandas.notnull(transactions_list)), None) events_list = pandas.read_csv(events) events_list = events_list.where((pandas.notnull(events_list)), None) transactions = [] for _, t in transactions_list.iterrows(): t['stp_id'] = t['orden_id'] del t['orden_id'] if t['estado'] in ['ND', 'success', 'liquidacion']: t['estado'] = 'succeeded' t['institucion_beneficiaria'] = str(t['institucion_beneficiaria']) t['cuenta_ordenante'] = str(t['cuenta_ordenante']) t['cuenta_beneficiario'] = str(t['cuenta_beneficiario']) transaction = Transaction(**t) transaction_events = events_list[events_list.transaction_id == t['id']] for _, e in transaction_events.iterrows(): transaction.events.append( Event(type=EventType[e['type']], metadata=e['meta'], created_at=datetime.strptime(e['created_at'], '%Y-%m-%d %H:%M:%S.%f'))) transaction.id = None transactions.append(transaction) requests_list = pandas.read_csv(requests) requests_list = requests_list.where((pandas.notnull(requests_list)), None) requests = [] for _, r in requests_list.iterrows(): r['method'] = r['method'].upper() request = Request(**r) request.id = None requests.append(request) Request.objects.insert(requests) for transaction in transactions: transaction.save()
def callback_spei_transaction(transaction_id, transaction_status): """Establece el estado de la transacción, valores permitidos succeeded y failed""" transaction = Transaction.objects.get(id=transaction_id) if transaction_status == Estado.succeeded.value: transaction.estado = Estado.succeeded event_type = EventType.completed elif transaction_status == Estado.failed.value: transaction.estado = Estado.failed event_type = EventType.error else: raise ValueError('Invalid event type') set_status_transaction(transaction.speid_id, transaction.estado.value) transaction.events.append( Event(type=event_type, metadata=str('Reversed by SPEID command'))) transaction.save()
def test_transaction(): transaction = Transaction( concepto_pago='PRUEBA', institucion_ordenante='646', cuenta_beneficiario='072691004495711499', institucion_beneficiaria='072', monto=1020, nombre_beneficiario='Ricardo Sánchez', nombre_ordenante='BANCO', cuenta_ordenante='646180157000000004', rfc_curp_ordenante='ND', speid_id='speid_id', ) transaction.events.append(Event(type=EventType.created)) transaction.events.append(Event(type=EventType.received)) transaction.events.append(Event(type=EventType.retry)) transaction.events.append(Event(type=EventType.retry)) transaction.events.append(Event(type=EventType.error)) transaction.events.append(Event(type=EventType.completed)) transaction.save() trx_saved = Transaction.objects.get(id=transaction.id) assert transaction.concepto_pago == trx_saved.concepto_pago assert transaction.institucion_beneficiaria == ( trx_saved.institucion_beneficiaria) assert transaction.cuenta_beneficiario == trx_saved.cuenta_beneficiario assert transaction.institucion_beneficiaria == ( trx_saved.institucion_beneficiaria) assert transaction.monto == trx_saved.monto assert transaction.nombre_beneficiario == trx_saved.nombre_beneficiario assert transaction.nombre_ordenante == trx_saved.nombre_ordenante assert transaction.cuenta_ordenante == trx_saved.cuenta_ordenante assert transaction.rfc_curp_ordenante == trx_saved.rfc_curp_ordenante assert transaction.speid_id == trx_saved.speid_id assert len(trx_saved.events) == 6 transaction.delete()
def retry_incoming_transactions(speid_ids: List[str]) -> None: for speid_id in speid_ids: transaction = Transaction.objects.get(speid_id=speid_id) transaction.events.append(Event(type=EventType.retry)) transaction.confirm_callback_transaction() transaction.save()