# -*- coding: utf-8 -*-

# from api.db_connect import *
import numpy as np
import datetime
import pandas as pd
import sys
from sqlalchemy import create_engine

reload(sys)
sys.setdefaultencoding('utf8')

'''
更新数据库中的 应还罚息
@author linfang
1、更新 user_repayment_plan 表中的 should_punish 字段
2、罚息计算，是还款成功（即还款状态为 3）才进行计算，如果还款未完成，则不应该计算罚息。
'''

#----------------------配置变量开始---------------------------
#TODO 查询计算罚息的还款计划，如果要更新哪个放款，则指定具体的放款id或还款时间段等其他你需要的条件，但是请别删除查询项
read_user_sql='''
select t1.id,t1.fund_code,t1.term_no,t1.deadline,t1.xyqb_repaid_at repaid_at,t1.principle cur_principle,t2.monthly_interest_rate rate,t2.contract_term,t2.contract_loan_amount contract_amount
from new_transaction.user_repayment_plan t1
left join audit.loan_manifest t2 on t1.ref_id = t2.ref_id
where t1.repay_status = 3 and date(t1.deadline) < date(t1.xyqb_repaid_at) and
t1.xyqb_repaid_at >= '2017-09-01 00:00:00' and t1.xyqb_repaid_at < '2017-10-10 00:00:00'
'''

# read_user_sql='''
# select t1.id,t1.fund_code,t1.term_no,t1.deadline,t1.xyqb_repaid_at repaid_at,t1.principle cur_principle,t2.monthly_interest_rate rate,t2.contract_term,t2.contract_loan_amount contract_amount
# from new_transaction.user_repayment_plan t1
# left join audit.loan_manifest t2 on t1.ref_id = t2.ref_id
# where t1.repay_status = 3 and date(t1.deadline) < date(t1.xyqb_repaid_at) and
# t1.real_loan_id = '38517285'
# '''
#TODO 这个字段一定要注意；如果不进行更新表中的数据，请设置为 False ！！！！！！
#TODO False 表示输出到控制台
update_flag=True
#TODO 数据源
engine_audit = create_engine('mysql+mysqldb://yulong:ohVU1nPITynSZwR2@172.16.3.201:3306/new_transaction?charset=utf8', echo=True)
#----------------------配置变量结束---------------------------




'''
晋商的剩余本金计算特殊区别
剩余本金计算
contract_amount：放款金额
term_no：期数
contract_term：合同期数
rate：利率
'''
def cal_surplus_prin(contract_amount, term_no, contract_term, rate, fund_code=0):
    prin = 0
    if fund_code == 300:
        avg = round(contract_amount / contract_term, 2)
        return contract_amount - avg * (term_no - 1)
    else:
        for i in xrange(1, term_no, 1):
            prin += np.ppmt(rate, i, contract_term, -contract_amount)
        return contract_amount - prin

# 计算当期本金
def cal_cur_prin(contract_amount, term_no, contract_term, rate, fund_code=0):
    prin = 0
    if fund_code == 300:
        avg = round(contract_amount / contract_term, 2)
        if term_no < contract_term:
            return avg
        else:
            return contract_amount - avg * (term_no - 1)
    else:
        if contract_term == 1:
            return contract_amount
        else:
            if term_no < contract_term:
                return np.ppmt(rate, term_no, contract_term, -contract_amount)
            else:# 最后一期
                other = 0
                for i in range(1,contract_term):
                    other += np.ppmt(rate, i, contract_term, -contract_amount)
                return  contract_amount - other



'''
剩余本息计算
'''
def cal_surplus_prininst(contract_amount, term_no, contract_term, rate):
    prin_inst = np.pmt(rate, contract_term, -contract_amount)
    return (contract_term + 1 - term_no) * prin_inst


