feat(seeder): implemented 4 pharmacies with staff in lean mode

This commit is contained in:
Tiago Yamamoto 2025-12-22 01:42:21 -03:00
parent d44a8873b9
commit ebfc72969c
2 changed files with 134 additions and 68 deletions

View file

@ -13,11 +13,30 @@ Microserviço utilitário para popular o banco de dados com dados de teste para
## 🎯 Modos de Operação ## 🎯 Modos de Operação
### 1. `mode=lean` (Recomendado para Dev) ### 1. `mode=lean` (Recomendado para Dev)
Gera um ambiente funcional mínimo: Gera um ambiente funcional com **4 Farmácias** em Anápolis e equipe completa em cada uma:
- **1 Farmácia** (Farmácia Modelo)
- **4 Usuários** (Admin, Dono, Colaborador, Entregador) #### 1. Farmácia Central (Sufixo 1)
- **15 Produtos** - **CNPJ**: 11.111.111/0001-11
- Ideal para testar fluxos de login, carrinho, checkout. - **Usuários**: `dono1`, `colab1`, `entregador1` (Senha: 123456)
- **Localização**: Centro de Anápolis
#### 2. Farmácia Jundiaí (Sufixo 2)
- **CNPJ**: 22.222.222/0001-22
- **Usuários**: `dono2`, `colab2`, `entregador2` (Senha: 123456)
- **Localização**: Bairro Jundiaí (Norte/Leste)
#### 3. Farmácia Jaiara (Sufixo 3)
- **CNPJ**: 33.333.333/0001-33
- **Usuários**: `dono3`, `colab3`, `entregador3` (Senha: 123456)
- **Localização**: Vila Jaiara (Norte/Oeste)
#### 4. Farmácia Universitária (Sufixo 4)
- **CNPJ**: 44.444.444/0001-44
- **Usuários**: `dono4`, `colab4`, `entregador4` (Senha: 123456)
- **Localização**: Cidade Universitária (Sul/Leste)
#### Admin Global
- **Usuário**: `admin` (Senha: admin123)
### 2. `mode=full` (Padrão/Load Test) ### 2. `mode=full` (Padrão/Load Test)
Gera volume de dados: Gera volume de dados:

View file

