package eloquent import ( "bytes" aes "cf-capital/module_server/handlers/aes" "cf-capital/module_server/handlers/aws" connection "cf-capital/module_server/handlers/connection" mail "cf-capital/module_server/handlers/email" JWT "cf-capital/module_server/handlers/jwt" "cf-capital/module_server/handlers/pdf" "context" "crypto/rand" "database/sql" "encoding/json" "encoding/xml" "errors" "fmt" "io" "io/ioutil" "net/http" "os" "strconv" "strings" "time" log "github.com/rs/zerolog/log" ) const otpChars = "1234567890" var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9'} var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" type Auth struct { ID string `json:"id"` } type OTPManager interface { GenerateOTP() VerifyOTP() ValidatePAN() CreateUser() EsignAgreement() UploadDocument() GetUser() } type auth struct { ID string `json:"id,omitempty"` } type OTPManagerTable struct { Data OTPManagerData Result OTPManagerDataResult } type responseBody struct { Status string `json:"status"` Message string `json:"message"` } type OTPManagerData struct { Phone string `json:"phone" validate:"required" len:"10"` Type int `json:"type" validate:"required"` OTP int `json:"otp" len:"6"` ReferredBy string `json:"referred_by"` } type OTPManagerDataResult struct { ID int `json:"id"` Sent int64 `json:"sent"` Token string `json:"token"` } type User struct { Data UserData Result UserDataResult Auth auth } type UserDataResult struct { ID int64 `json:"id"` } type UserData struct { Type int `json:"type"` FirstName string `json:"firstName" validate:"required"` MiddleName string `json:"middleName"` LastName string `json:"lastName" validate:"required"` Email string `json:"email" validate:"required"` PAN string `json:"pan" validate:"required"` DOB string `json:"dob" validate:"required"` Gender int64 `json:"gender" validate:"required"` Aadhaar string `json:"aadhaar"` } type PincodeDetails struct { Data PincodeDetailsData Result PincodeDetailsDataResult Auth auth } type PincodeDetailsDataResult struct { ID int64 `json:"id"` City string `json:"city"` State string `json:"state"` } type PincodeDetailsData struct { Pincode string `json:"pincode" validate:"required"` } type ValidatePANDetails struct { Data ValidatePANData Result ValidatePANDataResult Auth auth } type ValidatePANDataResult struct { Status string `json:"status"` FullName string `json:"full_name,omitempty"` FirstName string `json:"first_name"` MiddleName string `json:"middle_name"` LastName string `json:"last_name"` PAN string `json:"pan"` Category string `json:"category"` } type ValidatePANData struct { PAN string `json:"pan" validate:"required"` } type UserSignAgreement struct { Data UserSignAgreementData Result UserSignAgreementDataResult Auth auth } type UserSignAgreementDataResult struct { ID int64 `json:"id"` } type UserSignAgreementData struct { UserId int `json:"user_id"` Name string `json:"name"` Type int `json:"type" validate:"required"` LoadTime string `json:"loadTime" validate:"required"` ClickTime string `json:"clickTime" validate:"required"` IPAddress string `json:"ipAddress" validate:"required"` Latitude string `json:"latitude" validate:"required"` Longitude string `json:"longitude" validate:"required"` IsAgreementSigned string `json:"isAgreementSigned" validate:"required"` GetClientInfo getClientInfo } type DocumentUpload struct { Data DocumentUploadData Result DocumentUploadDataResult Auth auth } type DocumentUploadDataResult struct { ID int64 `json:"id"` } type DocumentUploadData struct { DocName string `json:"docName" validate:"required"` DocFormat string `json:"docFormat" validate:"required"` DocPassword string `json:"docPassword"` DocContent string `json:"docContent" validate:"required"` } type Bank struct { Data BankData Result BankDataResult Auth auth } type BankDataResult struct { ID int64 `json:"id"` } type BankData struct { BankId int64 `json:"bank_id,omitempty"` AccountHolder string `json:"accountHolder" validate:"required"` BankName string `json:"bankName" validate:"required"` BankIfsc string `json:"bankIfsc" validate:"required"` AccountNumber string `json:"accountNumber" validate:"required"` AccountType string `json:"accountType"` BranchName string `json:"branchName"` DpName string `json:"dpName"` Depository string `json:"depository"` BoId string `json:"boId"` } type UpdateAddress struct { Data UpdateAddressData Result UpdateAddressDataResult Auth auth } type UpdateAddressDataResult struct { ID int64 `json:"id"` } type UpdateAddressData struct { Address string `json:"address" validate:"required"` Pincode string `json:"pincode" validate:"required"` City string `json:"city" validate:"required"` State string `json:"state" validate:"required"` } type UserDetails struct { PersonalDetails personalDetails `json:"personal_details"` Address address `json:"address"` BankDetails bankDetails `json:"bank_details"` SignedAgreement signedAgreement `json:"signed_agreement"` Documents []documents `json:"documents"` } type documents struct { Name string `json:"name"` Path string `json:"path"` } type personalDetails struct { FirstName string `json:"first_name"` MiddleName string `json:"middle_name"` LastName string `json:"last_name"` Email string `json:"email"` Gender string `json:"gender"` Phone string `json:"phone"` PanNumber string `json:"pan_number"` Aadhaar string `json:"aadhaar"` DOB string `json:"dob"` ReferredBy string `json:"referred_by"` } type address struct { Address string `json:"address"` Pincode string `json:"pincode"` City string `json:"city"` State string `json:"state"` } type bankDetails struct { AccountHolder string `json:"account_holder_name"` BankName string `json:"bank_name"` BankIfsc string `json:"ifsc_code"` AccountNumber string `json:"account_number"` AccountType string `json:"account_type"` DpName string `json:"dpName"` Depository string `json:"depository"` BoId string `json:"boId"` } type signedAgreement struct { URL string `json:"agreement_link"` } type MakeTransaction struct { Data MakeTransactionData Result MakeTransactionDataResult Auth auth } type MakeTransactionDataResult struct { ID int64 `json:"id"` } type MakeTransactionData struct { TransactionType string `json:"transaction_type" validate:"required"` Quantity int `json:"quantity" validate:"required"` } type getClientInfo struct { OS string `json:"os" validate:"required"` Browser string `json:"browser" validate:"required"` FullVersion string `json:"fullVersion" validate:"required"` MajorVersion string `json:"majorVersion" validate:"required"` AppName string `json:"appName" validate:"required"` UserAgent string `json:"userAgent" validate:"required"` } type TwilioResponse struct { SMSMessage SMSMessage `xml:"SMSMessage"` } type SMSMessage struct { Sid string `xml:"Sid"` AccountSid string `xml:"AccountSid"` From string `xml:"From"` To string `xml:"To"` DateCreated string `xml:"DateCreated"` DateUpdated string `xml:"DateUpdated"` Status string `xml:"Status"` DetailedStatus string `xml:"DetailedStatus"` } type Nominee struct { NomineeID int64 `json:"nominee_id,omitempty"` Name string `json:"name" validate:"required"` Address string `json:"address" validate:"required"` DOB string `json:"dob" validate:"required"` Relation string `json:"relation" validate:"required"` AuthID string `json:"auth,omitempty"` } func (manager OTPManagerTable) GenerateOTP() (OTPManagerDataResult, error) { /* otpManagerDataResult, err := isRegistered(manager, tx) if err != nil { return otpManagerDataResult, err } */ var otpManagerDataResult OTPManagerDataResult if len(manager.Data.Phone) != 10 { return otpManagerDataResult, errors.New("Phone number invalid") } OTPManagerDataResult, err := sendOTP(manager) if err != nil { return OTPManagerDataResult, err } return OTPManagerDataResult, nil } func (manager OTPManagerTable) VerifyOTP() (OTPManagerDataResult, error) { var otpManagerDataResult OTPManagerDataResult if len(strconv.Itoa(manager.Data.OTP)) != 6 { return otpManagerDataResult, errors.New("Invalid OTP entered") } if len(manager.Data.Phone) != 10 { return otpManagerDataResult, errors.New("Phone number invalid") } /* otpManagerDataResult, err = isRegistered(manager, tx) if err != nil { return otpManagerDataResult, err } manager.Result.ID = otpManagerDataResult.ID */ tx, ctx, db := connection.Connect() log.Print("isValidOTP") otpManagerDataResult, err := isValidOTP(manager, tx, ctx) if err != nil { connection.Close(tx, db) return otpManagerDataResult, err } log.Print("isRegistered") var referredBy string otpManagerDataResult, referredBy, err = isRegistered(manager, tx, ctx) if err != nil { otpManagerDataResult, err = registerUser(manager, tx, ctx) if err != nil { tx.Rollback() return otpManagerDataResult, err } //return otpManagerDataResult, nil if len(referredBy) == 0 { updateUser(manager.Data.ReferredBy, otpManagerDataResult.ID, tx, ctx) } } connection.Close(tx, db) otpManagerDataResult.Token = JWT.Token(otpManagerDataResult.ID) return otpManagerDataResult, nil } func registerUser(manager OTPManagerTable, tx *sql.Tx, ctx context.Context) (OTPManagerDataResult, error) { dt := getDate() res, err := tx.ExecContext(ctx, "INSERT INTO users (mobile_number, user_type, referral_code, created_at) VALUES (?, ?, ?, ?)", manager.Data.Phone, manager.Data.Type, generateReferralCode(), dt.Format("2006-01-02 15:04:05")) var otpManagerDataResult OTPManagerDataResult if err != nil { log.Print(err.Error()) return otpManagerDataResult, errors.New("Not able to register the user") } user_id, err := res.LastInsertId() if err != nil { return otpManagerDataResult, errors.New("Not able to register the user") } otpManagerDataResult.ID = int(user_id) return otpManagerDataResult, nil } func sendOTP(manager OTPManagerTable) (OTPManagerDataResult, error) { dt := getDate() var otpManagerDataResult OTPManagerDataResult otpManagerDataResult.Sent = 0 otp, err := GetOTP(6) //log.Print(len(otp)) if err != nil || len(otp) != 6 { return otpManagerDataResult, errors.New("Not able to generate OTP") } tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, "INSERT INTO otp_manager (mobile_number, otp, created_at) VALUES (?, ?, ?)", manager.Data.Phone, otp, dt.Format("2006-01-02 15:04:05")) if err != nil { log.Print(err.Error()) tx.Rollback() return otpManagerDataResult, errors.New("Not able to pass generate OTP service") } otp_manager_id, err := res.LastInsertId() if err != nil { tx.Rollback() return otpManagerDataResult, errors.New("Not able to pass generate OTP service") } if otpInt, err := strconv.Atoi(otp); err == nil { manager.Data.OTP = otpInt } triggerOTP(manager, tx) connection.Close(tx, db) otpManagerDataResult.Sent = otp_manager_id return otpManagerDataResult, nil } func isRegistered(manager OTPManagerTable, tx *sql.Tx, ctx context.Context) (OTPManagerDataResult, string, error) { row := tx.QueryRow("select id, COALESCE(referred_by, '') from users where mobile_number = ? and user_type = ? limit 1", manager.Data.Phone, manager.Data.Type) var otpManagerDataResult OTPManagerDataResult var referredBy string err := row.Scan(&otpManagerDataResult.ID, &referredBy) if err != nil { log.Print(err.Error()) return otpManagerDataResult, referredBy, errors.New("User isn`t registered") } if otpManagerDataResult.ID == 0 { return otpManagerDataResult, referredBy, errors.New("User isn`t registered") } return otpManagerDataResult, referredBy, nil } func updateUser(referredBy string, ID int, tx *sql.Tx, ctx context.Context) { _, err := tx.ExecContext(ctx, fmt.Sprint("UPDATE users SET referred_by = ? where id = ? and deleted_at is null"), referredBy, ID) if err != nil { log.Print(err.Error()) } } func isValidOTP(manager OTPManagerTable, tx *sql.Tx, ctx context.Context) (OTPManagerDataResult, error) { if (manager.Data.Phone == "9833780136" || manager.Data.Phone == "1876543210" || manager.Data.Phone == "2876543210" || manager.Data.Phone == "3876543210" || manager.Data.Phone == "4876543210" || manager.Data.Phone == "4876543211" || manager.Data.Phone == "4876543212" || manager.Data.Phone == "4876543213" || manager.Data.Phone == "4876543214" || manager.Data.Phone == "4876543215" || manager.Data.Phone == "4876543216" || manager.Data.Phone == "4876543218" || manager.Data.Phone == "9131951982" || manager.Data.Phone == "9921896403") && manager.Data.OTP == 244126 { var otpManagerDataResultTest OTPManagerDataResult log.Print("Verify ByPassed") return otpManagerDataResultTest, nil } //log.Print("Run Query Data: ", manager.Data.Phone, manager.Data.OTP) row := tx.QueryRow("select id from otp_manager where mobile_number = ? and otp = ? and deleted_at is null", manager.Data.Phone, manager.Data.OTP) var otpManagerDataResult OTPManagerDataResult err := row.Scan(&otpManagerDataResult.ID) if err != nil { log.Print(err.Error()) return otpManagerDataResult, errors.New("Invalid OTP entered") } if otpManagerDataResult.ID == 0 { return otpManagerDataResult, errors.New("Invalid OTP entered") } log.Print(manager.Result.ID) //Soft Delete Verified OTP softDeleteOTP("otp_manager", manager.Data.Phone, tx, ctx) return otpManagerDataResult, nil } func softDeleteOTP(t string, i string, tx *sql.Tx, ctx context.Context) { dt := getDate() datetime := dt.Format("2006-01-02 15:04:05") res, err := tx.ExecContext(ctx, fmt.Sprint("UPDATE ", t, " SET deleted_at = ?, updated_at = ? where mobile_number = ? and deleted_at is null"), datetime, datetime, i) if err != nil { log.Print(err.Error()) } log.Print(res.RowsAffected()) } func GetOTP(max int) (string, error) { b := make([]byte, max) n, err := io.ReadAtLeast(rand.Reader, b, max) if n != max { log.Print(err) } for i := 0; i < len(b); i++ { b[i] = table[int(b[i])%len(table)] } return string(b), nil } func GetOTP1(length int) (string, error) { buffer := make([]byte, length) _, err := rand.Read(buffer) if err != nil { return "", err } otpCharsLength := len(otpChars) for i := 0; i < length; i++ { buffer[i] = otpChars[int(buffer[i])%otpCharsLength] } return string(buffer), nil } func isUserUpdated(manager User, tx *sql.Tx) (UserDataResult, error) { row := tx.QueryRow("select id from users where id = ? and first_name is not null", manager.Auth.ID) var userDataResult UserDataResult err := row.Scan(&userDataResult.ID) if err != nil && err != sql.ErrNoRows { log.Print(err.Error()) return userDataResult, errors.New("User already updated") } if userDataResult.ID != 0 { return userDataResult, errors.New("User already updated") } return userDataResult, nil } func (manager User) CreateUser() (UserDataResult, error) { dt := getDate() var userDataResult UserDataResult tx, ctx, db := connection.Connect() isUserAlreadyUpdated, errCheck := isUserUpdated(manager, tx) if errCheck != nil { log.Print("user already updated") tx.Rollback() return isUserAlreadyUpdated, errCheck } res, err := tx.ExecContext(ctx, "UPDATE users SET first_name = ?, middle_name = ?, last_name = ?, dob = ?, email = ?, pan = ?, gender = ?, aadhaar = ?, created_at = ? Where id = ?", manager.Data.FirstName, manager.Data.MiddleName, manager.Data.LastName, manager.Data.DOB, manager.Data.Email, manager.Data.PAN, manager.Data.Gender, manager.Data.Aadhaar, dt.Format("2006-01-02 15:04:05"), manager.Auth.ID) if err != nil { log.Print(err.Error()) tx.Rollback() return userDataResult, errors.New("Not able to create user") } user_id, err := res.LastInsertId() if err != nil { tx.Rollback() return userDataResult, errors.New("Not able to create user") } userDataResult.ID = user_id connection.Close(tx, db) return userDataResult, nil } func (manager UserSignAgreement) EsignAgreement() (UserSignAgreementDataResult, error) { dt := getDate() var userSignAgreementDataResult UserSignAgreementDataResult tx, ctx, db := connection.Connect() _, err := isAgreementAlreadySigned(manager, tx) if err != nil { log.Print(err.Error()) tx.Rollback() return userSignAgreementDataResult, err } res, err := tx.ExecContext(ctx, "INSERT INTO digital_sign_details (user_id, user_type, load_time, click_time, language, ip_address, latitude, longitude, isagreementsigned, client, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", manager.Auth.ID, manager.Data.Type, manager.Data.LoadTime, manager.Data.ClickTime, "ENGLISH", manager.Data.IPAddress, manager.Data.Latitude, manager.Data.Longitude, manager.Data.IsAgreementSigned, getStructToJsonString(manager.Data.GetClientInfo), dt.Format("2006-01-02 15:04:05")) if err != nil { tx.Rollback() log.Print(err.Error()) return userSignAgreementDataResult, errors.New("Failed to execute the query") } user_sign_agreement_id, err := res.LastInsertId() if err != nil { tx.Rollback() return userSignAgreementDataResult, errors.New("Not able to create agreement data") } userSignAgreementDataResult.ID = user_sign_agreement_id err, file := uploadAgreement(manager) if err != nil { log.Error().Err(err).Msg(err.Error()) } log.Print("SendSignAgreement") SendSignAgreement(tx, manager.Auth.ID, manager.Data.Name, file) connection.Close(tx, db) return userSignAgreementDataResult, nil } func getEmail(ID string, tx *sql.Tx) (string, error) { row := tx.QueryRow("select email from users where id = ? and email is not null", ID) var email string err := row.Scan(&email) if err != nil && err != sql.ErrNoRows { log.Print(err.Error()) return "", err } return email, nil } func SendSignAgreement(tx *sql.Tx, Id string, name string, file string) { email, errMessage := getEmail(Id, tx) if errMessage == nil { HtmlBody := "
\n
\n\n
\n\n\n\n\n\n\n
\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n
\n\n\n\n\n\n\n
\n\n
\n
\n
\nDear " + name + ",

