# -*- encoding: utf8 -*-
import sys
import datetime
import numpy as np
import math
import pandas as pd
from dateutil.relativedelta import relativedelta
from sqlalchemy import create_engine

reload(sys)
sys.setdefaultencoding("utf-8")
pd.options.mode.chained_assignment = None


'''
@author linfang
针对去哪儿 2015+2016年放款的还款计划拆分;
基于李学的拆分ok的还款计划拆分
'''

engine_qunaer = create_engine('mysql+mysqldb://yulong:ohVU1nPITynSZwR2@172.16.3.201:3306/qunaer_new?charset=utf8', echo=False).connect()
engine_djy = create_engine('mysql+mysqldb://wanglinfang_data_r:uh90888n7y8ijk8886@192.168.4.6:8066/dujiangyan?charset=utf8', echo=False).connect()
# 取小数点 前两位
def get_2_flo(num):
    begin = str(num).find('.')
    if begin == -1:
        return round(begin, 2)
    return float(str(num)[:begin + 3])

# 小数向上取数
def get_2_ceil(num):
    begin = str(num).find('.')
    if begin == -1 :
        return round(begin, 2)
    else:
        if str(num).__len__() - begin > 3:
            return math.ceil(num*100) / 100
        else:
            return float(str(num)[:begin + 3])


