Ejemplo n.º 1
0
def test_send_transaction(mock_send_transaction: MagicMock):
    params = dict(
        fecha_operacion=datetime.now(),
        institucion_ordenante='40012',
        institucion_beneficiaria='90646',
        clave_rastreo="PRUEBATAMIZI1",
        monto=100.0,
        nombre_ordenante="BANCO",
        tipo_cuenta_ordenante=40,
        cuenta_ordenante="846180000500000008",
        rfc_curp_ordenante="ND",
        nombre_beneficiario="TAMIZI",
        tipo_cuenta_beneficiario=40,
        cuenta_beneficiario="646180157000000004",
        rfc_curp_beneficiario="ND",
        concepto_pago="PRUEBA",
        referencia_numerica=2423,
        empresa="TAMIZI",
    )

    transaction = Transaction(**params)
    send_transaction(transaction.to_dict())

    task_params = mock_send_transaction.call_args[1]['kwargs']['transaction']

    for param, value in params.items():
        if param == 'fecha_operacion':
            continue
        assert value == task_params[param]
    assert (params['fecha_operacion'].isoformat() ==
            task_params['fecha_operacion'])
Ejemplo n.º 2
0
def test_transaction_constraints():
    transaction_data = dict(
        concepto_pago='PRUEBA',
        institucion_ordenante='646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='072',
        monto=1020,
        nombre_beneficiario='Rogelio Lopez',
        nombre_ordenante='BANCO',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='speid_id',
        fecha_operacion=datetime.today(),
        clave_rastreo='abc123',
    )

    transaction = Transaction(**transaction_data)
    transaction.save()
    assert transaction.id is not None
    assert transaction.compound_key is not None

    # Unique-Spare Index skip documents that not contains compound_key
    # and not allow saving duplicated values
    second_transaction = Transaction(**transaction_data)
    with pytest.raises(NotUniqueError):
        second_transaction.save()
    assert second_transaction.compound_key == transaction.compound_key
    assert second_transaction.id is None

    transaction.delete()
Ejemplo n.º 3
0
def test_get_order():
    transaction = Transaction(
        concepto_pago='PRUEBA',
        institucion_ordenante='646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='072',
        monto=1020,
        nombre_beneficiario='Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        nombre_ordenante='Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='speid_id',
    )

    order = transaction.get_order()

    assert order.fechaOperacion is None
    assert order.institucionOperante == transaction.institucion_ordenante
    assert order.institucionContraparte == transaction.institucion_beneficiaria
    assert transaction.clave_rastreo == order.claveRastreo
    assert transaction.tipo_cuenta_beneficiario == order.tipoCuentaBeneficiario
    assert transaction.rfc_curp_beneficiario == order.rfcCurpBeneficiario
    assert transaction.referencia_numerica == order.referenciaNumerica
    assert transaction.empresa == order.empresa
    assert order.nombreBeneficiario == 'Ricardo Sánchez Castillo de la Mancha'
    assert order.nombreOrdenante == 'Ricardo Sánchez Castillo de la Mancha'
    assert len(order.nombreBeneficiario) == 37
    assert len(order.nombreOrdenante) == 37
Ejemplo n.º 4
0
def create_orden():
    transaction = Transaction()
    try:
        external_transaction = StpTransaction(**request.json)
        transaction = external_transaction.transform()
        if CLABES_BLOCKED:
            clabes = CLABES_BLOCKED.split(',')
            if transaction.cuenta_beneficiario in clabes:
                capture_message('Transacción retenida')
                raise Exception

        previous_trx = Transaction.objects(
            clave_rastreo=transaction.clave_rastreo,
            cuenta_ordenante=transaction.cuenta_ordenante,
            cuenta_beneficiario=transaction.cuenta_beneficiario,
            monto=transaction.monto)
        assert len(previous_trx) == 0

        transaction.confirm_callback_transaction()
        transaction.save()

        r = request.json
        r['estado'] = Estado.convert_to_stp_state(transaction.estado)
    except Exception as exc:
        r = dict(estado='LIQUIDACION')
        transaction.estado = Estado.error
        transaction.save()
        capture_exception(exc)
    return 201, r
