def php_commission(user, product_id, start): """ 月利宝的表存的是php那边的流水.直接从这获取 :param user: :param product_id: :param start: :return: """ _amount = MonthProduct.objects.filter(user=user, product_id=product_id, created_at__gt=start, cancel_status=False).aggregate( Sum('amount')) if _amount['amount__sum']: commission = decimal.Decimal( _amount['amount__sum']) * decimal.Decimal("0.003") commission = commission.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_HALF_DOWN) first_intro = IntroducedBy.objects.filter(user=user).first() if first_intro and first_intro.introduced_by: first = MarginKeeper(first_intro.introduced_by) first.deposit(commission, description=u'月利宝一级淘金', catalog=u"全民淘金") income = PhpIncome(user=first_intro.introduced_by, invite=user, level=1, product_id=product_id, amount=_amount['amount__sum'], earning=commission, order_id=first.order_id, paid=True, created_at=timezone.now()) income.save()
def test_purchase(self): user1_margin_keeper = MarginKeeper(self.user1) user1_margin_keeper.deposit(100000) product = MockGenerator.generate_staging_p2p(u'test', 100000, per_user=0.1) user1_trader = P2PTrader(product, self.user1) # user1_trader.purchase(2000) user1_trader.purchase(1000) margin_records = MarginRecord.objects.all() self.assertEqual(len(margin_records), 2) for margin_record in margin_records: self.assertIsNotNone(margin_record.order_id) order = Order.objects.get(pk=user1_trader.order_id) notes = order.notes.all() self.assertEqual(len(notes), 2) self.assertEqual(notes[0].extra_data['status'], u'份额确认')
def commission(user, product, equity, start): """ 计算全民佣金,千三,取消第二级 :param user: :param product: :param equity: :param start: """ _amount = P2PRecord.objects.filter(user=user, product=product, create_time__gt=start).aggregate( Sum('amount')) if _amount['amount__sum'] and _amount['amount__sum'] <= equity: commission = decimal.Decimal( _amount['amount__sum']) * decimal.Decimal("0.003") commission = commission.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_HALF_DOWN) first_intro = IntroducedBy.objects.filter(user=user).first() if first_intro and first_intro.introduced_by: first = MarginKeeper(first_intro.introduced_by) first.deposit(commission, catalog=u"全民淘金") income = Income(user=first_intro.introduced_by, invite=user, level=1, product=product, amount=_amount['amount__sum'], earning=commission, order_id=first.order_id, paid=True, created_at=timezone.now()) income.save()
def test_settle(self): user1_margin_keeper = MarginKeeper(self.user1) user1_margin_keeper.deposit(100000) product = MockGenerator.generate_staging_p2p(u'test', 100000, per_user=1) user1_trader = P2PTrader(product, self.user1) user1_trader.purchase(100000) product = P2PProduct.objects.get(pk=product.id) # Now The product status should be pre settle, which means some one should do the final check, # Do money transfer, and if everything works, then he or she should change status to 还款中 product = P2PProduct.objects.get(pk=product.id) self.assertEqual(product.status, u'满标待打款') product.status = u'满标已打款' product.save() operator = P2POperator() operator.preprocess_for_settle(product=product) product = P2PProduct.objects.get(pk=product.id) self.assertEqual(product.status, u'满标待审核') # Now the equity should has contract, user should has amortization plan equity = P2PEquity.objects.filter(user=self.user1, product=product).first() try: f = equity.contract.open('r') except ValueError, e: self.fail("The contract not generated as expected")
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 test_full_process(self): user1_margin_keeper = MarginKeeper(self.user1) user1_margin_keeper.deposit(100000) operator = P2POperator() product = MockGenerator.generate_staging_p2p(u'测试用P2P产品第一号', 100000, per_user=1) # Run the operator and check nothing happened P2PTrader(product, self.user1).purchase(100000) product = P2PProduct.objects.first() self.assertEqual(product.status, u'满标待打款') # Stimulate that the money already paid product.status = u'满标已打款' product.save() # status -> 满标待审核 operator.watchdog() product = P2PProduct.objects.first() user_amortizations = UserAmortization.objects.filter( product_amortization__in=product.amortizations.all()) user_amortizations_count = len(user_amortizations) # Some body may manually set status to 满标已打款 in case some error detected, system should # support this case product = P2PProduct.objects.get(pk=product.id) product.status = u'满标已打款' # Regenerate user amortization plan operator.watchdog() product = P2PProduct.objects.first() user_amortizations = UserAmortization.objects.filter( product_amortization__in=product.amortizations.all()) # Even we regenerate everything, the user_amortization account should be the same self.assertEqual(len(user_amortizations), user_amortizations_count) # 满标待审核 -> 满标已审核 product = P2PProduct.objects.first() ProductKeeper(product).audit(self.user1) # status -> 还款中 operator.watchdog() product = P2PProduct.objects.get(pk=product.id) self.assertEqual(product.status, u'还款中') for a in product.amortizations.all(): a.ready_for_settle = True a.save() operator.watchdog() product = P2PProduct.objects.get(pk=product.id) self.assertEqual(product.status, u'已完成')
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 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 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 post(self, request): uuid = request.POST.get('uuid', '') error_message = request.POST.get('error_message', '') #try: # payinfo = PayInfo.objects.get(uuid=uuid, type='W') #except PayInfo.DoesNotExist: # return HttpResponse({ # u"没有找到 %s 该记录" % uuid # }) payinfo = PayInfo.objects.filter(uuid=uuid, type='W').first() if not payinfo: return HttpResponse({u"没有找到 %s 该记录" % uuid}) if payinfo.status == PayInfo.FAIL or payinfo.status == PayInfo.SUCCESS: logger.info( "The withdraw status [%s] already process , ignore it" % uuid) return HttpResponse({u"该%s 请求已经处理过,请勿重复处理" % uuid}) marginKeeper = MarginKeeper(payinfo.user) # 提现审核失败回滚时需要将扣除的各手续费返还 total_amount = payinfo.amount + payinfo.fee + payinfo.management_fee marginKeeper.withdraw_rollback(total_amount, error_message, uninvested=payinfo.management_amount) payinfo.status = PayInfo.FAIL payinfo.error_message = error_message payinfo.confirm_time = None payinfo.save() # 短信通知添加用户名 name = payinfo.user.wanglibaouserprofile.name or u'用户' send_messages.apply_async( kwargs={ "phones": [payinfo.user.wanglibaouserprofile.phone], "messages": [messages.withdraw_failed(name, error_message)] }) title, content = messages.msg_withdraw_fail(timezone.now(), payinfo.amount) inside_message.send_one.apply_async( kwargs={ "user_id": payinfo.user.id, "title": title, "content": content, "mtype": "withdraw" }) return HttpResponse({u"该 %s 请求已经处理完毕" % uuid})
def settle(self, savepoint=True): with transaction.atomic(savepoint=savepoint): equity_query = P2PEquity.objects.filter(user=self.user, product=self.product) if (not equity_query.exists()) or (len(equity_query) != 1): raise P2PException('can not get equity info.') equity = equity_query.first() equity.confirm = True equity.confirm_at = timezone.now() equity.save() catalog = u'申购确认' description = u'用户份额确认(%d)' % equity.equity self.__tracer(catalog, equity.equity, description) user_margin_keeper = MarginKeeper(self.user) user_margin_keeper.settle(equity.equity, savepoint=False)
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 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 php_commission_one_pay_one(user, invite, product_id, level, amount, earning): try: with transaction.atomic(): income, create_flag = PhpIncome.objects.get_or_create( user=user, invite=invite, product_id=product_id, defaults={ 'level': level, 'amount': amount, 'earning': earning, 'paid': False }) income = PhpIncome.objects.select_for_update().get(id=income.id) if income and not income.paid: margin = MarginKeeper(user) if level == 1: desc = u'月利宝一级淘金' elif level == 2: desc = u'月利宝二级淘金' else: desc = u'月利宝淘金' margin.deposit(earning, description=desc, catalog=u"全民淘金") income.order_id = margin.order_id income.paid = True income.save() return u'Success: [%s] introduced [%s] in [%s], level:%s, amount:%s, earning:%s' % ( user.id, invite.id, product_id, level, amount, earning) # Only for debug by hb on 2016-06-13 if income and income.paid: return u'Ignore: [%s] introduced [%s] in [%s], level:%s, amount:%s, earning:%s' % ( user.id, invite.id, product_id, level, amount, earning) if not income: return u'NotFound: [%s] introduced [%s] in [%s], level:%s, amount:%s, earning:%s' % ( user.id, invite.id, product_id, level, amount, earning) except Exception, ex: return u'[%s] introduced [%s] in [%s], Except:(%s)' % ( user.id, invite.id, product_id, ex)
def rollback(self, description=u'', savepoint=True): with transaction.atomic(savepoint=savepoint): equity = P2PEquity.objects.select_for_update().filter( user=self.user, product=self.product).first() if not equity: raise P2PException(u'No equity available for user') if equity.confirm: raise P2PException( u'The equity already confirmed, no way to revert') amount = equity.equity equity.delete() catalog = u'流标取消' record = self.__tracer(catalog, amount) user_margin_keeper = MarginKeeper(self.user, self.order_id) user_margin_keeper.unfreeze(amount, savepoint=False) # 流标要将红包退回账号 p2precord = P2PRecord.objects.filter(user=self.user, product=self.product, catalog=u"申购") if p2precord: for p2p in p2precord: result = redpack_backends.restore(p2p.order_id, p2p.amount, p2p.user) if result['ret_code'] == 0: user_margin_keeper.redpack_return( result['deduct'], description=u"%s 流标 红包退回%s元" % (self.product.short_name, result['deduct'])) return record
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)
class P2PTrader(object): 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 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 try: logger.debug( "=20151125= CoopRegister.process_for_purchase : [%s], [%s]" % (self.user.id, self.order_id)) CoopRegister(self.request).process_for_purchase( self.user, self.order_id) except Exception, reason: logger.debug( "=20151125= CoopRegister.process_for_purchase Except:{0}". format(reason)) pass
def withdraw(request): amount = request.DATA.get("amount", "").strip() card_id = request.DATA.get("card_id", "").strip() vcode = request.DATA.get("validate_code", "").strip() if not amount or not card_id: return {"ret_code": 20061, "message": u"信息输入不完整"} user = request.user if not user.wanglibaouserprofile.id_is_valid: return {"ret_code": 20062, "message": u"请先进行实名认证"} if user.wanglibaouserprofile.frozen: return {"ret_code": 20072, "message": u"用户账户已冻结,请联系客服"} try: float(amount) except: return {"ret_code": 20063, 'message': u'金额格式错误'} amount = util.fmt_two_amount(amount) if len(str(amount)) > 20: return {"ret_code": 20064, 'message': u'金额格式错误,大于100元且为100倍数'} margin = user.margin.margin if amount > margin: return {"ret_code": 20065, 'message': u'余额不足'} phone = user.wanglibaouserprofile.phone status, message = validate_validation_code(phone, vcode) if status != 200: # Modify by hb on 2015-12-02 #return {"ret_code": 20066, "message": u"验证码输入错误"} return {"ret_code": 20066, "message": message} card = Card.objects.filter(pk=card_id).first() if not card or card.user != user: return {"ret_code": 20067, "message": u"请选择有效的银行卡"} # 检测银行卡是否在黑名单中 black_list = BlackListCard.objects.filter(card_no=card.no).first() if black_list and black_list.user != user: return {"ret_code": 20072, "message": u'银行卡号异常,请联系客服'} # 检查白名单 white_list = WhiteListCard.objects.filter(user=user, card_no=card.no).first() if not white_list: # 增加银行卡号检测功能,检测多张卡 card_count = Card.objects.filter(no=card.no).count() if card_count > 1: return {"ret_code": 20073, "message": u'银行卡号有多张重复,请联系客服'} # 检测银行卡在以前的提现记录中是否为同一个用户 payinfo_record = PayInfo.objects.filter( card_no=card.no, type='W').order_by('-create_time').first() if payinfo_record: if payinfo_record.user != user: return {"ret_code": 20074, "message": u'银行卡号与身份信息不符,请联系客服'} # 计算提现费用 手续费 + 资金管理费 bank = card.bank uninvested = user.margin.uninvested # 充值未投资金额 # 获取费率配置 fee_misc = WithdrawFee() fee_config = fee_misc.get_withdraw_fee_config() # 检测提现最大最小金额 if amount > fee_config.get('max_amount') or amount <= 0: return {"ret_code": 20068, 'message': u'提现金额超出最大提现限额'} if amount < fee_config.get('min_amount'): if amount != margin: return { "ret_code": 20069, 'message': u'账户余额小于{}时需要一次性提完'.format(fee_config.get('min_amount')) } # 检测银行的单笔最大提现限额,如民生银行 if bank and bank.withdraw_limit: bank_limit = util.handle_withdraw_limit(bank.withdraw_limit) bank_max_amount = bank_limit.get('bank_max_amount', 0) if bank_max_amount: if amount > bank_max_amount: return {"ret_code": 20070, 'message': u'提现金额超出银行最大提现限额'} # 获取计算后的费率 fee, management_fee, management_amount = fee_misc.get_withdraw_fee( user, amount, margin, uninvested) # 实际提现金额 actual_amount = amount - fee - management_fee if actual_amount <= 0: return {"ret_code": 20071, "message": u'实际到账金额为0,无法提现'} pay_info = PayInfo() pay_info.amount = actual_amount pay_info.fee = fee pay_info.management_fee = management_fee pay_info.management_amount = management_amount pay_info.total_amount = amount pay_info.type = PayInfo.WITHDRAW pay_info.user = user pay_info.card_no = card.no pay_info.account_name = user.wanglibaouserprofile.name pay_info.bank = card.bank pay_info.request_ip = util.get_client_ip(request) pay_info.status = PayInfo.ACCEPTED pay_info.channel = "app" try: order = OrderHelper.place_order(user, Order.WITHDRAW_ORDER, pay_info.status, pay_info=model_to_dict(pay_info)) pay_info.order = order keeper = MarginKeeper(user, pay_info.order.pk) margin_record = keeper.withdraw_pre_freeze( amount, uninvested=management_amount) pay_info.margin_record = margin_record pay_info.save() return { "ret_code": 0, 'message': u'提现成功', "amount": amount, "phone": phone, "bank_name": bank.name, "order_id": order.id } except Exception, e: pay_info.error_message = str(e) pay_info.status = PayInfo.FAIL pay_info.save() return {"ret_code": 20065, 'message': u'余额不足'}
def experience_repayment_plan(): """ 体验标还款计划结算任务 每天下午17:00分开始执行 自动将当天17:00之间所有未结算的计划进行统一结算 结算的利息自动计入用户的资金账户余额 """ print(u"Getting experience gold repayment plan to start!") now = datetime.now() # start = local_to_utc(datetime(now.year, now.month, now.day - 1, 17, 0, 0), 'normal') end = local_to_utc(datetime(now.year, now.month, now.day, 17, 0, 0), 'normal') phone_list = list() message_list = list() amortizations = ExperienceAmortization.objects.filter( settled=False).filter(term_date__lt=end) for amo_tmp in amortizations: is_commit = False with transaction.atomic(savepoint=True): # 锁定还款计划 amo = ExperienceAmortization.objects.select_for_update().get( pk=amo_tmp.id) try: # Add by hb on 2016-06-08 : 避免体验金还款重复结算 if amo.settled: continue amo.settled = True amo.settlement_time = timezone.now() amo.save() if amo.interest > 0: # 体验金利息计入用户账户余额 description = u"体验金利息入账:%s元" % amo.interest user_margin_keeper = MarginKeeper(amo.user) user_margin_keeper.deposit(amo.interest, description=description, catalog=u"体验金利息入账") is_commit = True except Exception, e: logger.error( u"experience repayment error, amortization id : %s , message: %s" % (amo.id, e.message)) # 发站内信,利息大于6元 if amo_tmp.interest > 6 and is_commit: user_profile = amo_tmp.user.wanglibaouserprofile # 短信 phone_list.append(user_profile.phone) message_list.append( messages.experience_amortize(user_profile.name, amo_tmp.interest)) # 站内信 title, content = messages.experience_amortize_msg( user_profile.name, amo_tmp.product.name, amo_tmp.product.period, timezone.now(), amo_tmp.interest) inside_message.send_one.apply_async( kwargs={ "user_id": amo_tmp.user.id, "title": title, "content": content, "mtype": "amortize" })
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 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 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 post(self, request): action = request.POST.get('action') uuids_param = request.POST.get('transaction_uuids', '') uuids = re.findall(r'[\w\-_]+', uuids_param) payinfos = PayInfo.objects.filter(uuid__in=uuids, type='W').order_by('create_time') # These are the uuids exists in db for real uuids_param = ",".join([payinfo.uuid for payinfo in payinfos]) if action == 'preview' or action is None: return self.render_to_response({ 'payinfos': payinfos, 'total_amount': payinfos.aggregate(Sum("amount"))['amount__sum'], 'transaction_uuids': uuids_param }) elif action == 'confirm': for payinfo in payinfos: with transaction.atomic(): if payinfo.status != PayInfo.ACCEPTED and payinfo.status != PayInfo.PROCESSING: logger.info( "The withdraw status [%s] not in %s or %s, ignore it" % (payinfo.status, PayInfo.ACCEPTED, PayInfo.PROCESSING)) continue amount = payinfo.amount fee = payinfo.fee management_fee = payinfo.management_fee management_amount = payinfo.management_amount marginKeeper = MarginKeeper(payinfo.user) total_amount = amount + fee + management_fee marginKeeper.withdraw_ack(total_amount, uninvested=management_amount) payinfo.status = PayInfo.SUCCESS payinfo.confirm_time = timezone.now() payinfo.save() # 给提现记录表中的信息同步进行确认,同时将提现的费用充值到网利宝的公司提现账户 if fee > 0 or management_fee > 0: fee_total_amount = fee + management_fee withdraw_card = WithdrawCard.objects.filter( is_default=True).first() withdraw_card.amount += fee_total_amount withdraw_card.save() # 将提现信息单独记录到提现费用记录表中 withdraw_card = WithdrawCard.objects.filter( is_default=True).first() if withdraw_card: withdraw_card_record = WithdrawCardRecord() withdraw_card_record.type = PayInfo.WITHDRAW withdraw_card_record.amount = amount withdraw_card_record.fee = fee withdraw_card_record.management_fee = management_fee withdraw_card_record.management_amount = management_amount withdraw_card_record.withdrawcard = withdraw_card withdraw_card_record.payinfo = payinfo withdraw_card_record.user = payinfo.user withdraw_card_record.status = PayInfo.SUCCESS withdraw_card_record.message = u'用户提现费用存入' withdraw_card_record.save() # 取款确认时要检测该次提现是否是真正的在每个月的免费次数之内,如果是还需要将已扣除的费用返还给用户(仅限手续费) give_back = False if fee > 0: fee_misc = WithdrawFee() fee_config = fee_misc.get_withdraw_fee_config() withdraw_count = fee_misc.get_withdraw_success_count( payinfo.user) free_times = fee_config['fee']['free_times_per_month'] if withdraw_count <= free_times: give_back = True if give_back: # 1.给用户返还手续费 marginKeeper.deposit( fee, description=u'返还提现免费次数之内的手续费:{}元'.format(fee), catalog=u"返还手续费") # 2.从网利宝提现账户中减去手续费 withdraw_card = WithdrawCard.objects.filter( is_default=True).first() withdraw_card.amount -= fee withdraw_card.save() # 将提现信息单独记录到提现费用记录表中 withdraw_card_record = WithdrawCardRecord() withdraw_card_record.type = PayInfo.WITHDRAW withdraw_card_record.amount = fee withdraw_card_record.fee = fee withdraw_card_record.management_fee = 0 withdraw_card_record.management_amount = 0 withdraw_card_record.withdrawcard = withdraw_card withdraw_card_record.payinfo = payinfo withdraw_card_record.user = payinfo.user withdraw_card_record.status = PayInfo.SUCCESS withdraw_card_record.message = u'用户提现费用返还' withdraw_card_record.save() # 发站内信 title, content = messages.msg_withdraw_success( timezone.now(), payinfo.amount) inside_message.send_one.apply_async( kwargs={ "user_id": payinfo.user_id, "title": title, "content": content, "mtype": "withdraw" }) send_messages.apply_async( kwargs={ "phones": [payinfo.user.wanglibaouserprofile.phone], "messages": [ messages.withdraw_confirmed( payinfo.user.wanglibaouserprofile.name, amount) ] }) return HttpResponse({u"所有的取款请求已经处理完毕 %s" % uuids_param})
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 amortize(self, amortization, savepoint=True): with transaction.atomic(savepoint=savepoint): if amortization.settled: raise P2PException('amortization %s already settled.' % amortization) sub_amortizations = amortization.subs.all() description = unicode(amortization) catalog = u'分期还款' product = amortization.product 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) phone_list = list() message_list = list() settled_sub_amos = list() for sub_amo in sub_amortizations: user_margin_keeper = MarginKeeper(sub_amo.user) user_margin_keeper.amortize(sub_amo.principal, sub_amo.interest, sub_amo.penal_interest, sub_amo.coupon_interest, savepoint=False, description=description) sub_amo.settled = True sub_amo.settlement_time = timezone.now() sub_amo.save() amo_amount = sub_amo.principal + sub_amo.interest + sub_amo.penal_interest + sub_amo.coupon_interest # 加入重复回款的用户还需要扣回的金额及扣款操作 try: repeat_user = RepeatPaymentUser.objects.select_for_update()\ .filter(user_id=sub_amo.user.id, amount__gt=0).first() if repeat_user: repeat_amount = repeat_user.amount # if repeat_amount > 0: # 判断是否每天从回款中扣款 is_every_day = True if not repeat_user.is_every_day: product_ids = repeat_user.product_ids.split(',') product_ids = [ int(p_id) for p_id in product_ids if p_id.strip() != '' ] # 判断当期还款的产品id是否在用户新购标的id中, 不在说明该标不用扣款 if product.id not in product_ids: is_every_day = False if is_every_day: # 判断剩余应扣金额是否大于等于本期回款本息之合, 大于等于,则扣本息,否则扣剩余应扣金额 if repeat_amount >= amo_amount: reduce_amount = amo_amount reduce_amount_current = repeat_amount - amo_amount # 剩余应扣金额-本次扣除的本息之合 else: reduce_amount = repeat_amount reduce_amount_current = 0 print( "repeat_amount: %s, amo_amount: %s, type1:%s, type2:%s" % (repeat_amount, amo_amount, type(repeat_amount), type(amo_amount))) # 减账户余额 user_margin_keeper.reduce_margin( reduce_amount, u'系统重复回款扣回%s元' % reduce_amount) # 更新剩余应扣金额 repeat_user.amount = reduce_amount_current repeat_user.save() # 记录扣款流水 repeat_record = RepeatPaymentUserRecords( user_id=sub_amo.user.id, name=sub_amo.user.wanglibaouserprofile.name, phone=sub_amo.user.wanglibaouserprofile.phone, amount=reduce_amount, amount_current=reduce_amount_current, description=description) repeat_record.save() except Exception: logger.exception('err') logger.error("用户扣款失败,用户id:[%s], 回款本息合计:[%s]" % (sub_amo.user, amo_amount)) pass try: phone_list.append(sub_amo.user.wanglibaouserprofile.phone) message_list.append( messages.product_amortize( sub_amo.user.wanglibaouserprofile.name, amortization.product, # sub_amo.settlement_time, amo_amount)) title, content = messages.msg_bid_amortize( pname, timezone.now(), amo_amount) inside_message.send_one.apply_async( kwargs={ "user_id": sub_amo.user.id, "title": title, "content": content, "mtype": "amortize" }) except: logger.debug("") self.__tracer(catalog, sub_amo.user, sub_amo.principal, sub_amo.interest, sub_amo.penal_interest, amortization, description, sub_amo.coupon_interest) # 标的每一期还款完成后,检测该用户还款的本金是否有符合活动的规则,有的话触发活动规则 try: if sub_amo.principal > 0: # activity_backends.check_activity(sub_amo.user, 'repaid', 'pc', sub_amo.principal, product.id) check_activity_task.apply_async(kwargs={ "user_id": sub_amo.user.id, "trigger_node": 'repaid', "device_type": 'pc', "amount": sub_amo.principal, "product_id": product.id, }, queue='celery02') except Exception: logger.debug( "check activity on repaid, user: {}, principal: {}, product_id: {}" .format(sub_amo.user.id, sub_amo.principal, product.id)) try: weixin_user = WeixinUser.objects.filter( user=sub_amo.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.debug( ">>>> weixin msg send err, user_id:[%s], [%s] " % sub_amo.user.id, e) pass # 添加还款用户到渠道通知列表 @chenwb try: settled_sub_amos.append({ 'id': sub_amo.id, 'user': sub_amo.user.id, 'product': product.id, 'term': sub_amo.term, 'settled': sub_amo.settled, 'term_date': sub_amo.term_date.strftime('%Y-%m-%d %H:%M:%S'), 'settlement_time': sub_amo.settlement_time.strftime('%Y-%m-%d %H:%M:%S'), 'principal': float(sub_amo.principal), 'interest': float(sub_amo.interest), 'penal_interest': float(sub_amo.penal_interest), 'coupon_interest': float(sub_amo.coupon_interest), 'description': sub_amo.description, }) except: pass amortization.settled = True amortization.save() catalog = u'还款入账' send_messages.apply_async(kwargs={ "phones": phone_list, "messages": message_list }) self.__tracer(catalog, None, amortization.principal, amortization.interest, amortization.penal_interest, amortization) # 向渠道中心发送还款用户列表通知 @chenwb # Comment by hb on 2016-05-13 try: if settled_sub_amos: from .tasks import coop_amortizations_push coop_amortizations_push.apply_async(kwargs={ 'amortizations': settled_sub_amos, 'product_id': product.id, 'amo_act': 'amortize' }, queue='celery02') except: pass
pay_info.response_ip = util.get_client_ip(request) if not pay_info.bank and "bank" in params: bank = Bank.objects.filter(name=params['bank']).first() if bank: pay_info.bank = bank if pay_info.amount != amount: pay_info.status = PayInfo.FAIL pay_info.error_message += u' 金额不匹配' logger.error("orderId:%s amount:%s, response amount:%s" % (orderId, pay_info.amount, amount)) rs = {"ret_code":20086, "message":PayResult.EXCEPTION} else: if params['status'] == 1: pay_info.fee = self.FEE keeper = MarginKeeper(pay_info.user, pay_info.order.pk) margin_record = keeper.deposit(amount) pay_info.margin_record = margin_record pay_info.status = PayInfo.SUCCESS logger.error("orderId:%s yeepay response status:%s" % (orderId, params['status'])) 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
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 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 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())