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 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 generate_payinfo(cls, clean=False): if clean: PayInfo.objects.all().delete() banks = Bank.objects.all() # generate 5 payinfo per user for user in get_user_model().objects.all(): for i in range(0, 6): pay = PayInfo() pay.user = user pay.type = 'D' pay.amount = random.randrange(1000, 10000) pay.total_amount = pay.amount pay.order = OrderHelper.place_order() pay.bank = banks[random.randrange(0, len(banks))] pay.status = (PayInfo.INITIAL, PayInfo.PROCESSING, PayInfo.SUCCESS, PayInfo.FAIL, PayInfo.EXCEPTION, PayInfo.ACCEPTED)[random.randrange(0, 6)] pay.request_ip = '127.0.0.1' pay.save()
def __init__(self, product, user, order_id=None, request=None): self.user = user self.product = product if self.product.status != u"正在招标": raise P2PException(u'购买的标不在招标状态') self.request = request if order_id is None: self.order_id = OrderHelper.place_order(user, order_type=u'产品申购', product_id=product.id, status=u'新建').id else: self.order_id = order_id self.margin_keeper = MarginKeeper(user=user, order_id=self.order_id) self.product_keeper = ProductKeeper(product, order_id=self.order_id) self.equity_keeper = EquityKeeper(user=user, product=product, order_id=self.order_id) if request: self.device = split_ua(request) self.device_type = self.device['device_type'] else: self.device = split_ua(request) self.device_type = "pc"
def __init__(self, *args, **kwargs): self.user = kwargs.get('user', None) order_id = kwargs.get('order_id', None) if order_id is None: order_id = OrderHelper.place_order(user=self.user).id self.order_id = order_id
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 reward_user_5(user, introduced_by, reward_type, got_amount, product, only_show): reward = Reward.objects.filter(is_used=False, type=reward_type).first() text_content = u"【网利宝】您在邀请好友送收益的活动中,获得%s元收益,收益已经发放至您的网利宝账户。请注意查收。回复TD退订4008-588-066【网利宝】" % got_amount if only_show is not True: send_messages.apply_async( kwargs={ "phones": [user.wanglibaouserprofile.phone], "messages": [text_content] }) if only_show is not True: earning = Earning() earning.amount = got_amount earning.type = 'I' earning.product = product order = OrderHelper.place_order(introduced_by, Order.ACTIVITY, u"邀请送收益活动赠送", earning=model_to_dict(earning)) earning.order = order keeper = MarginKeeper(introduced_by, order.pk) # 赠送活动描述 desc = u'%s,邀请好友首次理财活动中,活赠%s元' % ( introduced_by.wanglibaouserprofile.name, got_amount) earning.margin_record = keeper.deposit(got_amount, description=desc) earning.user = introduced_by earning.save() message_content = u"您在邀请好友送收益的活动中,您的好友%s在活动期间完成首次投资,根据活动规则,您获得%s元收益。<br/>\ <a href = 'https://www.wanglibao.com/accounts/home/'>查看账户余额</a><br/>\ 感谢您对我们的支持与关注。<br/>\ 网利宝" % (safe_phone_str( user.wanglibaouserprofile.phone), got_amount) if only_show is not True: RewardRecord.objects.create(user=introduced_by, reward=reward, description=message_content) inside_message.send_one.apply_async( kwargs={ "user_id": introduced_by.id, "title": u"邀请送收益活动", "content": message_content, "mtype": "activity" }) else: print message_content print introduced_by.wanglibaouserprofile.name print safe_phone_str(user.wanglibaouserprofile.phone) print text_content
def generate(cls, clean=False): User = get_user_model() users = User.objects.all() for u in users: if not hasattr(u, 'margin'): margin = Margin(user=u) margin.save() for u in users: order = OrderHelper.place_order() keeper = MarginKeeper(order_id=order.id, user=u) keeper.deposit(100000000)
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 AuditEquityCreateContract(request, equity_id): equity = P2PEquity.objects.filter(id=equity_id).select_related('product').first() product = equity.product order = OrderHelper.place_order(order_type=u'生成合同文件', status=u'开始', equity_id=equity_id, product_id=product.id) if not equity.latest_contract: #create contract file EquityKeeperDecorator(product, order.id).generate_contract_one(equity_id=equity_id, savepoint=False) equity_new = P2PEquity.objects.filter(id=equity_id).first() try: f = equity_new.latest_contract lines = f.readlines() f.close() return HttpResponse("\n".join(lines)) except ValueError, e: raise Http404
def reward_earning(record, reward_user, got_amount, product, flag): from wanglibao_p2p.models import Earning from order.utils import OrderHelper from order.models import Order from django.forms import model_to_dict from wanglibao_margin.marginkeeper import MarginKeeper # 发放收益 earning = Earning() earning.amount = got_amount earning.type = 'I' earning.product = product order = OrderHelper.place_order(reward_user, Order.ACTIVITY, u"邀请送收益活动赠送", earning=model_to_dict(earning)) earning.order = order keeper = MarginKeeper(reward_user, order.pk) # 赠送活动描述 desc = u'%s,邀请好友理财活动中,获赠%s元' % (reward_user.wanglibaouserprofile.name, got_amount) earning.margin_record = keeper.deposit(got_amount, description=desc, catalog=u"邀请赠送") earning.user = reward_user earning.save() if flag == 1: IntroducedByReward.objects.filter(id=record.id).update( checked_status=1, checked_at=timezone.now(), user_send_status=True) else: IntroducedByReward.objects.filter(id=record.id).update( checked_status=1, checked_at=timezone.now(), introduced_send_status=True)
def preprocess_for_settle(cls, product): cls.logger.info('Enter pre process for settle for product: %d: %s', product.id, product.name) # Create an order to link all changes order = OrderHelper.place_order(order_type=u'满标状态预处理', status=u'开始', product_id=product.id) if product.status != u'满标已打款': raise P2PException(u'产品状态(%s)不是(满标已打款)' % product.status) with transaction.atomic(): # Generate the amotization plan and contract for each equity(user) amo_keeper = AmortizationKeeper(product, order_id=order.id) amo_keeper.generate_amortization_plan(savepoint=False) # for equity in product.equities.all(): # EquityKeeper(equity.user, equity.product, order_id=order.id).generate_contract(savepoint=False) # EquityKeeperDecorator(product, order.id).generate_contract(savepoint=False) product = P2PProduct.objects.get(pk=product.id) product.status = u'满标待审核' product.make_loans_time = timezone.now() product.save()
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 order_before_pay(self, user, amount, gate_id, request_ip, device_type, card_no=None, phone_for_card=None): """ 支付前的订单处理 card_no和phone_for_card为可选参数,其他为必填参数 网银支付(页面支付):无card_no和phone_for_card 快捷支付第一次支付:会带上card_no和phone_for_card,这时的卡号是完整的,用于绑卡 快捷支付后续支付:只有card_no,无phone_for_card,这时的卡号是10位的短号 无论长号还是短号,填入pay_info的都是长号 :param user: :param amount: :param gate_id: :param request_ip: :param device_type: :param request_para_str: 发往第三方的请求信息 :return: order.id """ # 处理必填信息 is_bind_pay = True if card_no else False bank, channel = self.get_bank_and_channel(gate_id, is_bind_pay)[:2] pay_info = PayInfo() pay_info.type = PayInfo.DEPOSIT pay_info.user = user pay_info.account_name = user.wanglibaouserprofile.name pay_info.amount = amount pay_info.total_amount = amount # pay_info.status = PayInfo.INITIAL pay_info.bank = bank pay_info.channel = channel # pay_info.phone_for_card = phone_for_card # todo better 是否记录更全面的客户端信息 pay_info.request_ip = request_ip pay_info.device = device_type # 处理可选的银行卡信息 if card_no: pay_info.card_no = self.get_card_no(card_no, user, gate_id, is_bind_pay) if phone_for_card: pay_info.phone_for_card = phone_for_card # order = OrderHelper.place_order(user, Order.PAY_ORDER, pay_info.status, # pay_info = model_to_dict(pay_info)) # 不同状态(已绑卡,未绑卡)事bank和card_no的处理 # 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 # todo better 时间处理 pay_info.status = PayInfo.PROCESSING pay_info.save() # OrderHelper.update_order(order, user, pay_info=model_to_dict(pay_info), status=pay_info.status) 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() return order.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
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
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 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}
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'余额不足'}
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 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}))
def post(self, request): user = request.user now = timezone.now() start_dt = local_to_utc(datetime(2016, 6, 7), 'min') user_joined = user.date_joined # 用户注册时间 device = split_ua(request) device_type = decide_device(device['device_type']) purchase_code = 'experience_purchase' experience_product = ExperienceProduct.objects.filter( isvalid=True).first() if not experience_product: return Response({'ret_code': 30001, 'message': u'体验标有误,请重试'}) total_amount = 0 total_amount_tmp = 0 # 查询用户符合条件的理财金记录 with transaction.atomic(savepoint=True): # 锁表,主要用来锁定体验金投资时的动作 purchase_lock_record = ExperiencePurchaseLockRecord.objects.select_for_update().\ filter(user=user, purchase_code=purchase_code).first() if not purchase_lock_record: # 没有记录时创建一条 try: purchase_lock_record = ExperiencePurchaseLockRecord.objects.create( user=user, purchase_code=purchase_code, purchase_times=0) except Exception: logger.exception( "Error: experience purchase err, user: %s, phone: %s" % (user.id, user.wanglibaouserprofile.phone)) return Response({ 'ret_code': 30003, 'message': u'体验金投资失败,请重试' }) experience_record = ExperienceEventRecord.objects.filter(user=user, apply=False) \ .filter(event__invalid=False, event__available_at__lt=now, event__unavailable_at__gt=now)\ .select_related('event') records_ids = '' if experience_record: catalog = u'购买体验标' for i in experience_record: total_amount_tmp += i.event.amount buy_p2p = P2PRecord.objects.filter(user_id=user.id).exists() buy_count = MarginRecord.objects.filter( user_id=user.id, catalog=catalog).count() if not buy_p2p: if user_joined > start_dt: # 如果查询到已经购买过至少 1 次体验标,则不再检测账户余额 if buy_count == 0: if total_amount_tmp >= 28888 and user.margin.margin < 1: return Response({ 'ret_code': 30009, 'message': u'账户余额不足,请先充值' }) for record in experience_record: event = record.event total_amount += event.amount records_ids += str(record.id) + ',' record.apply = True record.apply_amount = event.amount record.apply_at = timezone.now() record.apply_platform = device_type record.save() terms = get_amortization_plan(u'日计息一次性还本付息').generate( total_amount, experience_product.expected_earning_rate / 100.0, timezone.now(), experience_product.period) for index, term in enumerate(terms['terms']): amortization = ExperienceAmortization() amortization.product = experience_product amortization.user = user amortization.principal = term[1] # 本金 amortization.interest = term[2] # 利息 amortization.term = index + 1 # 期数 amortization.description = u'第%d期' % (index + 1) amortization.term_date = term[6] - timedelta(days=1) amortization.save() # 从账户中扣除 1 元 (没有购买过体验标的情况) if not buy_p2p: if user_joined > start_dt: if total_amount >= 28888 and buy_count == 0: amount = 1.00 order_id = OrderHelper.place_order( user, order_type=catalog, status=u'新建').id margin_keeper = MarginKeeper(user=user, order_id=order_id) margin_keeper.reduce_margin_common( amount, catalog=catalog, description=catalog) # 更新当前的一组流水id purchase_lock_record.purchase_times += 1 purchase_lock_record.description = records_ids purchase_lock_record.save() term_date = amortization.term_date interest = amortization.interest return Response({ 'ret_code': 0, 'data': { 'amount': total_amount, 'term_date': term_date.strftime("%Y-%m-%d"), 'interest': interest } }) else: return Response({ 'ret_code': 30002, 'message': u'没有体验金记录,无法购买体验标' })
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 send_reward(start, end, amount_min, percent): from wanglibao_sms.tasks import send_messages from wanglibao_p2p.models import Earning from order.utils import OrderHelper from order.models import Order from django.forms import model_to_dict from wanglibao_margin.marginkeeper import MarginKeeper from wanglibao.templatetags.formatters import safe_phone_str from marketing.models import RewardRecord from decimal import Decimal start = datetime.strptime(start, '%Y-%m-%d') end = datetime.strptime(end, '%Y-%m-%d') # 审核通过,给用户发放奖励 reward_type = u'邀请送收益' records = IntroducedByReward.objects.filter( checked_status=0, activity_start_at=local_to_utc(start, source_time='min'), activity_end_at=local_to_utc(end, source_time='max'), activity_amount_min=Decimal(amount_min), percent_reward=Decimal(percent), ) if not records.exists(): return for record in records: # with transaction.atomic(): user, introduced_by, reward_type, got_amount, product = record.user, record.introduced_by_person, reward_type, record.introduced_reward, record.product reward = Reward.objects.filter(is_used=False, type=reward_type).first() # 发送短信 # text_content = u"【网利宝】您在邀请好友送收益的活动中,获得%s元收益,收益已经发放至您的网利宝账户。请注意查收。" % got_amount # send_messages.apply_async(kwargs={ # "phones": [introduced_by.wanglibaouserprofile.phone], # "messages": [text_content] # }) # 发放收益 earning = Earning() earning.amount = got_amount earning.type = 'I' earning.product = product order = OrderHelper.place_order(introduced_by, Order.ACTIVITY, u"邀请送收益活动赠送", earning=model_to_dict(earning)) earning.order = order keeper = MarginKeeper(introduced_by, order.pk) # 赠送活动描述 desc = u'%s,邀请好友首次理财活动中,活赠%s元' % ( introduced_by.wanglibaouserprofile.name, got_amount) earning.margin_record = keeper.deposit(got_amount, description=desc, catalog=u"邀请首次赠送") earning.user = introduced_by earning.save() # 发放站内信 message_content = u"您在邀请好友送收益的活动中,您的好友%s在活动期间完成首次投资,根据活动规则,您获得%s元收益。<br/>\ <a href='/accounts/home/' target='_blank'>查看账户余额</a><br/>\ 感谢您对我们的支持与关注。<br/>\ 网利宝" % (safe_phone_str( user.wanglibaouserprofile.phone), got_amount) RewardRecord.objects.create(user=introduced_by, reward=reward, description=message_content) inside_message.send_one.apply_async( kwargs={ "user_id": introduced_by.id, "title": u"邀请送收益活动", "content": message_content, "mtype": "activity" }) IntroducedByReward.objects.filter(id=record.id).update( checked_status=1)
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 buy_month_product(token=None, red_packet_id=None, amount_source=None, user=None, device=None, period=0): """ 对这个购买的月利宝记录进行扣款冻结操作. :param token: month_product's unique token. ### :param product: pass a month_product object error! amount_source: 购买的总金额 ###### 以下 如果是 amount 是 优惠后的金额 :return: """ # 标志购买成功才去走活动检查. flag = False with transaction.atomic(savepoint=True): product = MonthProduct.objects.select_for_update().filter( token=token).first() if not product: return ret = dict() if product.trade_status != 'NEW': ret.update(status=1, token=product.token, msg='already saved!') else: # 未被取消的订单才可以扣款 if not product.cancel_status: # 状态成功, 对买家扣款, 加入冻结资金 try: buyer_keeper = PhpMarginKeeper(product.user, product.product_id) user = User.objects.filter(pk=user).first() # update by lili 2016-06-14 # 如果使用红包的话,需要先将红包的钱判断正确后存入用户账户,然后再去检测购买金额和余额 # 如果使用红包的话, 增加红包使用记录 if red_packet_id and int(red_packet_id) > 0: logger.info( 'buy_month_product token = {} used with red_pack_id = {}' .format(token, red_packet_id)) redpack = RedPackRecord.objects.filter( pk=red_packet_id).first() redpack_order_id = OrderHelper.place_order( user, order_type=u'优惠券消费', redpack=redpack.id, product_id=product.product_id, status=u'新建').id result = php_redpack_consume(red_packet_id, amount_source, user, product.id, device['device_type'], product.product_id) if result['ret_code'] != 0: raise Exception, result['message'] if result['rtype'] != 'interest_coupon': red_record = buyer_keeper.redpack_deposit( result['deduct'], u"购买月利宝抵扣%s元" % result['deduct'], order_id=redpack_order_id, savepoint=False) buyer_keeper.php_freeze(amount_source, description=u'月利宝购买冻结') product.trade_status = 'PAID' product.save() ret.update(status=1, token=token, msg='success') flag = True except Exception, e: logger.exception("buy_month_product failed:") logger.debug( 'buy_month_product failed with exception: {}, red_pack_id = {}' .format(str(e), red_packet_id)) product.trade_status = 'FAILED' product.save() ret.update(status=0, token=product.token, msg='pay failed!' + str(e))
def build_earning(product_id): p2p = P2PProduct.objects.select_related('activity__rule').get( pk=product_id) num = Earning.objects.filter(product=p2p).count() if num > 0: return #按用户汇总某个标的收益 earning = P2PRecord.objects.values('user').annotate( sum_amount=Sum('amount')).filter(product=p2p, catalog=u'申购') phone_list = [] earning_list = [] rule = p2p.activity.rule unit = period_unit(p2p.pay_method) #把收益数据插入earning表内 for obj in earning: # bind = Binding.objects.filter(user_id=obj.get('user')).first() # if bind and bind.isvip: earning = Earning() amount = rule.get_earning(obj.get('sum_amount'), p2p.period, p2p.pay_method) earning.amount = amount earning.type = 'D' earning.product = p2p user = User.objects.get(pk=obj.get('user')) order = OrderHelper.place_order(user, Order.ACTIVITY, u"活动赠送", earning=model_to_dict(earning)) earning.order = order keeper = MarginKeeper(user, order.pk) #赠送活动描述 desc = u'%s,%s赠送%s%s' % (p2p.name, p2p.activity.name, p2p.activity.rule.rule_amount * 100, '%') earning.margin_record = keeper.deposit(amount, description=desc, catalog=u"活动赠送") earning.user = user #earning.save() earning_list.append(earning) phone_list.append(user.wanglibaouserprofile.phone) earning_time = timezone.localtime( timezone.now()).strftime("%Y-%m-%d %H:%M:%S") title, content = messages.msg_bid_earning(p2p.name, p2p.activity.name, p2p.period, earning_time, rule.percent_text, amount, unit) inside_message.send_one.apply_async( kwargs={ "user_id": obj.get('user'), "title": title, "content": content, "mtype": "activity" }) #发送活动赠送短信 # send_messages.apply_async(kwargs={ # "phones": phone_list, # "messages": [messages.earning_message(rule.percent_text)] # }) Earning.objects.bulk_create(earning_list)
def prepayment(self, penal_interest, repayment_type, payment_date, savepoint=True): """ #1. 拿到当期未还款计划 #1.11 如果是按期提前还款 #1.12 利息 = 当期利息 #1.21 如果是按日提前还款 #1.22 利息 = 年利率/360*计息天数*本金 #2. 拿到此标的年华收益 #3. 计算日收益 #4. 计算当期未计息天数 """ pname = '' amortization_records_tmp = list() phone_list = list() message_list = list() with transaction.atomic(savepoint=savepoint): amortization = ProductAmortization.objects.select_for_update().get(id=self.amortization.id) if amortization.settled: raise PrepaymentException() # 1.生成产品提前还款记录 # amortization = self.amortization product_record = self.get_product_repayment(penal_interest, repayment_type, payment_date) order_id = OrderHelper.place_order(None, order_type=self.catalog, product_id=self.product.id, status=u'新建').id product_record.order_id = order_id amortization_records = list() # 用户还款计划 user_amortizations = amortization.subs.all().select_related('user__wanglibaouserprofile') product = amortization.product import re matches = re.search(u'日计息', product.pay_method) if matches and matches.group(): pname = u"%s,期限%s天" % (product.name, product.period) else: pname = u"%s,期限%s个月" % (product.name, product.period) for user_amortization in user_amortizations: logger.error("提前还款用户: [%s], [%s]" % (user_amortization.user.id, user_amortization.user.wanglibaouserprofile.phone)) # 计算最终计算提前还款的本金, 利息, 罚息, 加息 user_record = self.get_user_repayment(user_amortization, penal_interest, repayment_type, payment_date) logger.error("新的本金: [%s], 利息:[%s], 加息:[%s], repayment_type:[%s], payment_date:[%s]" % ( user_record.principal, user_record.interest, user_record.coupon_interest, repayment_type, payment_date)) user_margin_keeper = MarginKeeper(user_record.user) # 提前还款需要将加息金额还给用户(重新计算后的该用户所用加息券的加息金额) user_margin_keeper.amortize(user_record.principal, user_record.interest, user_record.penal_interest, user_record.coupon_interest, savepoint=False, description=self.description) order_id = OrderHelper.place_order(user_record.user, order_type=self.catalog, product_id=self.product.id, status=u'新建').id user_record.order_id = order_id user_record.amortization = amortization amortization_records.append(user_record) amortization_records_tmp.append(user_record) # 发消息临时list变量(不包含product_record) logger.error("order_id: %s" % order_id) amortization_records.append(product_record) AmortizationRecord.objects.bulk_create(amortization_records) ProductAmortization.objects.filter(product=self.product, settled=False)\ .update(settled=True, settlement_time=timezone.now()) UserAmortization.objects.filter(product_amortization__product=self.product, settled=False)\ .update(settled=True, settlement_time=timezone.now()) ProductKeeper(self.product).finish(None) # 将提前还款的消息发送放到事务外边 for user_record in amortization_records_tmp: try: # 提前还款短信 # 提前还款金额 = 本金 + 利息 + 罚息 + 加息 amo_amount = user_record.principal + user_record.interest + \ user_record.penal_interest + user_record.coupon_interest user = user_record.user user_profile = user.wanglibaouserprofile phone_list.append(user_profile.phone) message_list.append(messages.product_prepayment(user_profile.name, amortization.product, amo_amount)) # 标的每一期还款完成后,检测该用户还款的本金是否有符合活动的规则,有的话触发活动规则 try: if user_record.principal > 0: # activity_backends.check_activity(user, 'repaid', 'pc', user_record.principal, product.id) check_activity_task.apply_async(kwargs={ "user_id": user.id, "trigger_node": 'repaid', "device_type": 'pc', "amount": user_record.principal, "product_id": product.id }, queue='celery02') except Exception: logger.exception("==提前还款==活动检测==") logger.debug("提前还款, user: {}, principal: {}, product_id: {}".format( user, user_record.principal, product.id )) try: # 提前还款站内信 title, content = messages.msg_bid_prepayment(pname, timezone.now(), amo_amount) inside_message.send_one.apply_async(kwargs={ "user_id": user.id, "title": title, "content": content, "mtype": "amortize" }) except Exception, e: logger.exception("==提前还款==站内信==") logger.debug(("user:%s====提前还款==站内信==" % user.id) + traceback.format_exc()) try: weixin_user = WeixinUser.objects.filter(user=user).first() if weixin_user and weixin_user.subscribe: now = datetime.now().strftime('%Y年%m月%d日 %H:%M:%S') sentTemplate.apply_async(kwargs={ "kwargs": json.dumps({ "openid": weixin_user.openid, "template_id": PRODUCT_AMORTIZATION_TEMPLATE_ID, "keyword1": product.name, "keyword2": "%s 元" % str(amo_amount), "keyword3": now, }) }, queue='celery02') except Exception, e: logger.exception("==提前还款==微信模板==") logger.debug(("user:%s====提前还款==微信模板==" % user.id) + traceback.format_exc())