# 有退款的订单，更新还款计划-- 更新应还本金，利息
# 还款计划表 repayment_plan_2016
def step_2(year,month,insert_db=False):
    start_time = datetime.datetime(year, month, 1, 0, 0, 0)
    end_time = start_time + relativedelta(months=+1)
    sql_refund = '''
    select product_no,refund_amount,refund_principle,refund_fee_amount,refund_due_amount,refund_time from refund_detail
    where refund_status = 1 and refund_time >= '%s' and refund_time < '%s'
    ORDER by refund_time asc
    ''' % (start_time,end_time)
    sql_pay='''
    select product_no,rate,stages from pay_detail where product_no in %s
    '''
    sql_plan='''
    select id,product_no,current_stage_no,deadline,principle,fee_amount,due_amount
    from repayment_plan_2016
    where product_no = '%s' ORDER by current_stage_no asc
    '''
    sql_repay='''
    select product_no,current_stage_no,repay_amount,repay_principle,repay_fee_amount,repay_due_amount
    from repay_detail
    where repay_status = 1 and repay_type != 'REFUND_REPAY' and product_no = '%s' and repay_time < '%s'
    '''
    update_sql='''
    update repayment_plan_2016 set principle=%s ,fee_amount = %s,require_fee=%s ,due_amount=%s,status=%s where id=%s
    '''
    update_sql_2 = '''
      update repayment_plan_2016 set status = 2 where id = %s
    '''
    df_refund = pd.read_sql(sql_refund,engine_qunaer,chunksize=1000)
    i=0
    for df in df_refund:
        print '-------------update-------------',i
        i+=1000
        df.product_no = df.product_no.astype(str)
        df_pay = pd.read_sql(sql_pay % str(tuple(df.product_no.tolist())).replace(',)',')'),engine_qunaer)
        df=pd.merge(df,df_pay,on='product_no',how='inner')
        # print '-------------无退款本金---------------',df.ix[df.refund_principle == 0]
        df=df.ix[df.refund_principle < 0]
        for index,row in df.iterrows():
            list1=[]
            product_no = row['product_no']
            refund_time = row['refund_time']
            df_plan = pd.read_sql(sql_plan % product_no, engine_qunaer)
            #还款计划一定存在
            if len(df_plan) == 0:
                continue
            #还款在退款前
            df_repay = pd.read_sql(sql_repay % (product_no,refund_time), engine_qunaer)
            # 有退款本金的方可更新退款
            refund_principle = row['refund_principle']
            rate = float(row['rate'])
            if len(df_repay) == 0: #客户无还款情况
                status = 1
                # 如果有逾期的，则进行全额匹配逾期
                df_yq = df_plan.ix[df_plan.deadline < refund_time]
                if len(df_yq) > 0:
                    print '---------逾期退款-----------', df_yq
                    refund_principle = np.round(df_yq['principle'].sum() + refund_principle, 2)
                    up_vals = df_yq[['id']].values.tolist()
                    engine_qunaer.execute(update_sql_2, up_vals)
                # 剔除逾期还款后的
                df_plan = df_plan.ix[df_plan.deadline >= refund_time]
                left_principle=np.round(df_plan['principle'].sum()+refund_principle,2)
                if left_principle < 0:
                    # 这块有问题拆分的金额有问题
                    print  '----------------该还款计划有问题----------',product_no
                    continue
                if left_principle == 0:
                    status = 2
                stages = len(df_plan)
                # 分期服务费 =  本金 * 利率 * 期数
                # 金额第三位小数向上取值
                all_fee_amount = get_2_ceil(left_principle * rate * stages)
                avg_principle = get_2_flo(left_principle/stages)
                first_principle = left_principle - avg_principle * (stages -1)
                avg_fee_amount = get_2_flo(left_principle * rate)
                first_fee_amount = all_fee_amount - avg_fee_amount * (stages -1)
                # 不分期，30天免息
                if int(row['stages']) == 1:
                    all_fee_amount = 0
                    avg_fee_amount = 0
                    first_fee_amount = 0
                min_term_no = df_plan['current_stage_no'].min()
                for jindex,jrow in df_plan.iterrows():
                    if int(jrow['current_stage_no']) == min_term_no:
                        list1.append([first_principle,first_fee_amount,first_principle+first_fee_amount,0,status,int(jrow['id'])])
                    else:
                        list1.append([avg_principle, avg_fee_amount,avg_principle+avg_fee_amount, 0, status, int(jrow['id'])])
                if insert_db & (len(list1) > 0):
                    print '-------update--plan-----',list1.__len__()
                    engine_qunaer.execute(update_sql,list1)
            else: # 客户有还款
                # 如果 剩余应还 >= 退款本金，那么基于剩下的进行本金进行拆分
                #直接剔除已还款
                df_plan=df_plan.ix[~df_plan.current_stage_no.isin(df_repay.current_stage_no)]
                left_principle = np.round(df_plan['principle'].sum() + refund_principle,2)
                if left_principle >= 0: # 剩余未还本金 > 退款情况
                    #查看是否有逾期的情况，如果有逾期，则不进行更改
                    # 如果有逾期的，则进行全额匹配逾期
                    df_yq = df_plan.ix[df_plan.deadline < refund_time]
                    if len(df_yq) > 0:
                        print '---------逾期退款-----------', df_yq
                        refund_principle = np.round(df_yq['principle'].sum() + refund_principle, 2)
                        up_vals = df_yq[['id']].values.tolist()
                        engine_qunaer.execute(update_sql_2, up_vals)
                    # 剔除逾期还款后的
                    df_plan = df_plan.ix[df_plan.deadline >= refund_time]
                    left_principle = np.round(df_plan['principle'].sum() + refund_principle, 2)
                    if left_principle < 0:
                        print '----------------该还款计划有问题----------',product_no
                        continue
                    #剩余期数
                    stages = len(df_plan)
                    # 分期服务费 =  本金 * 利率 * 期数
                    # 金额第三位小数向上取值
                    all_fee_amount = get_2_ceil(left_principle * rate * stages)
                    avg_principle = get_2_flo(left_principle / stages)
                    first_principle = left_principle - avg_principle * (stages - 1)
                    avg_fee_amount = get_2_flo(left_principle * rate)
                    first_fee_amount = all_fee_amount - avg_fee_amount * (stages - 1)
                    status = 1
                    if left_principle == 0:
                        status = 2
                    min_term_no=df_plan['current_stage_no'].min()
                    for jindex, jrow in df_plan.iterrows():
                        if int(jrow['current_stage_no']) == int(min_term_no):
                            list1.append([first_principle, first_fee_amount,first_principle+first_fee_amount, 0, status, int(jrow['id'])])
                        else:
                            list1.append([avg_principle, avg_fee_amount,avg_principle+avg_fee_amount, 0, status, int(jrow['id'])])
                    if insert_db & (len(list1) > 0):
                        print '-------update--plan-----', list1.__len__()
                        engine_qunaer.execute(update_sql, list1)
                else: # 剩余未还本金 《 退款金额
                    print '----------剩余未还金额<退款金额------',product_no