Ejemplo n.º 5
0
def process_incoming_transaction(incoming_transaction: dict) -> dict:
    transaction = Transaction()
    try:
        external_tx = StpTransaction(**incoming_transaction)  # type: ignore
        transaction = external_tx.transform()
        if CLABES_BLOCKED:
            clabes = CLABES_BLOCKED.split(',')
            if transaction.cuenta_beneficiario in clabes or (
                    transaction.cuenta_ordenante in clabes):
                capture_message('Transacción retenida')
                raise Exception
        transaction.confirm_callback_transaction()
        transaction.save()
        r = incoming_transaction
        r['estado'] = Estado.convert_to_stp_state(transaction.estado)
    except (NotUniqueError, TypeError) as e:
        r = dict(estado='LIQUIDACION')
        capture_exception(e)
    except Exception as e:
        r = dict(estado='LIQUIDACION')
        transaction.estado = Estado.error
        transaction.events.append(Event(type=EventType.error, metadata=str(e)))
        transaction.save()
        capture_exception(e)
    return r
Ejemplo n.º 6
0
def test_create_order_event_failed_twice(mock_callback_api, client,
                                         default_outcome_transaction):
    trx = Transaction(**default_outcome_transaction)
    trx.stp_id = DEFAULT_ORDEN_ID
    trx.save()
    id_trx = trx.id

    data = dict(id=DEFAULT_ORDEN_ID, Estado='DEVOLUCION', Detalle="0")
    resp = client.post('/orden_events', json=data)
    assert resp.status_code == 200
    assert resp.data == "got it!".encode()

    trx = Transaction.objects.get(id=id_trx)
    assert trx.estado is Estado.failed

    num_events = len(trx.events)
    data = dict(id=DEFAULT_ORDEN_ID, Estado='DEVOLUCION', Detalle="0")
    resp = client.post('/orden_events', json=data)
    assert resp.status_code == 200
    assert resp.data == "got it!".encode()

    trx = Transaction.objects.get(id=id_trx)
    assert trx.estado is Estado.failed
    assert len(trx.events) == num_events
    trx.delete()

    trx.delete()
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
 def transform(self) -> Transaction:
     trans_dict = {
         camel_to_snake(k): v
         for k, v in self.__dict__.items()
         if not k.startswith('_')
     }
     trans_dict['stp_id'] = trans_dict.pop('clave', None)
     trans_dict['monto'] = round(trans_dict['monto'] * 100)
     transaction = Transaction(**trans_dict)
     transaction.speid_id = base62_uuid('SR')()
     transaction.fecha_operacion = datetime.strptime(
         str(transaction.fecha_operacion), '%Y%m%d'
     ).date()
     return transaction
Ejemplo n.º 9
0
def test_send_transaction(mock_callback_api):
    transaction = Transaction(
        fecha_operacion=datetime.today(),
        institucion_ordenante=40012,
        institucion_beneficiaria=90646,
        clave_rastreo="PRUEBATAMIZI1",
        monto=100.0,
        nombre_ordenante="BANCO",
        tipo_cuenta_ordenante=40,
        cuenta_ordenante="846180000500000008",
        rfc_curp_ordenante="ND",
        nombre_beneficiario="TAMIZI",
        tipo_cuenta_beneficiario=40,
        cuenta_beneficiario="646180157000000004",
        rfc_curp_beneficiario="ND",
        concepto_pago="PRUEBA",
        referencia_numerica=2423,
        empresa="TAMIZI",
    )
    res = send_transaction(transaction.to_dict())
    assert res['status'] == 'succeeded'
Ejemplo n.º 10
0
def test_send_order(create_account):
    transaction = Transaction(
        concepto_pago='PRUEBA',
        institucion_ordenante='90646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='40072',
        monto=1020,
        nombre_beneficiario='Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        nombre_ordenante='   Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='speid_id',
        tipo_cuenta_beneficiario=40,
    )

    order = transaction.create_order()

    assert order.institucionOperante == transaction.institucion_ordenante
    assert order.institucionContraparte == transaction.institucion_beneficiaria
    assert order.monto == 10.20
    assert transaction.clave_rastreo == order.claveRastreo
    assert transaction.tipo_cuenta_beneficiario == order.tipoCuentaBeneficiario
    assert transaction.rfc_curp_beneficiario == order.rfcCurpBeneficiario
    assert transaction.referencia_numerica == order.referenciaNumerica
    assert order.nombreBeneficiario == ('Ricardo Sanchez Castillo de la Mancha'
                                        ' S')
    assert order.nombreOrdenante == 'Ricardo Sanchez Castillo de la Mancha S'
    assert len(order.nombreBeneficiario) == 39
    assert len(order.nombreOrdenante) == 39

    order = transaction.create_order()
    assert transaction.stp_id == order.id

    transaction.delete()
