Example #1
0
    def handle_withdraw_result(cls, data):
        order_id = data.get('OrdId', '')
        try:
            pay_info = PayInfo.objects.select_for_update().get(pk=order_id)
        except PayInfo.DoesNotExist:
            logger.warning('Order not found, order id: ' + order_id + ', response: ' + str(data))
            return PayResult.EXCEPTION

        if pay_info.status == PayInfo.FAIL:
            return PayResult.WITHDRAW_FAIL

        pay_info = PayInfo.objects.select_for_update().get(pk=order_id)
        pay_info.response = str(data)
        pay_info.error_code = data.get('RespCode', '')
        pay_info.error_message = data.get('RespDesc', '')
        transaction_status = data.get('TransStat', '')

        keeper = MarginKeeper(pay_info.user, pay_info.order.pk)

        try:
            pay = HuifuPay()
            if pay.verify_sign(data, HuifuPay.WITHDRAW_FIELDS):
                if data['RespCode'] == '000':
                    if transaction_status == 'S':
                        if pay_info.status != PayInfo.SUCCESS:
                            keeper.withdraw_ack(pay_info.total_amount)
                        pay_info.status = PayInfo.SUCCESS
                        result = PayResult.WITHDRAW_SUCCESS
                    elif transaction_status == 'I':
                        pay_info.status = PayInfo.ACCEPTED
                        result = PayResult.WITHDRAW_SUCCESS
                    elif transaction_status == 'F':
                        is_already_successful = False
                        if pay_info.status == 'S':
                            is_already_successful = True
                        pay_info.status = PayInfo.FAIL
                        result = PayResult.WITHDRAW_FAIL
                        keeper.withdraw_rollback(pay_info.total_amount, u'', is_already_successful)
                else:
                    pay_info.status = PayInfo.FAIL
                    result = PayResult.WITHDRAW_FAIL
                    keeper.withdraw_rollback(pay_info.total_amount)
            else:
                pay_info.status = PayInfo.EXCEPTION
                result = PayResult.EXCEPTION
                pay_info.error_message = 'Invalid signature'
                logger.fatal('invalid signature. order id: %s', str(pay_info.pk))
        except(socket.error, SignException) as e:
            result = PayResult.EXCEPTION
            pay_info.status = PayInfo.EXCEPTION
            pay_info.error_message = str(e)
            logger.fatal('unexpected error. order id: %s. exception: %s', str(pay_info.pk), str(e))

        pay_info.save()
        OrderHelper.update_order(pay_info.order, pay_info.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
        return result
Example #2
0
    def handle_margin(self, amount, order_id, user_id, ip, response_content, device):
        try:
            pay_info = PayInfo.objects.select_for_update().filter(order_id=order_id).first()
        except Exception:
            logger.error("orderId:%s, order not exist, handle margin, try error" % order_id)
            return {"ret_code": 20085, "message": "order not exist, handle margin, try error"}

        if not pay_info:
            return {"ret_code": 20131, "message": "order not exist"}
        if pay_info.status == PayInfo.SUCCESS:
            return {"ret_code": 0, "message": PayResult.DEPOSIT_SUCCESS, "amount": amount}

        pay_info.error_message = ""
        pay_info.response = response_content
        pay_info.response_ip = ip

        if pay_info.amount != amount:
            pay_info.status = PayInfo.FAIL
            pay_info.error_message += u' 金额不匹配'
            logger.error("orderId:%s amount:%s, response amount:%s" % (order_id, pay_info.amount, amount))
            rs = {"ret_code": 20132, "message": PayResult.EXCEPTION}
        elif pay_info.user_id != user_id:
            pay_info.status = PayInfo.FAIL
            pay_info.error_message += u"用户不匹配"
            logger.error("orderId:%s 充值用户ID不匹配" % order_id)
            rs = {"ret_code": 20133, "message": PayResult.EXCEPTION}
        else:
            pay_info.fee = self.FEE
            keeper = MarginKeeper(pay_info.user, pay_info.order.pk)
            margin_record = keeper.deposit(amount)
            pay_info.margin_record = margin_record
            pay_info.status = PayInfo.SUCCESS
            logger.error("orderId:%s success" % order_id)
            rs = {"ret_code": 0, "message": "success", "amount": amount, "margin": margin_record.margin_current}

        pay_info.save()
        if rs['ret_code'] == 0:
            try:
                # fix@chenweibi, add order_id, handle_margin已经废弃未被使用
                tools.deposit_ok.apply_async(kwargs={"user_id": pay_info.user.id, "amount": pay_info.amount,
                                                     "device": device, "order_id": order_id})
            except:
                pass

            # 充值成功后,更新本次银行使用的时间
            if len(pay_info.card_no) == 10:
                Card.objects.filter(user=pay_info.user, no__startswith=pay_info.card_no[:6], no__endswith=pay_info.card_no[-4:]).update(last_update=timezone.now())
            else:
                Card.objects.filter(user=pay_info.user, no=pay_info.card_no).update(last_update=timezone.now())

        OrderHelper.update_order(pay_info.order, pay_info.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
        return rs
Example #3
0
 def settle_hike(cls, product):
     result = redpack_backends.settle_hike(product)
     if not result:
         return
     for x in result:
         order_id = OrderHelper.place_order(x['user'],
                                            order_type=u'加息',
                                            product_id=product.id,
                                            status=u'新建').id
         margin_keeper = MarginKeeper(user=x['user'], order_id=order_id)
         margin_keeper.hike_deposit(x['amount'],
                                    u"加息存入%s元" % x['amount'],
                                    savepoint=False)
         OrderHelper.update_order(Order.objects.get(pk=order_id),
                                  user=x['user'],
                                  status=u'成功',
                                  amount=x['amount'])
Example #4
0
 def amortize(self,
              principal,
              interest,
              penal_interest,
              coupon_interest,
              description=u'',
              savepoint=True):
     check_amount(principal)
     check_amount(interest)
     check_amount(penal_interest)
     principal = Decimal(principal)
     interest = Decimal(interest)
     penal_interest = Decimal(penal_interest)
     coupon_interest = Decimal(coupon_interest)
     with transaction.atomic(savepoint=savepoint):
         margin = Margin.objects.select_for_update().filter(
             user=self.user).first()
         catalog = u'还款入账'
         margin.margin += principal
         self.__tracer(u'本金入账', principal, margin.margin, u'本金入账')
         margin.margin += interest
         self.__tracer(u'利息入账', interest, margin.margin, u'利息入账')
         if penal_interest > 0:
             margin.margin += penal_interest
             self.__tracer(u'罚息入账', penal_interest, margin.margin, u'罚息入账')
         if coupon_interest > 0:
             margin.margin += coupon_interest
             description = u"加息存入{}元".format(coupon_interest)
             order_id = OrderHelper.place_order(
                 self.user,
                 order_type=Order.INTEREST_COUPON,
                 status=u'新建',
                 amount=coupon_interest).id
             # self.hike_deposit(coupon_interest, u"加息存入{}元".format(coupon_interest), order_id, savepoint=False)
             self.__tracer(u"加息存入", coupon_interest, margin.margin,
                           description, order_id)
             OrderHelper.update_order(Order.objects.get(pk=order_id),
                                      user=self.user,
                                      status=u'成功',
                                      amount=coupon_interest)
         margin.save()
Example #5
0
    def order_after_pay_error(self, error, order_id):
        # todo better error when error
        logger.exception(error)
        pay_info = PayInfo.objects.select_for_update().get(order_id=order_id)

        if pay_info.status == PayInfo.SUCCESS:
            return {
                "ret_code": 0,
                "message": PayResult.DEPOSIT_SUCCESS,
                "amount": pay_info.amount
            }

        order = Order.objects.get(id=order_id)
        user = User.objects.get(id=pay_info.user_id)

        if isinstance(error, ThirdPayError):
            error_code = error.code
            is_inner_error = False
        else:
            # todo better exception than just using code
            error_code = 20119
            is_inner_error = True
        error_message = error.message
        pay_info.save_error(error_code=error_code,
                            error_message=error_message,
                            is_inner_error=is_inner_error)
        OrderHelper.update_order(order,
                                 user,
                                 pay_info=model_to_dict(pay_info),
                                 status=pay_info.status)
        return {
            "ret_code": error_code,
            "message": error_message,
            'order_id': order_id,
            'pay_info_id': pay_info.id,
            'is_error': True
        }
Example #6
0
    def test_order(self):
        order = OrderHelper.place_order(type=u'充值', product_id='1234123')
        self.assertTrue(order.id >= 0)
        self.assertEqual(order.extra_data['product_id'], '1234123')

        order = OrderHelper.update_order(order, status=u'关闭')
        self.assertEqual(order.status, u'关闭')

        sub_order = OrderHelper.place_order(type=u'充值', somekey='value')
        sub_order.parent = order

        sub_order.save()

        order = Order.objects.get(pk=order.id)
        self.assertEqual(len(order.children.all()), 1)
Example #7
0
    def pre_pay(self, request, bank=None):
        """ 汇付天下直接进行邦卡支付,不能够获取验证码 """
        if not request.user.wanglibaouserprofile.id_is_valid:
            return {"ret_code": 20111, "message": "请先进行实名认证"}

        amount = request.DATA.get("amount", "").strip()
        card_no = request.DATA.get("card_no", "").strip()
        input_phone = request.DATA.get("phone", "").strip()
        gate_id = request.DATA.get("gate_id", "").strip()

        if not amount or not card_no or not gate_id:
            return {"ret_code": 20112, 'message': '信息输入不完整'}
        if len(card_no) > 10 and not input_phone:
            return {"ret_code": 20112, 'message': '信息输入不完整'}
        if card_no and len(card_no) == 10:
            return {'ret_code': 20013, 'message': '卡号格式不正确'}

        try:
            float(amount)
        except:
            return {"ret_code": 20114, 'message': '金额格式错误'}

        amount = fmt_two_amount(amount)

        user = request.user
        profile = user.wanglibaouserprofile

        bank = Bank.objects.filter(gate_id=gate_id).first()
        if not bank or not bank.huifu_bind_code.strip():
            return {"ret_code": 201151, "message": "不支持该银行"}

        if len(card_no) == 10:
            card = Card.objects.filter(user=user, no__startswith=card_no[:6], no__endswith=card_no[-4:]).first()
            card_no = card.no
        else:
            card = Card.objects.filter(no=card_no, user=user).first()

        if not card:
            card = self.bind_card_wlbk(user, card_no, bank, request)

        if not card:
            return {"ret_code": -1, "message": '银行卡不存在'}

        if bank and card and bank != card.bank:
            return {"ret_code": 201153, "message": "银行卡与银行不匹配"}
        if card and not card.is_bind_huifu:
            res = self.open_bind_card(user, bank, card)
            if res['ret_code'] != 0:
                return res

            card.is_bind_huifu = True
            card.save()

        try:
            pay_info = PayInfo()
            pay_info.amount = amount
            pay_info.total_amount = amount
            pay_info.type = PayInfo.DEPOSIT
            pay_info.status = PayInfo.INITIAL
            pay_info.user = user
            pay_info.channel = "huifu_bind"

            pay_info.request_ip = get_client_ip(request)
            order = OrderHelper.place_order(user, Order.PAY_ORDER, pay_info.status, pay_info=model_to_dict(pay_info))
            pay_info.order = order

            if card:
                pay_info.bank = card.bank
                pay_info.card_no = card.no
            else:
                pay_info.bank = bank
                pay_info.card_no = card_no

            pay_info.status = PayInfo.PROCESSING
            pay_info.account_name = profile.name
            pay_info.save()
            OrderHelper.update_order(order, user, pay_info=model_to_dict(pay_info), status=pay_info.status)

            # 充值
            req, res = self._card_pay_huifu(user=user, amount=pay_info.amount, card_no=card_no)

            pay_info.error_code = res['RespCode']
            pay_info.error_message = res['ErrMsg']
            pay_info.request = req
            pay_info.response = res
            pay_info.response_ip = get_client_ip(request)

            if res['RespCode'] != u'000000':
                pay_info.save()
                return {"ret_code": -3, "message": res['ErrMsg']}
            else:
                pay_info.fee = self.FEE
                keeper = MarginKeeper(pay_info.user, pay_info.order.pk)
                margin_record = keeper.deposit(amount)
                pay_info.margin_record = margin_record
                pay_info.status = PayInfo.SUCCESS
                pay_info.save()
                rs = {"ret_code": 0, "message": "success", "amount": amount, "margin": margin_record.margin_current}

            if rs['ret_code'] == 0:
                device = split_ua(request)
                try:
                    # fix@chenweibi, add order_id
                    tools.deposit_ok.apply_async(kwargs={"user_id": pay_info.user.id, "amount": pay_info.amount,
                                                         "device": device, "order_id": order.id})
                except:
                    pass

                # 充值成功后,更新本次银行使用的时间
                Card.objects.filter(user=pay_info.user, no=pay_info.card_no).update(last_update=timezone.now())

            OrderHelper.update_order(pay_info.order, pay_info.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
            return rs
        except Exception, e:
            message = PayResult.RETRY
            pay_info.status = PayInfo.FAIL
            pay_info.error_message = str(e)
            pay_info.save()
            OrderHelper.update_order(order, request.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
            return {"ret_code": "20119", "message": message}
Example #8
0
    def handle_pay_result(cls, request):
        # TODO Add a log

        flag = False

        order_id = request.POST.get('OrdId', '')
        try:
            pay_info = PayInfo.objects.select_for_update().get(pk=order_id)
        except PayInfo.DoesNotExist:
            logger.warning('Order not found, order id: ' + order_id + ', response: ' + request.body)
            return PayResult.EXCEPTION

        if pay_info.status == PayInfo.SUCCESS:
            return PayResult.DEPOSIT_SUCCESS

        amount = request.POST.get('OrdAmt', '')
        code = request.POST.get('RespCode', '')
        message = request.POST.get('ErrMsg', '')
        pay_info.error_code = code
        pay_info.error_message = message
        pay_info.response = request.body
        pay_info.response_ip = get_client_ip(request)

        result = u''
        try:
            pay = HuifuPay()
            if pay.verify_sign(request.POST.dict(), HuifuPay.PAY_FIELDS):
                if pay_info.amount != decimal.Decimal(amount):
                    pay_info.status = PayInfo.FAIL
                    pay_info.error_message += u' 金额不匹配'
                    logger.error('Amount mismatch, order id: %s request amount: %f response amount: %s',
                                 order_id, float(pay_info.amount), amount)
                    result = PayResult.EXCEPTION
                else:
                    if code == '000000':
                        keeper = MarginKeeper(pay_info.user, pay_info.order.pk)
                        margin_record = keeper.deposit(amount)
                        pay_info.margin_record = margin_record
                        pay_info.status = PayInfo.SUCCESS
                        result = PayResult.DEPOSIT_SUCCESS
                        phone = pay_info.user.wanglibaouserprofile.phone

                        flag = True
                    else:
                        pay_info.status = PayInfo.FAIL
                        result = PayResult.DEPOSIT_FAIL
            else:
                pay_info.error_message = 'Invalid signature. Order id: ' + order_id
                logger.error(pay_info.error_message)
                pay_info.status = PayInfo.EXCEPTION
                result = PayResult.EXCEPTION
        except (socket.error, SignException) as e:
            pay_info.error_message = str(e)
            pay_info.status = PayInfo.EXCEPTION
            logger.fatal('sign error! order id: ' + order_id + ' ' + str(e))
            result = PayResult.EXCEPTION

        pay_info.save()

        if flag:
            device = split_ua(request)
            try:
                # fix@chenweibi, add order_id
                tools.deposit_ok.apply_async(kwargs={"user_id": pay_info.user.id, "amount": pay_info.amount,
                                                     "device": device, "order_id": pay_info.order_id})
                CoopRegister(request).process_for_recharge(pay_info.user, pay_info.order_id)
            except:
                pass

        OrderHelper.update_order(pay_info.order, pay_info.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
        return result
Example #9
0
    def pre_pay(self, request):
        """
        返回跳转信息{'message': message,'form': form}供跳转js使用,message包含报错信息
            form包含跳转信息
        :param request:
        :return:
        """
        if not request.user.wanglibaouserprofile.id_is_valid:
            return self.render_to_response({
                'message': u'请先进行实名认证'
            })
        form = dict()
        message = ''
        try:
            amount_str = request.POST.get('amount', '')
            amount = decimal.Decimal(amount_str). \
                quantize(TWO_PLACES, context=decimal.Context(traps=[decimal.Inexact]))
            amount_str = str(amount)
            if amount <= 0:
                # todo handler the raise
                raise decimal.DecimalException()

            gate_id = request.POST.get('gate_id', '')
            bank = Bank.objects.get(gate_id=gate_id)

            # Store this as the default bank
            request.user.wanglibaouserprofile.deposit_default_bank_name = bank.name
            request.user.wanglibaouserprofile.save()

            pay_info = PayInfo()
            pay_info.amount = amount
            pay_info.total_amount = amount
            pay_info.type = PayInfo.DEPOSIT
            pay_info.status = PayInfo.INITIAL
            pay_info.user = request.user
            pay_info.bank = bank
            pay_info.channel = "huifu"
            pay_info.request_ip = get_client_ip(request)

            order = OrderHelper.place_order(request.user, Order.PAY_ORDER, pay_info.status,
                                            pay_info=model_to_dict(pay_info))
            pay_info.order = order
            pay_info.save()

            post = {
                'OrdId': pay_info.pk,
                'GateId': gate_id,
                'OrdAmt': amount_str
            }

            form = self.pay(post)
            pay_info.request = str(form)
            pay_info.status = PayInfo.PROCESSING
            pay_info.save()
            OrderHelper.update_order(order, request.user, pay_info=model_to_dict(pay_info), status=pay_info.status)

            # 处理第三方渠道的用户充值回调
            CoopRegister(request).process_for_recharge(request.user, order.id)
        except decimal.DecimalException:
            message = u'金额格式错误'
        except Bank.DoesNotExist:
            message = u'请选择有效的银行'
        except (socket.error, SignException) as e:
            message = PayResult.RETRY
            pay_info.status = PayInfo.FAIL
            pay_info.error_message = str(e)
            pay_info.save()
            OrderHelper.update_order(order, request.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
            logger.fatal('sign error! order id: ' + str(pay_info.pk) + ' ' + str(e))

        result = {
            'message': message,
            'form': form
        }

        return result
Example #10
0
    def purchase(self, amount, redpack=0, platform=u''):
        description = u'购买P2P产品 %s %s 份' % (self.product.short_name, amount)
        is_full = False
        product_balance_after = 0
        if self.user.wanglibaouserprofile.frozen:
            raise P2PException(u'用户账户已冻结,请联系客服')
        with transaction.atomic():
            if redpack:
                # 为防止用户同时打开两个浏览器同时使用加息券和红包,须先检测
                coupons = RedPackRecord.objects.filter(user=self.user, product_id=self.product.id) \
                    .filter(redpack__event__rtype='interest_coupon')
                if coupons:
                    raise P2PException(u'已经选择过加息券,不能重复或叠加使用')
                else:
                    this_redpack = RedPackRecord.objects.filter(
                        pk=redpack).first()
                    this_rtype = this_redpack.redpack.event.rtype
                    coupons = RedPackRecord.objects.filter(user=self.user, product_id=self.product.id) \
                        .exclude(redpack__event__rtype='interest_coupon')
                    if coupons and this_rtype == 'interest_coupon':
                        raise P2PException(u'红包和加息券不能同时叠加使用')

                redpack_order_id = OrderHelper.place_order(
                    self.user,
                    order_type=u'优惠券消费',
                    redpack=redpack,
                    product_id=self.product.id,
                    status=u'新建').id
                result = redpack_backends.consume(redpack, amount, self.user,
                                                  self.order_id,
                                                  self.device_type,
                                                  self.product.id)
                if result['ret_code'] != 0:
                    raise Exception, result['message']
                if result['rtype'] != 'interest_coupon':
                    red_record = self.margin_keeper.redpack_deposit(
                        result['deduct'],
                        u"购买P2P抵扣%s元" % result['deduct'],
                        order_id=redpack_order_id,
                        savepoint=False)
                OrderHelper.update_order(
                    Order.objects.get(pk=redpack_order_id),
                    user=self.user,
                    status=u'成功',
                    amount=amount,
                    deduct=result['deduct'],
                    redpack=redpack)

            product_record = self.product_keeper.reserve(amount,
                                                         self.user,
                                                         savepoint=False,
                                                         platform=platform)
            margin_record = self.margin_keeper.freeze(amount,
                                                      description=description,
                                                      savepoint=False)
            equity = self.equity_keeper.reserve(amount,
                                                description=description,
                                                savepoint=False)

            OrderHelper.update_order(Order.objects.get(pk=self.order_id),
                                     user=self.user,
                                     status=u'份额确认',
                                     amount=amount)

            product_balance_after = product_record.product_balance_after
            if product_balance_after <= 0:
                is_full = True

        # fix@chenweibin, add order_id
        # Modify by hb on 2015-11-25 : add "try-except"
        try:
            logger.debug("=20151125= decide_first.apply_async : [%s], [%s], [%s], [%s], [%s], [%s]" % \
                         (self.user.id, amount, self.device['device_type'], self.order_id, self.product.id, is_full) )
            tools.decide_first.apply_async(
                kwargs={
                    "user_id": self.user.id,
                    "amount": amount,
                    "device": self.device,
                    "order_id": self.order_id,
                    "product_id": self.product.id,
                    "is_full": is_full,
                    "product_balance_after": product_balance_after
                })
        except Exception, reason:
            logger.debug(
                "=20151125= decide_first.apply_async Except:{0}".format(
                    reason))
            pass
Example #11
0
class YeeShortPay:
    """ 易宝快捷支付 """

    FEE = 0

    def __init__(self):
        self.PRIV_KEY = settings.YEE_MER_PRIV_KEY
        self.YEE_PUB_KEY = settings.YEE_PUB_KEY
        self.MER_ID = settings.YEE_MER_ID
        self.BIND_URL = settings.YEE_SHORT_BIND
        self.BIND_CHECK_SMS = settings.YEE_SHORT_BIND_CHECK_SMS
        self.BIND_CARD_QUERY = settings.YEE_SHORT_BIND_CARD_QUERY
        self.BIND_PAY_REQUEST = settings.YEE_SHORT_BIND_PAY_REQUEST
        self.YEE_CALLBACK = settings.YEE_SHORT_CALLBACK
        self.UNBIND_CARD = settings.YEE_URL + '/api/bankcard/unbind'
        self.QUERY_TRX_RESULT = settings.YEE_URL + '/api/query/order' 

    def _sign(self, dic):
        values = self._sort(dic)
        h = SHA.new(values)
        signer = pk.new(self.PRIV_KEY)
        sign_result = signer.sign(h)
        sign_result = base64.b64encode(sign_result)
        dic["sign"] = sign_result

        rand_aes_key = util.randstr()
        data = self.aes_base64_encrypt(json.dumps(dic), rand_aes_key)

        encryptkey = self.rsa_base64_encrypt(rand_aes_key, self.YEE_PUB_KEY)
        return data, encryptkey

    def _sort(self, dic):
        keys = dic.keys()
        keys.sort()
        return "".join([str(dic[k]) for k in keys])

    def aes_base64_encrypt(self,data,key):
        cipher = AES.new(key)
        return base64.b64encode(cipher.encrypt(self._pkcs7padding(data)))

    def aes_base64_decrypt(self,data,key):
        """
        1. base64 decode
        2. aes decode
        3. dpkcs7padding
        """
        cipher = AES.new(key)
        return self._depkcs7padding(cipher.decrypt(base64.b64decode(data)))

    def _pkcs7padding(self, data):
        """
        对齐块
        size 16
        999999999=>9999999997777777
        """
        size = AES.block_size
        count = size - len(data)%size
        if count:
            data+=(chr(count)*count)
        return data

    def _depkcs7padding(self, data):
        """
        反对齐
        """
        newdata = ''
        for c in data:
            if ord(c) > AES.block_size:
                newdata+=c
        return newdata

    def rsa_base64_encrypt(self,data,key):
        """
        1. rsa encrypt
        2. base64 encrypt
        """
        cipher = PKCS1_v1_5.new(key)
        return base64.b64encode(cipher.encrypt(data))

    def rsa_base64_decrypt(self,data,key):
        """
        1. base64 decrypt
        2. rsa decrypt
        示例代码

        key = RSA.importKey(open('privkey.der').read())
        >>>
        >>> dsize = SHA.digest_size
        >>> sentinel = Random.new().read(15+dsize)      # Let's assume that average data length is 15
        >>>
        >>> cipher = PKCS1_v1_5.new(key)
        >>> message = cipher.decrypt(ciphertext, sentinel)
        >>>
        >>> digest = SHA.new(message[:-dsize]).digest()
        >>> if digest==message[-dsize:]:                # Note how we DO NOT look for the sentinel
        >>>     print "Encryption was correct."
        >>> else:
        >>>     print "Encryption was not correct."
        """
        cipher = PKCS1_v1_5.new(key)
        return cipher.decrypt(base64.b64decode(data), Random.new().read(15+SHA.digest_size))

    def _verify(self, dic, sign):
        sign = base64.b64decode(sign)
        values = self._sort(dic)
        verifier = pk.new(self.YEE_PUB_KEY)
        if verifier.verify(SHA.new(values), sign):
            return True
        else:
            return False

    def save_card(self, user, card_no, bank):
        """ 保存卡信息到个人名下 """
        if len(card_no) == 10:
            card = Card.objects.filter(user=user, no__startswith=card_no[:6], no__endswith=card_no[-4:]).first()
        else:
            card = Card.objects.filter(no=card_no, user=user).first()

        if not card:
            card = Card()
            card.user = user
            card.no = card_no
            card.is_default = False

        card.bank = bank
        card.is_bind_yee = True
        card.save()
        return True

    def _format_post(self, post):
        """ 签名格式化请求数据 """
        data, encryptkey = self._sign(post)
        return {"data": data, "encryptkey": encryptkey, "merchantaccount": self.MER_ID}

    def _request_yee(self, url, data):
        # logger.error("request yee_pay: %s" % data)
        post = self._format_post(data)
        res = requests.post(url, post)
        res_dict = self._response_data_change(res=json.loads(res.text))
        logger.error("yee_pay: %s | %s | %s" % (url, data, res_dict))
        return res_dict 

    def _request_yee_get(self, url, data):
        post = self._format_post(data)
        res = requests.get(url, params=post)
        res_dict = self._response_data_change(res=json.loads(res.text))
        logger.error("yee_pay: %s | %s | %s" % (url, data, res_dict))
        return res_dict 

    def _response_data_change(self, res):
        """ 将易宝返回的数据格式化成程序通用数据 """
        if 'error_code' in res:
            # logger.error(res)
            return {'ret_code': res['error_code'], 'message': res['error_msg']}

        if 'data' not in res:
            # logger.error(res)
            return {'ret_code': 20012, 'message': '易宝数据有误'}

        flag, data = self._response_decode(res=res)

        if 'error_code' in data:
            # logger.error(data)
            return {'ret_code': data['error_code'], 'message': data['error_msg'], 'data': data}

        if not flag:
            # logger.error(data)
            return {'ret_code': 20011, 'message': '签名验证失败', 'data': data}

        # logger.error("yee_pay response: %s" % data)
        return {'ret_code': 0, 'message': 'ok', 'data': data}

    def _response_decode(self, res):
        """ 返回数据合法性校验 """
        if 'encryptkey' in res and 'data' in res:
            ybaeskey = self.rsa_base64_decrypt(res['encryptkey'], self.PRIV_KEY)
            data = json.loads(self.aes_base64_decrypt(res['data'], ybaeskey))
            if 'sign' in data:
                sign = data.pop('sign')
                if self._verify(data, sign):
                    return True, data
                else:
                    return False, data
        return False, res

    def _bind_card_request(self, request, phone, card_no, request_id):
        """ 邦卡请求 """
        user = request.user

        post = dict()
        post['merchantaccount'] = self.MER_ID
        post['identityid'] = str(user.wanglibaouserprofile.id_number)
        post['identitytype'] = 5
        post['requestid'] = request_id
        post['cardno'] = card_no
        post['idcardtype'] = '01'
        post['idcardno'] = str(user.wanglibaouserprofile.id_number)
        post['username'] = user.wanglibaouserprofile.name
        post['phone'] = phone
        post['userip'] = util.get_client_ip(request)
        return self._request_yee(url=self.BIND_URL, data=post)

    def _bind_check_sms(self, request_id, validatecode):
        """ 绑卡校验验证码 """
        post = dict()
        post['merchantaccount'] = self.MER_ID
        post['requestid'] = request_id
        post['validatecode'] = validatecode
        return self._request_yee(url=self.BIND_CHECK_SMS, data=post)

    def bind_card_query(self, user):
        """ 查询已经绑定的银行卡 """
        if not user.wanglibaouserprofile.id_is_valid:
            return {"ret_code": 20071, "message": "请先进行实名认证"}

        post = dict()
        post['merchantaccount'] = self.MER_ID
        post['identityid'] = str(user.wanglibaouserprofile.id_number)
        post['identitytype'] = 5
        return self._request_yee_get(url=self.BIND_CARD_QUERY, data=post)

    def delete_bind(self, user, card, bank):
        """ 解绑银行卡 """
        if card.is_bind_yee:
            # 易宝通卡进出,不允许用户解绑,解绑线下进行
            # card.is_bind_yee = False
            # card.yee_bind_id = ''
            # card.save()
            return {'ret_code': 21110, 'message': '易宝支付解绑请联系客服'}
        return {'ret_code': 0, 'message': 'ok'}

    def unbind_card(self, user, mcard):
        """解绑,但有如下限制:解绑后只能绑原卡,或者绑原卡只是预留号码变更的"""
        res = self.bind_card_query(user)
        yee_bindid = identitytype = identityid = ''
        if 'data' in res and 'cardlist' in res['data']:
            identityid = res['data']['identityid']
            identitytype = res['data']['identitytype']
            for card in res['data']['cardlist']:
                if mcard.no.startswith(card['card_top']) \
                        and mcard.no.endswith(card['card_last']):
                    yee_bindid = card['bindid']
                    break
        if yee_bindid:
            post = dict()
            post['merchantaccount'] = self.MER_ID
            post['bindid'] = yee_bindid
            post['identitytype'] = identitytype
            post['identityid'] = identityid
            print '*'*100, self.UNBIND_CARD
            return self._request_yee(url=self.UNBIND_CARD, data=post)

    def _pay_request(self, request, order_id, card, pay_info):
        """ 支付请求 """
        post = dict()
        post['merchantaccount'] = self.MER_ID
        post['orderid'] = str(order_id)
        post['transtime'] = int(time.time())
        post['amount'] = int(pay_info.amount * 100)
        post['productname'] = '网利宝-APP充值'
        post['identityid'] = str(request.user.wanglibaouserprofile.id_number)
        post['identitytype'] = 5
        post['card_top'] = pay_info.card_no[:6]
        post['card_last'] = pay_info.card_no[-4:]
        post['callbackurl'] = self.YEE_CALLBACK
        post['userip'] = util.get_client_ip(request)
        return self._request_yee(url=self.BIND_PAY_REQUEST, data=post)

    def _query_trx_result(self, order_id):
        """
        去第三方查询交易结果
        """
        post = dict()
        post['merchantaccount'] = self.MER_ID
        post['orderid'] = str(order_id)
        return self._request_yee_get(url=self.QUERY_TRX_RESULT, data=post)

    def add_card_unbind(self, user, card_no, bank, request):
        """ 保存卡信息到个人名下,不绑定任何渠道 """
        if len(card_no) == 10:
            card = Card.objects.filter(user=user, no__startswith=card_no[:6], no__endswith=card_no[-4:],
                                       is_bind_yee=True).first()
        else:
            card = Card.objects.filter(no=card_no, user=user).first()

        add_card = False
        if not card:
            card = Card()
            card.user = user
            card.no = card_no
            card.is_default = False

            add_card = True

        card.bank = bank
        card.save()
        # if add_card:
        #     try:
        #         # 处理第三方用户绑卡回调
        #         CoopRegister(request).process_for_binding_card(request.user)
        #     except Exception, e:
        #         logger.error(e)

        return card

    def pre_pay(self, request):
        """ 获取验证码支付还是直接支付
            长卡号获取验证码
            短卡号直接支付
        """
        if not request.user.wanglibaouserprofile.id_is_valid:
            return {"ret_code": 20111, "message": "请先进行实名认证"}

        amount = request.DATA.get("amount", "").strip()
        card_no = request.DATA.get("card_no", "").strip()
        input_phone = request.DATA.get("phone", "").strip()
        gate_id = request.DATA.get("gate_id", "").strip()
        device_type = split_ua(request)['device_type']

        if not amount or not card_no:
            return {"ret_code": 20112, 'message': '信息输入不完整'}
        if len(card_no) > 10 and (not input_phone or not gate_id):
            return {"ret_code": 20113, 'message': '卡号格式不正确'}

        try:
            float(amount)
        except:
            return {"ret_code": 20114, 'message': '金额格式错误'}

        amount = util.fmt_two_amount(amount)
        # if amount < 10 or len(str(amount)) > 20:
        #     return {"ret_code": 20115, 'message': '充值须大于等于10元'}

        if len(str(amount)) > 20:
            return {"ret_code": 20115, 'message': '充值金额太大'}

        if amount < 0.009:
            # 涉及到小数精度,不能用0.01
            return {"ret_code": 20115, 'message': '充值金额太小(至少0.01元)'}

        user = request.user
        profile = user.wanglibaouserprofile
        card, bank = None, None
        if gate_id:
            bank = Bank.objects.filter(gate_id=gate_id).first()
            if not bank or not bank.yee_bind_code.strip():
                return {"ret_code": 201116, "message": "不支持该银行"}

        if len(card_no) == 10:
            card = Card.objects.filter(user=user, no__startswith=card_no[:6], no__endswith=card_no[-4:],
                                       is_bind_yee=True).first()
        else:
            #card = Card.objects.filter(no=card_no, user=user).first()
            card = Card.objects.filter(no=card_no, user=user, bank=bank).first()
            pay_record = PayInfo.objects.filter(card_no=card_no, user=user, bank=bank)
            if pay_record.filter(error_message__icontains='不匹配'):
                return {"ret_code":200118, "message":"银行卡与银行不匹配"}

        if not card:
            card = self.add_card_unbind(user, card_no, bank, request)

        if not card and not bank:
            return {'ret_code': 200117, 'message': '卡号不存在或银行不存在'}

        #if bank and card and bank != card.bank:
            #return {"ret_code": 200118, "message": "银行卡与银行不匹配"}

        # 商户生成的唯一绑卡请求号,最长50位
        request_id = '{phone}{time}'.format(phone=profile.phone, time=timezone.now().strftime("%Y%m%d%H%M%S"))
        if len(card_no) != 10:
            # 未绑定银行卡,需要先绑定银行卡获取验证码,然后在确认支付
            try:
                # 请求绑定银行卡
                res = self._bind_card_request(request, input_phone, card_no, request_id)
                if res['ret_code'] != 0:
                    # 600326已绑定,600302绑卡数超限
                    if res['ret_code'] in ['600326', '600302']:
                        self.sync_bind_card(user)
                        return {'ret_code': '20119', 'message': '银行卡已绑定,请返回使用快捷充值'}
                    else:
                        # logger.error(res)
                        return res
            except Exception, e:
                logger.error(e.message)
                return {"ret_code": "20120", "message": '绑定银行卡失败'}

        try:
            pay_info = PayInfo()
            pay_info.amount = amount
            pay_info.total_amount = amount
            pay_info.type = PayInfo.DEPOSIT
            pay_info.status = PayInfo.INITIAL
            pay_info.user = user
            pay_info.channel = "yeepay_bind"

            pay_info.device = device_type
            pay_info.request_ip = util.get_client_ip(request)
            order = OrderHelper.place_order(user, Order.PAY_ORDER, pay_info.status, pay_info=model_to_dict(pay_info))
            pay_info.order = order

            pay_info.bank = card.bank
            pay_info.card_no = card.no
            pay_info.phone_for_card = input_phone
            pay_info.request = ""
            pay_info.status = PayInfo.PROCESSING
            pay_info.account_name = profile.name
            pay_info.save()
            OrderHelper.update_order(order, user, pay_info=model_to_dict(pay_info), status=pay_info.status)

            if len(card_no) == 10:
                # 直接支付交易,已经绑定了银行卡,直接进行支付操作
                res = self._pay_request(request, order.id, card, pay_info)
                if res['ret_code'] != 0:
                    # logger.error(res)
                    pay_info.error_code = res['ret_code']
                    pay_info.error_message = res['message']
                    if 'data' in res:
                        pay_info.response = res['data']
                    pay_info.save()
                    return res

                margin = Margin.objects.filter(user=user).first()
                return {"ret_code": 22000, "message": u"充值申请已提交,请稍候查询余额。", "amount": amount, "margin": margin.margin}

            else:
                return {"ret_code": 0, "message": "ok", "order_id": order.id, "token": request_id}

        except Exception, e:
            logger.error(traceback.format_exc())
            message = PayResult.RETRY
            pay_info.status = PayInfo.FAIL
            pay_info.error_message = str(e)
            pay_info.save()
            OrderHelper.update_order(order, request.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
            return {"ret_code": "20119", "message": message}
Example #12
0
    def app_pay(self, request):
        if not request.user.wanglibaouserprofile.id_is_valid:
            return {"ret_code":20071, "message":"请先进行实名认证"}

        amount = request.DATA.get("amount", "").strip()
        deviceid = request.DATA.get("device_id", "").strip()

        if not amount or not deviceid:
            return {"ret_code":20072, 'message':'信息输入不完整'}

        try:
            float(amount)
        except:
            return {"ret_code":20073, 'message':'金额格式错误'}

        amount = util.fmt_two_amount(amount)
        #if amount < 100 or amount % 100 != 0 or len(str(amount)) > 20:
        if amount < 10 or len(str(amount)) > 20:
            #return {"ret_code":20074, 'message':'金额格式错误,大于100元且为100倍数'}
            return {"ret_code":20074, 'message':'充值金额需大于10元'}
        if amount > 20000:
            return {"ret_code":20073, 'message':'单笔充值不超过2万,单月不超过5万。如需充值更多金额可以去网站完成。'}

        terminal = deviceid.split(":")
        deviceid = terminal[-1]
        tmpdic = {"imei":0, "mac":1, "uuid":2, "other":3}
        if terminal[0] in tmpdic:
            terminaltype = tmpdic[terminal[0]]
        else:
            terminaltype = tmpdic['other']


        card_id = request.DATA.get("card_id", "")
        user = request.user
        #amount_sec = int(amount*100)
        amount_sec = long(amount*100)
        useragent = request.META.get("HTTP_USER_AGENT", "noagent").strip()

        try:
            pay_info = PayInfo()
            pay_info.amount = amount
            pay_info.total_amount = amount
            pay_info.type = PayInfo.DEPOSIT
            pay_info.status = PayInfo.INITIAL
            pay_info.user = user
            pay_info.channel = "yeepay"

            if card_id:
                card =  Card.objects.filter(id=card_id, user=user).first()
                if not card:
                    return {"ret_code":20075, 'message':'选择的银行卡不存在'}
                pay_info.bank = card.bank
                pay_info.card_no = card.no

            pay_info.request_ip = util.get_client_ip(request)
            order = OrderHelper.place_order(user, Order.PAY_ORDER, pay_info.status,
                                            pay_info = model_to_dict(pay_info))
            pay_info.order = order
            pay_info.save()

            profile = user.wanglibaouserprofile
            dic = {"merchantaccount":self.MER_ID, "orderid":str(order.id), "transtime":long(time.mktime(pay_info.create_time.timetuple())),
                    "amount":amount_sec, "productcatalog":"18", "productname":"网利宝-APP充值",
                    "identityid":str(user.id), "identitytype":2, "terminaltype":terminaltype,
                    "terminalid":deviceid, "userip":pay_info.request_ip, "userua":useragent,
                    "callbackurl":self.PAY_BACK_RETURN_URL, "fcallbackurl":self.PAY_RETURN_URL,
                    "version":0, "paytypes":"1", "cardno":card_id, "orderexpdate":60}
            data, encryptkey = self._sign(dic)
            logger.error("%s" % dic)

            pay_info.request = str(dic)
            pay_info.status = PayInfo.PROCESSING
            pay_info.account_name = profile.name
            pay_info.save()
            OrderHelper.update_order(order, user, pay_info=model_to_dict(pay_info), status=pay_info.status)

            params = {"data":data, "encryptkey":encryptkey, "merchantaccount":self.MER_ID}
            url = "%s?%s" % (self.PAY_URL, urllib.urlencode(params))
            logger.error(url)
            return {"ret_code":0, "url":url}
        except Exception, e:
            logger.error(traceback.format_exc())
            message = PayResult.RETRY
            pay_info.status = PayInfo.FAIL
            pay_info.error_message = str(e)
            pay_info.save()
            OrderHelper.update_order(order, request.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
            logger.fatal('sign error! order id: ' + str(pay_info.pk) + ' ' + str(e))
            return {"ret_code":"20076", "message":message}
Example #13
0
                rs = {"ret_code":0, "message":"success", "amount":amount, "uid":pay_info.user.id}
            else:
                pay_info.status = PayInfo.FAIL
                logger.error("orderId:%s yeepay response status: %s" % (orderId, params['status']))
                rs = {"ret_code":20087, "message":PayResult.DEPOSIT_FAIL}

        pay_info.save()
        if rs['ret_code'] == 0:
            device = split_ua(request)
            try:
                # fix@chenweibi, add order_id
                tools.deposit_ok.apply_async(kwargs={"user_id": pay_info.user.id, "amount": pay_info.amount,
                                                     "device": device, "order_id": orderId})
            except:
                pass
        OrderHelper.update_order(pay_info.order, pay_info.user, pay_info=model_to_dict(pay_info), status=pay_info.status)
        return rs

    def pre_pay(self, request):
        self.app_pay(request)


class YeeShortPay:
    """ 易宝快捷支付 """

    FEE = 0

    def __init__(self):
        self.PRIV_KEY = settings.YEE_MER_PRIV_KEY
        self.YEE_PUB_KEY = settings.YEE_PUB_KEY
        self.MER_ID = settings.YEE_MER_ID
Example #14
0
    def order_after_pay_succcess(self,
                                 amount,
                                 order_id,
                                 res_ip=None,
                                 res_content=None,
                                 request=None,
                                 need_bind_card=False):
        """
        处理订单和用户的账户
        :param amount:
        :param order_id:
        :param user_id:
        :param ip:
        :param res_content:
        :return:
        """
        # 参数校验
        pay_info = PayInfo.objects.select_for_update().filter(
            order_id=order_id).first()
        if not pay_info:
            # return {"ret_code":20131, "message":"order not exist", "amount": amount}
            raise ThirdPayError(20131, 'order not exist')
        if pay_info.status == PayInfo.SUCCESS:
            return {
                "ret_code": 0,
                "message": PayResult.DEPOSIT_SUCCESS,
                "amount": amount
            }
        if fmt_two_amount(pay_info.amount) != fmt_two_amount(amount):
            raise ThirdPayError(20132, PayResult.EXCEPTION)
        if pay_info.user_id != pay_info.user_id:
            raise ThirdPayError(20133, PayResult.EXCEPTION)

        # 更新pay_info和margin信息
        pay_info.error_message = ""
        if res_content:
            pay_info.response = res_content
        if res_ip:
            pay_info.response_ip = res_ip
        pay_info.fee = self.FEE
        keeper = MarginKeeper(pay_info.user, pay_info.order.pk)
        margin_record = keeper.deposit(amount)
        pay_info.margin_record = margin_record
        pay_info.status = PayInfo.SUCCESS
        pay_info.save()

        # 更新order信息
        # if len(pay_info.card_no) == 10:
        #     Card.objects.filter(user=pay_info.user, no__startswith=pay_info.card_no[:6], no__endswith=pay_info.card_no[-4:]).update(last_update=timezone.now(), is_bind_kuai=True)
        # else:
        #     Card.objects.filter(user=pay_info.user, no=pay_info.card_no).update(last_update=timezone.now(), is_bind_kuai=True)
        OrderHelper.update_order(pay_info.order,
                                 pay_info.user,
                                 pay_info=model_to_dict(pay_info),
                                 status=pay_info.status)
        # 绑卡
        if need_bind_card:
            self.add_card(pay_info.card_no, pay_info.bank, pay_info.user,
                          pay_info.channel)

        try:
            user = pay_info.user
            CoopRegister(request).process_for_recharge(user, order_id)
            # tools.deposit_ok(request.user.id, amount, pay_info.device, order_id)
            tools.deposit_ok.apply_async(
                kwargs={
                    "user_id": user.id,
                    "amount": amount,
                    "device": pay_info.device,
                    "order_id": order_id
                })
        except:
            logger.exception('recharge_call_back faile for ' + str(user) +
                             str(order_id))

        logger.critical("orderId:%s success" % order_id)
        rs = {
            "ret_code": 0,
            "message": "success",
            "amount": amount,
            "margin": margin_record.margin_current,
            "order_id": order_id
        }
        return rs