Exemplo n.º 1
0
def handle_withdraw_notify(is_success, sn, vas_name, vas_sn, data):
    tx = get_tx_by_sn(sn)
    withdraw_record = tx.record

    logger.info('withdraw notify: {0}'.format(data))
    if tx is None or withdraw_record is None:
        # 不存在
        logger.warning('withdraw [{0}] not exits.'.format(sn))
        return

    if is_duplicated_notify(tx, vas_name, vas_sn):
        logger.warning('withdraw notify duplicated: [{0}, {1}]'.format(
            vas_name, vas_sn))
        return

    if tx.state != WithdrawTxState.PROCESSING:
        logger.warning('bad withdraw notify: [sn: {0}]'.format(sn))
        return

    _record_withdraw_extra_info(withdraw_record, data)
    with require_transaction_context():
        tx = update_transaction_info(tx.id, vas_sn, vas_name=vas_name)
        if is_success:
            _success_withdraw(tx, withdraw_record)
        else:
            _fail_withdraw(tx, withdraw_record)

    # notify client.
    tx = get_tx_by_id(tx.id)
    _try_notify_client(tx, withdraw_record)
Exemplo n.º 2
0
def handle_prepaid_notify(is_success, sn, vas_name, vas_sn, amount, data):
    """
    :param is_success: 是否成功
    :param sn: 订单号
    :param vas_name: 来源系统
    :param vas_sn: 来源系统订单号
    :param data: 数据
    :return:
    """
    tx = get_tx_by_sn(sn)
    prepaid_record = tx.record

    if is_duplicated_notify(tx, vas_name, vas_sn):
        return

    if _is_duplicated_prepaid(tx, vas_name, vas_sn):
        # 重复支付
        logger.warning('duplicated prepaid: [{0}, {1}], [{2}, {3}]'.format(
            tx.vas_name, tx.vas_sn, vas_name, vas_sn))
        if is_success:
            # 成功支付, 充值到余额
            handle_duplicate_pay(vas_name, vas_sn, tx, prepaid_record)
        return

    with require_transaction_context():
        tx = update_transaction_info(tx.id, vas_sn, vas_name=vas_name)
        if is_success:
            succeed_prepaid(vas_name, tx, prepaid_record)
        else:
            fail_prepaid(tx)

    # notify client.
    tx = get_tx_by_id(tx.id)
    _try_notify_client(tx, prepaid_record)
Exemplo n.º 3
0
def handle_refund_notify(is_success, sn, vas_name, vas_sn, data):
    """
    :param is_success: 是否成功
    :param sn: 订单号
    :param vas_name: 来源系统
    :param vas_sn: 来源系统订单号
    :param data: 数据
    :return:
    """
    import time
    tx = get_tx_by_sn(sn)
    if tx is None:
        for i in range(10):
            # 这是因为_create_and_request_refund在一个事务中,notify到这儿的时候,事务没有结束,导致tx获取不到。
            # 这里的解决办法就是重试
            tx = get_tx_by_sn(sn)
            if tx is None:
                logger.warn(
                    'apply refund [{0}] is not finish, sleep then retry.')
                time.sleep(0.5)
                continue
            break
    refund_record = tx.record

    logger.info('refund notify: {0}, {1}, {2}, {3}, {4}'.format(
        is_success, sn, vas_name, vas_sn, data))
    if tx is None or refund_record is None:
        # 不存在
        logger.warning('refund [{0}] not exits.'.format(sn))
        return

    if is_duplicated_notify(tx, vas_name, vas_sn):
        logger.warning('refund notify duplicated: [{0}, {1}]'.format(
            vas_name, vas_sn))
        return

    if tx.state not in [RefundTxState.PROCESSING, RefundTxState.REFUNDED_IN]:
        logger.warning('bad refund notify: [sn: {0}]'.format(sn))
        return

    payment_tx = tx.super
    payment_record = payment_tx.record

    if payment_tx.state != PaymentTxState.REFUNDING:
        logger.warning(
            'bad refund notify: [sn: {0}], [payment_sn: {1}]'.format(
                sn, payment_tx.sn))
        return

    with require_transaction_context():
        tx = update_transaction_info(refund_record.tx_id, vas_sn)
        if is_success:
            handle_succeed_refund(vas_name, payment_record, refund_record)
        else:
            handle_fail_refund(payment_record, refund_record)

    # notify client.
    tx = get_tx_by_id(tx.id)
    _try_notify_client(tx, refund_record)
