270 lines
8.4 KiB
Go
270 lines
8.4 KiB
Go
// One-time migration: moves Qdrant auth users and client records into PostgreSQL.
|
||
// Run from the DoormileBackend directory: go run ./cmd/migrate_qdrant
|
||
package main
|
||
|
||
import (
|
||
"database/sql"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
|
||
"github.com/joho/godotenv"
|
||
_ "github.com/lib/pq"
|
||
"golang.org/x/crypto/bcrypt"
|
||
)
|
||
|
||
func hash(pw string) string {
|
||
b, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
|
||
if err != nil {
|
||
log.Fatalf("bcrypt error: %v", err)
|
||
}
|
||
return string(b)
|
||
}
|
||
|
||
func getenv(key, fallback string) string {
|
||
if v := os.Getenv(key); v != "" {
|
||
return v
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
func main() {
|
||
_ = godotenv.Load()
|
||
|
||
dsn := fmt.Sprintf(
|
||
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Kolkata",
|
||
getenv("DB_HOST", "127.0.0.1"),
|
||
getenv("DB_USER", "admin"),
|
||
getenv("DB_PASSWORD", "Package@321#"),
|
||
getenv("DB_NAME", "logistics"),
|
||
getenv("DB_PORT", "5433"),
|
||
)
|
||
|
||
db, err := sql.Open("postgres", dsn)
|
||
if err != nil {
|
||
log.Fatalf("open: %v", err)
|
||
}
|
||
defer db.Close()
|
||
if err = db.Ping(); err != nil {
|
||
log.Fatalf("ping: %v", err)
|
||
}
|
||
log.Println("✅ Connected to PostgreSQL")
|
||
|
||
// ── 1. Ensure client_id is nullable ──────────────────────────────────────
|
||
log.Println("🔧 Ensuring client_id is nullable in doormile_auth …")
|
||
_, _ = db.Exec(`ALTER TABLE doormile_auth ALTER COLUMN client_id DROP NOT NULL`)
|
||
|
||
// ── 2. Migrate doormile_auth ──────────────────────────────────────────────
|
||
// Source: Qdrant doormile_auth collection (5 users, original PIN = 1234)
|
||
// admin@doormile.com added to match the hardcoded React console login.
|
||
log.Println("\n📋 Migrating auth users …")
|
||
|
||
pin := "1234"
|
||
|
||
type authUser struct {
|
||
email string
|
||
role string
|
||
password string
|
||
}
|
||
users := []authUser{
|
||
{"suriya@tenext.in", "admin", "admin"},
|
||
{"admin@doormile.com", "admin", "admin"},
|
||
{"kamesh@doormile.com", "user", pin},
|
||
{"parthiban@doormile.com", "user", pin},
|
||
{"fazul@doormile.com", "user", pin},
|
||
{"care@doormile.com", "user", pin},
|
||
}
|
||
|
||
authInsert := `
|
||
INSERT INTO doormile_auth (email, password_hash, role, created_at, updated_at)
|
||
VALUES ($1, $2, $3, NOW(), NOW())
|
||
ON CONFLICT (email) DO NOTHING`
|
||
|
||
for _, u := range users {
|
||
if _, err := db.Exec(authInsert, u.email, hash(u.password), u.role); err != nil {
|
||
log.Printf(" ⚠️ skip %s: %v", u.email, err)
|
||
} else {
|
||
log.Printf(" ✓ %s [%s]", u.email, u.role)
|
||
}
|
||
}
|
||
|
||
// ── 3. Migrate doormile_clients ───────────────────────────────────────────
|
||
// Exact data from Qdrant payloads provided by user.
|
||
log.Println("\n📋 Migrating clients …")
|
||
|
||
var fazulID uint64
|
||
_ = db.QueryRow(`SELECT id FROM doormile_auth WHERE email = 'fazul@doormile.com'`).Scan(&fazulID)
|
||
|
||
type client struct {
|
||
firstName string
|
||
lastName string
|
||
phone string
|
||
city string
|
||
state string
|
||
neighbourhood string
|
||
pincode string
|
||
businessType string
|
||
status string
|
||
shippingFrequency string
|
||
logisticsSegment string
|
||
transitFrom string
|
||
transitTo string
|
||
parcelVolume float64
|
||
activeContracts int
|
||
logisticsProvider string
|
||
providerEfficiency string
|
||
dataConsent string
|
||
notes string
|
||
surveyLat float64
|
||
surveyLong float64
|
||
surveyAddress string
|
||
surveyZone string
|
||
surveyPincode string
|
||
registeredByID uint64
|
||
}
|
||
|
||
clients := []client{
|
||
{
|
||
// clientId: suriya_001
|
||
firstName: "Suriya",
|
||
phone: "PENDING_004", // phone was empty in Qdrant payload — update manually
|
||
city: "Coimbatore",
|
||
state: "Tamil Nadu",
|
||
neighbourhood: "RS Puram",
|
||
businessType: "ecommerce",
|
||
status: "newClient",
|
||
shippingFrequency: "Weekly",
|
||
transitFrom: "Coimbatore",
|
||
transitTo: "Chennai",
|
||
parcelVolume: 200,
|
||
activeContracts: 5,
|
||
logisticsProvider: "DTDC Express",
|
||
providerEfficiency: "High Efficiency",
|
||
dataConsent: "full",
|
||
registeredByID: 0,
|
||
},
|
||
{
|
||
// clientId: client_1780462654467
|
||
firstName: "Abhishek",
|
||
phone: "6374605674",
|
||
city: "Perur",
|
||
state: "Tamil Nadu",
|
||
neighbourhood: "RS Puram",
|
||
businessType: "wholesale",
|
||
status: "newClient",
|
||
shippingFrequency: "Weekly",
|
||
logisticsSegment: "First Mile, Last Mile",
|
||
transitFrom: "Perur",
|
||
transitTo: "Bengaluru",
|
||
parcelVolume: 0,
|
||
activeContracts: 0,
|
||
logisticsProvider: "Not disclosed",
|
||
providerEfficiency: "Not disclosed",
|
||
dataConsent: "basicOnly",
|
||
surveyLat: 11.0050875,
|
||
surveyLong: 76.9508337,
|
||
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
|
||
surveyZone: "RS Puram",
|
||
registeredByID: 0,
|
||
},
|
||
{
|
||
// clientId: client_1780558882620
|
||
firstName: "Doormile",
|
||
phone: "9876543210",
|
||
city: "Coimbatore",
|
||
state: "Tamil Nadu",
|
||
neighbourhood: "RS Puram",
|
||
businessType: "retail",
|
||
status: "newClient",
|
||
shippingFrequency: "Daily",
|
||
logisticsSegment: "First Mile, Last Mile",
|
||
transitFrom: "Coimbatore",
|
||
transitTo: "Bengaluru, Mumbai",
|
||
parcelVolume: 0,
|
||
activeContracts: 0,
|
||
logisticsProvider: "Not disclosed",
|
||
providerEfficiency: "Not disclosed",
|
||
dataConsent: "basicOnly",
|
||
surveyLat: 11.0050816,
|
||
surveyLong: 76.9508575,
|
||
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
|
||
surveyZone: "RS Puram",
|
||
registeredByID: 0,
|
||
},
|
||
{
|
||
// clientId: client_1781506364119 — recorded by Fazul
|
||
firstName: "Jonathan",
|
||
phone: "9629415740",
|
||
city: "Perur",
|
||
state: "Tamil Nadu",
|
||
neighbourhood: "RS Puram",
|
||
pincode: "641007",
|
||
businessType: "wholesale",
|
||
status: "newClient",
|
||
shippingFrequency: "Daily",
|
||
logisticsSegment: "First Mile, Middle Mile, Last Mile",
|
||
transitFrom: "Perur",
|
||
transitTo: "Chennai, Coimbatore, Madurai",
|
||
parcelVolume: 450,
|
||
activeContracts: 12,
|
||
logisticsProvider: "XpressBees",
|
||
providerEfficiency: "High Efficiency",
|
||
dataConsent: "full",
|
||
surveyLat: 11.0050812,
|
||
surveyLong: 76.9508625,
|
||
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
|
||
surveyZone: "RS Puram",
|
||
surveyPincode: "641007",
|
||
registeredByID: fazulID,
|
||
},
|
||
}
|
||
|
||
clientInsert := `
|
||
INSERT INTO doormile_clients (
|
||
first_name, last_name, phone,
|
||
city, state, neighbourhood, pincode,
|
||
surveylat, surveylong, survey_address, survey_zone, survey_pincode,
|
||
business_type, status,
|
||
shipping_frequency, logistics_segment,
|
||
transit_from, transit_to,
|
||
parcel_volume, active_contracts,
|
||
logistics_provider, provider_efficiency,
|
||
data_consent, notes,
|
||
registered_by_id,
|
||
created_at, updated_at
|
||
) VALUES (
|
||
$1,$2,$3,$4,$5,$6,$7,
|
||
$8,$9,$10,$11,$12,
|
||
$13,$14,$15,$16,$17,$18,
|
||
$19,$20,$21,$22,$23,$24,
|
||
$25,
|
||
NOW(),NOW()
|
||
)
|
||
ON CONFLICT (phone) DO NOTHING`
|
||
|
||
for _, cl := range clients {
|
||
_, err := db.Exec(clientInsert,
|
||
cl.firstName, cl.lastName, cl.phone,
|
||
cl.city, cl.state, cl.neighbourhood, cl.pincode,
|
||
cl.surveyLat, cl.surveyLong, cl.surveyAddress, cl.surveyZone, cl.surveyPincode,
|
||
cl.businessType, cl.status,
|
||
cl.shippingFrequency, cl.logisticsSegment,
|
||
cl.transitFrom, cl.transitTo,
|
||
cl.parcelVolume, cl.activeContracts,
|
||
cl.logisticsProvider, cl.providerEfficiency,
|
||
cl.dataConsent, cl.notes,
|
||
cl.registeredByID,
|
||
)
|
||
if err != nil {
|
||
log.Printf(" ⚠️ skip %s: %v", cl.firstName, err)
|
||
} else {
|
||
log.Printf(" ✓ %s — %s (%s) phone=%s", cl.firstName, cl.city, cl.businessType, cl.phone)
|
||
}
|
||
}
|
||
|
||
log.Println("\n✅ Migration complete.")
|
||
log.Println("\n⚠️ ACTION REQUIRED — Suriya client has no phone on record.")
|
||
log.Println(" Once you have Suriya's phone number run:")
|
||
log.Println(" UPDATE doormile_clients SET phone = '<number>' WHERE phone = 'PENDING_004';")
|
||
}
|