def logout(request): # update last login cur_usr = sup_fn.get_user(request) sess = Session.objects.get(pk=request.COOKIES.get('sessionid')) if sess.get_decoded()['type'] == 'ADMIN': usr_list = AdminUser.objects.filter(email=cur_usr.email) try: del request.session['email'] del request.session['timestamp'] del request.session['type'] del request.session['handling_side'] except KeyError: pass else: usr_list = User.objects.filter(email=cur_usr.email, status='ACTIVE') for usr in usr_list: usr.last_login = cur_usr.this_login usr.save() try: del request.session['email'] del request.session['timestamp'] del request.session['type'] except KeyError: pass sess.delete() return redirect('/login')
def get(self, request, format=None): usr = sup_fn.get_user(request) bor_id = request.GET.get('bor_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if bor_id == 'all': bor_list = BorrowRequest.objects.filter(usr_id = usr.id) bor_list = [bor for bor in bor_list if bor.status == 'DISBURSED' or 'PAYBACK' in bor.status] else: bor_list = BorrowRequest.objects.filter(id = bor_id) schedule_list = [] min_start_date = None max_end_date = None for bor in bor_list: loan_list = Loan.objects.filter(bor_id = bor.id) prod = Product.objects.get(id = bor.prod_id) bor.draw_down_date = timezone.localtime(bor.draw_down_date) start_date_day = bor.draw_down_date.day start_date_month = bor.draw_down_date.month + 1 start_date_year = bor.draw_down_date.year amount_per_month = prod.total_amount / prod.repayment_period interest_per_month = prod.total_amount * prod.APR_borrower * 0.01 * (prod.repayment_period / 12) / prod.repayment_period for i in range(prod.repayment_period): day = start_date_day month = (start_date_month + i-1) % 12 + 1 year = start_date_year + ((start_date_month+i-1) / 12) try: date = datetime.strptime(str(day)+'/'+str(month)+'/'+str(year), '%d/%m/%Y') except ValueError: date = datetime.strptime('1/'+str((month%12)+1)+'/'+str(year), '%d/%m/%Y') - dt.timedelta(days=1) today = datetime.strptime(timezone.localtime(timezone.now()).strftime('%d/%m/%Y'), '%d/%m/%Y') if date < today and bor.repaid_month >= (i+1): status = 'PAID' elif date < today and bor.repaid_month < (i+1): status = 'OVERDUE' elif date >= today: status = 'OPEN' schedule = { 'date': timezone.localtime(date).strftime('%d/%m/%Y'), 'os_principal': round(prod.total_amount - amount_per_month * (i+1),1), 'os_interest': round(prod.total_amount * prod.APR_borrower * 0.01 * (prod.repayment_period / 12) - interest_per_month * (i+1),1), 'os_balance': round(prod.total_amount - amount_per_month * (i+1),1)+round(prod.total_amount * prod.APR_borrower * 0.01 * (prod.repayment_period / 12) - interest_per_month * (i+1),1), 'paid_principal': round(amount_per_month, 1) if status == 'PAID' else 0, 'paid_interest': round(interest_per_month, 1) if status == 'PAID' else 0, 'ref_num': bor.ref_num, 'prod_name': prod.name_en, 'installment': round(amount_per_month+interest_per_month, 1), 'status': status, } schedule_list.append(schedule) serialized_table_list = RepayTableSerializer(schedule_list, many=True) content = {'data': serialized_table_list.data} return Response(content)
def get(self, request, format=None): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) prod_id = request.GET.get('prod_id') if prod_id == 'all': inv_list = Investment.objects.filter(usr_id=usr.id) else: inv_list = Investment.objects.filter(usr_id=usr.id,prod_id=prod_id) #color_lib = {'red':['#E08283','#E7505A','#D91E18'],'green':['#36D7B7','#4DB3A2','#26C281'],'yellow':['#F4D03F','#F7CA18','#F3C200']} color_lib = ['#E08283','#36D7B7','#F4D03F','#BF55EC','#3598DC'] i = 0 data_list = [] returning_principal = 0 returning_interest = 0 returned_principal = 0 returned_interest = 0 overdue = 0 for inv in inv_list: prod = Product.objects.get(id=inv.prod_id) loan_list = Loan.objects.filter(inv_id=inv.id) loan_list = [loan for loan in loan_list if 'DISBURSED' in loan.status or 'PAYBACK' in loan.status] returning_principal += sum([loan.remain_principal for loan in loan_list]) returning_interest += sum([loan.remain_interest_lender for loan in loan_list]) returned_principal += sum([loan.initial_amount-loan.remain_principal for loan in loan_list]) returned_interest += sum([loan.initial_amount for loan in loan_list]) * prod.APR_lender * 0.01 * (prod.repayment_period / 12) - sum([loan.remain_interest_lender for loan in loan_list]) overdue += sum([loan.overdue_principal+loan.overdue_interest for loan in loan_list]) if lang == 'en': if prod_id == 'all': name = 'All Products' else: name = Product.objects.get(id = prod_id).name_en data_list.append({'name': 'Returning Principal', 'amount': returning_principal, 'color': color_lib[0]}) data_list.append({'name': 'Returning Interest', 'amount': returning_interest, 'color': color_lib[1]}) data_list.append({'name': 'Returned Principal', 'amount': returned_principal, 'color': color_lib[2]}) data_list.append({'name': 'Returned Interest', 'amount': returned_interest, 'color': color_lib[3]}) data_list.append({'name': 'Overdue', 'amount': overdue,'color': color_lib[4]}) elif lang == 'zh': if prod_id == 'all': name = '全部產品' else: name = Product.objects.get(id = prod_id).name_zh.encode('utf8') data_list.append({'name': '待收本金', 'amount': returning_principal, 'color': color_lib[0]}) data_list.append({'name': '待收利息', 'amount': returning_interest, 'color': color_lib[1]}) data_list.append({'name': '已收本金', 'amount': returned_principal, 'color': color_lib[2]}) data_list.append({'name': '已收利息', 'amount': returned_interest, 'color': color_lib[3]}) data_list.append({'name': '逾期還款', 'amount': overdue,'color': color_lib[4]}) for data in data_list: data['amount'] = round(data['amount'], 2) #serialized_data_list = RepayPieSerializer(data_list, many=True) content = {'data': data_list} return Response(content)
def footer(request): user = sup_fn.get_user(request) lang = sup_fn.get_lang(request) if user.type == 'L': content = {'lang': lang,} return render(request, 'peerloan/lender/footer.html', content) if user.type == 'B': content = {'lang': lang,} return render(request, 'peerloan/borrower/footer.html', content)
def trans_records(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) if usr.type == 'B': content = { 'lang': lang, 'cate': 'trans_records', 'title': 'Transaction Records', } if lang == 'zh': content['title'] = '交易紀錄' return render(request, 'peerloan/borrower/trans_records.html', content)
def get(self, request, format=None): usr = sup_fn.get_user(request) bor_id = request.GET.get('bor_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') data_list = [] if bor_id == 'all': bor_list = BorrowRequest.objects.filter(usr_id = usr.id) bor_list = [bor for bor in bor_list if bor.status == 'DISBURSED' or 'PAYBACK' in bor.status] else: bor_list = BorrowRequest.objects.filter(id = bor_id) total_principal = 0 paid_principal = 0 paid_interest = 0 outstanding_principal = 0 outstanding_interest = 0 overdue_principal = 0 overdue_amount = 0 for bor in bor_list: prod = Product.objects.get(id = bor.prod_id) loan_list = Loan.objects.filter(bor_id = bor.id) total_principal += sum([loan.initial_amount for loan in loan_list]) paid_principal += sum([loan.initial_amount - loan.remain_principal for loan in loan_list]) paid_interest += sum([loan.initial_amount for loan in loan_list]) * prod.APR_borrower * 0.01 * (prod.repayment_period /12) - sum([loan.remain_interest_borrower for loan in loan_list]) outstanding_principal += sum([loan.remain_principal for loan in loan_list]) outstanding_interest += sum([loan.remain_interest_borrower for loan in loan_list]) overdue_principal += sum([loan.overdue_principal for loan in loan_list]) overdue_amount += sum([loan.overdue_principal+loan.overdue_interest for loan in loan_list]) total_principal = round(total_principal, 1) paid_principal = round(paid_principal, 1) paid_interest = round(paid_interest, 1) outstanding_principal = round(outstanding_principal, 1) outstanding_interest = round(outstanding_interest, 1) overdue_principal = round(overdue_principal, 1) overdue_amount = round(overdue_amount, 1) data_list.append({'key': 'Total Principal', 'value':'$'+str(total_principal)}) data_list.append({'key': 'Paid Principal', 'value':'$'+str(paid_principal)}) data_list.append({'key': 'Paid Interest', 'value':'$'+str(paid_interest)}) data_list.append({'key': 'Outstanding Principal', 'value':'$'+str(outstanding_principal)}) data_list.append({'key': 'Outstanding Interest', 'value':'$'+str(outstanding_interest)}) data_list.append({'key': 'Overdue Principal', 'value':'$'+str(overdue_principal)}) data_list.append({'key': 'Overdue Amount (included interest)', 'value':'$'+str(overdue_amount)}) serialized_data_list = KeyValueSerializer(data_list, many=True) content = {'data': serialized_data_list.data} return Response(content)
def get(self, request, format=None): usr = sup_fn.get_user(request) prod_id = request.GET.get('prod_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if prod_id == 'all': inv_list = Investment.objects.filter(usr_id=usr.id) else: inv_list = Investment.objects.filter(usr_id=usr.id, prod_id=prod_id) data_list = [] total_principal = 0 returned_principal = 0 returned_interest = 0 returning_principal = 0 returning_interest = 0 overdue_principal = 0 overdue_amount = 0 for inv in inv_list: loan_list = Loan.objects.filter(inv_id=inv.id) total_principal += sum([loan.initial_amount for loan in loan_list]) returned_principal += sum([loan.initial_amount - loan.remain_principal for loan in loan_list]) prod = Product.objects.get(id=inv.prod_id) returned_interest += sum([loan.initial_amount * prod.APR_lender * 0.01 * (prod.repayment_period/12) - loan.remain_interest_lender for loan in loan_list]) returning_principal += sum([loan.remain_principal for loan in loan_list]) returning_interest += sum([loan.remain_interest_lender for loan in loan_list]) overdue_principal += sum([loan.overdue_principal for loan in loan_list]) overdue_amount += sum([loan.overdue_principal+loan.overdue_interest for loan in loan_list]) returned_principal = round(returned_principal, 1) returned_interest = round(returned_interest, 1) returning_principal = round(returning_principal, 1) returning_interest = round(returning_interest, 1) overdue_principal = round(overdue_principal, 1) overdue_amount = round(overdue_amount, 1) data_list.append({'key': 'Total Principal', 'value':'$'+str(total_principal)}) data_list.append({'key': 'Returned Principal', 'value':'$'+str(returned_principal)}) data_list.append({'key': 'Returned Interest', 'value':'$'+str(returned_interest)}) data_list.append({'key': 'Returning Principal', 'value':'$'+str(returning_principal)}) data_list.append({'key': 'Returning Interest', 'value':'$'+str(returning_interest)}) data_list.append({'key': 'Overdue Principal', 'value':'$'+str(overdue_principal)}) data_list.append({'key': 'Overdue Amount (included interest)', 'value':'$'+str(overdue_amount)}) serialized_data_list = KeyValueSerializer(data_list, many=True) content = {'data': serialized_data_list.data} return Response(content)
def get(self, request, format=None): usr = sup_fn.get_user(request) prod_id = request.GET.get('prod_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if prod_id == 'all': prod_list = Product.objects.filter(status='ACTIVE') else: prod_list = Product.objects.filter(id=prod_id) rd_loan_list = [] for prod in prod_list: try: inv = Investment.objects.get(prod_id=prod.id, usr_id= usr.id) except ObjectDoesNotExist: continue loan_list = Loan.objects.filter(inv_id=inv.id) loan_list = [loan for loan in loan_list if loan.status=='DISBURSED' or 'PAYBACK' in loan.status] for loan in loan_list: try: bor = BorrowRequest.objects.get(id = loan.bor_id) except: continue rd_loan = { 'shadow_datetime': timezone.localtime(bor.draw_down_date), 'date': datetime.strftime(timezone.localtime(loan.update_timestamp), '%Y/%m/%d'), 'ref_num': bor.ref_num, 'amount': FLOAT_DATA_FORMAT.format(loan.initial_amount), 'interest': FLOAT_DATA_FORMAT.format(loan.total_repay_amount_lender - loan.initial_amount), 'installment': FLOAT_DATA_FORMAT.format(loan.instalment_lender), 'draw_down_date': datetime.strftime(timezone.localtime(bor.draw_down_date), '%Y/%m/%d'), 'expected_end_date': datetime.strftime(timezone.localtime(bor.expected_end_date), '%Y/%m/%d'), 'overdue_loan_receivable': FLOAT_DATA_FORMAT.format(loan.overdue_principal + loan.overdue_interest), 'loan_id': loan.id, } rd_loan_list.append(rd_loan) #serialized_data_list = ActiveInvSerializer(rd_loan_list, many=True) content = {'data': rd_loan_list} return Response(content)
def invest_now(request): user = sup_fn.get_user(request) lang = sup_fn.get_lang(request) if 'start_investing' in request.META.get('PATH_INFO').split('/'): rd_prod_list = [['all','All Products']] prod_list = Product.objects.filter(status='ACTIVE') for prod in prod_list: rd_prod_list.append([prod.id,prod.name_en]) content = { 'cate': 'invest_now', 'prod_list': rd_prod_list, } return render(request, 'peerloan/lender/start_invest.html', content) prod_list = Product.objects.filter(status='ACTIVE') rd_prod_list = [] for prod in prod_list: details = { 'prod_name': prod.name_en, 'total_amount': prod.total_amount, 'APR': prod.APR_lender, 'flat_rate': prod.flat_rate_lender, 'repayment_period': prod.repayment_period, 'amount_per_unit': prod.min_amount_per_loan, 'min_inv_unit_per_loan': 1, 'max_inv_unit_per_loan': int(prod.total_amount / prod.min_amount_per_loan), 'prod_id': prod.id, } rd_prod_list.append(details) content = { 'cate': 'invest_now', 'prod_list': rd_prod_list, } return render(request, 'peerloan/lender/invest_now.html', content)
def get(self, request, format=None): usr = sup_fn.get_user(request) bor_id = request.GET.get('bor_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if bor_id == 'all': bor_list = BorrowRequest.objects.filter(usr_id = usr.id) bor_list = [bor for bor in bor_list if bor.status == 'DISBURSED' or 'PAYBACK' in bor.status] else: bor_list = BorrowRequest.objects.filter(id = bor_id) # assume user applies not more than 3 loans color_lib = {'red':['#E08283','#E7505A','#D91E18'],'green':['#36D7B7','#4DB3A2','#26C281'],'yellow':['#F4D03F','#F7CA18','#F3C200']} data_list = [] i = 0 for bor in bor_list: loan_list = Loan.objects.filter(bor_id = bor.id) prod = Product.objects.get(id = bor.prod_id) paid_principal = sum([loan.initial_amount - loan.remain_principal for loan in loan_list]) outstanding_principal = sum([loan.remain_principal for loan in loan_list]) overdue_principal = sum([loan.overdue_principal for loan in loan_list]) if paid_principal != 0: data_list.append({'name':'Paid Principal ('+prod.name_en+')','amount':paid_principal,'color':color_lib['green'][i]}) if outstanding_principal != 0: data_list.append({'name':'Outstanding Principal ('+prod.name_en+')','amount':outstanding_principal,'color':color_lib['yellow'][i]}) if overdue_principal != 0: data_list.append({'name':'Overdue Principal ('+prod.name_en+')','amount':overdue_principal,'color':color_lib['red'][i]}) i += 1 serialized_data_list = RepayPieSerializer(data_list, many=True) content = {'data': serialized_data_list.data} return Response(content)
def switch_role(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) if usr.type == 'L': request.session['type'] = 'B' # upate borrower last login b_usr = User.objects.get(email=usr.email,type='B') b_usr.this_login = timezone.localtime(timezone.now()) b_usr.save() return redirect('/borrow_now') elif usr.type == 'B': if len(User.objects.filter(email = usr.email, status = 'ACTIVE')) == 2: request.session['type'] = 'L' return redirect('/portfolio/portfolio_summary') else: return redirect('/apply_to_be_investor') elif len(AdminUser.objects.filter(email=usr.email)) != 0: if request.session['handling_side'] == 'L': request.session['handling_side'] = 'B' elif request.session['handling_side'] == 'B': request.session['handling_side'] = 'L' return redirect('/pl_admin/application')
def investment(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) action = request.META.get('PATH_INFO').split('/')[2] if action == 'invest_now': if 'product_details' in request.META.get('PATH_INFO').split('/'): prod_list = Product.objects.filter(status='ACTIVE') prod_list = [prod for prod in prod_list if prod.repayment_plan != 'Promotion Balloon Payment'] if lang == 'en': thead_list = [ 'Product Name', 'Maximum Amount Per Loan (HK$)', 'Expected Annualised Return (%)', 'Repayment Period (months)', 'Amount Per Unit (HK$/month)', 'Investment Unit Per Loan', 'Expected Returning Schedule (Per Unit)' ] elif lang == 'zh': thead_list = [ '產品名稱', '每筆貸款的最高金額 (HK$)', '預期年回報 (%)', '還款期 (月)', '每單位金額 (HK$/月)', '每筆貸款的投資單位', '預計收回貸款時間表 (每單位)' ] tdata_list = [] for prod in prod_list: if lang == 'en': tdata = [ prod.name_en, FLOAT_DATA_FORMAT.format(prod.total_amount), FLOAT_DATA_FORMAT.format(prod.APR_lender), prod.repayment_period, FLOAT_DATA_FORMAT.format(prod.min_amount_per_loan), '1-' + str(int(prod.total_amount/prod.min_amount_per_loan)), '<a href=\'javascript:window.open("/loan_repay_schedule/?prod_id='+str(prod.id)+'","contestrules", "menubar=0,resizable=0,width=1000,height=800");\'><button class="btn green-jungle">Browse</button></a>' ] elif lang == 'zh': tdata = [ prod.name_zh, FLOAT_DATA_FORMAT.format(prod.total_amount), FLOAT_DATA_FORMAT.format(prod.APR_lender), prod.repayment_period, FLOAT_DATA_FORMAT.format(prod.min_amount_per_loan), '1-' + str(int(prod.total_amount/prod.min_amount_per_loan)), '<a href=\'javascript:window.open("/loan_repay_schedule/?prod_id='+str(prod.id).encode('utf8')+'","contestrules", "menubar=0,resizable=0,width=1000,height=800");\'><button class="btn green-jungle">瀏覽</button></a>' ] tdata_list.append(tdata) content = { 'lang': lang, 'caption': 'Product List', 'thead_list': thead_list, 'tdata_list': tdata_list } if lang == 'zh': content['caption'] = '產品列表' return render(request, 'peerloan/lender/table.html', content) acc = Account.objects.get(usr_id=usr.id) inv_list = Investment.objects.filter(usr_id=usr.id) prod_list = Product.objects.filter(status='ACTIVE') prod_list = [prod for prod in prod_list if prod.repayment_plan != 'Promotion Balloon Payment'] rd_prod_list = [] for prod in prod_list: try: inv = Investment.objects.get(usr_id=usr.id, prod_id=prod.id) except ObjectDoesNotExist: existed_investment = 0 on_hold_investment = 0 max_amt_per_loan = 'Not set' else: existed_investment = inv.usable_amount on_hold_investment = inv.on_hold_amount max_amt_per_loan = inv.max_amount_per_loan rd_prod_list.append({ 'id': str(prod.id), 'name_en': str(prod.name_en), 'name_zh': prod.name_zh.encode('utf8'), 'min_amount_per_loan': str(prod.min_amount_per_loan), 'total_amount': str(prod.total_amount), 'existed_investment': existed_investment, 'str_existed_investment': FLOAT_DATA_FORMAT.format(existed_investment), 'on_hold_investment': on_hold_investment, 'str_on_hold_investment': FLOAT_DATA_FORMAT.format(on_hold_investment), 'max_amt_per_loan': FLOAT_DATA_FORMAT.format(max_amt_per_loan) if max_amt_per_loan !='Not set' else max_amt_per_loan, }) disbursed_amount = 0 for inv in inv_list: loan_list = Loan.objects.filter(inv_id=inv.id) disbursed_amount += sum([loan.remain_principal_lender for loan in loan_list if 'PAYBACK' in loan.status]) content = { 'lang': lang, 'cate': 'investment', 'sub_cate': 'invest_now', 'title': 'Invest Now', #'account_balance': '%.2f'%(acc.balance + sum([inv.total_amount for inv in inv_list]) + disbursed_amount), 'account_balance': '%.2f'%(acc.balance + sum([inv.usable_amount+inv.on_hold_amount for inv in inv_list]) + disbursed_amount), 'str_account_balance': FLOAT_DATA_FORMAT.format(acc.balance + sum([inv.usable_amount+inv.on_hold_amount for inv in inv_list]) + disbursed_amount), 'unallocated': '%.2f'%(acc.balance), 'str_unallocated': FLOAT_DATA_FORMAT.format(acc.balance), 'prod_list': rd_prod_list } if lang == 'zh': content['title'] = ' 開始投資' return render(request, 'peerloan/lender/invest_now.html', content) elif action == 'reallocate_fund': acc = Account.objects.get(usr_id=usr.id) inv_list = Investment.objects.filter(usr_id=usr.id) prod_list = Product.objects.filter(status='ACTIVE') prod_list = [prod for prod in prod_list if prod.repayment_plan != 'Promotion Balloon Payment'] rd_prod_list = [] for prod in prod_list: try: inv = Investment.objects.get(usr_id=usr.id, prod_id=prod.id) except ObjectDoesNotExist: existed_investment = 0 on_hold_investment = 0 investment_setting = '--' max_amount_per_loan = 0 else: existed_investment = round(inv.usable_amount, 2) on_hold_investment = round(inv.on_hold_amount, 2) investment_setting = inv.option max_amount_per_loan = round(inv.max_amount_per_loan, 2) rd_prod_list.append({ 'id': str(prod.id), 'name_en': str(prod.name_en), 'name_zh': prod.name_zh.encode('utf8'), 'min_amount_per_loan': str(prod.min_amount_per_loan), 'total_amount': str(prod.total_amount), 'existed_investment': existed_investment, 'str_existed_investment': FLOAT_DATA_FORMAT.format(existed_investment), 'on_hold_investment': on_hold_investment, 'str_on_hold_investment': FLOAT_DATA_FORMAT.format(on_hold_investment), 'investment_setting': str(investment_setting), 'max_amount_per_loan': max_amount_per_loan, 'str_max_amount_per_loan': FLOAT_DATA_FORMAT.format(max_amount_per_loan) }) disbursed_amount = 0 for inv in inv_list: loan_list = Loan.objects.filter(inv_id=inv.id) disbursed_amount += sum([loan.remain_principal_lender for loan in loan_list if 'PAYBACK' in loan.status]) content = { 'lang': lang, 'cate': 'investment', 'sub_cate': 'reallocate_fund', 'title': 'Reallocate Fund', #'account_balance': '%.2f'%(acc.balance + sum([inv.total_amount for inv in inv_list]) + disbursed_amount), 'account_balance': '%.2f'%(acc.balance + sum([inv.usable_amount+inv.on_hold_amount for inv in inv_list]) + disbursed_amount), 'str_account_balance': FLOAT_DATA_FORMAT.format(acc.balance + sum([inv.usable_amount+inv.on_hold_amount for inv in inv_list]) + disbursed_amount), 'unallocated': '%.2f'%(acc.balance), 'str_unallocated': FLOAT_DATA_FORMAT.format(acc.balance), 'prod_list': rd_prod_list } if lang == 'zh': content['title'] = '調配投資金額' return render(request, 'peerloan/lender/reallocate_fund.html', content) elif action == 'transfer_fund': inv_list = Investment.objects.filter(usr_id=usr.id) rd_prod_list = [] for inv in inv_list: prod = Product.objects.get(id=inv.prod_id) if lang == 'en': rd_prod_list.append({'prod_id':str(prod.id), 'prod_name':str(prod.name_en), 'usable_amount':str(inv.usable_amount)}) elif lang == 'zh': rd_prod_list.append({'prod_id':str(prod.id), 'prod_name':prod.name_zh.encode('utf8'), 'usable_amount':str(inv.usable_amount)}) content = { 'lang': lang, 'prod_list': rd_prod_list, 'cate': 'investment', 'sub_cate': 'transfer_fund', } if lang == 'en': content['title'] = 'Transfer Fund Between Products' content['instruction'] = """Fund Transfer only applicable to the product which have your investment instruction record, if you have not invested in such product before, please click "Invest Now" to set your investment instruction first. Fund Transfer instruction will be executed immediately.""" if lang == 'zh': content['title'] = '調配資金' content['instruction'] = """調配資金只適用於已有投資紀錄的產品,如你從未投資於該產品,請即按入"現在投資"以設定該產品的投資指示,你的資金調配指示將會即時執行。""" return render(request, 'peerloan/lender/transfer_form.html', content)
def borrow_now(request): user = sup_fn.get_user(request) lang = sup_fn.get_lang(request) prod_list = Product.objects.filter(status='ACTIVE') rd_prod_list = [] for prod in prod_list: # calculate the installment rate_per_month = prod.APR_borrower * 0.01 / 12 if prod.repayment_plan == 'Instalment': instalment_borrower = prod.min_amount * (rate_per_month / (1- (1 + rate_per_month)**(-(prod.repayment_period/12)*12))) if prod.repayment_plan == 'Balloon Payment': instalment_borrower = prod.min_amount * rate_per_month # check num of applied prod bor_list = BorrowRequest.objects.filter(usr_id=user.id) bor_list = [bor for bor in bor_list if bor.status not in ['PAYBACK COMPLETED', 'REJECTED', 'CANCELLED']] num_of_applied_prod = len(bor_list) # check which step if num_of_applied_prod != 0: step = 'auto_reject' else: try: bor = BorrowRequest.objects.filter(usr_id=user.id, prod_id=prod.id).latest('update_timestamp') except ObjectDoesNotExist: if num_of_applied_prod == 0: step = 'apply' else: step = 'auto_reject' else: if bor.status == 'AUTO APPROVED': step = 'upload_docs' elif bor.status == 'DOC UPLOADED': step = 'confirm_agreement' elif bor.status == 'PAYBACK COMPLETED' or bor.status == 'REJECTED' or bor.status == 'CANCELLED': step = 'apply' elif bor.status == 'FUND MATCHING COMPLETED': step = 'confirm_memorandum' else: # status = draw down, repay, ... step = 'auto_reject' if lang == 'en': prod_name = prod.name_en elif lang == 'zh': prod_name = prod.name_zh rd_prod_list.append({ 'id': prod.id, 'name': prod_name, #'min_amount': int(prod.min_amount), 'min_amount': FLOAT_DATA_FORMAT.format(prod.min_amount), 'total_amount': FLOAT_DATA_FORMAT.format(prod.total_amount), 'APR_borrower': FLOAT_DATA_FORMAT.format(prod.APR_borrower if prod.fake_APR_borrower == None else prod.fake_APR_borrower), 'repayment_period': prod.repayment_period if prod.fake_repayment_period == None else prod.fake_repayment_period, 'instalment_borrower': FLOAT_DATA_FORMAT.format(instalment_borrower), 'step': step, }) content = { 'lang': lang, 'cate': 'borrow_now', 'prod_list': rd_prod_list, } return render(request, 'peerloan/borrower/borrow_now.html', content)
def my_account(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) sub_cate = request.META.get('PATH_INFO').split('/')[2] # borrower side ============================================================================================= if usr.type == 'B': if sub_cate == 'all_application_listing': if 'detail' in request.META.get('PATH_INFO').split('/'): # bor detail bor_id = request.GET.get('bor_id') bor = BorrowRequest.objects.get(id=bor_id) prod = Product.objects.get(id=bor.prod_id) los_list = LoanSchedule.objects.filter(bor_id=bor.id, status='OVERDUE') basic_info = { 'product': prod.name_en, 'total_amount': 'HK$' + FLOAT_DATA_FORMAT.format(bor.amount), 'instalment': 'HK$' + FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'draw_down_date': bor.draw_down_date.strftime('%Y/%m/%d'), 'expected_end_date': bor.expected_end_date.strftime('%Y/%m/%d'), 'overdue_loan_payment': 'HK$' + FLOAT_DATA_FORMAT.format( sum([ los.overdue_interest_accumulated for los in los_list ])), 'tenor': str(prod.repayment_period) + ' months', 'status': ''.join([i for i in bor.status if (not i.isdigit())]) } if prod.repayment_plan == 'Promotion Balloon Payment': basic_info['tenor'] = str(9) + ' months' if lang == 'zh': basic_info['product'] = prod.name_zh basic_info['tenor'] = str(prod.repayment_period) + ' 月' if prod.repayment_plan == 'Promotion Balloon Payment': basic_info['tenor'] = str(9) + ' 月' # create repayment table los_list = LoanSchedule.objects.filter(bor_id=bor.id) repayment_table = [] repayment_history = [] remain_balance = bor.amount for i in range(prod.repayment_period): los = los_list[i] remain_balance -= los.principal if remain_balance <= 0.02: remain_balance = 0 row = { 'tenor': str(i + 1), 'due_date': los.due_date, 'instalment_amount': FLOAT_DATA_FORMAT.format(los.instalment), 'interest': FLOAT_DATA_FORMAT.format(los.interest), 'principal': FLOAT_DATA_FORMAT.format(los.principal), 'outstanding_principal': FLOAT_DATA_FORMAT.format(remain_balance), } repayment_table.append(row) if 'PAID' in los.status or 'PAYBACK COMPLETED' in los.status: row = { 'due_date': los.due_date, 'repayment_date': timezone.localtime( los.repayment_date).strftime('%Y/%m/%d'), 'overdue_day': los.overdue_days, 'overdue_interest': FLOAT_DATA_FORMAT.format( los.overdue_interest_accumulated), 'payment_amount': FLOAT_DATA_FORMAT.format(los.received_amount), 'repayment_method': los.repayment_method, 'repayment_type': los.repayment_type, } repayment_history.append(row) # calculate early settle loan_list = Loan.objects.filter(bor_id=bor.id) if bor.repaid_month == 0: last_pay_date = bor.draw_down_date else: los = LoanSchedule.objects.get(bor_id=bor.id, tenor=bor.repaid_month) last_pay_date = datetime.strptime(los.due_date, '%Y/%m/%d') last_pay_date = pytz.timezone('Asia/Hong_Kong').localize( last_pay_date) days = (timezone.localtime(timezone.now()) - last_pay_date).days if days < 0: days = 0 rate_per_day = prod.APR_borrower * 0.01 / 360 remain_principal = sum( [loan.remain_principal for loan in loan_list]) early_settlement_amount = remain_principal * ( 1 + rate_per_day * days) early_settle = { 'date': timezone.localtime(timezone.now()).strftime('%Y/%m/%d') + ' (as today)', 'amount': 'HK$' + FLOAT_DATA_FORMAT.format(early_settlement_amount) } if lang == 'zh': early_settle['date'] = timezone.localtime( timezone.now()).strftime('%Y/%m/%d') + ' (在今日)' content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'all_application_listing', 'title': 'Loan - ' + bor.ref_num, 'form_action': 'javascript:;', 'basic_info': basic_info, 'repayment_table': repayment_table, 'repayment_history': repayment_history, 'early_settle': early_settle, 'bod_list': BorrowRequestDocument.objects.filter(bor_id=bor.id), } if lang == 'zh': content['title'] = '貸款 - %s' % bor.ref_num.encode("utf8") return render( request, 'peerloan/borrower/all_application_listing_detail.html', content) else: # bor table status_list = [ 'All', 'AUTO APPROVED', 'DOC UPLOADED', 'AGREEMENT CONFIRMED', 'PENDING DOC/IV', 'DISBURSED', 'PAYBACK', 'PAYBACK OVERDUE', 'PAYBACK COMPLETED' ] content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'all_application_listing', 'title': 'Application Listing', 'status_list': status_list, } if lang == 'zh': content['title'] = '申請列表' return render( request, 'peerloan/borrower/all_application_listing.html', content) if sub_cate == 'active_loan': if 'repayment_details' in request.META.get('PATH_INFO').split('/'): # repay detail page bor_list = BorrowRequest.objects.filter(usr_id=usr.id) bor_list = [ bor for bor in bor_list if bor.status == 'DISBURSED' or 'PAYBACK' in bor.status ] rd_bor_list = [['all', 'All Active Loan']] for bor in bor_list: rd_bor_list.append( [bor.id, 'Loan Ref No.: ' + bor.ref_num]) content = { 'cate': 'my_account', 'sub_cate': 'active_loan', 'bor_list': rd_bor_list, } return render(request, 'peerloan/borrower/repayment_details.html', content) else: # active loan page bor_list = BorrowRequest.objects.filter(usr_id=usr.id) bor_list = [ bor for bor in bor_list if bor.status == 'DISBURSED' or 'PAYBACK' in bor.status ] detail_list = [] app_list = [] for bor in bor_list: detail = {} prod = Product.objects.get(id=bor.prod_id) loan_list = Loan.objects.filter(bor_id=bor.id) detail['prod_name'] = prod.name_en detail['total_amount'] = prod.total_amount detail['installment'] = round(bor.instalment_borrower, 2) detail['draw_down_date'] = loan_list[ 0].draw_down_date.strftime("%d/%m/%Y") detail['expected_end_date'] = loan_list[ 0].expected_end_date.strftime("%d/%m/%Y") detail['overdue_loan_payment'] = sum([ loan.overdue_principal + loan.overdue_interest for loan in loan_list ]) detail['bor_ref_num'] = bor.ref_num detail['repayment_period'] = prod.repayment_period detail['APR'] = prod.APR_borrower detail_list.append(detail) bod_list = BorrowRequestDocument.objects.filter( bor_id=bor.id) app_list.append(bod_list) content = { 'cate': 'my_account', 'sub_cate': 'active_loan', 'bor_list': bor_list, 'detail_list': detail_list, 'app_list': app_list, } return render(request, 'peerloan/borrower/active_loan.html', content) if sub_cate == 'loan_status': if 'view_detail' in request.META.get('PATH_INFO').split('/'): # bor detail bor_id = request.GET.get('bor_id') bor = BorrowRequest.objects.get(id=bor_id) prod = Product.objects.get(id=bor.prod_id) if bor.status == 'APPLIED': fields = [] fields.append({ 'name': 'Product Name', 'value': prod.name_en }) fields.append({ 'name': 'Total Applied Amount', 'value': prod.total_amount }) fields.append({'name': 'APR', 'value': prod.APR_borrower}) fields.append({ 'name': 'Upload Supplementary Documents', 'type': 'upload_file', 'value': 'supply_doc' }) fields.append({ 'name': 'Supplementaty Documents Description', 'type': 'input', 'value': 'supply_doc_descri' }) fields.append({ 'name': 'Applicaton Date', 'value': bor.create_timestamp.strftime('%Y-%m-%d') }) fields.append({'name': 'Status', 'value': bor.status}) buttons = [] buttons.append({'name': 'Submit', 'type': 'submit'}) buttons.append({ 'name': 'Close', 'type': 'button', 'onclick': 'window.close()' }) elif bor.status == 'VALIDATED' or 'MATCHING' in bor.status: fields = [] loan_list = Loan.objects.filter(bor_id=bor.id) if len(loan_list) == 0: fields.append({'name': 'Matched Amount', 'value': 0}) else: fields.append({ 'name': 'Matched Amount', 'value': sum([loan.initial_amount for loan in loan_list]) }) fields.append({ 'name': 'Total Applied Amount', 'value': prod.total_amount }) fields.append({ 'name': 'Application Date', 'value': bor.create_timestamp.strftime('%Y-%m-%d') }) fields.append({ 'name': 'Matching Starting Date', 'value': bor.update_timestamp.strftime('%Y-%m-%d') }) fields.append({ 'name': 'Matching Expiring Date', 'value': (bor.update_timestamp + dt.timedelta(days=7)).strftime('%Y-%m-%d') }) fields.append({'name': 'APR', 'value': prod.APR_borrower}) fields.append({'name': 'Status', 'value': bor.status}) buttons = [] buttons.append({ 'name': 'Close', 'type': 'button', 'onclick': 'window.close()' }) elif 'PAYBACK' in bor.status or bor.status == 'DRAWN DOWN': return redirect('/my_account/active_loan') elif bor.status == 'COMPLETED': fields = [] loan_list = Loan.objects.filter(bor_id=bor.id) fields.append({ 'name': 'Borrowed Principal', 'value': sum([loan.remain_principal for loan in loan_list]) }) fields.append({ 'name': 'Total Interest', 'value': sum([ loan.remain_interest_borrower for loan in loan_list ]) }) fields.append({ 'name': 'Total Overdue Interest', 'value': sum([loan.overdue_interest for loan in loan_list]) }) fields.append({'name': 'APR', 'value': prod.APR_borrower}) total_interest = prod.total_amount * prod.APR_borrower * 0.01 * prod.repayment_period / 12 + sum( [loan.paid_overdue_interest for loan in loan_list]) effective_APR = (total_interest / prod.total_amount) * ( 12 / prod.repayment_period) * 100 fields.append({ 'name': 'Effective APR', 'value': effective_APR }) fields.append({ 'name': 'Effective Flat Rate', 'value': 'PENDING' }) buttons = [] buttons.append({ 'name': 'Close', 'type': 'button', 'onclick': 'window.close()' }) content = { 'title': 'Loan Reference Number - ' + bor.ref_num, 'cate': 'my_account', 'sub_cate': 'loan_status', 'form_action': '/ack/', 'fields': fields, 'buttons': buttons, } return render(request, 'peerloan/borrower/form.html', content) else: # bor table status_list = [ 'All', 'AUTO APPROVED', 'DOC UPLOADED', 'AGREEMENT CONFIRMED', 'PENDING DOC/IV', 'PENDING VERIFIED', 'VALIDATED', 'FUND MATCHING', 'FUND MATCHING COMPLETED', 'DISBURSED', 'PAYBACK', 'PAYBACK OVERDUE', 'PAYBACK COMPLETED' ] content = { 'cate': 'my_account', 'sub_cate': 'loan_status', 'status_list': status_list, } return render(request, 'peerloan/borrower/loan_status.html', content) if sub_cate == 'change_acc_info': details = json.loads(usr.detail_info) usr_info = { 'usr_id': usr.id, 'password': '******', 'mobile': sup_fn.try_KeyError(details, 'Mobile'), 'address': sup_fn.try_KeyError(details, 'Residential Address'), } content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'change_acc_info', 'title': 'Change Account Information', 'form_action': 'javascript:;', 'usr_info': usr_info, } if lang == 'zh': content['title'] = '更換賬戶資料' return render(request, 'peerloan/borrower/change_acc_info.html', content) if sub_cate == 'repayment_and_settlement': usr = sup_fn.get_user(request) bor_list = BorrowRequest.objects.filter(usr_id=usr.id) bor_list = [ bor for bor in bor_list if ('PAYBACK' in bor.status or 'DISBURSED' in bor.status) and 'COMPLETED' not in bor.status ] content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'repayment_and_settlement', 'title': 'Repayment and Settlement', } if lang == 'zh': content['title'] = '供款及提早還款' if len(bor_list) != 0: bor = bor_list[0] inputs = {'bor_id': bor.id, 'type': 'instalment'} outputs = sup_fn.calculate_repay_amount(inputs) content['instalment_month'] = outputs['instalment_month'] total_amount = max( 0, outputs['instalment_amount'] + outputs['overdue_interest'] + outputs['late_charge'] - outputs['overpay_amount']) content[ 'instalment_amount'] = 'HK$%s, included: <br>instalment: HK$%s;<br>overdue interest: HK$%s;<br>late charge: HK$%s;<br>overpay amount: HK$%s.' % ( FLOAT_DATA_FORMAT.format(total_amount), FLOAT_DATA_FORMAT.format(outputs['instalment_amount']), FLOAT_DATA_FORMAT.format(outputs['overdue_interest']), FLOAT_DATA_FORMAT.format(outputs['late_charge']), FLOAT_DATA_FORMAT.format(outputs['overpay_amount'])) if lang == 'zh': content[ 'instalment_amount'] = 'HK$%s, 包含: <br>分期還款金額: HK$%s;<br>逾期利息: HK$%s;<br>逾期收費: HK$%s;<br>多繳金額: HK$%s。' % ( FLOAT_DATA_FORMAT.format(total_amount), FLOAT_DATA_FORMAT.format( outputs['instalment_amount']), FLOAT_DATA_FORMAT.format( outputs['overdue_interest']), FLOAT_DATA_FORMAT.format(outputs['late_charge']), FLOAT_DATA_FORMAT.format( outputs['overpay_amount'])) # calculate early settlement inputs = {'bor_id': bor.id, 'type': 'early_settlement'} outputs = sup_fn.calculate_repay_amount(inputs) total_amount = max( 0, outputs['early_settlement_amount'] + outputs['late_charge'] - outputs['overpay_amount']) content[ 'early_settlement_amount'] = 'HK$%s, included: <br>principal: HK$%s;<br>interest: HK$%s;<br>late charge: HK$%s;<br>overpay amount: HK$%s.' % ( FLOAT_DATA_FORMAT.format(total_amount), FLOAT_DATA_FORMAT.format(outputs['principal']), FLOAT_DATA_FORMAT.format(outputs['interest']), FLOAT_DATA_FORMAT.format(outputs['late_charge']), FLOAT_DATA_FORMAT.format(outputs['overpay_amount'])) if lang == 'zh': content[ 'early_settlement_amount'] = 'HK$%s, 包含: <br>本金: HK$%s;<br>利息: HK$%s;<br>逾期收費: HK$%s;<br>多繳金額: HK$%s。' % ( FLOAT_DATA_FORMAT.format(total_amount), FLOAT_DATA_FORMAT.format(outputs['principal']), FLOAT_DATA_FORMAT.format(outputs['interest']), FLOAT_DATA_FORMAT.format(outputs['late_charge']), FLOAT_DATA_FORMAT.format( outputs['overpay_amount'])) content['bor_id'] = bor.id content['bor_ref_num'] = bor.ref_num return render( request, 'peerloan/borrower/repayment_and_settlement.html', content) else: if lang == 'en': content[ 'instruction'] = 'No record, you can apply a loan first. Click <a href="/borrow_now" style="color:#fff;"><u>here</u></a>' elif lang == 'zh': content[ 'instruction'] = '沒有找到記錄,請先申請貸款。<a href="/borrow_now" style="color:#fff;">點擊此處</a>' return render(request, 'peerloan/borrower/acknowledgement.html', content) # borrower side end ======================================================================================= # lender side ============================================================================================= elif usr.type == 'L': if sub_cate == 'deposit_money': if lang == 'en': fields = [] fields.append({'name': 'Bank Name', 'value': 'Hang Seng Bank'}) fields.append({ 'name': 'Bank Account Number', 'value': '239-498-348883' }) fields.append({ 'name': 'Name of Account Holder', 'value': 'P L Technology Limited' }) fields.append({ 'name': 'Bank Deposit Slip', 'value': 'receipt', 'type': 'upload_file', 'additional_text': 'Please keep your original bank slip at least 3 months (from upload date) for record.', 'required': 'True' }) fields.append({ 'name': 'Deposit Amount', 'value': 'transfer_amt', 'type': 'input', 'required': 'True' }) #fields.append({'name': 'Your Reference', 'value': 'ur_ref', 'type': 'input'}) buttons = [] buttons.append({'name': 'Submit', 'type': 'submit'}) buttons.append({ 'name': 'Cancel', 'type': 'button', 'onclick': 'window.history.back()' }) content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'deposit_money', 'title': 'Deposit Money', 'instruction': """Zwap only accept cheque deposit or bank transfer from a local bank account under your own name, please upload the deposit slip here, the fund will be ready in your Zwap's account within 1 business day for bank transfer, and 2 business days for cheque deposit. """, 'form_action': '/ack/', 'fields': fields, 'buttons': buttons, } elif lang == 'zh': fields = [] fields.append({'name': '銀行名稱', 'value': '恒生銀行'}) fields.append({'name': '戶口號碼', 'value': '239-498-348883'}) fields.append({ 'name': '戶口持有人名稱', 'value': 'P L Technology Limited' }) fields.append({ 'name': '銀行存款單據', 'value': 'receipt', 'type': 'upload_file', 'additional_text': '請保留你的正本收據三個月(從上傅日起計)以作紀錄。', 'required': 'True' }) fields.append({ 'name': '存入金額', 'value': 'transfer_amt', 'type': 'input', 'required': 'True' }) #fields.append({'name': 'Your Reference', 'value': 'ur_ref', 'type': 'input'}) buttons = [] buttons.append({'name': '提交', 'type': 'submit'}) buttons.append({ 'name': '取消', 'type': 'button', 'onclick': 'window.history.back()' }) content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'deposit_money', 'title': '存入資金', 'instruction': """Zwap只接受以你名下之本地銀行戶口發出之支票存款,或銀行轉賬形式存款,請上載你的銀行 存款收據,經核實後我們將於一個工作天內存入資金至你的Zwap帳戶,如以支票形式存款,則須兩個工作天核實。 """, 'form_action': '/ack/', 'fields': fields, 'buttons': buttons, } return render(request, 'peerloan/lender/form.html', content) elif sub_cate == 'withdraw_money': acc = Account.objects.get(usr_id=usr.id) if lang == 'en': fields = [] if acc.balance == 0: fields.append({ 'name': 'Withdrawal Amount', 'value': '/my_account/deposit_money', 'text': 'Please deposit money first', 'type': 'href', 'required': 'True' }) else: fields.append({ 'name': 'Withdrawal Amount', 'value': 'withdraw_amt', 'type': 'ion-slider', 'required': 'True' }) details = json.loads(usr.detail_info) bank_acc = sup_fn.try_KeyError(details['Individual'], 'Bank Account') if bank_acc == '--': fields.append({ 'name': 'Bank Account', 'value': '/my_account/change_acc_info', 'text': 'Please input your bank account information first', 'type': 'href' }) else: fields.append({ 'name': 'Bank Account', 'value': 'Bank Account', 'hidden_value': bank_acc, 'type': 'text_and_hidden' }) #fields.append({'name': 'Your Reference', 'value': 'Your Reference', 'type': 'input'}) fields.append({ 'name': 'One Time Password', 'value': 'OTP', 'type': 'OTP', 'required': 'True' }) buttons = [] if acc.balance == 0 or bank_acc == '--': buttons.append({ 'name': 'Submit', 'type': 'submit', 'disabled': 'disabled' }) else: buttons.append({'name': 'Submit', 'type': 'submit'}) buttons.append({ 'name': 'Cancel', 'type': 'button', 'onclick': 'window.history.back()' }) content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'withdraw_money', 'title': 'Withdraw Money', 'instruction': """Please specify the amount you would like to withdraw from your Zwap's account. We will deposit the request amount to your registered bank account by cheque within 1 business day after validation. """, 'form_action': '/ack/', 'usr_id': usr.id, 'fields': fields, 'buttons': buttons, 'acc_balance': acc.balance, 'OTP_action': 'Withdraw Money', 'mobile': json.loads(usr.detail_info)['Individual']['Mobile'] } elif lang == 'zh': fields = [] if acc.balance == 0: fields.append({ 'name': '提取金額', 'value': '/my_account/deposit_money', 'text': '請先存入資金', 'type': 'href', 'required': 'True' }) else: fields.append({ 'name': '提取金額', 'value': 'withdraw_amt', 'type': 'ion-slider', 'required': 'True' }) details = json.loads(usr.detail_info) bank_acc = sup_fn.try_KeyError(details['Individual'], 'Bank Account') if bank_acc == '--': fields.append({ 'name': '銀行戶口', 'value': '/my_account/change_acc_info', 'text': '請先輸入你的銀行戶口資料', 'type': 'href' }) else: fields.append({ 'name': '銀行戶口', 'value': 'Bank Account', 'hidden_value': bank_acc, 'type': 'text_and_hidden' }) #fields.append({'name': 'Your Reference', 'value': 'Your Reference', 'type': 'input'}) fields.append({ 'name': '一次性密碼', 'value': 'OTP', 'type': 'OTP', 'required': 'True' }) buttons = [] if acc.balance == 0 or bank_acc == '--': buttons.append({ 'name': '提交', 'type': 'submit', 'disabled': 'disabled' }) else: buttons.append({'name': '提交', 'type': 'submit'}) buttons.append({ 'name': '取消', 'type': 'button', 'onclick': 'window.history.back()' }) content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'withdraw_money', 'title': '提取資金', 'instruction': """請註明你要從你的Zwap帳戶提取的金額,經核實後我們將於一個工作天內以支票形式存入你已登記的銀行戶口內。 """, 'form_action': '/ack/', 'usr_id': usr.id, 'fields': fields, 'buttons': buttons, 'acc_balance': acc.balance, 'OTP_action': 'Withdraw Money', 'mobile': json.loads(usr.detail_info)['Individual']['Mobile'] } error = request.GET.get('error') if lang == 'en': if error == 'invalid_OTP': content['error_msg'] = 'Please input a valid OTP' if error == 'OTP_not_matched': content[ 'error_msg'] = 'The OTP doesn\'t match to our record, please try again' if error == 'OTP_expired': content[ 'error_msg'] = 'The OTP is expired, please receive a new OTP first' elif lang == 'zh': if error == 'invalid_OTP': content['error_msg'] = '請輸入一個有效的OTP' if error == 'OTP_not_matched': content['error_msg'] = '你輸入的OTP與我們的記錄不符合,請重新操作' if error == 'OTP_expired': content['error_msg'] = '你的OTP已經逾期,請重新獲取OTP' return render(request, 'peerloan/lender/form.html', content) elif sub_cate == 'transaction_records': content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'transaction_records', 'title': 'Transaction Records', } if lang == 'zh': content['title'] = '交易記錄' return render(request, 'peerloan/lender/trans_records.html', content) elif sub_cate == 'change_acc_info': details = json.loads(usr.detail_info) usr_info = { 'usr_id': usr.id, 'password': '******', 'mobile': sup_fn.try_KeyError(details['Individual'], 'Mobile'), 'address': sup_fn.try_KeyError(details['Individual'], 'Residential Address'), 'bank_account': sup_fn.try_KeyError(details['Individual'], 'Bank Account'), } if sup_fn.try_KeyError(details, 'Corporate') != '--': usr_info['office_address'] = sup_fn.try_KeyError( details['Corporate'], 'Office Address') content = { 'lang': lang, 'cate': 'my_account', 'sub_cate': 'change_acc_info', 'title': 'Change Account Information', 'form_action': 'javascript:;', 'usr_info': usr_info, } if lang == 'zh': content['title'] = '更改帳戶資料' return render(request, 'peerloan/lender/change_acc_info.html', content)
def settings(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) sub_cate = request.META.get('PATH_INFO').split('/')[2] # lender side ============================================================================================= if usr.type == 'L': if sub_cate == 'sms_email_notification': if lang == 'en': uri_list = UserInformation.objects.filter(info_type='Settings') elif lang == 'zh': uri_list = UserInformation.objects.filter(info_type='Settings') notification = json.loads(usr.notification) i = 0 for uri in uri_list: uri.details = json.loads(uri.details, object_pairs_hook=OrderedDict) for k, v in uri.details.iteritems(): v['no'] = i v['checked'] = notification[k] i += 1 content = { 'lang': lang, 'cate': 'settings', 'sub_cate': 'sms_email_notification', 'title': 'SMS/Email Notification', 'uri_list': uri_list, } if lang == 'zh': content['title'] = '手機短訊/電郵提示' return render(request, 'peerloan/lender/sms_email_notification.html' ,content) if sub_cate == 'account_information': # check last change acc info request try: uor = UserOperationRequest.objects.filter(usr_id=usr.id, type='Change Account Information', status='PENDING APPROVAL').latest('create_timestamp') except ObjectDoesNotExist: notice = '' else: if uor != None: notice = 'Your request has submitted. You can make another request after the current request is proceeded.' uri_list = UserInformation.objects.filter(section="Individual", info_type="Account Information") details = [] for uri in uri_list: details.append((uri.section, json.loads(uri.details, object_pairs_hook=OrderedDict))) details = OrderedDict(details) existed_details = OrderedDict() for section, terms in details.iteritems(): existed_details[section] = OrderedDict() for name, values in terms.iteritems(): try: existed_details[section][name] = json.loads(usr.detail_info)[section][name] except KeyError: existed_details[section][name] = '--' buttons = [] buttons.append({"name": "Submit", "type":"submit"}) content = { 'cate': 'settings', 'sub_cate': sub_cate, 'title': 'Account Information', 'notice': notice, 'details': details, 'existed_details': existed_details, 'form_action': '/ack/', 'buttons': buttons, } return render(request, 'peerloan/lender/change_acc_info.html', content)
def get(self, request, format=None): usr = sup_fn.get_user(request) prod_id = request.GET.get('prod_id') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if prod_id == 'all': inv_list = Investment.objects.filter(usr_id=usr.id) else: inv_list = Investment.objects.filter(usr_id=usr.id, prod_id=prod_id) schedule_list = [] schedule2_list = [] min_start_date = None max_end_date = None for inv in inv_list: loan_list = Loan.objects.filter(inv_id = inv.id) loan_list = [loan for loan in loan_list if 'DISBURSED' in loan.status or 'PAYBACK' in loan.status] prod = Product.objects.get(id = inv.prod_id) rate_per_month = prod.APR_lender * 0.01 / 12 for loan in loan_list: try: bor = BorrowRequest.objects.get(id=loan.bor_id) except: continue bor.draw_down_date = timezone.localtime(bor.draw_down_date) start_date_day = bor.draw_down_date.day start_date_month = bor.draw_down_date.month + 1 start_date_year = bor.draw_down_date.year remain_principal = loan.initial_amount #remain_interest = loan.total_repay_amount_lender - loan.initial_amount ratio = prod.APR_lender / bor.getBorAPR(prod.APR_borrower) remain_interest = (loan.total_repay_amount_lender - loan.initial_amount) * ratio for i in range(prod.repayment_period): day = start_date_day month = (start_date_month + i-1) % 12 + 1 year = start_date_year + ((start_date_month+i-1) / 12) interest = remain_principal * rate_per_month interest_ldr = interest * ratio principal = loan.instalment_lender - interest remain_interest -= interest_ldr remain_principal -= principal try: date = datetime.strptime(str(day)+'/'+str(month)+'/'+str(year), '%d/%m/%Y') except ValueError: date = datetime.strptime('1/'+str((month%12)+1)+'/'+str(year), '%d/%m/%Y') - dt.timedelta(days=1) today = datetime.strptime(timezone.localtime(timezone.now()).strftime('%d/%m/%Y'), '%d/%m/%Y') if date < today and bor.repaid_month >= (i+1): status = 'PAID' elif date < today and bor.repaid_month < (i+1): status = 'OVERDUE' elif date >= today: status = 'OPEN' schedule = { #'date': timezone.localtime(date).strftime('%d/%m/%Y'), 'date': date, 'initial_principal': loan.initial_amount, 'os_principal': remain_principal, 'os_interest': remain_interest, 'os_balance': remain_principal + remain_interest, 'paid_principal': principal if status == 'PAID' else 0, 'paid_interest': interest if status == 'PAID' else 0, 'ref_num': loan.ref_num, 'prod_name': prod.name_en, 'installment': loan.instalment_lender, 'status': status, } schedule_list.append(schedule) # month base view date_set = set() for schedule in schedule_list: date = datetime.strptime(datetime.strftime(schedule['date'], '%m/%Y'), '%m/%Y') date_set.add(date) for date in date_set: schedule_sub_list = [schedule for schedule in schedule_list if schedule['date'].month == date.month and schedule['date'].year == date.year] schedule = { 'shadow_datetime': date, 'date': datetime.strftime(date, '%Y/%m'), 'initial_principal': FLOAT_DATA_FORMAT.format(sum([s['initial_principal'] for s in schedule_sub_list])), 'os_principal': FLOAT_DATA_FORMAT.format(abs(sum([s['os_principal'] for s in schedule_sub_list]))), 'os_interest': FLOAT_DATA_FORMAT.format(abs(sum([s['os_interest'] for s in schedule_sub_list]))), 'os_balance': FLOAT_DATA_FORMAT.format(abs(sum([s['os_balance'] for s in schedule_sub_list]))), 'paid_principal': FLOAT_DATA_FORMAT.format(sum([s['paid_principal'] for s in schedule_sub_list])), 'paid_interest': FLOAT_DATA_FORMAT.format(sum([s['paid_interest'] for s in schedule_sub_list])), 'ref_num': '', 'prod_name': '', 'installment': FLOAT_DATA_FORMAT.format(sum([s['installment'] for s in schedule_sub_list])), 'status': '', } schedule2_list.append(schedule) serialized_table_list = schedule2_list content = {'data': serialized_table_list} return Response(content)
def auth(request): lang = sup_fn.get_lang(request) if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') # admin login if 'pl_admin' in request.META.get('HTTP_REFERER').split('/'): if len(AdminUser.objects.filter(email=email)) == 0: return HttpResponse('Admin side: account doesn\'t exist.') else: usr = AdminUser.objects.filter(email=email)[0] if usr.password != hashlib.md5(password).hexdigest(): return HttpResponse('Admin side: wrong password.') else: request.session['type'] = 'ADMIN' request.session['email'] = email request.session['handling_side'] = 'B' request.session['timestamp'] = datetime.strftime( timezone.localtime(timezone.now()), '%Y-%m-%d %H:%M:%S') request.session.save() # update last login usr = sup_fn.get_user(request) usr.this_login = timezone.localtime(timezone.now()) usr.save() return redirect('/pl_admin/application') # user login if len( User.objects.filter(email=email, password=hashlib.md5(password).hexdigest(), status='ACTIVE')) == 0: # login failed if lang == 'en': content = { 'status': 'Login Failed!', 'content': 'You can go back to login page and try to login again.', } if len(User.objects.filter(email=email, status='ACTIVE')) == 0: content['header'] = 'Account doesn\'t exist or is locked.' else: content['header'] = 'The password is incorrect.' if lang == 'zh': content = { 'status': '登入失敗!', 'content': '你可以返回登入頁面并嘗試重新登入。', } if len(User.objects.filter(email=email, status='ACTIVE')) == 0: content['header'] = '用戶名不存在。' else: content['header'] = '密碼不正確。' usr_list = User.objects.filter(email=email, status='ACTIVE') for usr in usr_list: # accumulate both lender & borrower account usr.account_attempt += 1 if usr.account_attempt >= ACCOUNT_ATTEMPT_TIMES: usr.status = 'LOCKED' usr.save() if len(usr_list) != 0: if usr_list[0].account_attempt >= ACCOUNT_ATTEMPT_TIMES: # generate token def generate_unique_sequence64(size=64, chars=string.ascii_uppercase + string.digits): uor_list = UserOperationRequest.objects.filter( type='Forget Password', status="ACTIVE") token_list = [ json.loads(uor.details)['token'] for uor in uor_list ] while 1: rand_seq = ''.join( random.choice(chars) for _ in range(size)) if rand_seq not in token_list: return rand_seq new_token = generate_unique_sequence64() details = {"token": new_token, "email": email} new_uor = UserOperationRequest( usr_id=0, type='Forget Password', details=json.dumps(details), status='ACTIVE', create_timestamp=timezone.localtime(timezone.now()), update_timestamp=timezone.localtime(timezone.now())) new_uor.save() usr_emailing = emailing.GeneralEmail(email_addr=email) usr_emailing.unlock_account(token=new_token) content['lang'] = lang return render(request, 'peerloan/general/general_ack.html', content) else: # login successfully request.session['email'] = email request.session['timestamp'] = datetime.strftime( timezone.localtime(timezone.now()), '%Y-%m-%d %H:%M:%S') # check password case sensitively usr = User.objects.filter(email=email, status='ACTIVE')[0] if hashlib.md5(password).hexdigest() != usr.password: content = { 'status': 'Login Failed!', 'header': 'The password is incorrect.', 'content': 'You can go back to login page and try to login again.', } return render(request, 'peerloan/general/general_ack.html', content) """ if len(User.objects.filter(email=email, password__exact=hashlib.md5(password).hexdigest(), status='ACTIVE')) == 1 and User.objects.filter(email=email, password__exact=password, status='ACTIVE')[0].type == 'ADMIN': request.session['type'] = 'ADMIN' request.session['handling_side'] = 'B' request.session.save() # update last login usr = sup_fn.get_user(request) usr.this_login = timezone.localtime(timezone.now()) usr.save() return redirect('/pl_admin/application') """ if len( User.objects.filter( email=email, password__exact=hashlib.md5(password).hexdigest(), status='ACTIVE')) == 2: request.session['type'] = 'L' request.session.save() # update last login usr_list = User.objects.filter(email=email) for usr in usr_list: usr.account_attempt = 0 usr.this_login = timezone.localtime(timezone.now()) usr.save() return redirect('/portfolio/portfolio_summary') else: request.session['type'] = 'B' request.session.save() # update last login usr = sup_fn.get_user(request) usr.account_attempt = 0 usr.this_login = timezone.localtime(timezone.now()) usr.save() return redirect('/borrow_now')
def get_initial_queryset(self): user = sup_fn.get_user(self.request) trx_list = UserTransaction.objects.filter(usr_id=user.id) return trx_list
def get(self, request, format=None): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) prod_id = request.GET.get('prod_id') if prod_id == 'all': inv_list = Investment.objects.filter(usr_id=usr.id) else: inv_list = Investment.objects.filter(usr_id=usr.id,prod_id=prod_id) acc = Account.objects.get(usr_id = usr.id) #color_lib = {'red':['#E08283','#E7505A','#D91E18'],'green':['#36D7B7','#4DB3A2','#26C281'],'yellow':['#F4D03F','#F7CA18','#F3C200'],'purple':['#BF55EC']} color_lib = ['#E08283','#36D7B7','#F4D03F','#BF55EC','#3598DC'] data_list = [] i = 0 if prod_id == 'all': total_balance = acc.balance + sum([inv.on_hold_amount + inv.usable_amount for inv in inv_list]) if lang == 'en': data_list.append({'name': 'Total Account Balance', 'amount': total_balance, 'color': color_lib[i]}) i += 1 data_list.append({'name': 'Available Amount', 'amount': acc.balance, 'color': color_lib[i]}) i += 1 elif lang == 'zh': #data_list.append({'name': '總賬戶結餘', 'amount': total_balance, 'color': color_lib[i]}) #i += 1 data_list.append({'name': '可用金額', 'amount': acc.balance, 'color': color_lib[i]}) i += 1 for inv in inv_list: prod = Product.objects.get(id=inv.prod_id) if lang == 'en': data_list.append({'name': 'Queuing Amount in %s' % (prod.name_en), 'amount': inv.usable_amount + inv.on_hold_amount, 'color': color_lib[i]}) elif lang == 'zh': data_list.append({'name': '分配在' + (prod.name_zh.encode('utf8')), 'amount': inv.usable_amount + inv.on_hold_amount, 'color': color_lib[i]}) i += 1 else: if len(inv_list) == 0: prod = Product.objects.get(id=prod_id) if lang == 'en': data_list.append({'name': 'Total Queuing Amount %s' % (prod.name_en), 'amount': 0, 'color': color_lib[i]}) i += 1 data_list.append({'name': 'Queuing Amount %s' % (prod.name_en) + ' (not matched)', 'amount': 0, 'color': color_lib[i]}) i += 1 data_list.append({'name': 'Queuing Amount %s' % (prod.name_en) + ' (on hold)', 'amount': 0, 'color': color_lib[i]}) i += 1 elif lang == 'zh': #data_list.append({'name': '總分配在' + (prod.name_zh.encode('utf8')), 'amount': 0, 'color': color_lib[i]}) #i += 1 data_list.append({'name': '分配在' + (prod.name_zh.encode('utf8')) + ' (未匹配)', 'amount': 0, 'color': color_lib[i]}) i += 1 data_list.append({'name': '分配在' + (prod.name_zh.encode('utf8')) + ' (未提款)', 'amount': 0, 'color': color_lib[i]}) i += 1 else: for inv in inv_list: prod = Product.objects.get(id=inv.prod_id) if lang == 'en': data_list.append({'name': 'Total Queuing Amount %s' % (prod.name_en), 'amount': inv.usable_amount + inv.on_hold_amount, 'color': color_lib[i]}) i += 1 data_list.append({'name': 'Queuing Amount %s' % (prod.name_en) + ' (not matched)', 'amount': inv.usable_amount, 'color': color_lib[i]}) i += 1 data_list.append({'name': 'Queuing Amount %s' % (prod.name_en) + ' (on hold)', 'amount': inv.on_hold_amount, 'color': color_lib[i]}) i += 1 elif lang == 'zh': #data_list.append({'name': '總分配在' + (prod.name_zh.encode('utf8')), 'amount': inv.usable_amount + inv.on_hold_amount, 'color': color_lib[i]}) #i += 1 data_list.append({'name': '分配在' + (prod.name_zh.encode('utf8')) + ' (未匹配)', 'amount': inv.usable_amount, 'color': color_lib[i]}) i += 1 data_list.append({'name': '分配在' + (prod.name_zh.encode('utf8')) + ' (未提款)', 'amount': inv.on_hold_amount, 'color': color_lib[i]}) i += 1 for data in data_list: data['amount'] = round(data['amount'], 2) #serialized_data_list = RepayPieSerializer(data_list, many=True) content = {'data': data_list} return Response(content)
def apply_to_be_investor(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) try: uor = UserOperationRequest.objects.filter(usr_id=usr.id, type="Apply To Be Investor").latest('create_timestamp') except ObjectDoesNotExist: # the first time apply nationality_list = [] f = open('/home/ubuntu/project_peerloan/peerloan/peerloan_src/nationality.csv', 'r') for row in csv.DictReader(f): nationality_list.append(row['Nationality']) f.close() country_list = [] f = open('/home/ubuntu/project_peerloan/peerloan/peerloan_src/countries_of_the_world.csv', 'r') for row in csv.DictReader(f): country_list.append(row['Country']) f.close() """ buttons = [] buttons.append({"name": "Submit", "type":"submit"}) buttons.append({"name": "Back", "type":"button", "onclick":"window.history.back()"}) """ content = { 'lang': lang, 'title': 'Lender Application Form', 'form_action': '/ack/', 'nationality_list': nationality_list, 'country_list': country_list, 'usr_details': sup_fn.sync_from_usr(usr.id), 'gender_list': OrderedDict( ( ('Male', 'Male'), ('Female', 'Female') ) ), #'buttons': buttons, } if lang == 'zh': content['title'] = '貸方申請表' additional_content = { 'gender_list':OrderedDict( ( ('Male', '男性'), ('Female', '女性') ) ), } content.update(additional_content) return render(request, 'peerloan/borrower/investor_application_form.html', content) else: # approved if uor.status == 'APPROVED': details = json.loads(uor.details) content = { 'lang': lang, 'title': 'Agreement', 'form_action': '/ack/', 'mobile': details['Individual']['Mobile'], 'uor_id': uor.id, } if lang == 'zh': content['title'] = '合約' error = request.GET.get('error') if lang == 'en': if error == 'invalid_OTP': content['error_msg'] = 'Please input a valid OTP' if error == 'OTP_not_matched': content['error_msg'] = 'The OTP doesn\'t match to our record, please receive a new OTP and try again' if error == 'OTP_expired': content['error_msg'] = 'The OTP is expired, please receive a new OTP first' elif lang == 'zh': if error == 'invalid_OTP': content['error_msg'] = '請輸入一個有效的OTP' if error == 'OTP_not_matched': content['error_msg'] = '你輸入的OTP與我們的記錄不符合,請重新操作' if error == 'OTP_expired': content['error_msg'] = '你的OTP已經逾期,請重新獲取OTP' return render(request, 'peerloan/borrower/investor_agreement_form.html', content) # wait for approval elif uor.status == 'DOC UPLOADED' or uor.status == 'PENDING DOC/IV': if lang == 'en': details = json.loads(uor.details, object_pairs_hook=OrderedDict) for k, v in details['File Uploaded'].iteritems(): details['File Uploaded'][k] = '<a href="/file/'+v+'" target="_blank">View</a>' buttons = [] buttons.append({"name": "Print Acknowledgement", "type":"button", "onclick":"javascript:window.print()"}) content = { 'lang': lang, 'title': 'Lender Application - Acknowledgement', 'form_action': 'javascript:;', 'instruction': """Thank you for your application. We will process your application within 1 business day and notice you the application result by SMS and email.""", 'details': details, 'buttons': buttons, } elif lang == 'zh': en2zh_dict = { 'Account Type': '戶口類型', 'Individual': '個人', 'Corporate': '企業', 'File Uploaded': '上載文件', 'Company Name': '公司名稱', 'Established at': '成立日期', 'CR NO.': '公司註冊號碼', 'Office Address': '公司地址', 'Company Size': '公司規模', 'more than 500': '多於 500', 'Office Tel': '公司電話', 'Industry': '行業', 'Surname': '姓氏', 'Given Name': '名', 'Gender': '性別', 'Male': '男性', 'Female': '女性', 'Education Level': '教育程度', 'Primary School': '小學', 'Secondary School': '中學', 'Tertiary': '專上學院', 'Bachelors': '大學', 'Masters or above': '碩士或以上', 'HKID': '香港身份證號碼', 'Nationality': '國籍', 'Date of Birth': '出生日期', 'Occupation': '職業', 'Type of Employment': '受僱類型', 'Full Time Employed': '全職', 'Part Time Employed': '兼職', 'Self-Employed': '自僱', 'Unemployed': '待業', 'Housewife': '家庭主婦', 'Retired': '退休', 'Annual Income': '年收入', 'Residential Address': '住宅地址', 'Home Phone No.': '住宅電話', 'Mobile': '手提電話', 'Source of Fund': '資金來源', 'Salary': '薪金', 'Business': '生意', 'Investment': '投資', 'Others': '其他', 'Other Source of Fund': '其他資金來源', 'Customer Declaration': '顧客聲明', 'Application No': '申請編號', 'HKID Proof': '香港身份證證明', 'Address Proof': '住址證明', 'BR/CR': '商業登記證/公司註冊證明書', } details = json.loads(uor.details, object_pairs_hook=OrderedDict) for k, v in details['File Uploaded'].iteritems(): details['File Uploaded'][k] = '<a href="/file/'+v.encode('utf8')+'" target="_blank">瀏覽</a>' zh_details = OrderedDict() for section, fields in details.iteritems(): zh_details[en2zh_dict[section]] = OrderedDict() for k, v in details[section].iteritems(): zh_v = sup_fn.try_KeyError(en2zh_dict, v) if zh_v != '--': zh_details[en2zh_dict[section]][en2zh_dict[k]] = zh_v else: zh_details[en2zh_dict[section]][en2zh_dict[k]] = v buttons = [] buttons.append({"name": "列印通知", "type":"button", "onclick":"javascript:window.print()"}) content = { 'lang': lang, 'title': '確認通知 - 貸方申請已收到', 'form_action': 'javascript:;', 'instruction': """感謝你的申請,我們會於一個工作天內處理你的申請,並以手機短訊及電郵通知你申請結果。""", 'details': zh_details, 'buttons': buttons, } return render(request, 'peerloan/borrower/form_with_section.html', content) elif uor.status == 'REJECTED' or uor.status == 'CANCELLED': content = { 'lang': lang, 'title': 'Application State Changed - Acknowledgement', 'instruction': """Thank you for your application. Unfortunately, we are sorry to inform you that your application have been %s. Please contact admin for more information.""" % (uor.status), } if lang == 'zh': content = { 'lang': lang, 'title': '確認通知 - 申請狀態更變', 'instruction': """感謝你的申請, 我們很遺憾地通知你,你的申請未能成功批核。""", } return render(request, 'peerloan/borrower/acknowledgement.html', content)
def get(self, request, format=None): if request.method == 'GET': usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) status = request.GET.get('status') start_date = request.GET.get('start_date') # check XSS if sup_fn.checkHTMLtags([v for k, v in request.GET.iteritems()]): return HttpResponse('Invalid input.') if usr.type == 'B': bor_list = BorrowRequest.objects.filter(usr_id=usr.id) if status != 'All': if status == 'AGREEMENT CONFIRMED': bor_list = [bor for bor in bor_list if 'AGREEMENT CONFIRMED' in bor.status or 'VALIDATED' in bor.status or 'FUND MATCHING' in bor.status] else: bor_list = [bor for bor in bor_list if status.upper() in bor.status] if start_date != 'All': start_date = datetime.strptime(start_date, '%m/%d/%Y') bor_list = [bor for bor in bor_list if datetime.strptime(timezone.localtime(bor.create_timestamp).strftime('%m/%d/%Y'), '%m/%d/%Y')>= start_date] data_list = [] for bor in bor_list: details = {} prod = Product.objects.get(id=bor.prod_id) details['shadow_datetime'] = timezone.localtime(bor.update_timestamp) details['updated_date'] = datetime.strftime(timezone.localtime(bor.update_timestamp), '%Y/%m/%d') details['prod_name'] = prod.name_en if lang == 'zh': details['prod_name'] = prod.name_zh details['ref_num'] = bor.ref_num details['amount'] = FLOAT_DATA_FORMAT.format(bor.amount) details['APR'] = FLOAT_DATA_FORMAT.format(bor.getBorAPR(prod.APR_borrower if prod.fake_APR_borrower == None else prod.fake_APR_borrower)) details['apply_date'] = datetime.strftime(timezone.localtime(bor.create_timestamp), '%Y/%m/%d') details['repayment_progress'] = str(bor.repaid_month)+'/'+str(prod.repayment_period) details['status'] = ''.join([i for i in bor.status if (not i.isdigit())]) details['bor_id'] = bor.id if bor.status == 'AUTO APPROVED': details['href'] = '/product/upload_docs/?prod_id='+str(prod.id) elif bor.status == 'DOC UPLOADED': details['href'] = '/product/confirm_agreement/?prod_id='+str(prod.id) elif bor.status == 'AGREEMENT CONFIRMED' or bor.status == 'VALIDATED' or bor.status == 'FUND MATCHING': details['href'] = '/ack_page/?action=confirm_agreement' elif bor.status == 'DISBURSED' or 'PAYBACK' in bor.status: details['href'] = '/my_account/all_application_listing/detail/?bor_id='+str(bor.id) elif bor.status == 'FUND MATCHING COMPLETED': details['href'] = '/product/confirm_memorandum/?prod_id='+str(prod.id) else: details['href'] = 'javascript:;' data_list.append(details) #serialized_data_list = LaasSerializer(data_list, many=True) content = {'data': data_list} return Response(content) if usr.type == 'L': inv_list = Investment.objects.filter(usr_id = usr.id) loan_list = [] for inv in inv_list: loans = Loan.objects.filter(inv_id = inv.id) for loan in loans: loan_list.append(loan) if status != 'All': loan_list = [loan for loan in loan_list if status.upper() in loan.status] if start_date != 'All': start_date = datetime.strptime(start_date, '%m/%d/%Y') loan_list = [loan for loan in loan_list if datetime.strptime(timezone.localtime(loan.create_timestamp).strftime('%m/%d/%Y'), '%m/%d/%Y')>= start_date] data_list = [] for loan in loan_list: details = {} bor = BorrowRequest.objects.get(id=loan.bor_id) prod = Product.objects.get(id=bor.prod_id) details['updated_date'] = datetime.strftime(timezone.localtime(loan.update_timestamp), '%d/%m/%Y') details['prod_name'] = prod.name_en details['ref_num'] = bor.ref_num details['amount'] = loan.initial_amount details['APR'] = prod.APR_lender details['draw_down_date'] = datetime.strftime(timezone.localtime(loan.draw_down_date), '%d/%m/%Y') details['status'] = bor.status data_list.append(details) serialized_data_list = LoanLenderSerializer(data_list, many=True) content = {'data': serialized_data_list.data} return Response(content) else: return HttpResponse('Wrong request method.')
def get(self, request, format=None): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) this_month = datetime.strptime(request.GET.get('date'), '%m/%Y') this_month = pytz.timezone('Asia/Hong_Kong').localize(this_month) if datetime.now().month == this_month.month and datetime.now().year == this_month.year: period = datetime.strftime(this_month, '%Y/%m/%d')+' - '+datetime.strftime(datetime.now(), '%Y/%m/%d') else: month = this_month.month year = this_month.year month += 1 if month == 13: year += 1 month = 1 next_month = datetime.strptime(str(year)+'/'+str(month), '%Y/%m') period = datetime.strftime(this_month, '%Y/%m/%d')+' - '+datetime.strftime(next_month - dt.timedelta(days=1), '%Y/%m/%d') if datetime.now().month == this_month.month and datetime.now().year == this_month.year: res_details = sup_fn.generate_portfolio_summary(usr_id=usr.id, date=this_month) else: try: mps = MonthlyPortfolioSummary.objects.get(usr_id=usr.id, month=this_month.month, year=this_month.year) except ObjectDoesNotExist: content = {} # data 1 content['account_summary'] = { 'Account Amount': FLOAT_DATA_FORMAT.format(0), 'Unallocated Amount': FLOAT_DATA_FORMAT.format(0), 'Un-matched Amount': FLOAT_DATA_FORMAT.format(0), 'Matched Amount': FLOAT_DATA_FORMAT.format(0) } # data 2 & 3 data_list = [] if lang == 'en': data_list.append({'name': 'Normal Repayment', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Normal Settlement', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Early Settlement', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) elif lang == 'zh': data_list.append({'name': '正常供款', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '最後一期供款', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '提早還款', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) #serialized_data_list = RepayPieSerializer(data_list, many=True) content['data_2'] = data_list content['title_2'] = 'HK$'+FLOAT_DATA_FORMAT.format(0) data_list = [] if lang == 'en': data_list.append({'name': 'Overdue 0 day', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Overdue 1-29 days', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Overdue 30-59 days', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Overdue 60-89 days', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': 'Overdue 90-120 days', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) elif lang == 'zh': data_list.append({'name': '逾期0日', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '逾期1-29日', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '逾期30-59日', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '逾期60-89日', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) data_list.append({'name': '逾期90-120日', 'amount': FLOAT_DATA_FORMAT.format(0), 'color': ''}) #serialized_data_list = RepayPieSerializer(data_list, many=True) content['data_3'] = data_list content['title_3'] = 'Repayment Status' content['basic_info'] = { 'Accrued Interest': FLOAT_DATA_FORMAT.format(0), 'Weighted Annual Interest Rate': FLOAT_DATA_FORMAT.format(0)+'%', 'Active Account': 0, 'New Account': FLOAT_DATA_FORMAT.format(0)+' (included '+FLOAT_DATA_FORMAT.format(0)+' borrowers)', 'Period': period, } if lang == 'zh': content['basic_info']['New Account'] = FLOAT_DATA_FORMAT.format(0)+' (包含'+FLOAT_DATA_FORMAT.format(0)+'個借款人)' return Response(content) else: res_details = json.loads(mps.details) content = {} # data 1 dict = res_details['Portfolio Summary ($)'] content['account_summary'] = { 'Account Amount': FLOAT_DATA_FORMAT.format(dict['Unallocated Amount']+dict['Unmatched Amount']+dict['Matched Amount']), 'Unallocated Amount': FLOAT_DATA_FORMAT.format(dict['Unallocated Amount']), 'Un-matched Amount': FLOAT_DATA_FORMAT.format(dict['Unmatched Amount']), 'Matched Amount': FLOAT_DATA_FORMAT.format(dict['Matched Amount']) } # data 2 & 3 dict = res_details['Portfolio Summary ($)'] data_list = [] if lang == 'en': data_list.append({'name': 'Normal Repayment', 'amount': FLOAT_DATA_FORMAT.format(dict['Normal Run-Down']), 'color': ''}) data_list.append({'name': 'Normal Settlement', 'amount': FLOAT_DATA_FORMAT.format(dict['Normal Settlement']), 'color': ''}) data_list.append({'name': 'Early Settlement', 'amount': FLOAT_DATA_FORMAT.format(dict['Early Settlement']), 'color': ''}) elif lang == 'zh': data_list.append({'name': '正常供款', 'amount': FLOAT_DATA_FORMAT.format(dict['Normal Run-Down']), 'color': ''}) data_list.append({'name': '最後一期供款', 'amount': FLOAT_DATA_FORMAT.format(dict['Normal Settlement']), 'color': ''}) data_list.append({'name': '提早還款', 'amount': FLOAT_DATA_FORMAT.format(dict['Early Settlement']), 'color': ''}) #serialized_data_list = RepayPieSerializer(data_list, many=True) #content['data_2'] = serialized_data_list.data content['data_2'] = data_list content['title_2'] = 'HK$'+FLOAT_DATA_FORMAT.format(dict['Normal Run-Down']+dict['Normal Settlement']+dict['Early Settlement']) dict = res_details['Net Flow and Delinquency ($)'] data_list = [] if lang == 'en': data_list.append({'name': 'Overdue 0 day', 'amount': FLOAT_DATA_FORMAT.format(dict['0 DPD (Current)']), 'color': ''}) data_list.append({'name': 'Overdue 1-29 day', 'amount': FLOAT_DATA_FORMAT.format(dict['1-29 DPD (Cycle 1)']), 'color': ''}) data_list.append({'name': 'Overdue 30-59 day', 'amount': FLOAT_DATA_FORMAT.format(dict['30-59 DPD (Cycle 2)']), 'color': ''}) data_list.append({'name': 'Overdue 60-89 day', 'amount': FLOAT_DATA_FORMAT.format(dict['60-89 DPD (Cycle 3)']), 'color': ''}) data_list.append({'name': 'Overdue 90-120 day', 'amount': FLOAT_DATA_FORMAT.format(dict['90-120 DPD (Cycle 4)']), 'color': ''}) data_list.append({'name': 'Overdue 120+ day', 'amount': FLOAT_DATA_FORMAT.format(res_details['Portfolio Summary ($)']['Gross Charge Off']), 'color': ''}) elif lang == 'zh': data_list.append({'name': '逾期0日', 'amount': FLOAT_DATA_FORMAT.format(dict['0 DPD (Current)']), 'color': ''}) data_list.append({'name': '逾期1-29日', 'amount': FLOAT_DATA_FORMAT.format(dict['1-29 DPD (Cycle 1)']), 'color': ''}) data_list.append({'name': '逾期30-59日', 'amount': FLOAT_DATA_FORMAT.format(dict['30-59 DPD (Cycle 2)']), 'color': ''}) data_list.append({'name': '逾期60-89日', 'amount': FLOAT_DATA_FORMAT.format(dict['60-89 DPD (Cycle 3)']), 'color': ''}) data_list.append({'name': '逾期90-120日', 'amount': FLOAT_DATA_FORMAT.format(dict['90-120 DPD (Cycle 4)']), 'color': ''}) data_list.append({'name': '逾期120+日', 'amount': FLOAT_DATA_FORMAT.format(res_details['Portfolio Summary ($)']['Gross Charge Off']), 'color': ''}) #serialized_data_list = RepayPieSerializer(data_list, many=True) #content['data_3'] = serialized_data_list.data content['data_3'] = data_list content['title_3'] = 'Repayment Status' content['basic_info'] = { 'Accrued Interest': FLOAT_DATA_FORMAT.format(res_details['Portfolio Summary ($)']['Accrued Interest']), 'Weighted Annual Interest Rate': FLOAT_DATA_FORMAT.format(res_details['Return']['Weighted Annual Interest Rate'])+'%', 'Active Account': res_details['Portfolio Summary (#)']['Active Account'], 'New Account': FLOAT_DATA_FORMAT.format(res_details['Portfolio Summary ($)']['New Account'])+' (included '+str(res_details['Portfolio Summary (#)']['New Account'])+' borrowers)', 'Period': period, } if lang == 'zh': content['basic_info']['New Account'] = FLOAT_DATA_FORMAT.format(res_details['Portfolio Summary ($)']['New Account'])+' (包含'+str(res_details['Portfolio Summary (#)']['New Account'])+'個借款人)' return Response(content)
def header(request): user = sup_fn.get_user(request) lang = sup_fn.get_lang(request) http_referer = request.META.get('PATH_INFO') # get category and sub-category to active the button if len(http_referer.split('/')) > 2: cate = http_referer.split('/')[2] if len(http_referer.split('/')) > 3: sub_cate = http_referer.split('/')[3] else: sub_cate = '' else: cate, sub_cate = '', '' last_login = user.last_login if last_login == None: last_login = user.this_login last_login = timezone.localtime(last_login) content = { 'usr':user, 'cate': cate, 'sub_cate': sub_cate, 'lang':lang, 'last_login': last_login.strftime('%Y/%m/%d %H:%M'), } if user.type == 'L': return render(request, 'peerloan/lender/header.html', content) elif user.type == 'B': return render(request, 'peerloan/borrower/header.html', content) elif len(AdminUser.objects.filter(email=user.email)) != 0: side = request.session['handling_side'] ptn_list = PendingTaskNotification.objects.filter(status='UNREAD') if side == 'B': application_ptn_no = 0 disburse_ptn_no = 0 repayment_ptn_no = 0 for ptn in ptn_list: if ptn.type == 'Application': application_ptn_no += 1 elif ptn.type == 'Disburse': disburse_ptn_no += 1 elif ptn.type == 'Repayment': repayment_ptn_no += 1 ptn_cnt = { 'application': application_ptn_no, 'disbursement': disburse_ptn_no, 'repayment': repayment_ptn_no } for k, v in ptn_cnt.iteritems(): if v == 0: ptn_cnt[k] = '' content['ptn_cnt'] = ptn_cnt return render(request, 'peerloan/admin/borrower/header.html', content) if side == 'L': ptn_cnt = { 'application': len([ptn for ptn in ptn_list if ptn.type == 'Apply To Be Investor']), 'deposit': len([ptn for ptn in ptn_list if ptn.type == 'Deposit Money']), 'cash_out': len([ptn for ptn in ptn_list if ptn.type == 'Withdraw Money']), } for k, v in ptn_cnt.iteritems(): if v == 0: ptn_cnt[k] = '' content['ptn_cnt'] = ptn_cnt return render(request, 'peerloan/admin/lender/header.html', content)
def get(self, request, format=None): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) trend = request.GET.get('trend') year = int(request.GET.get('year')) """ if lang == 'en': num_to_month = { 1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'July', 8: 'Aug', 9: 'Sept', 10: 'Oct', 11: 'Nov', 12: 'Dec' } elif lang == 'zh': num_to_month = { 1: '1月', 2: '2月', 3: '3月', 4: '4月', 5: '5月', 6: '6月', 7: '7月', 8: '8月', 9: '9月', 10: '10月', 11: '11月', 12: '12月' } """ num_to_month = { 1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'July', 8: 'Aug', 9: 'Sept', 10: 'Oct', 11: 'Nov', 12: 'Dec' } mps_list = MonthlyPortfolioSummary.objects.filter(usr_id=usr.id, year=year) data_list = [] content = {} if year == datetime.now().year: months = datetime.now().month - 1 else: months = 12 for i in range(months): filtered_mps_list = [mps for mps in mps_list if mps.month==(i+1)] if len(filtered_mps_list) != 0: mps = filtered_mps_list[0] details = json.loads(mps.details) if trend == 'Outstanding Balance': data_list.append({'x': num_to_month[mps.month].encode('utf8'), 'y': details['Portfolio Summary ($)']['Matched Amount']}) elif trend == 'No. of Active Account': data_list.append({'x': num_to_month[mps.month].encode('utf8'), 'y': details['Portfolio Summary (#)']['Active Account']}) elif trend == 'Accrued Interest': data_list.append({'x': num_to_month[mps.month].encode('utf8'), 'y': details['Portfolio Summary ($)']['Accrued Interest']}) elif trend == 'New Account': data_list.append({'x': num_to_month[mps.month].encode('utf8'), 'y': details['Portfolio Summary ($)']['New Account']}) elif trend == 'No. of New Account': data_list.append({'x': num_to_month[mps.month].encode('utf8'), 'y': details['Portfolio Summary (#)']['New Account']}) else: data_list.append({'x': num_to_month[i+1].encode('utf8'), 'y': 0}) content['data'] = data_list content['title'] = trend if trend == 'Outstanding Balance': content['formatter'] = 'HK${value}' elif trend == 'No. of Active Account': content['formatter'] = '{value}' elif trend == 'Accrued Interest': content['formatter'] = 'HK${value}' elif trend == 'New Account': content['formatter'] = 'HK${value}' elif trend == 'No. of New Account': content['formatter'] = '{value}' return Response(content)
def product(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) action = request.META.get('PATH_INFO').split('/')[2] if action == 'apply': bor_list = BorrowRequest.objects.filter(usr_id=usr.id) bor_list = [ bor for bor in bor_list if bor.status not in ['PAYBACK COMPLETED', 'REJECTED', 'CANCELLED'] ] num_of_applied_prod = len(bor_list) # check which step if num_of_applied_prod != 0: return redirect('/borrow_now') prod_id = request.GET.get('prod_id') prod = Product.objects.get(id=prod_id) if request.method == 'POST': form = CaptchaForm(request.POST) if form.is_valid(): # check hkid cannot repeat from other loan application simplified_hkid = request.POST.get('HKID').replace( '(', '').replace(')', '').lower() other_bor_list = BorrowRequest.objects.filter( (~Q(usr_id=usr.id)) & Q(simplified_hkid=simplified_hkid)) if len(other_bor_list) != 0: return redirect( '/ack_page/?action=apply_loan_rejected&reason=repeated_hkid' ) # check hkid should be consistent with the one on he's lender account try: ldr_usr = User.objects.get(email=usr.email, type='L') except ObjectDoesNotExist: '' else: ldr_details = json.loads(ldr_usr.detail_info) ldr_simplified_hkid = ldr_details['Individual'][ 'HKID'].replace('(', '').replace(')', '').lower() if simplified_hkid != ldr_simplified_hkid: return redirect( '/ack_page/?action=apply_loan_rejected&reason=hkid_not_matched' ) # check social score fs = classes.FriendlyScore() fs.getToken() code, fs_usr_details = fs.get( endpoint='users/partner-id/%s/show' % (usr.id), params={}) social_total_score = 0 social_fraud_risk_score = 0 if code == 200: social_total_score = float(fs_usr_details['score_points']) social_fraud_risk_score = float( fs_usr_details['risk_score']) prod_id = int( request.META.get('HTTP_REFERER').split('/?prod_id=')[-1]) prod = Product.objects.get(id=prod_id) inputs = { 'major': request.POST.get('Subject'), 'resident': request.POST.get('Living Status'), 'living_with': request.POST.get('Living with'), 'university': request.POST.get('Studying University'), 'GPA': float(request.POST.get('Overall GPA')), 'date_of_birth': request.POST.get('Date of Birth'), 'year': request.POST.get('Currently Studying'), 'social_total_score': '>400' if social_total_score > 400 else '0-400', 'social_fraud_risk_score': '>1' if social_fraud_risk_score > 1 else '0-1', 'repayment_plan': prod.repayment_plan, } result = sup_fn.calculate_loan_amount(inputs) discount_rate = 0 if code == 200: if float(fs_usr_details['score_points']) > 431: discount_rate = 0.1 ref_num = sup_fn.generate_ref_num('borrow_request', 'LOA') amount = min(result['amount'], float(request.POST.get('Applied Amount'))) if prod.repayment_plan == 'Instalment': rate_per_month = prod.APR_borrower * ( 1 - discount_rate) * 0.01 / 12 instalment_borrower = amount * ( rate_per_month / (1 - (1 + rate_per_month)**(-12 * (prod.repayment_period / 12)))) rate_per_month = prod.APR_lender * 0.01 / 12 instalment_lender = amount * ( rate_per_month / (1 - (1 + rate_per_month)**(-12 * (prod.repayment_period / 12)))) elif prod.repayment_plan == 'Balloon Payment' or prod.repayment_plan == 'Promotion Balloon Payment': rate_per_month = prod.APR_borrower * ( 1 - discount_rate) * 0.01 / 12 instalment_borrower = amount * rate_per_month rate_per_month = prod.APR_lender * 0.01 / 12 instalment_lender = amount * rate_per_month bor_detail_info = OrderedDict() for name, value in request.POST.iteritems(): if len(name) != 0: if str(name)[0].isupper() and value != '': bor_detail_info[name] = value approval_records = { 1: { 'approval_amount': amount, 'APR': prod.APR_borrower * (1 - discount_rate), 'tenor': prod.repayment_period, } } bor_detail_info['Approval Records'] = approval_records # if year 1 hasn't GPA if request.POST.get('No GPA') == 'on': bor_detail_info['Overall GPA'] = 2 if result['status'] == 'REJECT': status = 'REJECTED' else: status = 'AUTO APPROVED' new_bor = BorrowRequest( amount=amount, prod_id=prod_id, usr_id=usr.id, ref_num=ref_num, repaid_month=0, instalment_lender=instalment_lender, instalment_borrower=instalment_borrower, simplified_hkid=simplified_hkid, detail_info=json.dumps(bor_detail_info), discount_rate=discount_rate, status=status, create_timestamp=timezone.localtime(timezone.now()), update_timestamp=timezone.localtime(timezone.now())) new_bor.save() # update aut inputs = { 'usr_id': usr.id, 'description': 'Submitted "%s" application, apply amount $%s' % (prod.name_en, request.POST.get('Applied Amount')), 'ref_id': new_bor.id, 'model': 'BorrowRequest', 'by': 'Borrower: ' + usr.email, 'datetime': timezone.localtime(timezone.now()), 'action': 'create', 'type': 'Application', 'status': 'UNREAD', } sup_fn.update_aut(inputs) inputs = { 'usr_id': usr.id, 'description': 'Auto approved $%s, tenor %s, interest rate %s%s' % (amount, prod.repayment_period, prod.APR_borrower * (1 - discount_rate), '%'), 'ref_id': new_bor.id, 'model': 'BorrowRequest', 'by': 'Borrower: ' + usr.email, 'datetime': timezone.localtime(timezone.now()), 'details': { 'usr_ip': request.META.get('REMOTE_ADDR') }, 'action': 'create', 'type': 'Application', 'status': 'UNREAD', } sup_fn.update_aut(inputs) sup_fn.update_ptn(inputs) # sync to usr sync_list = [ 'Home Phone No.', 'Surname', 'Given Name', 'Account Number', 'Mobile', 'Gender', 'Residential Address', 'Bank Code', 'Living Status', 'Living with', 'Date of Birth', 'HKID', 'Studying University', 'Subject' ] sync_dict = {} for name in sync_list: try: sync_dict[name] = bor_detail_info[name] except KeyError: continue sup_fn.sync_to_usr(usr_id=usr.id, dict=sync_dict) if result['status'] == 'REJECT': return redirect('/ack_page/?action=apply_loan_rejected') return redirect('/product/upload_docs/?prod_id=' + str(prod_id)) # if form is not valid hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) usr_details = {} for k, v in request.POST.iteritems(): usr_details[k] = v else: # Captcha form = '' hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) usr_details = sup_fn.sync_from_usr(usr.id) #if lang == 'en': content = { 'lang': lang, 'cate': 'borrow_now', 'title': prod.name_en + ' - Application Form', 'form_action': '?prod_id=' + str(prod_id), 'prod': prod, 'usr_id': usr.id, 'usr_details': usr_details, #'applied_amount_list': ['5000', '10000', '15000', '20000', '25000', '30000', '35000', '40000'], 'applied_amount_list': OrderedDict(( ('5000', FLOAT_DATA_FORMAT.format(5000)), ('10000', FLOAT_DATA_FORMAT.format(10000)), ('15000', FLOAT_DATA_FORMAT.format(15000)), ('20000', FLOAT_DATA_FORMAT.format(20000)), ('25000', FLOAT_DATA_FORMAT.format(25000)), ('30000', FLOAT_DATA_FORMAT.format(30000)), ('35000', FLOAT_DATA_FORMAT.format(35000)), ('40000', FLOAT_DATA_FORMAT.format(40000)), )), 'loan_purpose_list': OrderedDict( (('Tuition', 'Tuition'), ('Investment', 'Investment'), ('Travel', 'Travel'), ('Debt payment', 'Debt payment'), ('Others', 'Others'))), 'gender_list': OrderedDict((('Male', 'Male'), ('Female', 'Female'))), 'living_status_list': OrderedDict( (('Public Housing', 'Public Housing'), ('Owned by Family', 'Owned by Family'), ('Rent', 'Rent'), ('Quarter', 'Quarter'), ('Student Hall of Residence', 'Student Hall of Residence'))), 'living_with_list': OrderedDict((('Parents', 'Parents'), ('Relatives', 'Relatives'), ('Friends or Classmates', 'Friends or Classmates'), ('Others', 'Others'))), 'university_list': OrderedDict( (('The University of Hong Kong', 'The University of Hong Kong'), ('The Chinese University of Hong Kong', 'The Chinese University of Hong Kong'), ('The Hong Kong University of Science and Technology', 'The Hong Kong University of Science and Technology'), ('The Hong Kong Polytechnic University', 'The Hong Kong Polytechnic University'), ('City University of Hong Kong', 'City University of Hong Kong'), ('Hong Kong Baptist University', 'Hong Kong Baptist University'), ('The Hong Kong Institute of Education', 'The Hong Kong Institute of Education'), ('Lingnan University', 'Lingnan University'), ('The Open University of Hong Kong', 'The Open University of Hong Kong'))), 'study_year_list': ['Year 1', 'Year 2', 'Year 3', 'Year 4'], 'subject_list': OrderedDict( (('Medical/Health', 'Medical/Health'), ('Law', 'Law'), ('Accounting', 'Accounting'), ('Construction and Environment', 'Construction and Environment'), ('Engineering', 'Engineering'), ('Design', 'Design'), ('Business/Finance/Economic', 'Business/Finance/Economic'), ('Education and Language', 'Education and Language'), ('Information Technology/Computing', 'Information Technology/Computing'), ('Social Sciences', 'Social Sciences'), ('Hotel and Tourism', 'Hotel and Tourism'), ('Others', 'Others'))), 'form': form, 'hashkey': hashkey, 'image_url': image_url, } # if prod is promotion, only allow to apply $10000 if prod.repayment_plan == 'Promotion Balloon Payment': content['applied_amount_list'] = OrderedDict( (('10000', FLOAT_DATA_FORMAT.format(10000)), )) if lang == 'zh': additional_content = { #'cate': 'borrow_now', 'title': prod.name_zh.encode("utf8") + ' - 申請表', #'form_action': '?prod_id='+str(prod_id), #'prod': prod, #'usr_id': usr.id, #'usr_details': usr_details, #'applied_amount_list': ['5000', '10000', '15000', '20000', '25000', '30000', '35000', '40000'], 'loan_purpose_list': OrderedDict( (('Tuition', '學費'), ('Investment', '投資'), ('Travel', '旅遊'), ('Debt payment', '還款'), ('Others', '其他'))), 'gender_list': OrderedDict((('Male', '男性'), ('Female', '女性'))), 'living_status_list': OrderedDict( (('Public Housing', '公共房屋'), ('Owned by Family', '私人住宅'), ('Rent', '租住'), ('Quarter', '宿舍'), ('Student Hall of Residence', '學生宿舍'))), 'living_with_list': OrderedDict( (('Parents', '父母'), ('Relatives', '親戚'), ('Friends or Classmates', '朋友/同學'), ('Others', '其他'))), 'university_list': OrderedDict( (('The University of Hong Kong', '香港大學'), ('The Chinese University of Hong Kong', '香港中文大學'), ('The Hong Kong University of Science and Technology', '香港科技大學'), ('The Hong Kong Polytechnic University', '香港理工大學'), ('City University of Hong Kong', '香港城市大學'), ('Hong Kong Baptist University', '香港浸會大學'), ('The Hong Kong Institute of Education', '香港教育大學'), ('Lingnan University', '嶺南大學'), ('The Open University of Hong Kong', '香港公開大學'))), 'study_year_list': ['Year 1', 'Year 2', 'Year 3', 'Year 4'], 'subject_list': OrderedDict( (('Medical/Health', '醫療/健康'), ('Law', '法律'), ('Accounting', '會計'), ('Construction and Environment', '建築及環境'), ('Engineering', '工程'), ('Design', '設計'), ('Business/Finance/Economic', '商業/財務/經濟'), ('Education and Language', '教育及語言'), ('Information Technology/Computing', '資訊科技/電子計算'), ('Social Sciences', '社會科學'), ('Hotel and Tourism', '酒店及旅遊'), ('Others', '其他'))), #'form': form, #'hashkey': hashkey, #'image_url': image_url, } content.update(additional_content) return render(request, 'peerloan/borrower/loan_application_form.html', content) if action == 'upload_docs': prod_id = request.GET.get('prod_id') prod = Product.objects.get(id=prod_id) bor = BorrowRequest.objects.filter( usr_id=usr.id, prod_id=prod_id, status="AUTO APPROVED").latest('update_timestamp') # get repayment table inputs = { 'date_type': 'month only', 'start_balance': bor.amount, 'rate_per_month': bor.getBorAPR(prod.APR_borrower) * 0.01 / 12, 'instalment': bor.instalment_borrower, 'repayment_plan': prod.repayment_plan, 'repayment_period': prod.repayment_period, } repayment_table = sup_fn.generate_repayment_schedule(inputs) bank_code_list = {} f = open( '/home/ubuntu/project_peerloan/peerloan/peerloan_src/bank_code_list.csv', 'r') for row in csv.DictReader(f): bank_code_list[str( row['Bank_Code']).zfill(3)] = row['Bank_Name_in_English'] f.close() bank_code_list = OrderedDict( sorted(bank_code_list.items(), key=lambda kv: kv[1])) content = { 'lang': lang, 'cate': 'borrow_now', 'title': prod.name_en + ' - Upload Supporting Documents', 'form_action': '/ack/', 'prod': prod, 'usr_details': sup_fn.sync_from_usr(usr.id), 'bor': bor, 'bor_amount': FLOAT_DATA_FORMAT.format(bor.amount), 'APR': FLOAT_DATA_FORMAT.format( bor.getBorAPR(prod.APR_borrower if prod.fake_APR_borrower == None else prod.fake_APR_borrower)), 'monthly_repayment_amount': FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'repayment_table': repayment_table, 'bank_code_list': bank_code_list, } if lang == 'zh': content['title'] = prod.name_zh.encode("utf8") + ' - 上載申請文件' return render(request, 'peerloan/borrower/loan_upload_docs_form.html', content) if action == 'confirm_agreement': prod_id = request.GET.get('prod_id') prod = Product.objects.get(id=prod_id) bor = BorrowRequest.objects.filter( prod_id=prod_id, usr_id=usr.id, status='DOC UPLOADED').latest('update_timestamp') details = json.loads(bor.detail_info) if prod.repayment_plan == 'Promotion Balloon Payment': start_month = 4 else: start_month = 1 end_month = prod.repayment_period start_date = sup_fn.check_future_date_exists(timezone.localtime( timezone.now()), months=start_month) end_date = sup_fn.check_future_date_exists(timezone.localtime( timezone.now()), months=end_month) if prod.repayment_plan == 'Instalment': last_instalment_amount = round(bor.instalment_borrower, 2) elif prod.repayment_plan == 'Balloon Payment' or prod.repayment_plan == 'Promotion Balloon Payment': last_instalment_amount = round( bor.instalment_borrower + bor.amount, 2) info = { 'loan_agreement_date': datetime.strftime(bor.create_timestamp, '%d/%m/%Y'), 'loan_drawdown_date': datetime.strftime(timezone.localtime(timezone.now()), '%d/%m/%Y'), 'lender': 'P L Technology Limited', 'lender_licence_no': '0741/2016', 'address': 'Unit 1306, Lucky Centre, 165-171 Wanchai Road, Wanchai', 'borrower': '%s %s' % (details['Surname'], details['Given Name']), 'HKID': details['HKID'], 'residential_address': details['Residential Address'], 'loan_principal_amount': FLOAT_DATA_FORMAT.format(bor.amount), 'interest_rate': FLOAT_DATA_FORMAT.format( bor.getBorAPR(prod.APR_borrower if prod.fake_APR_borrower == None else prod.fake_APR_borrower)), 'instalment_amount': FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'due_date': str(timezone.localtime(timezone.now()).day) + sup_fn.date_postfix(timezone.localtime(timezone.now()).day) + ' day of each calendar', 'first_instalment': start_date.strftime('%Y/%m/%d'), 'first_instalment_amount': FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'last_instalment': end_date.strftime('%Y/%m/%d'), 'last_instalment_amount': FLOAT_DATA_FORMAT.format(last_instalment_amount), 'bank_name': details['Bank Code'] + ' ' + sup_fn.bank_code_name_converter(details['Bank Code']), 'account_number': details['Account Number'], 'account_holder': '%s %s' % (details['Surname'], details['Given Name']), 'mobile': details['Mobile'], } if lang == 'zh': info['due_date'] = '每月的第' + str( timezone.localtime(timezone.now()).day).encode("utf8") + '天' content = { 'lang': lang, 'cate': 'borrow_now', 'title': 'Key Terms of Personal Loan Agreement', 'form_action': '/ack/', 'info': info, 'bor_id': bor.id, 'bor_ref_num': bor.ref_num } if lang == 'zh': content['title'] = '私人貸款協議之主要條款' error = request.GET.get('error') if lang == 'en': if error == 'invalid_OTP': content['error_msg'] = 'Please input a valid OTP' if error == 'OTP_not_matched': content[ 'error_msg'] = 'The OTP doesn\'t match to our record, please receive a new OTP and try again' if error == 'OTP_expired': content[ 'error_msg'] = 'The OTP is expired, please receive a new OTP first' elif lang == 'zh': if error == 'invalid_OTP': content['error_msg'] = '請輸入一個有效的OTP' if error == 'OTP_not_matched': content['error_msg'] = '你輸入的OTP與我們的記錄不符合,請重新操作' if error == 'OTP_expired': content['error_msg'] = '你的OTP已經逾期,請重新獲取OTP' return render(request, 'peerloan/borrower/loan_agreement_form.html', content) if action == 'confirm_memorandum': prod_id = request.GET.get('prod_id') prod = Product.objects.get(id=prod_id) bor = BorrowRequest.objects.filter( prod_id=prod_id, usr_id=usr.id, status='FUND MATCHING COMPLETED').latest('update_timestamp') if request.method == 'POST': form = CaptchaForm(request.POST) if form.is_valid(): draw_down_date = sup_fn.find_earliest_business_day( date=timezone.localtime(timezone.now()), cut_off=16) details = json.loads(bor.detail_info) details['Confirm Memorandum Date'] = datetime.strftime( draw_down_date, '%Y/%m/%d %H:%M:%S') details['Memorandum Captcha'] = str( request.POST.get('captcha_1')) bor.detail_info = json.dumps(details) bor.status = 'MEMORANDUM CONFIRMED' bor.update_timestamp = timezone.localtime(timezone.now()) bor.save() # update aut inputs = { 'usr_id': usr.id, 'description': 'Confirmed memorandum with Captcha%s' % (request.POST.get('captcha_1')), 'ref_id': bor.id, 'model': 'BorrowRequest', 'by': 'Borrower: ' + usr.email, 'datetime': timezone.localtime(timezone.now()), 'action': 'modify', 'type': 'Disburse', 'status': 'UNREAD', } sup_fn.update_aut(inputs) sup_fn.update_ptn(inputs) action = 'confirm_memorandum' return redirect('/ack_page/?action=' + action) hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) else: # Captcha form = '' hashkey = CaptchaStore.generate_key() image_url = captcha_image_url(hashkey) details = json.loads(bor.detail_info) draw_down_date = sup_fn.find_earliest_business_day( date=timezone.localtime(timezone.now()), cut_off=16) if prod.repayment_plan == 'Promotion Balloon Payment': start_month = 4 else: start_month = 1 end_month = prod.repayment_period start_date = sup_fn.check_future_date_exists(draw_down_date, months=start_month) end_date = sup_fn.check_future_date_exists(draw_down_date, months=end_month) if prod.repayment_plan == 'Instalment': last_instalment_amount = round(bor.instalment_borrower, 2) elif prod.repayment_plan == 'Balloon Payment' or prod.repayment_plan == 'Promotion Balloon Payment': last_instalment_amount = round( bor.instalment_borrower + bor.amount, 2) info = { 'loan_agreement_date': datetime.strftime(bor.create_timestamp, '%d/%m/%Y'), 'loan_drawdown_date': datetime.strftime(draw_down_date, '%d/%m/%Y'), 'lender': 'P L Technology Limited', 'lender_licence_no': '0741/2016', 'address': 'Unit 1306, Lucky Centre, 165-171 Wanchai Road, Wanchai', 'borrower': '%s %s' % (details['Surname'], details['Given Name']), 'HKID': details['HKID'], 'residential_address': details['Residential Address'], 'loan_principal_amount': FLOAT_DATA_FORMAT.format(bor.amount), 'interest_rate': FLOAT_DATA_FORMAT.format( bor.getBorAPR(prod.APR_borrower if prod.fake_APR_borrower == None else prod.fake_APR_borrower)), 'instalment_amount': FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'due_date': str(draw_down_date.day) + sup_fn.date_postfix(draw_down_date.day) + ' day of each calendar', 'first_instalment': start_date.strftime('%Y/%m/%d'), 'first_instalment_amount': FLOAT_DATA_FORMAT.format(bor.instalment_borrower), 'last_instalment': end_date.strftime('%Y/%m/%d'), 'last_instalment_amount': FLOAT_DATA_FORMAT.format(last_instalment_amount), 'bank_name': details['Bank Code'] + ' ' + sup_fn.bank_code_name_converter(details['Bank Code']), 'account_number': details['Account Number'], 'account_holder': '%s %s' % (details['Surname'], details['Given Name']), 'mobile': details['Mobile'], } if lang == 'zh': info['due_date'] = '每月的第' + str( draw_down_date.day).encode("utf8") + '天' content = { 'lang': lang, 'cate': 'borrow_now', 'title': 'Memorandum of Agreement', 'form_action': '?prod_id=' + str(prod_id), 'info': info, 'form': form, 'hashkey': hashkey, 'image_url': image_url, } if lang == 'zh': content['title'] = '協議備忘錄' return render(request, 'peerloan/borrower/loan_memorandum_form.html', content) if action == 'invest': prod_id = request.GET.get('prod_id') prod = Product.objects.get(id=prod_id) acc = Account.objects.get(usr_id=usr.id) total_usable_amount = acc.balance try: inv = Investment.objects.get(usr_id=usr.id, prod_id=prod_id) except ObjectDoesNotExist: # set up new inv inv = {'total_amount': total_usable_amount, 'used_amount': 0} content = { 'prod': prod, 'total_usable_amount': total_usable_amount, 'inv': inv, 'sub_cate': prod_id, 'used_percentage': 0, 'lang': lang, } if lang == 'en': content[ 'title'] = 'Setting Up Your Investment - ' + prod.name_en content[ 'instruction'] = """The below investment settings define how you invest the money in this product. After you filled up the below form, Peerloan will allocate your investment fund to the selected product automatically.""" if lang == 'zh': content['title'] = '設置你的投資 - ' + prod.name_zh_hk content[ 'instruction'] = """以下投資設置詳述你將如何投資該產品。在你完成以下表格之後,點點眾貸將會自動地分配你的投資資金到該產品。""" else: # change inv settings total_usable_amount += inv.usable_amount + inv.on_hold_amount try: used_percentage = round( ((inv.on_hold_amount / prod.min_amount_per_loan) / int(total_usable_amount / prod.min_amount_per_loan)) * 100 + 1, 1) except ZeroDivisionError: used_percentage = 0 content = { 'prod': prod, 'total_usable_amount': total_usable_amount, 'inv': inv, 'used_percentage': used_percentage, 'lang': lang, } if lang == 'en': content[ 'title'] = 'Change Your Investment Setting - ' + prod.name_en content[ 'instruction'] = """The below investment settings define how you invest the money in this product. After you filled up the below form, Peerloan will allocate your investment fund to the selected product automatically.""" if lang == 'zh': content['title'] = '更換你的投資設置 - ' + prod.name_zh_hk content[ 'instruction'] = """以下投資設置詳述你將如何投資該產品。在你完成以下表格之後,點點眾貸將會自動地分配你的投資資金到該產品。""" return render(request, 'peerloan/lender/invest_form.html', content) if action == 'transfer': inv_list = Investment.objects.filter(usr_id=usr.id) rd_prod_list = [] for inv in inv_list: prod = Product.objects.get(id=inv.prod_id) rd_prod_list.append({ 'prod_id': str(prod.id), 'prod_name': str(prod.name_en), 'usable_amount': str(inv.usable_amount) }) content = { 'prod_list': rd_prod_list, } if lang == 'en': content['title'] = 'Transfer Fund Between Products' content[ 'instruction'] = """Please specify the amount of fund you would like to switch from this portfolio to another portfolio. The instruction will be executed immediately.""" if lang == 'zh': content['title'] = '資金轉賬' content['instruction'] = """請說明你希望的轉賬金額及收賬的投資組合。該指示將會被立即執行。""" return render(request, 'peerloan/lender/transfer_form.html', content)
def portfolio(request): usr = sup_fn.get_user(request) lang = sup_fn.get_lang(request) # return schedule if 'active_investment' in request.META.get('PATH_INFO').split('/'): # active investment page prod_list = Product.objects.filter(status='ACTIVE') if lang == 'en': rd_prod_list = [['all', 'All Products']] elif lang == 'zh': rd_prod_list = [['all', '全部產品']] for prod in prod_list: if lang == 'en': rd_prod_list.append([prod.id, prod.name_en]) elif lang == 'zh': rd_prod_list.append([prod.id, prod.name_zh.encode('utf8')]) content = { 'lang': lang, 'cate': 'portfolio', 'sub_cate': 'active_investment', 'prod_list': rd_prod_list, } return render(request, 'peerloan/lender/active_inv.html', content) elif 'estimated_returning_schedule' in request.META.get('PATH_INFO').split( '/'): content = { 'lang': lang, 'prod_list': Product.objects.filter(status='ACTIVE') } return render(request, 'peerloan/lender/estimated_returning_schedule.html', content) this_month = datetime.strftime(timezone.localtime(timezone.now()), '%m/%Y') search_month_list = [] search_start_date = {'year': 2016, 'month': 06} for i in range(12): month = (search_start_date['month'] + i) % 12 if month == 0: month = 12 year = search_start_date['year'] + (search_start_date['month'] + i - 1) / 12 date = datetime.strptime(str(month) + '/' + str(year), '%m/%Y') search_month_list.append({ 'name': date.strftime('%B %Y'), 'value': date.strftime('%m/%Y') }) content = { 'lang': lang, 'cate': 'portfolio', 'sub_cate': 'portfolio_summary', 'title': 'Portfolio Summary', 'this_month': this_month, 'search_month_list': search_month_list, 'today': datetime.strftime(timezone.localtime(timezone.now()), '%Y/%m/%d') } if lang == 'zh': content['title'] = '投資總覽' return render(request, 'peerloan/lender/portfolio_summary.html', content)