# 应还罚息计算
def step_5(year,month,insert_db=False):
    start_time = datetime.datetime(year, month, 1, 0, 0, 0)
    end_time = start_time + relativedelta(months=+1)
    sql_plan='''
    select id,product_no,current_stage_no,deadline,repay_time,principle,fee_amount,repay_due_amount
    from repayment_plan_201701
    where require_fee > 0 and date(repay_time) > date(deadline) and repay_time >= '%s' and repay_time < '%s'
    ''' % (start_time,end_time)
    sql_pay='''
    select product_no,stages,loan_time,trans_time,is_ptf from pay_detail where product_no in %s
    '''
    update_sql='''
    update repayment_plan_201701 set due_amount = %s where id=%s
    '''
    df_plan=pd.read_sql(sql_plan,engine_qunaer)
    product_nos=df_plan.product_no.astype(str).unique().tolist()
    df_pay = pd.read_sql(sql_pay % str(tuple(product_nos)).replace(',)',')'),engine_qunaer)
    df_plan=pd.merge(df_plan,df_pay,on='product_no',how='left')
    #罚息利率统一为 0.001
    df_plan['rate'] = 0.001
    #逾期天数
    df_plan.deadline=pd.to_datetime(df_plan.deadline).dt.date
    df_plan.repay_time=pd.to_datetime(df_plan.repay_time).dt.date
    df_plan['days'] = 0
    df_plan['days'] = df_plan.apply(lambda x:(x.repay_time -x.deadline).days,axis = 1)
    df_plan['punish'] = df_plan.apply(lambda x:round(x.days * round(x.rate * (x.principle+x.fee_amount),2),2),axis=1)
    if insert_db:
        df_plan['id'] = df_plan['id'].map('{:.0f}'.format)
        up_vals=df_plan[['punish','id']].values.tolist()
        engine_qunaer.execute(update_sql,up_vals)
    return df_plan



#校验未钩稽上的还款流水
def check_repay_plan(year,month):
    start_time = datetime.datetime(year, month, 1, 0, 0, 0)
    end_time = start_time + relativedelta(months=+1)
    sql_repay='''
    select repay_no,product_no,current_stage_no from repay_detail where repay_status = 1 and repay_type != 'REFUND_REPAY'
    and repay_time >= '%s' and repay_time < '%s'
    ''' % (start_time,end_time)
    df=pd.read_sql(sql_repay,engine_qunaer)
    product_nos = df.product_no.astype(str).tolist()
    sql_pay='''
    select product_no from pay_detail where is_ptf = 0 and loan_time >= '2017-01-01' and product_no in %s
    ''' % str(tuple(product_nos)).replace(',)',')')
    sql_pay2='''
    select product_no from pay_detail where is_ptf = 1 and trans_time >= '2017-01-01' and product_no in %s
    ''' % str(tuple(product_nos)).replace(',)',')')
    df1=pd.read_sql(sql_pay,engine_qunaer)
    df2=pd.read_sql(sql_pay2,engine_qunaer)
    df_pay=pd.concat([df1,df2],ignore_index=True,axis=0)
    df = df.ix[df.product_no.isin(df_pay.product_no)]
    sql_plan='''
    select repay_no from repayment_plan_2016 where repay_amount > 0 and repay_time >= '%s' and repay_time < '%s'
    ''' % (start_time,end_time)
    df_plan=pd.read_sql(sql_plan,engine_qunaer)
    #plan_repay_nos 会有 'A,B'两笔流水在一笔订单的情况,需要转换下
    df_plan_1=df_plan.ix[df_plan.repay_no.str.contains(',')]
    df_plan_2=df_plan.ix[~df_plan.repay_no.str.contains(',')]
    plan_repay_nos=tuple(df_plan_2.repay_no.astype(str).tolist())
    df=df.ix[~df.repay_no.isin(plan_repay_nos)]
    #剔除 plan_1 中的数据
    if len(df_plan_1) > 0:
        list1=[]
        for index,row in df_plan_1.iterrows():
            tmp = row['repay_no']
            tmp = str(tmp).strip().split(',')
            for repay_no in tmp:
                list1.append(str(repay_no))
        df=df.ix[~df.repay_no.isin(list1)]
    return df

