package commands
import (
connection "cf-capital/module_server/handlers/connection"
mail "cf-capital/module_server/handlers/email"
investmentV1 "cf-capital/module_server/handlers/investment/statement-v1"
server_handlers "cf-server/server/handlers"
slack "cf-capital/module_server/handlers/slack"
"database/sql"
"encoding/json"
"fmt"
log "github.com/rs/zerolog/log"
"net/http"
"os"
"reflect"
"time"
)
type responseBody struct {
Status string `json:"status"`
Message string `json:"message"`
}
type Accounts struct {
SchemeID int64
AccountID int64
XIRR_RATE float64
InvestorID int64
InitialAmount float64
EndDate string
StartDate string
InterestCredited float64
}
type InterestEntry struct {
AccountID int64
Type string
Credit float64
Debit float64
}
type Customers struct {
Name string
Mobile int64
Scheme string
AccountID int64
}
func DailyCron() http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
dt := getDate()
params := map[string]interface{}{
"Service": "CFC Cron Service - 0.0.1",
"Status": "Running",
"Date": dt.Format("2006-01-02"),
}
slack.SendSlack("New User Registration", params)
//Cron Service - Start
//Daily()
//End
params = map[string]interface{}{
"Service": "CFC Cron Service - 0.0.1",
"Status": "Closed",
"Date": dt.Format("2006-01-02"),
}
slack.SendSlack("New User Registration", params)
server_handlers.FormatResponse(w, 200)
_ = json.NewEncoder(w).Encode(responseBody{Status: "OK", Message: "Daily cron - successfully executed"})
}
}
func Daily() {
dt := getDate()
tx, ctx, db := connection.Connect()
query := "select ac.scheme_id, ac.account_id, s.xirr_rate, investor_id, initial_amount, start_date, COALESCE(end_date, '') as end_date, IF ((select txn_id from transaction where status = 'SUCCESS' and txn_type = 'INTEREST_CREDIT' and date(txn_date) = DATE(NOW() - INTERVAL 1 DAY) and ac.account_id = transaction.account_id limit 1) is null, 0, 1) as interest_credited from account ac left join scheme s on ac.scheme_id = s.scheme_id where account_status = 'ACTIVE' and start_date <= DATE(NOW() - INTERVAL 1 DAY)"
//query := "select ac.scheme_id, ac.account_id, s.xirr_rate, investor_id, initial_amount, start_date, COALESCE(end_date, '') as end_date, IF ((select txn_id from transaction where status = 'SUCCESS' and txn_type = 'INTEREST_CREDIT' and date(created_at) = DATE(NOW()) and ac.account_id = transaction.account_id) is null, 0, 1) as interest_credited from account ac left join scheme s on ac.scheme_id = s.scheme_id where account_status = 'ACTIVE' and s.scheme_type = 'FLEXI' and end_date = '0000-00-00' and start_date <= DATE(NOW() - INTERVAL 1 DAY)"
rows, err := tx.Query(query)
var accounts []Accounts
var customers []Customers
today := dt.Format("2006-01-02")
for rows.Next() {
var account Accounts
err = rows.Scan(&account.SchemeID, &account.AccountID, &account.XIRR_RATE, &account.InvestorID, &account.InitialAmount, &account.StartDate, &account.EndDate, &account.InterestCredited)
if account.InterestCredited == 0 {
if err != nil {
log.Print(err.Error())
}
if len(account.EndDate) == 0 || account.EndDate == "0000-00-00" {
account.EndDate = today
}
//account.InitialAmount = GetClosingBalance(account.AccountID)
accounts = append(accounts, account)
//log.Print(account.InitialAmount)
//log.Print("AccountID:", account.AccountID)
//log.Print("start:", account.StartDate)
//log.Print("end:", account.EndDate)
} else {
log.Print("Interest already credited")
}
}
if len(accounts) > 0 {
log.Print("calculating interest")
var investment investmentV1.FlexiPlan
var interestEntries []InterestEntry
for i := 0; i < len(accounts); i++ {
var investmentStruct investmentV1.FlexiPlan
var invest investmentV1.Invest
var interestEntry InterestEntry
var customer Customers
investmentStruct.AccountId = accounts[i].AccountID
investmentStruct.Principal = accounts[i].InitialAmount
investmentStruct.MonthlyROI = accounts[i].XIRR_RATE
investmentStruct.StartDate = accounts[i].StartDate
investmentStruct.EndDate = accounts[i].EndDate
investmentStruct.ForIndividualInvestment = accounts[i].EndDate
investment, _ = investmentStruct.DailyCron()
txns := getTransactionsByAccountID(tx, accounts[i].AccountID)
/*log.Print(txns)
dataJson, _ := json.Marshal(investment)
log.Print(string(dataJson))
return*/
//----- ----- ----- ----- Multiple Interest Credit Entry START ----- ----- ----- -----
if len(investment.Payout) > 0 {
//log.Print(len(investment.Payout))
payoutDateMap := make(map[string]bool)
for f := 1; f < len(investment.Payout); f++ {
if investment.Payout[f].Amount > 0 {
payoutDate := investment.Payout[f].Date
if ok := payoutDateMap[payoutDate.Format("2006-01-02")]; !ok {
payoutDateMap[payoutDate.Format("2006-01-02")] = true
log.Print("Interest calculating Account ID ", accounts[i].AccountID, " ", payoutDate.Format("2006-01-02"))
//if payoutDate.Format("2006-01-02") < today && isInterestCredited(tx, accounts[i].AccountID, payoutDate) == 0{
if payoutDate.Format("2006-01-02") < today {
if ok := txns[payoutDate.Format("2006-01-02")]; !ok {
interestEntry.AccountID = accounts[i].AccountID
interestEntry.Type = "Deposit"
interestEntry.Credit = investment.Payout[f].Amount
interestEntries = append(interestEntries, interestEntry)
log.Print("creating CreatePassbook")
_, err = investmentV1.CreatePassbook(interestEntry.AccountID, tx, ctx, "Interest Accrued for Date "+investment.Payout[f].Date.Format("2006-01-02"), interestEntry.Credit, 0, investment.Payout[f].PrincipalAmount)
if err != nil {
tx.Rollback()
log.Print(err.Error())
}
invest.AccountID = accounts[i].AccountID
invest.Amount = interestEntry.Credit
invest.PaymentMethod = 1
invest.PaymentGateway = 1
invest.MHP = accounts[i].SchemeID
invest.TxnDate = investment.Payout[f].Date.Format("2006-01-02")
invest.ReferenceCode = investmentV1.GetRequestID()
log.Print("creating CreateTransaction")
_, err = investmentV1.CreateTransaction(invest, tx, ctx, "INTEREST_CREDIT", "SUCCESS")
if err != nil {
log.Print(err.Error())
tx.Rollback()
}
if isMonthEnd() == 1 {
customer.Name = "A"
customer.Mobile = 0
customer.Scheme = "A"
customer.AccountID = 0
customers = append(customers, customer)
}
} else {
//log.Print("Interest already calculated ", investment.Payout[f].Date, " Account Id", accounts[i].AccountID)
}
} else {
log.Print("Beyond date ", investment.Payout[f].Date, " Account Id", accounts[i].AccountID)
}
}
}
}
} else {
log.Print("No Interest accrued: Account ID ", accounts[i].AccountID)
}
//----- ----- ----- ----- Multiple Interest Credit Entry END ----- ----- ----- -----
//----- ----- ----- ----- Single Interest Credit Entry START ----- ----- ----- -----
/*if investment.IndividualInvestment.TotalInterest > 0 {
interestEntry.AccountID = accounts[i].AccountID
interestEntry.Type = "Deposit"
interestEntry.Credit = investment.IndividualInvestment.TotalInterest
interestEntries = append(interestEntries, interestEntry)
log.Print("creating CreatePassbook")
_, err = investmentV1.CreatePassbook(interestEntry.AccountID, tx, ctx, "Interest Accrued for Date "+today, interestEntry.Credit, 0)
if err != nil {
tx.Rollback()
log.Print(err.Error())
}
invest.AccountID = accounts[i].AccountID
invest.Amount = interestEntry.Credit
invest.PaymentMethod = 1
invest.PaymentGateway = 1
invest.MHP = accounts[i].SchemeID
invest.ReferenceCode = investmentV1.GetRequestID()
log.Print("creating CreateTransaction")
_, err = investmentV1.CreateTransaction(invest, tx, ctx, "INTEREST_CREDIT")
if err != nil {
log.Print(err.Error())
tx.Rollback()
}
} else {
log.Print("No Interest accrued: Account ID", accounts[i].AccountID)
}*/
//----- ----- ----- ----- Single Interest Credit Entry END ----- ----- ----- -----
}
} else {
log.Print("No entries are found")
}
if len(customers) > 0 {
//sendMonthEndCommunication(customers)
}
connection.Close(tx, db)
}
func isInterestCredited(tx *sql.Tx, accountId int64, date time.Time) int64 {
//dt,_ := time.Parse("2006-01-02 15:04:05", date)
row := tx.QueryRow("select txn_id from transaction where status = 'SUCCESS' and txn_type = 'INTEREST_CREDIT' and account_id = ? and date(txn_date) = ?", accountId, date.Format("2006-01-02"))
var txn_id int64
err := row.Scan(&txn_id)
if err != nil && err != sql.ErrNoRows {
log.Print("isInterestCredited, error exeception")
log.Print(err.Error())
return 1
}
if txn_id > 0 {
return 1
}
return 0
}
func getTransactionsByAccountID(tx *sql.Tx, accountId int64) map[string]bool {
//dt,_ := time.Parse("2006-01-02 15:04:05", date)
rows, err := tx.Query("select date(txn_date) from transaction where status = 'SUCCESS' and txn_type = 'INTEREST_CREDIT' and account_id = ?", accountId)
transactions := make(map[string]bool)
for rows.Next() {
var txnDate string
err = rows.Scan(&txnDate)
if err != nil && err != sql.ErrNoRows {
log.Print("getTransactionsByAccountID, no entry")
log.Print(err.Error())
}else{
transactions[txnDate] = true
}
}
return transactions
}
func GetClosingBalance(accountId int64) float64 {
tx, _, db := connection.Connect()
//Interest Paid Out (Debit)
row := tx.QueryRow("select IF(amount is null, 0, SUM(amount)) as amount from transaction where txn_type in ('INTEREST_DEBIT', 'INTEREST_DEBIT_MONTHLY', 'WITHDRAW','WITHDRAW_MONTHLY') and status = 'SUCCESS' and account_id = ?", accountId)
var interestPaidOut float64
var interestGained float64
err := row.Scan(&interestPaidOut)
if err != nil {
log.Print("GetClosingBalance: interestPaidOut")
log.Print(err.Error())
return 0
}
//End
//Interest Gained (Credit)
row = tx.QueryRow("select IF(amount is null, 0, SUM(amount)) as amount from transaction where txn_type in ('INTEREST_CREDIT', 'DEPOSIT') and status = 'SUCCESS' and account_id = ?", accountId)
err = row.Scan(&interestGained)
if err != nil {
log.Print("GetClosingBalance: interestGained")
log.Print(err.Error())
return 0
}
//End
connection.Close(tx, db)
return interestGained - interestPaidOut
}
func InterestCalculationByDays() {
log.Print(os.Args[1:])
dt := getDate()
format := "2006-01-02"
tx, ctx, db := connection.Connect()
query := "select ac.scheme_id, account_id, s.xirr_rate, investor_id, initial_amount, start_date, COALESCE(end_date, '') as end_date from account ac left join scheme s on ac.scheme_id = s.scheme_id where account_status = 'ACTIVE' and s.scheme_type = 'FLEXI' and s.tenure_type = 'D' and end_date is null"
rows, err := tx.Query(query)
var accounts []Accounts
today := dt.Format(format)
for rows.Next() {
var account Accounts
err = rows.Scan(&account.SchemeID, &account.AccountID, &account.XIRR_RATE, &account.InvestorID, &account.InitialAmount, &account.StartDate, &account.EndDate)
if err != nil {
log.Print(err.Error())
}
if len(account.EndDate) == 0 {
account.EndDate = today
}
accounts = append(accounts, account)
}
log.Print("calculating interest")
if len(accounts) > 0 {
var interestEntries []InterestEntry
for i := 0; i < len(accounts); i++ {
var investmentStruct investmentV1.FlexiPlan
var invest investmentV1.Invest
var interestEntry InterestEntry
investmentStruct.Principal = accounts[i].InitialAmount
investmentStruct.MonthlyROI = accounts[i].XIRR_RATE
investmentStruct.StartDate = accounts[i].StartDate
investmentStruct.EndDate = accounts[i].EndDate
end, _ := time.Parse(format, accounts[i].EndDate)
start, _ := time.Parse(format, accounts[i].StartDate)
diff := end.Sub(start)
days := int64(diff.Hours() / 24)
if days > 1 {
//get only one day's calculation
days = 1
}
log.Print("Days:", days)
log.Print(investmentStruct)
//data, _ := investmentStruct.FlexiV1()
investment, _ := investmentStruct.InterestCalculationByDays(days)
log.Print(investment.TotalInterestEarned)
if investment.IndividualInvestment.TotalInterest > 0 {
interestEntry.AccountID = accounts[i].AccountID
interestEntry.Type = "Deposit"
interestEntry.Credit = investment.TotalInterestEarned
interestEntries = append(interestEntries, interestEntry)
_, err = investmentV1.CreatePassbook(interestEntry.AccountID, tx, ctx, interestEntry.Type, interestEntry.Credit, 0, 0)
if err != nil {
tx.Rollback()
log.Print(err.Error())
}
invest.AccountID = accounts[i].AccountID
invest.Amount = interestEntry.Credit
invest.PaymentMethod = 1
invest.PaymentGateway = 1
invest.MHP = accounts[i].SchemeID
invest.ReferenceCode = investmentV1.GetRequestID()
log.Print("creating CreateTransaction")
_, err = investmentV1.CreateTransaction(invest, tx, ctx, "INTEREST_CREDIT", "SUCCESS")
if err != nil {
log.Print(err.Error())
tx.Rollback()
}
} else {
log.Print("No Interest accrued: Account ID", accounts[i].AccountID)
}
}
} else {
log.Print("No entries are found")
}
connection.Close(tx, db)
}
func getDate() time.Time {
loc, _ := time.LoadLocation("Asia/Kolkata")
dt := time.Now().In(loc)
return dt
}
func getLastDayOfMonth() int {
now := time.Now()
currentYear, currentMonth, _ := now.Date()
currentLocation := now.Location()
firstOfMonth := time.Date(currentYear, currentMonth, 1, 0, 0, 0, 0, currentLocation)
return firstOfMonth.AddDate(0, 1, -1).Day()
}
func getFirstDayOfMonth() int {
now := time.Now()
currentYear, currentMonth, _ := now.Date()
currentLocation := now.Location()
firstOfMonth := time.Date(currentYear, currentMonth, 1, 0, 0, 0, 0, currentLocation)
return firstOfMonth.Day()
}
func isMonthEnd() int {
now := time.Now()
if now.Day() == getLastDayOfMonth() {
return 1
}
return 0
}
func isMonthStart() int {
now := time.Now()
if now.Day() == getFirstDayOfMonth() {
return 1
}
return 0
}
func sendMonthEndCommunication(customers []Customers) {
currentTime := time.Now()
dateTime := currentTime.Format("Mon 2006-01-2 15:04:05")
HtmlBody := "
" +
"
" +
"
" +
"
" +
"
" +
"" +
"" +
"| Email | " +
"Test | " +
"
" +
"
" +
"
"
//storage.Save(customers)
log.Print("trigger email, month end")
_, err := mail.Email(HtmlBody, fmt.Sprint("System - Monthly Withdrawal ", dateTime))
if err != nil {
log.Print("trigger email error")
log.Print(err.Error())
}
}
func (d Customers) String() string {
v := reflect.ValueOf(d)
var csvString string
for i := 0; i < v.NumField(); i++ {
csvString = fmt.Sprintf("%v%v,", csvString, v.Field(i).Interface())
}
return csvString
}