package handlers import ( server_handlers "cf-server/server/handlers" "database/sql" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "os" "strings" "time" log "github.com/rs/zerolog/log" _ "github.com/go-sql-driver/mysql" "github.com/speps/go-hashids/v2" ) type User struct { ID int `json:"id"` Name string `json:"name"` } type ErrorResponse struct { Status string `json:"status"` Message string `json:"message"` } type ApplicationData struct { ID string `json:"id"` FirstName string `json:"id"` LastName string `json:"id"` MiddleName string `json:"id"` EmployeeId string `json:"id"` } type CreditLimit struct { ID int `json:"id"` UpdatedCreditLimit int `json:"updated_credit_limit"` AssignedCreditLimit int `json:"assigned_credit_limit"` Status int `json:"status"` } type TransactionLogs struct { ApplicationId int `json:"application_id"` Amount int `json:"amount"` TransactionAt string `json:"transaction_at"` EMIDate string `json:"emi_date"` Status int `json:"status"` CFTransactionId string `json:"cf_transaction_id"` } type TransactionLogResponse struct { TransactionId string `json:"transaction_id"` QubeRefId string `json:"qube_ref_id"` } type responseTransaction struct { Status string `json:"status"` Message string `json:"message"` TransactionLogResponse TransactionLogResponse `json:"data"` } type Request struct { Id string `json:"id"` TransactionId string `json:"transaction_id"` QubeRefId string `json:"qube_ref_id"` Amount int `json:"amount"` } type Repayment struct { EMIDate string `json:"emi_date"` Amount string `json:"amount"` BounceCharges string `json:"bounce_charges"` DelayPenalty string `json:"delay_penalty"` DueDate string `json:"due_date"` TotalPayable string `json:"total_payable"` AmountDue string `json:"amount_due"` Status string `json:"status"` } type PaymentStatus struct { CFTransactionId string `json:"cf_transaction_id"` TransactionAmount string `json:"transaction_amount"` TransactionAt string `json:"transaction_at"` Status string `json:"status"` Repayment []Repayment `json:"repayment"` } type ResponsePaymentStatus struct { Status string `json:"status"` Message string `json:"message"` PaymentStatus PaymentStatus `json:"data"` } type LoanStatus struct { KYC bool `json:"kyc"` EMandate bool `json:"e_mandate"` AgreementSigned bool `json:"agreement_signed"` IsLimitActive bool `json:"is_limit_active"` } type responseBody struct { Status string `json:"status"` Message string `json:"message"` LoanStatus LoanStatus `json:"data"` } type QueuePayload struct { Id int `json:"id"` QubeRefId string `json:"qube_ref_id"` EMIDate string `json:"emi_date"` DueDate string `json:"due_date"` Amount int `json:"amount"` TransactionLogId int64 `json:"transaction_log_id"` CFTransactionId string `json:"cf_transaction_id"` } type QueueListener struct { CMD string `json:"cmd"` QueuePayload QueuePayload `json:"param"` JobHandler string `json:"job_handler"` CON string `json:"con"` } const bill_generation_day int = 20 const due_days_from_month_start int = 5 const default_offer_id int = 35 const default_merchant_id int = 1 var loan_status LoanStatus var payment_status_data *PaymentStatus func GetApplicationStatus() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var reqEvent Request body, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } json.Unmarshal(body, &reqEvent) hd := hashids.NewData() hd.Salt = os.Getenv("HASH") hd.MinLength = 20 h, _ := hashids.NewWithData(hd) appId, _ := h.DecodeWithError(reqEvent.Id) if len(appId) == 0 { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Invalid application id received"}) } loan_status, err := connection(appId[0]) if err != nil { log.Print("connection error %s", err) server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Request is not valid"}) return } products := responseBody{ Status: "OK", Message: "application status fetched", LoanStatus: loan_status, } bytes, _ := json.Marshal(products) if err != nil { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: err.Error()}) return } server_handlers.FormatResponse(w, 200) _ = json.NewEncoder(w).Encode(bytes) } } func connection(appId int) (LoanStatus, error) { log.Print("application id %s", appId) db, err := DBCon() if err != nil { panic(err.Error()) log.Print("Connection Error# %s", err.Error()) } results, err := db.Query("select if (kyc_logs.status is null, 0, kyc_logs.status) as KYC, if (mandate.id is null, 0, if (mandate.status = 'active',1,0)) as EMandate, if (digital_sign.id is null, 0, digital_sign.id) as AgreementSigned, if (credit_limit.status is null, 0, credit_limit.status) as IsLimitActive from applications left join digital_sign on digital_sign.application_id = applications.id left join mandate on mandate.application_id = applications.id left join kyc_logs on kyc_logs.application_id = applications.id left join credit_limit on credit_limit.application_id = applications.id where applications.id = ?", appId) if err != nil { panic(err.Error()) log.Print("Query Error# %s", err.Error()) } var loan_status LoanStatus var KYC, EMandate, AgreementSigned, IsLimitActive int for results.Next() { err = results.Scan(&KYC, &EMandate, &AgreementSigned, &IsLimitActive) if err != nil { panic(err.Error()) } } if KYC > 0 { loan_status.KYC = true } else { loan_status.KYC = false } if EMandate > 0 { loan_status.EMandate = true } else { loan_status.EMandate = false } if AgreementSigned > 0 { loan_status.AgreementSigned = true } else { loan_status.AgreementSigned = false } if IsLimitActive > 0 { loan_status.IsLimitActive = true } else { loan_status.IsLimitActive = false } defer db.Close() return loan_status, nil } func DBCon() (*sql.DB, error) { u := os.Getenv("USER") d := os.Getenv("DB") ho := os.Getenv("HOST") p := os.Getenv("CRE") conn := u + ":" + p + "@tcp(" + ho + ":3306)/" + d db, err := sql.Open("mysql", conn) return db, err } func getPaymentDBStatus(req Request) ([]Repayment, error) { db, err := DBCon() hd := hashids.NewData() hd.Salt = os.Getenv("HASH") hd.MinLength = 20 h, _ := hashids.NewWithData(hd) appId, _ := h.DecodeWithError(req.TransactionId) if len(appId) == 0 { var repayment []Repayment return repayment, errors.New("Invalid transaction id received") } log.Print("transaction id %s", appId[0]) if err != nil { panic(err.Error()) log.Print("Connection Error# %s", err.Error()) } log.Print("TransactionLog") results, err := db.Query("select transaction_logs.id, transaction_logs.cf_transaction_id, transaction_logs.amount, transaction_logs.transaction_at, transaction_logs.status from transaction_logs where id = ?", appId[0]) if err != nil { panic(err.Error()) log.Print("Query Error# %s", err.Error()) } payment_status_data = new(PaymentStatus) for results.Next() { var transaction_id int err = results.Scan(&transaction_id, &payment_status_data.CFTransactionId, &payment_status_data.TransactionAmount, &payment_status_data.TransactionAt, &payment_status_data.Status) if err != nil { panic(err.Error()) } log.Print("EMIPayment") emi_payments_results, err := db.Query("select emi_date as EMIDate, amount as Amount, bounce_charges as BounceCharges, delay_penalty as DelayPenalty, due_date as DueDate, total_payable as TotalPayable, amount_due as AmountDue, status as Status from emi_payments where transaction_log_id = ?", transaction_id) for emi_payments_results.Next() { var repayment Repayment err = emi_payments_results.Scan(&repayment.EMIDate, &repayment.Amount, &repayment.BounceCharges, &repayment.DelayPenalty, &repayment.DueDate, &repayment.TotalPayable, &repayment.AmountDue, &repayment.Status) if err != nil { panic(err.Error()) } log.Print("Transaction Fetched") log.Print(repayment) payment_status_data.Repayment = append(payment_status_data.Repayment, repayment) } } log.Print("Total Transaction Fetched") log.Print(payment_status_data.Repayment) defer db.Close() return payment_status_data.Repayment, nil } func InitiateTransaction() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req Request body, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } json.Unmarshal(body, &req) db, err := DBCon() loc, _ := time.LoadLocation("Asia/Kolkata") if err != nil { panic(err.Error()) log.Print("Connection Error# %s", err.Error()) } hd := hashids.NewData() hd.Salt = os.Getenv("HASH") hd.MinLength = 20 h, _ := hashids.NewWithData(hd) appId, _ := h.DecodeWithError(req.Id) if len(appId) == 0 { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Invalid application id received"}) //return "Invalid application id received", errors.New("Invalid application id received") } log.Print("application id %s", appId[0]) log.Print("TransactionLog") log.Print("ReqID#", req.Id) log.Print("Req QubeRef#", req.QubeRefId) transaction_logs_select_results, err := db.Query("select id from transaction_logs where application_id = ? and status = 0", appId[0]) if err != nil { panic(err.Error()) log.Print("Query Error# %s", err.Error()) } for transaction_logs_select_results.Next() { var TrId int err = transaction_logs_select_results.Scan(&TrId) if err != nil { panic(err.Error()) } if TrId > 0 { log.Print("Previous transaction is under process %s", TrId) server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Previous transaction is under process"}) //return "", errors.New("Previous transaction is under process") } } results, err := db.Query("select id, first_name, last_name, middle_name, employee_id from applications where id = ? and employee_id = ?", appId[0], req.QubeRefId) if err != nil { panic(err.Error()) log.Print("Query Error# %s", err.Error()) } var applicationData ApplicationData var creditLimit CreditLimit for results.Next() { err = results.Scan(&applicationData.ID, &applicationData.FirstName, &applicationData.MiddleName, &applicationData.LastName, &applicationData.EmployeeId) if err != nil { panic(err.Error()) } log.Print("CS Name: ", applicationData.FirstName) credit_limit_results, err := db.Query("select id, updated_credit_limit, assigned_credit_limit, status from credit_limit where application_id = ?", applicationData.ID) if err != nil { panic(err.Error()) log.Print("Query Error# %s", err.Error()) } for credit_limit_results.Next() { err = credit_limit_results.Scan(&creditLimit.ID, &creditLimit.UpdatedCreditLimit, &creditLimit.AssignedCreditLimit, &creditLimit.Status) if err != nil { panic(err.Error()) } log.Print("Updated Credit Limit: ", creditLimit.UpdatedCreditLimit) } } if creditLimit.Status == 0 { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Credit limit is Inactive. Please sign the agreement and authorize the e-mandate"}) //return "FAIL", errors.New("Credit limit is Inactive. Please sign the agreement and authorize the e-mandate") } if req.Amount > creditLimit.UpdatedCreditLimit { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Requested amount is greater than credit limit"}) //return "FAIL", errors.New("Requested amount is greater than credit limit") } if creditLimit.UpdatedCreditLimit == 0 { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Credit limit is over"}) //return "FAIL", errors.New("Credit limit is over") } var transactionLogResponse TransactionLogResponse if creditLimit.UpdatedCreditLimit > 0 && creditLimit.Status == 1 { firstName := strings.ToUpper(applicationData.FirstName) now := time.Now().In(loc) cf_transaction_id := fmt.Sprint(applicationData.ID, firstName[0:2], now.Unix()) log.Print("CF TransactionId:", cf_transaction_id) current_time := time.Now().In(loc).Format("2006-01-02 15:04:05") var transactionLog = TransactionLogs{ApplicationId: appId[0], Amount: req.Amount, TransactionAt: current_time, EMIDate: setEMIDate(), Status: 0, CFTransactionId: cf_transaction_id} transaction_logs_results, err := db.Exec("INSERT INTO transaction_logs (application_id, amount, transaction_at, emi_date, status, cf_transaction_id) values (?, ?, ?, ?, ?, ?)", transactionLog.ApplicationId, transactionLog.Amount, transactionLog.TransactionAt, transactionLog.EMIDate, transactionLog.Status, transactionLog.CFTransactionId) if err != nil { panic(err.Error()) log.Print(err.Error()) } transaction_log_id, err := transaction_logs_results.LastInsertId() if err != nil { log.Print("Error Get Last inserted ID:", err.Error()) } else { log.Print("LastInsertId:", transaction_log_id) } h, _ := hashids.NewWithData(hd) transaction_log_id_en, _ := h.EncodeInt64([]int64{transaction_log_id}) transactionLogResponse.TransactionId = transaction_log_id_en transactionLogResponse.QubeRefId = req.QubeRefId transactionData := responseTransaction{ Status: "OK", Message: "Transaction detail successfully updated", TransactionLogResponse: transactionLogResponse, } var queuePayload = QueuePayload{Id: transactionLog.ApplicationId, QubeRefId: req.QubeRefId, EMIDate: transactionLog.EMIDate, DueDate: transactionLog.EMIDate, Amount: transactionLog.Amount, TransactionLogId: transaction_log_id, CFTransactionId: transactionLog.CFTransactionId} var queueListener = QueueListener{CMD: "command:generatePayment", QueuePayload: queuePayload, JobHandler: "App\\Helper\\CmdHelper@runCommand", CON: "repayment"} queueBytes, _ := json.Marshal(queueListener) queue_results, err := db.Query("INSERT INTO queue (application_id, `from`, payload, available_at) values (?, ?, ?, ?)", transactionLog.ApplicationId, "runCommand", string(queueBytes), current_time) _ = queue_results if err != nil { log.Print("Queue Insert: ", err.Error()) } defer db.Close() bytes, _ := json.Marshal(transactionData) server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(bytes) //return string(bytes), nil } server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Credit limit is Inactive. Please sign the agreement and authorize the e-mandate"}) //return "FAIL", errors.New("Credit limit is Inactive. Please sign the agreement and authorize the e-mandate") } } /* func user(){ http.HandleFunc("/", homeLink) log.Fatal(http.ListenAndServe(":10000", nil)) } */ func GetPaymentStatus() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var reqEvent Request println(r.Body) body, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } json.Unmarshal(body, &reqEvent) repayment, err := getPaymentDBStatus(reqEvent) if err != nil { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: err.Error()}) } if repayment == nil { server_handlers.FormatResponse(w, 400) _ = json.NewEncoder(w).Encode(responseBody{Status: "FAIL", Message: "Schedule is not generated yet"}) } paymentStatus := PaymentStatus{ CFTransactionId: payment_status_data.CFTransactionId, TransactionAmount: payment_status_data.TransactionAmount, TransactionAt: payment_status_data.TransactionAt, Status: payment_status_data.Status, Repayment: repayment, } var responsePaymentStatus = ResponsePaymentStatus{Status: "OK", Message: "repayment_details", PaymentStatus: paymentStatus} bytes, _ := json.Marshal(responsePaymentStatus) server_handlers.FormatResponse(w, 200) _ = json.NewEncoder(w).Encode(bytes) } } /*func HandleRequestProxy(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { var reqEvent Request json.Unmarshal([]byte(request.Body), &reqEvent) errorResponse := ErrorResponse{Status: "FAIL", Message: "invalid request"} ApiResponse, err := reqValidation(request, reqEvent) if err != nil { return ApiResponse, nil } switch request.HTTPMethod { case "GET": switch request.Path { case "/credit-service/application-status": res, err := GetApplicationStatus(ctx, reqEvent) if err != nil { errorResponse.Message = err.Error() bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, nil } ApiResponse = events.APIGatewayProxyResponse{Body: res, StatusCode: 200} case "/credit-service/transaction": res, err := getPaymentStatus(ctx, reqEvent) if err != nil { errorResponse.Message = err.Error() bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, nil } ApiResponse = events.APIGatewayProxyResponse{Body: res, StatusCode: 200} } case "POST": switch request.Path { case "/credit-service/transaction": res, err := initiateTransaction(ctx, reqEvent) if err != nil { errorResponse.Message = err.Error() bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, nil } ApiResponse = events.APIGatewayProxyResponse{Body: res, StatusCode: 200} } } return ApiResponse, nil }*/ /*func reqValidation(request events.APIGatewayProxyRequest, reqEvent Request) (events.APIGatewayProxyResponse, error){ ApiResponse := events.APIGatewayProxyResponse{} errorResponse := ErrorResponse{Status: "FAIL", Message: "Invalid request received"} var x_client_key string; var x_client_secret string; for k, v := range request.Headers { if k == "X-Client-Id" { x_client_key = v }else if k == "X-Client-Secret" { x_client_secret = v } } if x_client_key != os.Getenv("XClientId") || x_client_secret != os.Getenv("XClientSecret"){ errorResponse.Message = "Unauthorized access" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 401} return ApiResponse, errors.New(errorResponse.Message) } switch request.HTTPMethod { case "GET": switch request.Path { case "/credit-service/application-status": if len(reqEvent.Id) == 0 { errorResponse.Message = "Application id is missing" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, errors.New(errorResponse.Message) } case "/credit-service/transaction": if len(reqEvent.TransactionId) == 0 { errorResponse.Message = "Transaction id is missing" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, errors.New(errorResponse.Message) } } return ApiResponse, nil case "POST": switch request.Path { case "/credit-service/transaction": if len(reqEvent.Id) == 0 { errorResponse.Message = "Application id is missing" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, errors.New(errorResponse.Message) } if len(reqEvent.QubeRefId) == 0 { errorResponse.Message = "Qube Ref id is missing" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, errors.New(errorResponse.Message) } if reqEvent.Amount <= 0 { errorResponse.Message = "Transaction amount should be greater than zero" bytes, _ := json.Marshal(errorResponse) ApiResponse = events.APIGatewayProxyResponse{Body: string(bytes), StatusCode: 400} return ApiResponse, errors.New(errorResponse.Message) } } return ApiResponse, nil } return ApiResponse, errors.New(errorResponse.Message) }*/ func monthInterval(y int, m time.Month) (firstDay time.Time) { firstDay = time.Date(y, m, 1, 0, 0, 0, 0, time.UTC) //lastDay = time.Date(y, m+1, 1, 0, 0, 0, -1, time.UTC) return firstDay } func setEMIDate() string { loc, _ := time.LoadLocation("Asia/Kolkata") todayOneMonth := time.Now().In(loc).AddDate(0, 1, 0) year, month, day := todayOneMonth.Date() first := monthInterval(year, month) var h string if day >= bill_generation_day { h = first.AddDate(0, 1, (due_days_from_month_start - 1)).Format("2006-01-02") } else { h = first.AddDate(0, 0, (due_days_from_month_start - 1)).Format("2006-01-02") } return h } //func main() { // log.Print("Main started") //log.Print(os.Hostname()) /* var request Request var ctx context.Context */ //var r *http.Request /* request.Id = "k3gD8Lp6VgGVaE7z10J2" request.TransactionId = "k3gD8Lp6VgGVaE7z10J2" request.QubeRefId = "XCTF1302921092" request.Amount = 4500 */ //GetApplicationStatus(ctx, request); //getPaymentStatus(ctx, request); //log.Print(initiateTransaction(ctx, request)) //user() // lambda.Start(HandleRequestProxy) //}