\nWelcome to the Credit Fair Capital . Thank you for signing up. We have over 30 years of experience managing finance for investors and institutions like IDFC First, ABFL, Avanse, Northern Arc, etc. Our goal is to be the most trusted platform for investors with a smooth onboarding process and transparency.

\nWith a range of investment products that provide fixed interest ranging from 9% to 11%, you could choose from a variety of investment options. You can login at Login. Please find attached the signed agreement.

\nWe are just a click away if you ever need assistance. With us, we hope to provide you with the best experience possible.

\nThe Credit Fair Capital team is happy to have you on board.
\n
\n
\n Regards,
\n Team Credit Fair Capital
\n info@creditfaircapital.in
\n +91-8097400463

\n

Disclaimer: This message (including any attachments) may contain\n confidential, proprietary, privileged and/or private information. The information is intended for the use only\n to whom they are addressed. If you are not the intended recipient of this message, please notify the sender\n immediately, and delete the message and any attachments. Any disclosure, reproduction, distribution or other use\n of this message or any attachments by an individual or entity other than the intended recipient is prohibited.We\n do not guarantee the security of any information transmitted through email and, are not liable for any\n interception, corruption or delays. Anyone communicating with us by email accepts the risks and\n consequences.\n

\n
\n \n
\n
\n
\n
\n

