2025-11-18 15:32:20 +07:00

319 lines
7.7 KiB
Go

package main
import (
"context"
"database/sql"
"fmt"
"gen_transit_point/model"
"gen_transit_point/utils"
"log"
"strings"
"time"
_ "github.com/lib/pq"
"github.com/opentracing/opentracing-go"
"github.com/xuri/excelize/v2"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/logger"
)
func InitGormDB(host string, port int, user, pass, dbname string) (*gorm.DB, error) {
dsn := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
host, port, user, pass, dbname,
)
gormDB, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
PrepareStmt: true,
Logger: logger.Default.LogMode(logger.Warn),
})
if err != nil {
return nil, err
}
// Setup connection pooling
sqlDB, err := gormDB.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
return gormDB, nil
}
func main() {
ctx := context.Background()
now := time.Now()
dbhost := "127.0.0.1"
dbport := 5432
dbuser := "postgres"
dbpass := "postgres"
dbname := "oslogweb"
//prod
/* dbhost := "38.47.91.219"
dbport := 5454
dbuser := "postgres"
dbpass := "0n35p1r1t2025"
dbname := "oslogweb" */
gormDB, err := InitGormDB(dbhost, dbport, dbuser, dbpass, dbname)
if err != nil {
log.Fatalf("Gagal init GORM: %v", err)
}
sqlDB, err := gormDB.DB()
if err != nil {
log.Fatalf("Gagal ambil sql.DB: %v", err)
}
if err := sqlDB.Ping(); err != nil {
log.Fatalf("Gagal ping database: %v", err)
}
fmt.Println("Koneksi ke DB berhasil ✅")
filename := "transit_point_indosps.xlsx"
f, err := excelize.OpenFile(filename)
if err != nil {
log.Fatalf("Gagal membuka file Excel: %v", err)
}
defer f.Close()
sheets := f.GetSheetList()
if len(sheets) == 0 {
log.Fatal("File Excel tidak memiliki sheet.")
}
sheetName := sheets[0]
fmt.Printf("Membaca sheet: %s\n", sheetName)
rows, err := f.GetRows(sheetName)
if err != nil {
log.Fatalf("Gagal membaca baris: %v", err)
}
excelData := []model.TransitPoint{}
//skip header nya jadi init dari 1 bukan 0
for i := 1; i < len(rows); i++ {
row := rows[i]
if len(row) < 5 {
continue
}
name := strings.TrimSpace(row[1])
if name == "" {
continue
}
address := strings.TrimSpace(row[2])
lat := strings.TrimSpace(row[3])
lon := strings.TrimSpace(row[4])
var latF, lonF float64
fmt.Sscanf(lat, "%f", &latF)
fmt.Sscanf(lon, "%f", &lonF)
excelData = append(excelData, model.TransitPoint{
CompanyID: 784,
Name: name,
Address: address,
Latitude: latF,
Longitude: lonF,
CreatedDate: utils.FormatToWithoutTZ(ctx, now),
CreatedBy: "system",
})
}
names := []string{}
for _, p := range excelData {
names = append(names, fmt.Sprintf("'%s'", strings.ReplaceAll(p.Name, "'", "''")))
}
filter := fmt.Sprintf("AND a.company_id=784 AND a.name IN (%s)", strings.Join(names, ","))
data, err := GetTransitPoints(ctx, gormDB, filter)
if err != nil {
log.Fatalf("Gagal GetTransitPoints: %v", err)
}
dbMap := map[string]model.TransitPoint{}
for _, d := range data {
dbMap[d.Name] = *d
}
for _, p := range excelData {
geomWkt := GenerateGeomWkt(ctx, gormDB, p.Longitude, p.Latitude, float64(100))
p.GeomWkt = geomWkt
p.ModifiedBy = "system"
p.ModifiedDate = utils.FormatToWithoutTZ(ctx, now)
if existing, exists := dbMap[p.Name]; exists {
if existing.Address != p.Address || existing.Latitude != p.Latitude || existing.Longitude != p.Longitude {
_, err := UpdateTransitPointDB(ctx, gormDB, &p)
if err != nil {
log.Printf("Gagal update %s: %v", p.Name, err)
} else {
fmt.Printf("Berhasil update: %s\n", p.Name)
}
}
} else {
_, err := InsertTransitPointDB(ctx, gormDB, &p)
if err != nil {
log.Printf("Gagal insert %s: %v", p.Name, err)
} else {
fmt.Printf("Berhasil insert: %s\n", p.Name)
}
}
}
}
func InsertTransitPointDB(ctx context.Context, db *gorm.DB, data *model.TransitPoint) (*model.TransitPoint, error) {
span, spanCtx := opentracing.StartSpanFromContext(ctx, "insertTransitPointDB")
defer span.Finish()
payload := data.BeforeCheck(spanCtx)
tx := db.WithContext(spanCtx).Begin().Scopes(payload.TableName(spanCtx))
if err := tx.Error; err != nil {
return nil, err
}
if payload.GeomWkt.String != "" {
tx.Clauses(clause.Expr{SQL: "ST_GeomFromText(?, 4326)", Vars: []interface{}{payload.GeomWkt}})
}
tx.Create(&payload)
if err := tx.Error; err != nil {
tx.Rollback()
return nil, err
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return nil, err
}
return payload.Convert(spanCtx), nil
}
func UpdateTransitPointDB(ctx context.Context, db *gorm.DB, data *model.TransitPoint) (*model.TransitPoint, error) {
span, spanCtx := opentracing.StartSpanFromContext(ctx, "updateTransitPointDB")
defer span.Finish()
payload := data.BeforeCheck(spanCtx)
tx := db.WithContext(spanCtx).Begin().Scopes(payload.TableName(spanCtx))
if err := tx.Error; err != nil {
return nil, err
}
// Update GeomWkt jika ada
if payload.GeomWkt.String != "" {
tx = tx.Model(&payload).Clauses(clause.Expr{
SQL: "geom = ST_GeomFromText(?, 4326)",
Vars: []interface{}{payload.GeomWkt},
})
}
tx = tx.Model(&payload).Where("id = ?", payload.ID).Updates(map[string]interface{}{
"address": payload.Address,
"latitude": payload.Latitude,
"longitude": payload.Longitude,
"modified_by": payload.ModifiedBy,
"modified_date": payload.ModifiedDate,
})
if tx.Error != nil {
tx.Rollback()
return nil, tx.Error
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return nil, err
}
return payload.Convert(spanCtx), nil
}
func GenerateGeomWkt(ctx context.Context, db *gorm.DB, lon, lat, bufferRadius float64) string {
var value sql.NullString
tx := db.WithContext(ctx)
query := fmt.Sprintf("SELECT ST_AsText(ST_Buffer(ST_GeomFromText('POINT(%0.7f %0.7f)', 4326), 0.00001 * %v, 'quad_segs=2')) AS geom_text LIMIT 1", lon, lat, bufferRadius)
tx = tx.Raw(query)
tx.Row().Scan(&value)
return strings.TrimSpace(value.String)
}
func GetTransitPoints(ctx context.Context, db *gorm.DB, filter string) ([]*model.TransitPoint, error) {
tx := db.WithContext(ctx)
query := fmt.Sprintf(`SELECT a.id,a.company_id,a.customer_id,a.customer_ids,a.trip_group_transit_point_id,a.status,a.blacklist
,a.latitude,a.longitude,a.register_date,a.unregister_date,a.created_date,a.modified_date
,a.name,a.code,a.geocode,a.address,a.created_by,a.modified_by,a.pic_name,a.pic_phone,a.pic_mobile
,a.transit_point_type,a.remark,a.coords,a.fax,a.mobile_no,a.phone,a.image,a.zip_code,a.geom
FROM m_transit_point AS a
WHERE a.name IS NOT NULL AND a.name <> ''
%v`, filter)
fmt.Printf("query : %v\n", query)
rows, err := tx.Raw(query).Rows()
if err != nil {
return nil, err
}
defer rows.Close()
data := []*model.TransitPoint{}
for rows.Next() {
dataScan := model.TransitPointDB{}
err := rows.Scan(
&dataScan.ID,
&dataScan.CompanyID,
&dataScan.CustomerID,
&dataScan.CustomerIDs,
&dataScan.TripGroupTransitPointID,
&dataScan.Status,
&dataScan.Blacklist,
&dataScan.Latitude,
&dataScan.Longitude,
&dataScan.RegisterDate,
&dataScan.UnregisterDate,
&dataScan.CreatedDate,
&dataScan.ModifiedDate,
&dataScan.Name,
&dataScan.Code,
&dataScan.Geocode,
&dataScan.Address,
&dataScan.CreatedBy,
&dataScan.ModifiedBy,
&dataScan.PicName,
&dataScan.PicPhone,
&dataScan.PicMobile,
&dataScan.TransitPointType,
&dataScan.Remark,
&dataScan.Coords,
&dataScan.Fax,
&dataScan.MobileNo,
&dataScan.Phone,
&dataScan.Image,
&dataScan.ZipCode,
&dataScan.GeomWkb,
)
if err != nil {
return nil, err
}
result := dataScan.Convert(ctx)
data = append(data, result)
}
return data, nil
}