@ -115,7 +115,6 @@ func SeedLean(dsn string) (string, error) {
updated_at TIMESTAMPTZ NOT NULL updated_at TIMESTAMPTZ NOT NULL
)`) )`)
// Add missing users table creation here to be complete for independent seeder run
mustExec(db, `CREATE TABLE users ( mustExec(db, `CREATE TABLE users (
id UUID PRIMARY KEY, id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id), company_id UUID NOT NULL REFERENCES companies(id),
@ -142,65 +141,95 @@ func SeedLean(dsn string) (string, error) {
updated_at TIMESTAMPTZ NOT NULL updated_at TIMESTAMPTZ NOT NULL
)`) )`)
// Create 1 Pharmacy
pharmacyID := uuid.Must(uuid.NewV7())
now := time.Now().UTC()
_, err = db.ExecContext(ctx, `
INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, city, state, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`,
pharmacyID, "12345678000199", "Farmácia Modelo", "farmacia", "CRF-GO-12345", true, AnapolisLat, AnapolisLng, "Anápolis", "GO", now, now,
)
if err != nil {
return "", fmt.Errorf("create pharmacy: %v", err)
}
// I'll proceed with creating users:
// Helper for hashing // Helper for hashing
hashPwd := func(pwd string) string { hashPwd := func(pwd string) string {
h, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) h, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
return string(h) return string(h)
} }
defaultPwdHash := hashPwd("123456")
// 1. Admin // Fixed Pharmacies Data
adminID := uuid.Must(uuid.NewV7()) pharmacies := []struct {
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at) Name string
VALUES ('%s', '%s', 'Admin', 'Administrador', 'admin', 'admin@saveinmed.com', true, '%s', NOW(), NOW())`, CNPJ string
adminID, pharmacyID, hashPwd("admin123"), Lat float64
)) Lng float64
Suffix string // for usernames/emails e.g. "1" -> dono1, email1
}{
{
Name: "Farmácia Central",
CNPJ: "11111111000111",
Lat: AnapolisLat,
Lng: AnapolisLng,
Suffix: "1",
},
{
Name: "Farmácia Jundiaí",
CNPJ: "22222222000122",
Lat: AnapolisLat + 0.015, // Slightly North
Lng: AnapolisLng + 0.010, // East
Suffix: "2",
},
{
Name: "Farmácia Jaiara",
CNPJ: "33333333000133",
Lat: AnapolisLat + 0.030, // More North
Lng: AnapolisLng - 0.010, // West
Suffix: "3",
},
{
Name: "Farmácia Universitária",
CNPJ: "44444444000144",
Lat: AnapolisLat - 0.020, // South
Lng: AnapolisLng + 0.020, // East
Suffix: "4",
},
}
// 2. Owner (Dono) now := time.Now().UTC()
ownerID := uuid.Must(uuid.NewV7())
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
VALUES ('%s', '%s', 'Dono', 'João Dono', 'dono', 'dono@farmacia.com', true, '%s', NOW(), NOW())`,
ownerID, pharmacyID, hashPwd("123456"),
))
// 3. Employee (Colaborador)
empID := uuid.Must(uuid.NewV7())
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
VALUES ('%s', '%s', 'Colaborador', 'Maria Colaboradora', 'colaborador', 'colaborador@farmacia.com', true, '%s', NOW(), NOW())`,
empID, pharmacyID, hashPwd("123456"),
))
// 4. Delivery (Entregador)
// Delivery person usually needs their own "company" or is linked to the pharmacy?
// For now, linking to the same pharmacy for simplicity, or creating a carrier?
// The prompt implies "entregador" as a user role.
// Linking to Pharmacy for simplicity (internal delivery fleet).
delID := uuid.Must(uuid.NewV7())
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
VALUES ('%s', '%s', 'Entregador', 'José Entregador', 'entregador', 'entregador@farmacia.com', true, '%s', NOW(), NOW())`,
delID, pharmacyID, hashPwd("123456"),
))
log.Println("✅ [Lean] Users created: admin, dono, colaborador, entregador")
// Create Products for the Pharmacy
rng := rand.New(rand.NewSource(time.Now().UnixNano())) rng := rand.New(rand.NewSource(time.Now().UnixNano()))
products := generateProducts(rng, pharmacyID, 15) createdUsers := []string{}
for _, p := range products {
for _, ph := range pharmacies {
// 1. Create Company
companyID := uuid.Must(uuid.NewV7())
_, err = db.ExecContext(ctx, `
INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, city, state, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`,
companyID, ph.CNPJ, ph.Name, "farmacia", fmt.Sprintf("CRF-GO-%s", ph.Suffix), true, ph.Lat, ph.Lng, "Anápolis", "GO", now, now,
)
if err != nil {
return "", fmt.Errorf("create library %s: %v", ph.Name, err)
}
// 2. Create Users (Dono, Colab, Entregador)
roles := []struct {
Role string
UserBase string
NameBase string
}{
{"Dono", "dono", "Dono"},
{"Colaborador", "colab", "Colaborador"},
{"Entregador", "entregador", "Entregador"},
}
for _, r := range roles {
uid := uuid.Must(uuid.NewV7())
username := fmt.Sprintf("%s%s", r.UserBase, ph.Suffix)
email := fmt.Sprintf("%s%s@saveinmed.com", r.UserBase, ph.Suffix)
name := fmt.Sprintf("%s %s", r.NameBase, ph.Name)
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', true, '%s', NOW(), NOW())`,
uid, companyID, r.Role, name, username, email, defaultPwdHash,
))
createdUsers = append(createdUsers, fmt.Sprintf("%s (%s)", username, r.Role))
}
// 3. Create Products (20-50 products per pharmacy)
numProds := 20 + rng.Intn(31) // 20-50
prods := generateProducts(rng, companyID, numProds)
for _, p := range prods {
_, err := db.NamedExecContext(ctx, ` _, err := db.NamedExecContext(ctx, `
INSERT INTO products (id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at) INSERT INTO products (id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at)
VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents, :stock, :created_at, :updated_at) VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents, :stock, :created_at, :updated_at)
@ -209,9 +238,27 @@ func SeedLean(dsn string) (string, error) {
log.Printf("insert product lean: %v", err) log.Printf("insert product lean: %v", err)
} }
} }
log.Println("✅ [Lean] Created 15 products") log.Printf("✅ [Lean] %s created with %d products", ph.Name, len(prods))
}
return "Lean seed completed. Users: admin, dono, colaborador, entregador (Pass: 123456/admin123)", nil // 4. Create Global Admin (linked to first pharmacy for FK constraint, or standalone if nullable? Schema says NOT NULL)
// Build Admin linked to "Farmácia Central" (Suffix 1)
// Find ID of first pharmacy? I need to track it.
// Actually, just query it or store it.
// Simpler: I'll just create a separate "Admin Company" or link to one.
// Linking to Central is fine.
var centralID string
err = db.Get(&centralID, "SELECT id FROM companies WHERE cnpj = '11111111000111'")
if err == nil {
adminID := uuid.Must(uuid.NewV7())
mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
VALUES ('%s', '%s', 'Admin', 'Administrador Global', 'admin', 'admin@saveinmed.com', true, '%s', NOW(), NOW())`,
adminID, centralID, hashPwd("admin123"),
))
createdUsers = append(createdUsers, "admin (Admin)")
}
return fmt.Sprintf("Lean seed completed. 4 Pharmacies. Users: %s. Pass: 123456 (admin: admin123)", len(createdUsers)), nil
} }
func SeedFull(dsn string) (string, error) { func SeedFull(dsn string) (string, error) {