def post(self, request): logger.info('web_pay_request_para:' + str(request.POST)) try: user = request.user amount = fmt_two_amount(request.POST.get('amount')) gate_id = request.POST.get('gate_id') request_ip = get_client_ip(request) device_type = split_ua(request)['device_type'] channel = PayOrder.get_bank_and_channel(gate_id)[1] except: logger.exception('third_pay_error') result = {'message': '参数错误'} return self.render_to_response(result) if channel == 'yeepay': result = YeeProxyPay().proxy_pay(user, amount, gate_id, request_ip, device_type) elif channel == 'baopay': result = BaoProxyPay().proxy_pay(user, amount, gate_id, request_ip, device_type) else: result = HuifuPay().pre_pay(request) print 'pay_jump_para' + str(result) return self.render_to_response(result)
def _process(self, request): try: request_ip = get_client_ip(request) if request.method == 'GET': message_dict = request.GET elif request.method == 'POST': message_dict = request.POST pay_message = YeeProxyPayCallbackMessage().parse_message( message_dict, request_ip) result = YeeProxyPay().proxy_pay_callback(pay_message, request) amount = pay_message.amount except ThirdPayError, e: logger.exception('third_pay_error') result = {'ret_code': e.code} amount = 0
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 _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 destroy(self, request, pk=None): card_id = request.DATA.get('card_id', '') card = Card.objects.filter(id=card_id, user=self.request.user).first() if card: # 将删除的银行卡添加到异常银行卡名单中 black_list = BlackListCard() black_list.user = self.request.user black_list.card_no = card.no black_list.message = u'删除银行卡,手机号:{}'.format( self.request.user.wanglibaouserprofile.phone) black_list.ip = get_client_ip(request) black_list.save() # 删除银行卡 card.delete() return Response({'id': card_id}) else: return Response( { "message": u"查不到银行卡,请联系管理员", 'error_number': ErrorNumber.duplicate }, status=status.HTTP_400_BAD_REQUEST)
def bao_proxy_pay_process_request(request, just_parse_message=False): try: request_ip = get_client_ip(request) if request.method == 'GET': message_dict = request.GET elif request.method == 'POST': message_dict = request.POST pay_message = BaoProxyPayCallbackMessage().parse_message( message_dict, request_ip) if just_parse_message: if pay_message.ret_code == 0: code = 0 amount = pay_message.amount else: code = pay_message.ret_code amount = 0 return code, amount code = BaoProxyPay().proxy_pay_callback(pay_message, request)['ret_code'] amount = pay_message.amount except ThirdPayError, e: logger.exception('third_pay_error') code = e.code amount = 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}
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
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
def bind_pay_dynnum(request): """ 根据银行设置的支付渠道进行支付渠道的支付 1、确认支付功能 """ logger.error(request.DATA) user = request.user order_id = request.DATA.get("order_id", "").strip() token = request.DATA.get("token", "").strip() vcode = request.DATA.get("vcode", "").strip() input_phone = request.DATA.get("phone", "").strip() set_the_one_card = request.DATA.get('set_the_one_card', '').strip() device = split_ua(request) ip = util.get_client_ip(request) mode = request.DATA.get('mode', '').strip() if not order_id.isdigit(): return {"ret_code": 20125, "message": "订单号错误"} if not order_id or not token: return {"ret_code": 20120, "message": "请重新获取验证码"} pay_info = PayInfo.objects.filter(order_id=order_id).first() if not pay_info or pay_info.status == PayInfo.SUCCESS: return {"ret_code": 20121, "message": "订单不存在或已支付成功"} card_no = pay_info.card_no 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: # res = {"ret_code": 20002, "message": "银行卡未绑定"} channel = pay_info.channel else: channel = card.bank.channel if channel == 'huifu': res = {'ret_code': 20003, 'message': '汇付天下请选择快捷支付渠道'} elif channel == 'yeepay': res = YeeShortPay().dynnum_bind_pay(request) elif channel == 'kuaipay': res = KuaiShortPay().dynnum_bind_pay(user, vcode, order_id, token, input_phone, device, ip, request, mode=mode) elif channel == 'baopay': res = BaoPayInterface(user, ip, device).dynnum_bind_pay(order_id, vcode, mode, request) else: res = {"ret_code": 20004, "message": "请对银行绑定支付渠道"} if not card: # 宝付这个时候卡才生产,在调用dynnum_bind_pay之前是没卡的 card = Card.objects.get(no=pay_info.card_no) if res.get('ret_code') == 0: if set_the_one_card: TheOneCard(request.user).set(card.id) # # Modify by hb on 2015-12-24 : 如果ret_code返回非0, 还需进一步判断card是否有绑定记录, 因为有可能出现充值失败但绑卡成功的情况 # try: # bind_flag = 0 # if (card.bank.channel == 'kuaipay' and res.get('ret_code') == 0) or ( # card.bank.channel == 'yeepay' and res.get('ret_code') == 22000): # bind_flag = 1; # else: # card = Card.objects.filter(user=user, id=card.id).first() # if card and (card.is_bind_huifu or card.is_bind_kuai or card.is_bind_yee): # logger.error('=20151224= deposit failed but binding success: [%s] [%s]' % (card.user, card.no)) # bind_flag = 1; # if bind_flag == 1: # CoopRegister(request).process_for_binding_card(user) # except Exception, ex: # logger.exception('=20151224= bind_card_callback_failed: [%s] [%s] [%s]' % (user, card_no, ex)) process_for_bind_card(user, card, res, request) return res
def bind_pay_deposit(request): """ 根据银行设置的支付渠道进行支付渠道的支付 1、获取验证码 2、快捷支付功能 """ logger.error(request.DATA) card_no = request.DATA.get("card_no", "").strip() gate_id = request.DATA.get("gate_id", "").strip() input_phone = request.DATA.get("phone", "").strip() device_type = split_ua(request)['device_type'] ip = util.get_client_ip(request) mode = request.DATA.get('mode', '').strip() user = request.user if user.wanglibaouserprofile.utype == '3': return {"ret_code": 30059, "message": u"企业用户无法请求该接口"} if not user.wanglibaouserprofile.id_is_valid: return {"ret_code": 20111, "message": "请先进行实名认证"} if not card_no and not gate_id: return {"ret_code": 20001, 'message': '信息输入不完整'} if len(card_no) > 10 and (not input_phone or not gate_id): return {"ret_code": 20112, 'message': '信息输入不完整'} user_bind_cards = Card.objects.filter( user=user).filter(Q(is_bind_kuai=True) | Q(is_bind_yee=True)) if len(card_no) > 10 and user_bind_cards.filter(no=card_no).count() == 0 and \ user_bind_cards.filter(~Q(no=card_no)).count() > 0: # 只允许绑一张 return {"ret_code": 20113, 'message': '为确保账户安全,资金同卡进出,不能再绑卡'} if gate_id: bank = Bank.objects.filter(gate_id=gate_id).first() else: 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: return {"ret_code": 20001, 'message': '信息输入不完整'} bank = card.bank if not bank: return {"ret_code": 20002, "message": "银行ID不正确"} #验证银行卡和银行匹配 if len(card_no) != 10 and bank.cards_info: cardinfo = check_bank_carkinfo(card_no, bank) #返回ret_code为20075的话表示银行卡和银行不匹配 if cardinfo['ret_code'] == 20075: return cardinfo amount = request.DATA.get('amount', '').strip() try: amount = float(amount) amount = util.fmt_two_amount(amount) if amount < 0: raise ValueError() except: return {"ret_code": 20114, 'message': '金额格式错误'} if bank.channel == 'huifu': result = HuifuShortPay().pre_pay(request) return result elif bank.channel == 'yeepay': result = YeeShortPay().pre_pay(request) return result elif bank.channel == 'baopay': res = BaoPayInterface(user, ip, device_type).pre_pay(card_no, amount, input_phone, gate_id, request) return res elif bank.channel == 'kuaipay': stop_no_sms_channel = Misc.objects.filter( key='kuai_qpay_stop_no_sms_channel').first() if stop_no_sms_channel and stop_no_sms_channel.value == '1' and \ len(card_no) == 10 and not request.DATA.get('mode'): # mode != vcode_for_qpay # Modify by hb on 2016-04-28 #return {'ret_code': 201183, return {'ret_code': 201181, 'message': u'该银行支付升级,请更新App版本'} result = KuaiShortPay().pre_pay(user, amount, card_no, input_phone, gate_id, device_type, ip, request, mode=mode) return result else: return {"ret_code": 20004, "message": "请选择支付渠道"}
def withdraw(request): amount = request.DATA.get("amount", "").strip() card_id = request.DATA.get("card_id", "").strip() vcode = request.DATA.get("validate_code", "").strip() if not amount or not card_id: return {"ret_code": 20061, "message": u"信息输入不完整"} user = request.user if not user.wanglibaouserprofile.id_is_valid: return {"ret_code": 20062, "message": u"请先进行实名认证"} if user.wanglibaouserprofile.frozen: return {"ret_code": 20072, "message": u"用户账户已冻结,请联系客服"} try: float(amount) except: return {"ret_code": 20063, 'message': u'金额格式错误'} amount = util.fmt_two_amount(amount) if len(str(amount)) > 20: return {"ret_code": 20064, 'message': u'金额格式错误,大于100元且为100倍数'} margin = user.margin.margin if amount > margin: return {"ret_code": 20065, 'message': u'余额不足'} phone = user.wanglibaouserprofile.phone status, message = validate_validation_code(phone, vcode) if status != 200: # Modify by hb on 2015-12-02 #return {"ret_code": 20066, "message": u"验证码输入错误"} return {"ret_code": 20066, "message": message} card = Card.objects.filter(pk=card_id).first() if not card or card.user != user: return {"ret_code": 20067, "message": u"请选择有效的银行卡"} # 检测银行卡是否在黑名单中 black_list = BlackListCard.objects.filter(card_no=card.no).first() if black_list and black_list.user != user: return {"ret_code": 20072, "message": u'银行卡号异常,请联系客服'} # 检查白名单 white_list = WhiteListCard.objects.filter(user=user, card_no=card.no).first() if not white_list: # 增加银行卡号检测功能,检测多张卡 card_count = Card.objects.filter(no=card.no).count() if card_count > 1: return {"ret_code": 20073, "message": u'银行卡号有多张重复,请联系客服'} # 检测银行卡在以前的提现记录中是否为同一个用户 payinfo_record = PayInfo.objects.filter( card_no=card.no, type='W').order_by('-create_time').first() if payinfo_record: if payinfo_record.user != user: return {"ret_code": 20074, "message": u'银行卡号与身份信息不符,请联系客服'} # 计算提现费用 手续费 + 资金管理费 bank = card.bank uninvested = user.margin.uninvested # 充值未投资金额 # 获取费率配置 fee_misc = WithdrawFee() fee_config = fee_misc.get_withdraw_fee_config() # 检测提现最大最小金额 if amount > fee_config.get('max_amount') or amount <= 0: return {"ret_code": 20068, 'message': u'提现金额超出最大提现限额'} if amount < fee_config.get('min_amount'): if amount != margin: return { "ret_code": 20069, 'message': u'账户余额小于{}时需要一次性提完'.format(fee_config.get('min_amount')) } # 检测银行的单笔最大提现限额,如民生银行 if bank and bank.withdraw_limit: bank_limit = util.handle_withdraw_limit(bank.withdraw_limit) bank_max_amount = bank_limit.get('bank_max_amount', 0) if bank_max_amount: if amount > bank_max_amount: return {"ret_code": 20070, 'message': u'提现金额超出银行最大提现限额'} # 获取计算后的费率 fee, management_fee, management_amount = fee_misc.get_withdraw_fee( user, amount, margin, uninvested) # 实际提现金额 actual_amount = amount - fee - management_fee if actual_amount <= 0: return {"ret_code": 20071, "message": u'实际到账金额为0,无法提现'} pay_info = PayInfo() pay_info.amount = actual_amount pay_info.fee = fee pay_info.management_fee = management_fee pay_info.management_amount = management_amount pay_info.total_amount = amount pay_info.type = PayInfo.WITHDRAW pay_info.user = user pay_info.card_no = card.no pay_info.account_name = user.wanglibaouserprofile.name pay_info.bank = card.bank pay_info.request_ip = util.get_client_ip(request) pay_info.status = PayInfo.ACCEPTED pay_info.channel = "app" try: order = OrderHelper.place_order(user, Order.WITHDRAW_ORDER, pay_info.status, pay_info=model_to_dict(pay_info)) pay_info.order = order keeper = MarginKeeper(user, pay_info.order.pk) margin_record = keeper.withdraw_pre_freeze( amount, uninvested=management_amount) pay_info.margin_record = margin_record pay_info.save() return { "ret_code": 0, 'message': u'提现成功', "amount": amount, "phone": phone, "bank_name": bank.name, "order_id": order.id } except Exception, e: pay_info.error_message = str(e) pay_info.status = PayInfo.FAIL pay_info.save() return {"ret_code": 20065, 'message': u'余额不足'}
def post(self, request, *args, **kwargs): #result, message = verify_captcha(request.POST) #if not result: # return self.render_to_response({ # 'result': message # }) user = request.user if not user.wanglibaouserprofile.id_is_valid: return self.render_to_response({'result': u'请先进行实名认证'}) if user.wanglibaouserprofile.frozen: return self.render_to_response( {'result': u'账户已冻结!请联系网利宝客服:4008-588-066'}) phone = user.wanglibaouserprofile.phone code = request.POST.get('validate_code', '') status, message = validate_validation_code(phone, code) if status != 200: return self.render_to_response({ # Modify by hb on 2015-12-02 #'result': u'短信验证码输入错误' 'result': message }) result = PayResult.WITHDRAW_SUCCESS try: card_id = request.POST.get('card_id', '') card = Card.objects.get(pk=card_id, user=user) card_no = card.no # 检测银行卡是否在黑名单中 black_list = BlackListCard.objects.filter(card_no=card_no).first() if black_list and black_list.user != user: raise AbnormalCardException # 检查白名单 white_list = WhiteListCard.objects.filter(user=user, card_no=card_no).first() if not white_list: # 增加银行卡号检测功能,检测多张卡 card_count = Card.objects.filter(no=card_no).count() if card_count > 1: raise ManyCardException # 检测银行卡在以前的提现记录中是否为同一个用户 payinfo_record = PayInfo.objects.filter( card_no=card_no).order_by('-create_time').first() if payinfo_record: if payinfo_record.user != user: raise AbnormalCardException amount_str = request.POST.get('amount', '') amount = decimal.Decimal(amount_str). \ quantize(TWO_PLACES, context=decimal.Context(traps=[decimal.Inexact])) margin = user.margin.margin # 账户余额 uninvested = user.margin.uninvested # 充值未投资金额 # 获取费率配置 fee_misc = WithdrawFee() fee_config = fee_misc.get_withdraw_fee_config() # 计算提现费用 手续费 + 资金管理费 # 提现最大最小金额判断 if amount > fee_config.get('max_amount') or amount <= 0: raise decimal.DecimalException if amount < fee_config.get('min_amount'): if amount != margin: raise decimal.DecimalException # 获取计算后的费率 fee, management_fee, management_amount = fee_misc.get_withdraw_fee( user, amount, margin, uninvested) actual_amount = amount - fee - management_fee # 实际到账金额 if actual_amount <= 0: raise decimal.DecimalException # 检测个别银行的单笔提现限额,如民生银行 bank_limit = util.handle_withdraw_limit(card.bank.withdraw_limit) bank_max_amount = bank_limit.get('bank_max_amount', 0) if bank_max_amount: if amount > bank_max_amount: raise decimal.DecimalException pay_info = PayInfo() pay_info.amount = actual_amount pay_info.fee = fee pay_info.management_fee = management_fee pay_info.management_amount = management_amount pay_info.total_amount = amount pay_info.type = PayInfo.WITHDRAW pay_info.user = user pay_info.card_no = card.no pay_info.account_name = user.wanglibaouserprofile.name pay_info.bank = card.bank pay_info.request_ip = get_client_ip(request) pay_info.status = PayInfo.ACCEPTED order = OrderHelper.place_order(user, Order.WITHDRAW_ORDER, pay_info.status, pay_info=model_to_dict(pay_info)) pay_info.order = order keeper = MarginKeeper(user, pay_info.order.pk) margin_record = keeper.withdraw_pre_freeze( amount, uninvested=management_amount) pay_info.margin_record = margin_record pay_info.save() try: device = split_ua(request) except: device = {'device_type': 'pc'} name = user.wanglibaouserprofile.name or u'用户' withdraw_submit_ok.apply_async( kwargs={ "user_id": user.id, "user_name": name, "phone": user.wanglibaouserprofile.phone, "amount": amount, "bank_name": card.bank.name, "order_id": order.id, "device": device }) except decimal.DecimalException: result = u'提款金额在0~{}之间'.format(fee_config.get('max_amount')) except Card.DoesNotExist: result = u'请选择有效的银行卡' except ManyCardException: result = u'银行卡号存在重复,请尝试其他银行卡号码,如非本人操作请联系客服' except AbnormalCardException: result = u'银行卡号与身份信息存在异常, 如非本人操作请联系客服' except MarginLack as e: result = u'余额不足' pay_info.error_message = str(e) pay_info.status = PayInfo.FAIL pay_info.save() # return self.render_to_response({ # 'result': result # }) return HttpResponseRedirect( reverse('withdraw-complete-result', kwargs={'result': result}))
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}
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}
if not self._verify(params, sign): return {"ret_code":20083, "message":"params sign invalid"} if params['merchantaccount'] != self.MER_ID: return {"ret_code":20084, "message":"params merhantaccount invalid"} orderId = params['orderid'] pay_info = PayInfo.objects.filter(order_id=orderId).first() if not pay_info: return {"ret_code":20085, "message":"order not exist"} if pay_info.status == PayInfo.SUCCESS: return {"ret_code":0, "message":PayResult.DEPOSIT_SUCCESS, "amount":amount} pay_info.error_message = str(params['status']) pay_info.response = "%s" % params pay_info.response_ip = util.get_client_ip(request) if not pay_info.bank and "bank" in params: bank = Bank.objects.filter(name=params['bank']).first() if bank: pay_info.bank = bank if pay_info.amount != amount: pay_info.status = PayInfo.FAIL pay_info.error_message += u' 金额不匹配' logger.error("orderId:%s amount:%s, response amount:%s" % (orderId, pay_info.amount, amount)) rs = {"ret_code":20086, "message":PayResult.EXCEPTION} else: if params['status'] == 1: pay_info.fee = self.FEE keeper = MarginKeeper(pay_info.user, pay_info.order.pk)