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
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
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'])
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()
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 }
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)
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 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
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}
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
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