Exemplo n.º 4
0
def _create_refund(channel, payment_tx, amount, client_notify_url):
    cur_payment_state = payment_tx.state

    # start refunding.
    transit_transaction_state(payment_tx.id, payment_tx.state,
                              PaymentTxState.REFUNDING)

    payment_tx = get_tx_by_id(payment_tx.id)
    payment_record = payment_tx.record
    if payment_tx.state != PaymentTxState.REFUNDING:
        raise PaymentNotRefundableError()

    if amount + payment_record.refunded_amount > payment_record.paid_amount:
        raise RefundAmountError(payment_record.paid_amount,
                                payment_record.refunded_amount, amount)

    comments = "退款-{0}".format(payment_record.product_name)

    user_ids = [
        user_roles.tx_to_user(payment_record.payer_id),
        user_roles.from_user(payment_record.payee_id)
    ]
    if payment_record.type == PaymentType.GUARANTEE:
        secure_user_id = get_system_account_user_id(SECURE_USER_NAME)
        user_ids.append(user_roles.guaranteed_by(secure_user_id))
    elif payment_record.type == PaymentType.DIRECT:
        # check balance.
        # 直付退款时收款方余额必须足够
        balance = get_user_cash_balance(payment_record.payee_id)
        if amount > balance.available:
            raise RefundBalanceError(amount, balance.available)
    tx = create_transaction(channel.name,
                            TransactionType.REFUND,
                            amount,
                            comments,
                            user_ids,
                            super_id=payment_tx.id,
                            vas_name=payment_tx.vas_name,
                            order_id=payment_record.order_id)

    fields = {
        'tx_id': tx.id,
        'sn': tx.sn,
        'payment_sn': payment_record.sn,
        'payment_state': cur_payment_state,
        'payer_id': payment_record.payer_id,
        'payee_id': payment_record.payee_id,
        'order_id': payment_record.order_id,
        'amount': amount,
        'client_notify_url': client_notify_url
    }

    refund_record = RefundRecord(**fields)
    db.session.add(refund_record)

    return payment_record, tx, refund_record
Exemplo n.º 5
0
Arquivo: models.py Projeto: webee/pay
    def get_cheque_record_from_cash_token(cash_token):
        try:
            from api_x.zyt.biz.transaction.dba import get_tx_by_id
            tx_id, hash_sign = cash_token.split('_')
            tx_id = ints.base36_to_int(tx_id)

            tx = get_tx_by_id(tx_id)
            if tx is None or tx.type != TransactionType.CHEQUE:
                return None
            cheque_record = tx.record
            if cheque_record.cash_token == cash_token:
                return cheque_record
        except Exception as _:
            pass
        return None
Exemplo n.º 6
0
def handle_payment_notify(is_success, sn, vas_name, vas_sn, amount, data=None):
    """
    :param is_success: 是否成功
    :param sn: 订单号
    :param vas_name: 来源系统
    :param vas_sn: 来源系统订单号
    :param data: 数据
    :return:
    """
    logger.info(
        'receive payment notify: [{0}], [{1}], [{2}], [{3}], [{4}]'.format(
            is_success, sn, vas_name, vas_sn, amount))
    tx = get_payment_tx_by_sn(sn)
    payment_record = tx.record

    if amount != payment_record.real_amount:
        # 单次支付的金额一定要完全一致
        raise AmountValueMissMatchError(payment_record.real_amount, amount)

    if is_duplicated_notify(tx, vas_name, vas_sn):
        return

    with require_transaction_context():
        if is_success:
            # update paid amount
            payment_record.add_paid(amount)

            if _is_duplicated_payment(tx, vas_name, vas_sn):
                # 重复支付
                logger.warning(
                    'duplicated payment: [{0}, {1}], [{2}, {3}], [{4}]'.format(
                        tx.vas_name, tx.vas_sn, vas_name, vas_sn, amount))
                handle_duplicate_payment(vas_name, vas_sn, tx, payment_record)
                return

            # 直付和担保付的不同操作
            if payment_record.type == PaymentType.DIRECT:
                succeed_payment(vas_name, tx, payment_record)
            elif payment_record.type == PaymentType.GUARANTEE:
                secure_payment(vas_name, tx, payment_record)
        else:
            fail_payment(payment_record)
        tx = update_transaction_info(tx.id, vas_sn, vas_name=vas_name)

    # notify client.
    tx = get_tx_by_id(tx.id)
    _try_notify_client(tx, payment_record)
Exemplo n.º 7
0
def confirm_payment(channel, order_id):
    payment_record = get_payment_by_channel_order_id(channel.id, order_id)
    if payment_record is None or payment_record.type != PaymentType.GUARANTEE:
        raise TransactionNotFoundError(
            'guarantee payment tx channel=[{0}], order_id=[{1}] not found.'.
            format(channel.name, order_id))

    tx = get_tx_by_id(payment_record.tx_id)
    # 只有担保才能确认
    # 另外,担保可能发生退款的情况,则需要退款完成之后再次确认。
    if tx.state == PaymentTxState.SECURED:
        _confirm_payment(payment_record)
    elif tx.state == PaymentTxState.REFUNDING:
        msg = 'payment is REFUNDING, try again later.'
        logger.warn(msg)
        raise TransactionStateError(msg)
    else:
        logger.warn('payment state should be SECURED.')
Exemplo n.º 8
0
def _cash_cheque(cheque_record, to_id):
    from api_x.zyt.vas import NAME
    tx = cheque_record.tx
    with require_transaction_context():
        tx = update_transaction_info(tx.id, tx.sn, vas_name=NAME)
        if cheque_record.type == ChequeType.INSTANT:
            event_ids = transfer_frozen(tx.sn, cheque_record.from_id, to_id,
                                        cheque_record.amount)
            transit_transaction_state(tx.id, ChequeTxState.FROZEN,
                                      ChequeTxState.CASHED, event_ids)
        elif cheque_record.type == ChequeType.LAZY:
            event_ids = transfer(tx.sn, cheque_record.from_id, to_id,
                                 cheque_record.amount)
            transit_transaction_state(tx.id, ChequeTxState.CREATED,
                                      ChequeTxState.CASHED, event_ids)

        # update to id.
        add_tx_user(tx.id, user_roles.to_user(to_id))
        cheque_record.to_id = to_id
        db.session.add(cheque_record)

    # notify client.
    tx = get_tx_by_id(tx.id)
    _try_notify_client(tx, cheque_record)