예제 #1
0
    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
예제 #2
0
    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())