Ejemplo n.º 11
0
def test_get_transactions(client, default_income_transaction,
                          default_outcome_transaction, mock_callback_api):
    resp = client.post('/ordenes', json=default_income_transaction)
    assert resp.status_code == 201
    trx_in = Transaction.objects.order_by('-created_at').first()

    trx_out = Transaction(**default_outcome_transaction)
    trx_out.stp_id = DEFAULT_ORDEN_ID
    trx_out.save()

    resp = client.get('/transactions?'
                      'status=submitted&prefix_ordenante=6461801570')
    assert resp.status_code == 200
    assert str(trx_out.id) == resp.json[0]['_id']['$oid']

    resp = client.get('/transactions?'
                      'status=submitted&prefix_beneficiario=6461801570')
    assert resp.status_code == 200
    assert str(trx_in.id) == resp.json[0]['_id']['$oid']

    resp = client.get('/transactions')
    assert resp.status_code == 200
    assert len(resp.json) == 2
Ejemplo n.º 12
0
def test_invalid_id_order_event(client, default_outcome_transaction):
    trx = Transaction(**default_outcome_transaction)
    trx.stp_id = DEFAULT_ORDEN_ID
    trx.save()
    id_trx = trx.id

    data = dict(id='9', Estado='LIQUIDACION', Detalle="0")
    resp = client.post('/orden_events', json=data)
    assert resp.status_code == 200
    assert resp.data == "got it!".encode()

    trx = Transaction.objects.get(id=id_trx)
    assert trx.estado is Estado.submitted
    trx.delete()
Ejemplo n.º 13
0
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()
Ejemplo n.º 14
0
def get_orders():
    estado = request.args.get('estado', default=None, type=str)
    prefix_ordenante = request.args.get('prefix_ordenante',
                                        default=None,
                                        type=str)
    prefix_beneficiario = request.args.get('prefix_beneficiario',
                                           default=None,
                                           type=str)
    query = dict()
    if estado:
        query['estado'] = estado
    if prefix_ordenante:
        query['cuenta_ordenante__startswith'] = prefix_ordenante
    if prefix_beneficiario:
        query['cuenta_beneficiario__startswith'] = prefix_beneficiario

    transactions = Transaction.objects(**query).order_by('-created_at')
    return 200, transactions
Ejemplo n.º 15
0
def test_create_orden_duplicated(client, default_income_transaction):
    resp = client.post('/ordenes', json=default_income_transaction)
    transaction = Transaction.objects.order_by('-created_at').first()
    assert transaction.estado is Estado.succeeded
    assert resp.status_code == 201
    assert resp.json['estado'] == 'LIQUIDACION'

    default_income_transaction['Clave'] = 2456304
    resp = client.post('/ordenes', json=default_income_transaction)
    transactions = Transaction.objects(
        clave_rastreo=default_income_transaction['ClaveRastreo']).order_by(
            '-created_at')
    assert len(transactions) == 1
    assert transactions[0].stp_id == 2456303
    assert transactions[0].estado is Estado.succeeded
    assert resp.status_code == 201
    assert resp.json['estado'] == 'LIQUIDACION'
    for t in transactions:
        t.delete()
Ejemplo n.º 16
0
def test_reverse_transaction(client, default_outcome_transaction,
                             mock_callback_api):
    trx = Transaction(**default_outcome_transaction)
    trx.stp_id = DEFAULT_ORDEN_ID
    trx.save()

    assert trx.estado is Estado.submitted

    resp = client.get('/transactions?'
                      'status=submitted&prefix_ordenante=6461801570')
    assert resp.status_code == 200

    resp = client.patch(f'/transactions/{resp.json[0]["_id"]["$oid"]}/reverse')
    assert resp.status_code == 201
    trx = Transaction.objects.get(id=resp.json["_id"]["$oid"])

    assert trx.estado is Estado.failed
    trx.delete()