#校验放款表中的费率是否正确
def check_pay_rate(year,month):
    start_time = datetime.datetime(year, month, 1, 0, 0, 0)
    end_time = start_time + relativedelta(months=+1)
    sql_pay='''
    select product_no,loan_amount,stages,rate,fee_amount from pay_detail
    where is_ptf = 0 and loan_time >= '%s' and loan_time < '%s'
    ''' % (start_time,end_time)
    sql_pay_2='''
    select product_no,loan_amount,stages,rate,fee_amount from pay_detail
    where is_ptf =1 and trans_time >= '%s' and trans_time < '%s'
    ''' % (start_time,end_time)
    df_1=pd.read_sql(sql_pay,engine_qunaer)
    df_2=pd.read_sql(sql_pay,engine_qunaer)
    df=pd.concat([df_1,df_2],axis=0,ignore_index=True)
    df['new_fee_amount']=df.apply(lambda x:get_2_ceil(x.stages*x.loan_amount*x.rate),axis = 1)
    df['diff'] = np.round(df['new_fee_amount'] - df['fee_amount'],2)
    df=df.ix[df['diff'] != 0]
    return df

# 拆分的还款计划同都江堰的比较
def check_plan_vs_djy(year,month,is_ptf = False):
    df_out=pd.DataFrame()
    start_time = datetime.datetime(year, month, 1, 0, 0, 0)
    end_time = start_time + relativedelta(months=+1)
    sql_refund = '''
    select product_no from refund_detail where refund_time >= '%s' and refund_time < '%s'
    ''' % (start_time,end_time)
    sql_plan='''
    select product_no,current_stage_no,principle,fee_amount from repayment_plan_2016
    where product_no in %s
    '''
    sql_djy='''
    select loan_no product_no,term_no current_stage_no,capital_amount,fee_amount djy_fee_amount from qunar_repayment_plan
    where loan_no in %s
    '''
    df_refund=pd.read_sql(sql_refund,engine_qunaer,chunksize=5000)
    for df in df_refund:
        product_nos=df.product_no.astype(str).tolist()
        df_plan=pd.read_sql(sql_plan % str(tuple(product_nos)).replace(',)',')'),engine_qunaer)
        #16年放款的产品编号
        product_nos = df_plan.product_no.astype(str).tolist()
        df_djy=pd.read_sql(sql_djy % str(tuple(product_nos)).replace(',)',')'),engine_djy )
        df=pd.merge(df_plan,df_djy,on=['product_no','current_stage_no'],how='outer')
        df.fillna(0,inplace=True)
        df['diff1']=np.round(df['capital_amount'] - df['principle'],2)
        df['diff2'] = np.round(df['djy_fee_amount'] - df['fee_amount'],2)
        df_out=df_out.append(df.ix[(df['diff1'] != 0) | (df['diff2'] != 0)])
    return df_out


if __name__ == '__main__':
    year = 2017
    month = 7
    # 首先校验放款利率，如果正常，放款进行录入放款计划
    # 利率 如果出现 0.5 0.65 等这种数据是有问题的，利率太大了。
    # 其他的计算结果 如果不一致，可能是因为有退款影响的结果，利率不变
    # df=check_pay_rate(year,month)
    # print '-------------利率有问题----------',df

    # 录入还款计划--- 转分期订单+非转分期订单
    # step_1(year,month,is_ptf=False,insert_db=True)
    # step_1(year, month, is_ptf=True, insert_db=True)

    # deadline 同步都江堰
    # df=step_1_1(year,month,is_ptf = False,insert_db=True)
    # df.to_csv('E:/diff6.csv')
    # df=step_1_1(year, month, is_ptf=True, insert_db=True)
    # df.to_csv('E:/diff7.csv')

    #根据退款，进行更新还款计划
    # step_2(year,month,insert_db=True)
    # 校验还款计划更新的对否
    # df=check_plan_vs_djy(year,month,is_ptf=False)
    # df.to_csv('E:/diff.csv')
    # df = check_plan_vs_djy(year, month, is_ptf=True)
    # df.to_csv('E:/diff2.csv')


