package transabsensi import ( "encoding/base64" "errors" "fmt" "log" "os" "strconv" "strings" "time" "com.sismedika.com.absensi/graph/model" "com.sismedika.com.absensi/pkg/config" db "com.sismedika.com.absensi/pkg/database" ) // diambil dari graph/model/struct nya TransAbsensiResponse type TransAbsensiCheckDistanceResponse model.TransAbsensiCheckDistanceResponse type TransAbsensiResponse model.TransAbsensiResponse // fungsi untuk Check Distance antara kantor dengan current user location func (transabsensi *TransAbsensiCheckDistanceResponse) CheckDistance(M_StaffID string, M_CompanyID string, CurrentLatitude string, CurrentLongitude string) (*model.TransAbsensiCheckDistanceResponse, error) { // inisialisasi var err error var ret model.TransAbsensiCheckDistanceResponse var rMaxDistance int var rCurrentDistance float64 var rMCompanyLongitude string var rMCompanyLatitude string var statusCheck string q := `SELECT M_CompanyLatitude, M_CompanyLongitude, M_CompanyMaxDistance FROM m_company WHERE M_CompanyIsActive = 'Y' AND M_CompanyID = ?` row := db.Handle.QueryRow( q, M_CompanyID) db.LogSQL(q) err = row.Scan( &rMCompanyLatitude, &rMCompanyLongitude, &rMaxDistance, ) if err != nil { log.Printf("Error m_company select max distance: %v", err) log.Printf("Executing query: %s\n", q) return nil, err } // get distance qCurrentDistance := `SELECT distance_v2(?, ?, ?, ?)` rowxCurrentDistance := db.Handle.QueryRow( qCurrentDistance, CurrentLatitude, CurrentLongitude, rMCompanyLatitude, rMCompanyLongitude, ) db.LogSQL(qCurrentDistance) err = rowxCurrentDistance.Scan( &rCurrentDistance, ) if err != nil { log.Printf("Error m_staff select: %v", err) log.Printf("Executing query: %s\n", qCurrentDistance) return nil, err } // check distance qCheckDistance := `SELECT IF(distance_v2(?, ?, ?, ?) < ?, 'range', 'not range') AS distance_status` rowx := db.Handle.QueryRow( qCheckDistance, CurrentLatitude, CurrentLongitude, rMCompanyLatitude, rMCompanyLongitude, rMaxDistance, ) db.LogSQL(qCheckDistance) err = rowx.Scan( &statusCheck, ) if err != nil { log.Printf("Error m_staff select: %v", err) log.Printf("Executing query: %s\n", qCheckDistance) return nil, err } if statusCheck == "range" { // buat di set isi nya kosong dulu ret.Status = new(string) ret.Message = new(string) ret.Selfie = new(string) ret.CurrentDistance = new(string) ret.MaxDistance = new(string) ret.Unit = new(string) // di set kan langsung dengan * atau pointer *ret.Status = "OK" *ret.Selfie = "FALSE" *ret.Unit = "m" *ret.CurrentDistance = strconv.FormatFloat(rCurrentDistance, 'f', -1, 64) *ret.MaxDistance = strconv.Itoa(rMaxDistance) *ret.Message = "Masih dalam jarak absensi" } if statusCheck != "range" { // buat di set isi nya kosong dulu ret.Status = new(string) ret.Message = new(string) ret.Selfie = new(string) ret.CurrentDistance = new(string) ret.MaxDistance = new(string) ret.Unit = new(string) // di set kan langsung dengan * atau pointer *ret.Status = "OK" *ret.Selfie = "TRUE" *ret.Unit = "m" *ret.CurrentDistance = strconv.FormatFloat(rCurrentDistance, 'f', -1, 64) *ret.MaxDistance = strconv.Itoa(rMaxDistance) *ret.Message = "Max Distance : " + strconv.Itoa(rMaxDistance) + " meter. Current Distance: " + strconv.FormatFloat(rCurrentDistance, 'f', -1, 64) + ". Jauh dari area absensi, perlu foto selfie" } // hasil return nya return &ret, err } // fungsi untuk absen masuk clock in func (transabsensi *TransAbsensiResponse) ClockInAbsensi(T_TransactionM_StaffID string, T_TransactionM_CompanyID string, T_TransactionCurrentLatitude string, T_TransactionCurrentLongitude string, T_TransactionCurrentDistance string, T_TransactionSelfiePhoto string, token string, isSelfie string) (*model.TransAbsensiResponse, error) { // inisialisasi var err error var ret model.TransAbsensiResponse var varGetToken string var varGetM_StaffNIP string var varProsesFotoSelfie string var jamClockIn string var varFileName string // check user token qCheckTokenStaff := `SELECT M_StaffToken, LOWER(M_StaffNIP) AS M_StaffNIP FROM m_staff WHERE M_StaffIsActive = 'Y' AND M_StaffToken = ? ` rowCheckTokenStaff := db.Handle.QueryRow( qCheckTokenStaff, token, ) db.LogSQL(qCheckTokenStaff) err = rowCheckTokenStaff.Scan( &varGetToken, &varGetM_StaffNIP, ) if err != nil { log.Printf("Error m_staff select token: %v", err) log.Printf("Executing query: %s\n", qCheckTokenStaff) return nil, err } // check varGetToken jk M_StaffToken kosong if varGetToken == "" { log.Printf("Error Token Kosong, Silahkan Login Dulu: %v", err) log.Printf("Executing query: %s\n", qCheckTokenStaff) return nil, err } ret.Status = new(string) ret.Message = new(string) // lanjut proses absen if varGetToken != "" { // tanpa selfie T_TransactionSelfiePhoto di set kosong if isSelfie != "TRUE" { T_TransactionSelfiePhoto = "" varProsesFotoSelfie = "" } // selfie true if isSelfie == "TRUE" { // pecah string strToArrayFoto := strings.Split(T_TransactionSelfiePhoto, ",") // check apakah sudah sesuai apa belum if len(strToArrayFoto) == 0 { log.Printf("Eror Tidak Sesuai Format %v", err) return &ret, err } // jika sesuai ambil strToArrayFoto ke 1 atau index ke 1 if len(strToArrayFoto) > 0 { base64DataFoto := strToArrayFoto[1] T_TransactionSelfiePhoto = base64DataFoto } currentTime := time.Now() // setting jam absen jam := currentTime.Hour() menit := currentTime.Minute() detik := currentTime.Second() jamClockIn = fmt.Sprintf("%02d:%02d:%02d", jam, menit, detik) formattedTime := currentTime.Format("2006-01-02_15_04_05") // buat nama file varProsesFotoSelfie = "clockin_" + varGetM_StaffNIP + "_" + formattedTime strPhoto := varProsesFotoSelfie + ".jpg" // folder upload file nya selfie_attachment akan otomatis sesuai bulan dan tahun folderName := currentTime.Format("200601") folder := "selfie_attachment/" + folderName + "/" photoPath := config.Data.Get("document") + folder log.Printf("documentPath: %s", photoPath) // create folder selfie_attachment jika belum ada if _, err := os.Stat(photoPath); errors.Is(err, os.ErrNotExist) { err = os.MkdirAll(photoPath, os.ModePerm.Perm()) if err != nil { log.Printf("here %v", err) return &ret, err } } photoPath = photoPath + strPhoto // proses decode decodedByte, err := base64.StdEncoding.DecodeString(T_TransactionSelfiePhoto) if err != nil { log.Printf("here %v", err) return &ret, err } fs, err := os.Create(photoPath) if err != nil { log.Printf("here %v", err) return &ret, err } defer fs.Close() fs.Write(decodedByte) fs.Sync() varProsesFotoSelfie = "selfie_attachment/" + folderName + "/" + strPhoto varFileName = strPhoto } qInsertClockIn := `INSERT INTO t_transaction ( T_TransactionM_AbsensiTypeID, T_TransactionM_StaffID, T_TransactionM_CompanyID, T_TransactionClockAbsensi, T_TransactionDate, T_TransactionCurrentLatitude, T_TransactionCurrentLongitude, T_TransactionCurrentDistance, T_TransactionFileName, T_TransactionSelfiePhotoPath, T_TransactionIsActive, T_TransactionCreated ) VALUES ( ?, ?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, NOW() )` _, err = db.Handle.Exec(qInsertClockIn, "1", T_TransactionM_StaffID, T_TransactionM_CompanyID, &jamClockIn, T_TransactionCurrentLatitude, T_TransactionCurrentLongitude, T_TransactionCurrentDistance, &varFileName, &varProsesFotoSelfie, "Y", ) // set status jika tidak error if err == nil { *ret.Status = "OK" *ret.Message = "Proses Absensi Masuk Berhasil" } // set status jika error if err != nil { *ret.Status = "ERR" *ret.Message = "ERROR : " + err.Error() } } return &ret, err }