Ejemplo n.º 17
0
def test_process_transaction(client, default_outcome_transaction):
    trx = Transaction(**default_outcome_transaction)
    trx.stp_id = DEFAULT_ORDEN_ID
    trx.save()

    assert trx.estado is Estado.submitted

    resp = client.get('/transactions?'
                      'status=submitted&prefix_ordenante=6461801570')
    assert resp.status_code == 200

    resp = client.patch(f'/transactions/{resp.json[0]["_id"]["$oid"]}/process')
    assert resp.status_code == 201
    trx = Transaction.objects.get(id=resp.json["_id"]["$oid"])

    assert trx.estado is Estado.submitted
    assert trx.stp_id is not None
    trx.delete()
Ejemplo n.º 18
0
def test_order_event_duplicated(client, default_outcome_transaction,
                                mock_callback_api):
    trx = Transaction(**default_outcome_transaction)
    trx.stp_id = DEFAULT_ORDEN_ID
    trx.save()
    id_trx = trx.id

    data = dict(id=DEFAULT_ORDEN_ID, Estado='LIQUIDACION', Detalle="0")
    resp = client.post('/orden_events', json=data)
    assert resp.status_code == 200
    assert resp.data == "got it!".encode()

    data = dict(id=DEFAULT_ORDEN_ID, Estado='DEVOLUCION', Detalle="0")
    resp = client.post('/orden_events', json=data)
    assert resp.status_code == 200
    assert resp.data == "got it!".encode()

    trx = Transaction.objects.get(id=id_trx)
    assert trx.estado is Estado.failed
    trx.delete()
Ejemplo n.º 19
0
def transaction():
    transaction = Transaction(
        concepto_pago='PRUEBA',
        institucion_ordenante='90646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='40072',
        monto=1020,
        nombre_beneficiario='Ricardo Sánchez',
        nombre_ordenante='BANCO',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='speid_id',
    )
    transaction.save()

    yield transaction

    transaction.delete()
Ejemplo n.º 20
0
def test_fail_send_order_no_account_registered():
    transaction = Transaction(
        concepto_pago='PRUEBA',
        institucion_ordenante='90646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='40072',
        monto=1020,
        nombre_beneficiario='Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        nombre_ordenante='   Ricardo Sánchez Castillo de la Mancha S.A. de CV',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='speid_id',
        tipo_cuenta_beneficiario=40,
    )
    transaction_id = transaction.save().id

    with pytest.raises(MalformedOrderException):
        transaction.create_order()

    transaction = Transaction.objects.get(id=transaction_id)
    assert transaction.estado is Estado.error
    transaction.delete()
Ejemplo n.º 21
0
def outcome_transaction() -> Generator[Transaction, None, None]:
    transaction = Transaction(
        stp_id=2456305,
        concepto_pago='PRUEBA',
        institucion_ordenante='90646',
        cuenta_beneficiario='072691004495711499',
        institucion_beneficiaria='40072',
        monto=2511,
        nombre_beneficiario='Ricardo Sánchez',
        tipo_cuenta_beneficiario=40,
        nombre_ordenante='BANCO',
        cuenta_ordenante='646180157000000004',
        rfc_curp_ordenante='ND',
        speid_id='go' + datetime.now().strftime('%m%d%H%M%S'),
        version=1,
    )
    transaction.save()
    yield transaction
    transaction.delete()
Ejemplo n.º 22
0
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()
Ejemplo n.º 23
0
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, ValidationError):
        transaction.set_state(Estado.failed)
        transaction.save()
Ejemplo n.º 24
0
 def transform(self) -> Transaction:
     transaction = Transaction(**self.to_dict())
     return transaction
Ejemplo n.º 25
0
 def transform(self):
     transaction = Transaction(**self.to_dict())
     transaction.fecha_operacion = datetime.today()
     transaction.estado = Estado.submitted
     return transaction
Ejemplo n.º 26
0
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()