'''
罚息公式计算
funding_name:资金方名字
contract_amount：放款金额
contract_term:放款期数
term_no：期数
deadline：应还日期
repaid_at：客户实还日期
monthly_amount:应还金额
rate:年利率
2017年新版的罚息公式
违约服务费=借款本金*1%+逾期本金*0.5%*逾期天数
返回：
lkb_deplay_fee:量化派逾期费
'''
def cal_deplay_fee(contract_amount, deadline, repaid_at,cur_principle=0, contract_term=1, term_no=1, rate=0, fund_code=0):
    contract_term = int(contract_term)
    term_no = int(term_no)
    result = {'lkb_deplay_fee': 0}
    lkb_deplay_days = (repaid_at.date() - deadline.date()).days
    if lkb_deplay_days < 1:
        return result
    if (repaid_at >= datetime.datetime(2017, 1, 20, 10, 0, 0)) and (repaid_at < datetime.datetime(2017, 5, 2, 14, 16, 0)): # 2017-1-20 号修改了罚息计算公式
        principle = cal_surplus_prin(contract_amount, term_no, contract_term, rate, fund_code)
        result['lkb_deplay_fee'] = np.round(contract_amount * 0.01 + principle * 0.005 * lkb_deplay_days,2)
        return result
    elif (repaid_at >= datetime.datetime(2017, 5, 2, 14, 16, 0)) and (repaid_at < datetime.datetime(2017,6,23,19,7,0)):  # 2017-5-2 修改了罚息公式  当期逾期服务费不超过当期借款本金的20%
        principle = cal_surplus_prin(contract_amount, term_no, contract_term, rate, fund_code)
        result['lkb_deplay_fee'] = np.round(contract_amount * 0.01 + principle * 0.005 * lkb_deplay_days, 2)
        # 直接使用还款计划的应还本金
        # cur_principle = cal_cur_prin(contract_amount, term_no, contract_term, rate, fund_code)
        if result['lkb_deplay_fee'] > cur_principle * 0.2:
            result['lkb_deplay_fee'] = np.round(cur_principle * 0.2, 2)
        return result
    elif repaid_at >= datetime.datetime(2017,6,23,19,7,0):# 2017-6-23 修改了罚息公式,当期 罚息不超过 借款本金的20%
        principle = cal_surplus_prin(contract_amount, term_no, contract_term, rate, fund_code)
        result['lkb_deplay_fee'] = np.round(contract_amount * 0.01 + principle * 0.005 * lkb_deplay_days, 2)
        # cur_principle = cal_cur_prin(contract_amount, term_no, contract_term, rate, fund_code)
        if result['lkb_deplay_fee'] > contract_amount * 0.2:
           result['lkb_deplay_fee'] = np.round(contract_amount * 0.2, 2)
        return result
    return result







update_sql = '''
update user_repayment_plan set should_punish = %s where id = %s
'''
step = 10000
df_gen = pd.read_sql(sql=read_user_sql, con=engine_audit, chunksize=10000)
df_out=pd.DataFrame()
i = 0
for df in df_gen:
    print '-----------------------i: %s -------------------------' % i
    i += 1
    df.fillna(0, inplace=True)
    print '------------------------------>len(df.ix[df.contract_term].isnull()) : ---->', len(df.ix[df.contract_term].isnull())
    # 计算罚息
    df_bad = df.ix[(df.contract_term == 0)]
    print '---------------------rows with problems: len(df.ix[(df.contract_term == 0) ])------>', len(df_bad)
    if len(df_bad) > 0:
        df_bad.to_csv('df_bad_%s.csv' % i, index=None)
    df_good = df.ix[(df.contract_term != 0)]
    df_good['should_punish'] = df_good[['contract_amount', 'deadline', 'repaid_at','cur_principle', 'contract_term', 'term_no', 'rate', 'fund_code']].apply(lambda x: cal_deplay_fee(**dict(x))['lkb_deplay_fee'], axis=1)
    # 更新数据库
    df_good['id'] = df_good['id'].map('{:.0f}'.format)
    df_good['should_punish']=df_good['should_punish'].apply(lambda x:round(x,2))
    up_val = df_good[['should_punish', 'id']].values.tolist()
    if update_flag == True:
        engine_audit.execute(update_sql, up_val)
    else:
        print up_val
    print '-----------------------i: %s done-------------------------' % i
print '---------------------------------done !-------------------------------'