\n
\n
\n
\n
\n
" log.Print("trigger email - Sign Agreement") attachment := map[string]string{"File": file, "FileName": "Signed Agreement.pdf"} _, err := mail.EmailAttachment(email, HtmlBody, fmt.Sprint("Sign Agreement"), attachment) if err != nil { log.Print("trigger email error - Sign Agreement") log.Print(err.Error()) } }else{ log.Print("email not found - Sign Agreement") } } func uploadAgreement(manager UserSignAgreement) (error, string) { dt := getDate() var documentUploadDataResult DocumentUploadDataResult path := fmt.Sprint("/capital/", manager.Auth.ID, "/ifa_esigned_agreement.pdf") pdfString, _ := pdf.ToPDF(manager.Data.Name) _, err := aws.Upload(pdfString, path) if err != nil { log.Error().Err(err).Msg(err.Error()) return errors.New("s3: Failed to upload document"), "" } tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, "INSERT INTO documents (user_id, name, path, created_at) VALUES (?, ?, ?, ?)", manager.Auth.ID, "ifa_esigned_agreement", path, dt.Format("2006-01-02 15:04:05")) if err != nil { log.Error().Err(err).Msg(err.Error()) tx.Rollback() return errors.New("Failed to execute the query"), "" } document_id, err := res.LastInsertId() if err != nil { log.Error().Err(err).Msg(err.Error()) tx.Rollback() return errors.New("Not able to create document data"), "" } documentUploadDataResult.ID = document_id connection.Close(tx, db) return nil, pdfString } func getUploadedDocument(file string) string { resp, err := aws.Get(file) if err != nil { log.Error().Err(err).Msg("s3: Failed to get document") } return resp } func (manager DocumentUpload) UploadDocument() (DocumentUploadDataResult, error) { dt := getDate() var documentUploadDataResult DocumentUploadDataResult path := fmt.Sprint("/capital/", manager.Auth.ID, "/", strings.ToLower(manager.Data.DocName), ".", strings.ToLower(manager.Data.DocFormat)) _, err := aws.Upload(manager.Data.DocContent, path) if err != nil { return documentUploadDataResult, errors.New("s3: Failed to upload document") } tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, "INSERT INTO documents (user_id, name, path, created_at) VALUES (?, ?, ?, ?)", manager.Auth.ID, manager.Data.DocName, path, dt.Format("2006-01-02 15:04:05")) if err != nil { log.Print(err.Error()) tx.Rollback() return documentUploadDataResult, errors.New("Failed to execute the query") } document_id, err := res.LastInsertId() if err != nil { log.Print(err.Error()) tx.Rollback() return documentUploadDataResult, errors.New("Not able to create document data") } documentUploadDataResult.ID = document_id connection.Close(tx, db) return documentUploadDataResult, nil } func (manager Bank) GetBank() ([]BankData, error) { tx, _, db := connection.Connect() bankDetails, errCheck := getBank(manager, tx) if errCheck != nil { log.Print(errCheck.Error()) connection.Close(tx, db) return bankDetails, errCheck } /*if len(bankDetails.Data.AccountHolder) == 0 { log.Print("bank not added!") connection.Close(tx, db) return bank, errors.New("bank not added") }*/ connection.Close(tx, db) return bankDetails, nil } func (manager Bank) AddBank() (BankDataResult, error) { dt := getDate() var bankDataResult BankDataResult tx, ctx, db := connection.Connect() log.Print("isBankAlreadyUpdated") lendboxUpdated, errMessage := isBankAlreadyUpdated(manager.Auth.ID, tx) log.Print("leave isBankAlreadyUpdated") if errMessage != nil { log.Print("errMessage: ", errMessage) tx.Rollback() return bankDataResult, errors.New("Bank already updated") } if manager.Data.AccountType == "SA" { manager.Data.AccountType = "savings" } else if manager.Data.AccountType == "CA" { manager.Data.AccountType = "current" } if lendboxUpdated == 0 { res, err := tx.ExecContext(ctx, "INSERT INTO bank_details (user_id, account_holder_name, bank_name, ifsc_code, account_number, account_type, branch_name, dp_name, depository, bo_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", manager.Auth.ID, manager.Data.AccountHolder, manager.Data.BankName, manager.Data.BankIfsc, manager.Data.AccountNumber, NewNullString(manager.Data.AccountType), NewNullString(manager.Data.BranchName), NewNullString(manager.Data.DpName), NewNullString(manager.Data.Depository), NewNullString(manager.Data.BoId), dt.Format("2006-01-02 15:04:05")) if err != nil { log.Print(err.Error()) tx.Rollback() return bankDataResult, errors.New("Failed to execute the query") } bank_id, err := res.LastInsertId() if err != nil { tx.Rollback() return bankDataResult, errors.New("Not able to create bank data") } bankDataResult.ID = bank_id } else { res, err := tx.ExecContext(ctx, fmt.Sprint("UPDATE bank_details SET account_holder_name = ?, bank_name = ?, ifsc_code = ?, account_number = ?, account_type = ?, branch_name = ?, dp_name = ?, depository = ?, bo_id = ?, updated_at = ? where user_id = ? and deleted_at is null"), manager.Data.AccountHolder, manager.Data.BankName, manager.Data.BankIfsc, manager.Data.AccountNumber, NewNullString(manager.Data.AccountType), NewNullString(manager.Data.BranchName), NewNullString(manager.Data.DpName), NewNullString(manager.Data.Depository), NewNullString(manager.Data.BoId), dt.Format("2006-01-02 15:04:05"), manager.Auth.ID) if err != nil { log.Print(err.Error()) tx.Rollback() return bankDataResult, errors.New("Failed to execute the statement") } log.Print(res.RowsAffected()) bankDataResult.ID = lendboxUpdated } connection.Close(tx, db) return bankDataResult, nil } func (manager Bank) UpdateBankDetailsLendboxFlag() error { dt := getDate() tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, fmt.Sprint("UPDATE bank_details SET lendbox_updated = ?, updated_at = ? where user_id = ? and deleted_at is null"), 1, dt.Format("2006-01-02 15:04:05"), manager.Auth.ID) if err != nil { log.Print(err.Error()) tx.Rollback() return errors.New("Failed to execute the statement") } log.Print(res.RowsAffected()) connection.Close(tx, db) return nil } func (manager UpdateAddress) UpdateAddress() (UpdateAddressDataResult, error) { dt := getDate() var updateAddressDataResult UpdateAddressDataResult tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, fmt.Sprint("UPDATE users SET address = ?, pincode = ?, city = ?, state = ?, updated_at = ? where id = ? and deleted_at is null"), manager.Data.Address, manager.Data.Pincode, manager.Data.City, manager.Data.State, dt.Format("2006-01-02 15:04:05"), manager.Auth.ID) if err != nil { log.Print(err.Error()) tx.Rollback() return updateAddressDataResult, errors.New("Failed to execute the query") } log.Print(res.RowsAffected()) connection.Close(tx, db) return updateAddressDataResult, nil } func isBankAlreadyUpdated(AuthID string, tx *sql.Tx) (int64, error) { row := tx.QueryRow("select id, COALESCE(lendbox_updated, 0) as lendbox_updated from bank_details where user_id = ?", AuthID) var ID int64 var lendboxUpdated int64 err := row.Scan(&ID, &lendboxUpdated) if err == sql.ErrNoRows { return 0, nil } if err != nil { log.Print(err.Error()) return 0, errors.New("Unable to update bank") } log.Print("Bank ID:", ID) if ID != 0 && lendboxUpdated == 1 { return 0, errors.New("Unable to update bank") } log.Print("ID", ID) log.Print("lendboxUpdated", lendboxUpdated) return ID, nil } func isPANValidated(manager ValidatePANDetails, tx *sql.Tx) (ValidatePANDataResult, error, bool) { log.Print("Auth ID", manager.Auth.ID) row := tx.QueryRow("select id, response from pan_validation_logs where user_id = ? order by id desc", manager.Auth.ID) var validatePANDataResult ValidatePANDataResult var panJsonLog string var ID int64 err := row.Scan(&ID, &panJsonLog) if err == sql.ErrNoRows { return validatePANDataResult, nil, true } if err != nil { log.Print(err.Error()) return validatePANDataResult, err, false } if ID != 0 { err = json.Unmarshal([]byte(panJsonLog), &validatePANDataResult) if err != nil { log.Print(err.Error()) return validatePANDataResult, err, false } result := splitName(validatePANDataResult.FullName) validatePANDataResult.FirstName = result.FirstName validatePANDataResult.MiddleName = result.MiddleName validatePANDataResult.LastName = result.LastName validatePANDataResult.FullName = "" log.Print(validatePANDataResult) return validatePANDataResult, errors.New("PAN already validated"), true } return validatePANDataResult, nil, true } func (manager ValidatePANDetails) ValidatePAN() (ValidatePANDataResult, error, bool) { tx, _, db := connection.Connect() log.Print("calling isPANValidated") validatePANDataResult, err, boolV := isPANValidated(manager, tx) if err != nil { connection.Close(tx, db) return validatePANDataResult, err, boolV } log.Print("calling validatePAN") validatePANDataResult, err = validatePAN(manager, tx) if err != nil { connection.Close(tx, db) return validatePANDataResult, err, false } connection.Close(tx, db) return validatePANDataResult, nil, true } func validatePAN(manager ValidatePANDetails, tx *sql.Tx) (ValidatePANDataResult, error) { var validatePANDataResult ValidatePANDataResult /*body := []byte("{\"full_name\":\"SUNIL KHORWAL\",\"category\":\"Individual\",\"pan\":\"DXGPK5946H\",\"status\":\"VALID\"}") if manager.Data.PAN != "AAAAA0000A" {*/ //We will add this secret key in env os.Setenv("DIGIO_SECRET_KEY", "QUlMSkFSUDFaS0YxN0dPTlZCNTlHQTFPTVZHRTNSNUk6WkJFSkFKTTQ3RDk5STdTSUFVUVUzVEY5WEQ0TTZMU0s=") client := &http.Client{ Timeout: time.Second * 10, } postBody, _ := json.Marshal(map[string]string{"id_no": manager.Data.PAN}) responseBody := bytes.NewBuffer(postBody) req, err := http.NewRequest("POST", "https://api.digio.in/v3/client/kyc/fetch_id_data/PAN", responseBody) if err != nil { return validatePANDataResult, err } req.Header.Add("Content-Type", "application/json") req.Header.Add("authorization", fmt.Sprint("Basic ", os.Getenv("DIGIO_SECRET_KEY"))) response, err := client.Do(req) if err != nil { return validatePANDataResult, err } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { log.Print(err.Error()) return validatePANDataResult, err } err = json.Unmarshal(body, &validatePANDataResult) if err != nil { log.Print(err.Error()) return validatePANDataResult, err } /*} else { log.Print("Dummy PAN") err := json.Unmarshal(body, &validatePANDataResult) if err != nil { log.Print(err.Error()) return validatePANDataResult, err } log.Print("Dummy PAN Status", validatePANDataResult.Status) }*/ panStatus := validatePANDataResult.Status result := splitName(validatePANDataResult.FullName) validatePANDataResult.FirstName = result.FirstName validatePANDataResult.MiddleName = result.MiddleName validatePANDataResult.LastName = result.LastName validatePANDataResult.FullName = "" err = saveValidationLogs(manager, string(body)) if err != nil { return validatePANDataResult, err } if panStatus == "INVALID" { return validatePANDataResult, errors.New("Invalid PAN Number") } return validatePANDataResult, nil } func saveValidationLogs(manager ValidatePANDetails, logs string) error { dt := getDate() tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, "INSERT INTO pan_validation_logs (user_id, response, created_at) VALUES (?, ?, ?)", manager.Auth.ID, logs, dt.Format("2006-01-02 15:04:05")) if err != nil { log.Print(err.Error()) tx.Rollback() return errors.New("Failed to execute the query") } pan_log_id, err := res.LastInsertId() if err != nil { tx.Rollback() return errors.New("Not able to create pan validation logs data") } log.Print("pan_log_id") log.Print(pan_log_id) connection.Close(tx, db) return nil } func splitName(name string) ValidatePANDataResult { var validatePANDataResult ValidatePANDataResult explodedName := strings.Split(name, " ") if len(explodedName) == 2 { validatePANDataResult.FirstName = explodedName[0] validatePANDataResult.LastName = explodedName[1] } else if len(explodedName) > 2 { validatePANDataResult.FirstName = explodedName[0] validatePANDataResult.MiddleName = explodedName[1] validatePANDataResult.LastName = explodedName[2] } else if len(explodedName) == 1 { validatePANDataResult.FirstName = explodedName[0] } return validatePANDataResult } func (manager MakeTransaction) MakeTransaction() (MakeTransactionDataResult, error) { dt := getDate() var makeTransactionDataResult MakeTransactionDataResult tx, ctx, db := connection.Connect() res, err := tx.ExecContext(ctx, "INSERT INTO transaction_log (user_id, type, ncd_sold_date, ncd_sold_count, created_at) VALUES (?, ?, ?, ?, ?)", manager.Auth.ID, manager.Data.TransactionType, dt.Format("2006-01-02 15:04:05"), NewNullString(fmt.Sprint(manager.Data.Quantity)), dt.Format("2006-01-02 15:04:05")) if err != nil { log.Print(err.Error()) tx.Rollback() return makeTransactionDataResult, errors.New("Failed to execute the query") } bank_id, err := res.LastInsertId() if err != nil { tx.Rollback() return makeTransactionDataResult, errors.New("Not able to create transaction logs data") } makeTransactionDataResult.ID = bank_id connection.Close(tx, db) return makeTransactionDataResult, nil } func (manager PincodeDetails) GetPincodeDetails() (PincodeDetailsDataResult, error) { tx, _, db := connection.Connect() pincodeDetailsDataResult, err := getPincodeData(manager, tx) if err != nil { tx.Rollback() return pincodeDetailsDataResult, err } connection.Close(tx, db) return pincodeDetailsDataResult, nil } func (manager Nominee) AddNominee() (Nominee, error) { tx, ctx, db := connection.Connect() dt := getDate() var nominee Nominee nomineeDetails, errCheck := getNominee(manager, tx) if errCheck != nil && errCheck.Error() != "Nominee is not added" { tx.Rollback() log.Print(errCheck.Error()) connection.Close(tx, db) return nominee, errCheck } if nomineeDetails.NomineeID > 0 { log.Print("Nominee already added!") connection.Close(tx, db) return nominee, errors.New("Nominee already added!") } res, err := tx.ExecContext(ctx, "INSERT INTO nominee (investor_id, name, address, dob, relation, created_at) VALUES (?, ?, ?, ?, ?, ?)", manager.AuthID, manager.Name, manager.Address, manager.DOB, manager.Relation, dt.Format("2006-01-02 15:04:05")) if err != nil { tx.Rollback() log.Print(err.Error()) return nominee, errors.New("Not able to add the nominee") } nomineeID, err := res.LastInsertId() if err != nil { tx.Rollback() return nominee, errors.New("Not able to add the nominee") } nominee.NomineeID = nomineeID connection.Close(tx, db) return nominee, nil } func getBank(manager Bank, tx *sql.Tx) ([]BankData, error) { res, err := tx.Query("select id, COALESCE(account_holder_name, ''), COALESCE(bank_name, ''), COALESCE(ifsc_code, ''), COALESCE(account_number, ''), COALESCE(account_type, ''), COALESCE(branch_name, '') from bank_details where user_id = ?", manager.Auth.ID) var bankItem []BankData for res.Next() { var bank BankData err = res.Scan(&bank.BankId, &bank.AccountHolder, &bank.BankName, &bank.BankIfsc, &bank.AccountNumber, &bank.AccountType, &bank.BranchName) if err != nil && err != sql.ErrNoRows { log.Error().Err(err).Msg(err.Error()) return bankItem, errors.New("Not able to fetch the bank details") } bankItem = append(bankItem, bank) } if len(bankItem) == 0 { log.Print("bank not added") return bankItem, errors.New("Bank is not added") } log.Print("Bank", bankItem) return bankItem, nil } func getNominee(manager Nominee, tx *sql.Tx) (Nominee, error) { row := tx.QueryRow("select nominee_id, name, address, DATE_FORMAT(dob, '%Y-%m-%d') as dob, CONCAT(UCASE(LEFT(relation, 1)), LCASE(SUBSTRING(relation, 2))) as relation from nominee where investor_id = ?", manager.AuthID) var nominee Nominee err := row.Scan(&nominee.NomineeID, &nominee.Name, &nominee.Address, &nominee.DOB, &nominee.Relation) if err != nil && err != sql.ErrNoRows { log.Print(err.Error()) return nominee, errors.New("Not able to fetch the nominee details") } if nominee.NomineeID == 0 { log.Print("Nominee not added") return nominee, errors.New("Nominee is not added") } log.Print("Nominee", nominee) return nominee, nil } func (manager Nominee) GetNominee() (Nominee, error) { tx, _, db := connection.Connect() var nominee Nominee nomineeDetails, errCheck := getNominee(manager, tx) if errCheck != nil { log.Print(errCheck.Error()) connection.Close(tx, db) return nominee, errCheck } if nomineeDetails.NomineeID == 0 { log.Print("Nominee not added!") connection.Close(tx, db) return nominee, errors.New("Nominee not added") } connection.Close(tx, db) return nomineeDetails, nil } func getPincodeData(manager PincodeDetails, tx *sql.Tx) (PincodeDetailsDataResult, error) { row := tx.QueryRow("select id, district as city, state from pincode where pincode = ?", manager.Data.Pincode) var pincodeDetailsDataResult PincodeDetailsDataResult err := row.Scan(&pincodeDetailsDataResult.ID, &pincodeDetailsDataResult.City, &pincodeDetailsDataResult.State) if err != nil { log.Print(err.Error()) return pincodeDetailsDataResult, errors.New("Not able to fetch the pincode details") } if pincodeDetailsDataResult.ID == 0 { return pincodeDetailsDataResult, errors.New("Not able to fetch the pincode details") } log.Print(manager.Result.ID) return pincodeDetailsDataResult, nil } func (manager UserDetails) GetUser(ID string) (UserDetails, error) { tx, _, db := connection.Connect() var userDetails UserDetails // Get Customer Details row := tx.QueryRow("select COALESCE(ua.first_name, ''), COALESCE(ua.middle_name, ''), COALESCE(ua.last_name, ''), COALESCE(ua.email, ''), COALESCE(ua.mobile_number, ''), COALESCE(ua.gender, ''), COALESCE(ua.pan, ''), COALESCE(ua.aadhaar, ''), COALESCE(ua.dob, ''), COALESCE(ua.address, ''), COALESCE(ua.pincode, ''), COALESCE(ua.city, ''), COALESCE(ua.state, ''), (select COALESCE(CONCAT(COALESCE(first_name, ''), ' ', COALESCE(middle_name, ''), ' ', COALESCE(last_name, '')), '') from creditcapital.users where referral_code = ua.referred_by limit 1) as referred_by from creditcapital.users as ua where ua.id = ?", ID) var referredBy sql.NullString err := row.Scan(&userDetails.PersonalDetails.FirstName, &userDetails.PersonalDetails.MiddleName, &userDetails.PersonalDetails.LastName, &userDetails.PersonalDetails.Email, &userDetails.PersonalDetails.Phone, &userDetails.PersonalDetails.Gender, &userDetails.PersonalDetails.PanNumber, &userDetails.PersonalDetails.Aadhaar, &userDetails.PersonalDetails.DOB, &userDetails.Address.Address, &userDetails.Address.Pincode, &userDetails.Address.City, &userDetails.Address.State, &referredBy) if err != nil { log.Print(err.Error()) tx.Rollback() return userDetails, errors.New("Not able to fetch the user details") } userDetails.PersonalDetails.ReferredBy = strings.TrimSpace(referredBy.String) if len(userDetails.PersonalDetails.Aadhaar) > 0 { userDetails.PersonalDetails.Aadhaar = aes.DecryptData(userDetails.PersonalDetails.Aadhaar) } // Get Customer Bank Details row = tx.QueryRow("select COALESCE(account_holder_name, ''), COALESCE(bank_name, ''), COALESCE(ifsc_code, ''), COALESCE(account_number, ''), COALESCE(account_type, ''), COALESCE(dp_name, ''), COALESCE(depository, ''), COALESCE(bo_id, '') from bank_details where user_id = ?", ID) err = row.Scan(&userDetails.BankDetails.AccountHolder, &userDetails.BankDetails.BankName, &userDetails.BankDetails.BankIfsc, &userDetails.BankDetails.AccountNumber, &userDetails.BankDetails.AccountType, &userDetails.BankDetails.DpName, &userDetails.BankDetails.Depository, &userDetails.BankDetails.BoId) if err != nil { //connection.Close(tx, db) log.Print(err.Error()) } // Get Customer Agreement Details row = tx.QueryRow("select COALESCE(path, '') from documents where user_id = ? and name='ifa_esigned_agreement' order by created_at desc limit 1", ID) err = row.Scan(&userDetails.SignedAgreement.URL) if err != nil { log.Error().Err(err).Msg(err.Error()) } else if len(userDetails.SignedAgreement.URL) > 0 { //Get Base64encoded string userDetails.SignedAgreement.URL = getUploadedDocument(userDetails.SignedAgreement.URL) } // Get Customer Documents Details res, err := tx.Query("select COALESCE(name, ''), COALESCE(path, '') from documents where user_id = ?", ID) for res.Next() { var documents documents err = res.Scan(&documents.Name, &documents.Path) if err != nil { tx.Rollback() log.Print(err.Error()) return userDetails, nil } userDetails.Documents = append(userDetails.Documents, documents) } connection.Close(tx, db) return userDetails, nil } func isAgreementAlreadySigned(manager UserSignAgreement, tx *sql.Tx) (UserSignAgreementDataResult, error) { row := tx.QueryRow("select id from digital_sign_details where user_id = ?", manager.Auth.ID) var userSignAgreementDataResult UserSignAgreementDataResult err := row.Scan(&userSignAgreementDataResult.ID) if err == sql.ErrNoRows { return userSignAgreementDataResult, nil } if err != nil { return userSignAgreementDataResult, errors.New("Agreement already signed") } if userSignAgreementDataResult.ID != 0 { return userSignAgreementDataResult, errors.New("Agreement already signed") } return userSignAgreementDataResult, nil } func triggerOTP(manager OTPManagerTable, tx *sql.Tx) (string, error) { url := "https://d6ec9bd6c3c1ad0ed21992e8489260a6e188c1b91f2fbef1:eb94ec99984c63dd07a92e270b784bca2100ebe51692984e@api.exotel.com/v1/Accounts/kmgobalcredit1/Sms/send" payload := strings.NewReader(fmt.Sprint("From=KMCRED&To=91", manager.Data.Phone, "&Body=Your%20Credit%20Fair%20Capital%20verification%20code%20is%20", manager.Data.OTP, "%0ABest%20Regards%2C%0ATeam%20Credit%20Fair%20Capital&DltEntityId=1301159108481756475&DltTemplateId=1307166850873150723&SmsType=transactional")) client := &http.Client{} req, err := http.NewRequest("POST", url, payload) if err != nil { log.Print(err) return "", err } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") res, err := client.Do(req) if err != nil { log.Print(err) return "", err } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { log.Print(err) return "", err } log.Print(string(body)) //byteValue, _ := ioutil.ReadAll(xmlFile) // we initialize our Users array var twilioResponse TwilioResponse // we unmarshal our byteArray which contains our // xmlFiles content into 'results' which we defined above err = xml.Unmarshal(body, &twilioResponse) if err != nil { log.Print(err) } //log.Print(results.ADDRESSValue) log.Print(twilioResponse.SMSMessage.DetailedStatus) return string(body), nil } func getStructToJsonString(lists interface{}) string { jsonLists, err := json.Marshal(lists) if err != nil { fmt.Printf("Error: %s", err.Error()) } return string(jsonLists) } func NewNullString(s string) sql.NullString { if len(s) == 0 { return sql.NullString{} } return sql.NullString{ String: s, Valid: true, } } func getDate() time.Time { loc, _ := time.LoadLocation("Asia/Kolkata") dt := time.Now().In(loc) return dt } func generateReferralCode() string { var code string for ok := ""; ok == ""; ok = code { code = getCode() print(code) } return code } func getCode() string { ll := len(chars) b := make([]byte, 6) _, err := rand.Read(b) if err != nil { return "" } // generates len(b) random bytes for i := 0; i < 6; i++ { b[i] = chars[int(b[i])%ll] } return string(b) }