276 lines
8.2 KiB
Go
276 lines
8.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/gofrs/uuid/v5"
|
|
_ "github.com/jackc/pgx/v5/stdlib"
|
|
"github.com/jmoiron/sqlx"
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"github.com/saveinmed/backend-go/internal/config"
|
|
"github.com/saveinmed/backend-go/internal/domain"
|
|
)
|
|
|
|
func main() {
|
|
cfg := config.Load()
|
|
|
|
db, err := sqlx.Open("pgx", cfg.DatabaseURL)
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to DB: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
if err := db.Ping(); err != nil {
|
|
log.Fatalf("Failed to ping DB: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
log.Println("🧹 Cleaning database...")
|
|
cleanDB(ctx, db)
|
|
|
|
log.Println("🌱 Seeding data...")
|
|
seedData(ctx, db, cfg)
|
|
|
|
log.Println("✅ Seeding complete!")
|
|
}
|
|
|
|
func cleanDB(ctx context.Context, db *sqlx.DB) {
|
|
tables := []string{
|
|
"reviews", "shipments", "payment_preferences", "orders", "order_items",
|
|
"cart_items", "products", "companies", "users", "shipping_settings",
|
|
}
|
|
|
|
for _, table := range tables {
|
|
_, err := db.ExecContext(ctx, fmt.Sprintf("TRUNCATE TABLE %s CASCADE", table))
|
|
if err != nil {
|
|
// Ignore error if table doesn't exist or is empty
|
|
log.Printf("Warning cleaning %s: %v", table, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func seedData(ctx context.Context, db *sqlx.DB, cfg config.Config) {
|
|
// 1. Seed Admin
|
|
adminCompanyID := uuid.Must(uuid.NewV7())
|
|
createCompany(ctx, db, &domain.Company{
|
|
ID: adminCompanyID,
|
|
CNPJ: "00000000000000",
|
|
CorporateName: "SaveInMed Admin",
|
|
Category: "admin",
|
|
LicenseNumber: "ADMIN",
|
|
IsVerified: true,
|
|
})
|
|
createUser(ctx, db, &domain.User{
|
|
CompanyID: adminCompanyID,
|
|
Role: "Admin",
|
|
Name: cfg.AdminName,
|
|
Username: cfg.AdminUsername,
|
|
Email: cfg.AdminEmail,
|
|
}, cfg.AdminPassword, cfg.PasswordPepper)
|
|
|
|
// 2. Distributors (Sellers)
|
|
distributor1ID := uuid.Must(uuid.NewV7())
|
|
createCompany(ctx, db, &domain.Company{
|
|
ID: distributor1ID,
|
|
CNPJ: "11111111000111",
|
|
CorporateName: "Distribuidora Nacional",
|
|
Category: "distribuidora",
|
|
LicenseNumber: "DIST-001",
|
|
IsVerified: true,
|
|
Latitude: -23.55052,
|
|
Longitude: -46.633308,
|
|
})
|
|
createUser(ctx, db, &domain.User{
|
|
CompanyID: distributor1ID,
|
|
Role: "Owner",
|
|
Name: "Dono da Distribuidora",
|
|
Username: "distribuidora",
|
|
Email: "distribuidora@saveinmed.com",
|
|
}, "123456", cfg.PasswordPepper)
|
|
createShippingSettings(ctx, db, distributor1ID)
|
|
|
|
// 3. Pharmacies (Buyers)
|
|
pharmacy1ID := uuid.Must(uuid.NewV7())
|
|
createCompany(ctx, db, &domain.Company{
|
|
ID: pharmacy1ID,
|
|
CNPJ: "22222222000122",
|
|
CorporateName: "Farmácia Central",
|
|
Category: "farmacia",
|
|
LicenseNumber: "FARM-001",
|
|
IsVerified: true,
|
|
Latitude: -23.56052,
|
|
Longitude: -46.643308,
|
|
})
|
|
createUser(ctx, db, &domain.User{
|
|
CompanyID: pharmacy1ID,
|
|
Role: "Owner",
|
|
Name: "Dono da Farmácia",
|
|
Username: "farmacia",
|
|
Email: "farmacia@saveinmed.com",
|
|
}, "123456", cfg.PasswordPepper)
|
|
|
|
// 4. Products
|
|
products := []struct {
|
|
Name string
|
|
Price int64
|
|
Stock int64
|
|
}{
|
|
{"Dipirona 500mg", 500, 1000},
|
|
{"Paracetamol 750mg", 750, 1000},
|
|
{"Ibuprofeno 600mg", 1200, 500},
|
|
{"Amoxicilina 500mg", 2500, 300},
|
|
{"Omeprazol 20mg", 1500, 800},
|
|
}
|
|
|
|
var productIDs []uuid.UUID
|
|
|
|
for _, p := range products {
|
|
id := uuid.Must(uuid.NewV7())
|
|
expiry := time.Now().AddDate(1, 0, 0)
|
|
createProduct(ctx, db, &domain.Product{
|
|
ID: id,
|
|
SellerID: distributor1ID,
|
|
Name: p.Name,
|
|
Description: "Medicamento genérico de alta qualidade",
|
|
Batch: "BATCH-" + id.String()[:8],
|
|
ExpiresAt: expiry,
|
|
PriceCents: p.Price,
|
|
Stock: p.Stock,
|
|
})
|
|
productIDs = append(productIDs, id)
|
|
}
|
|
|
|
// 5. Orders
|
|
// Create an order from Pharmacy to Distributor
|
|
orderID := uuid.Must(uuid.NewV7())
|
|
totalCents := int64(0)
|
|
|
|
// Items
|
|
qty := int64(10)
|
|
price := products[0].Price
|
|
itemTotal := price * qty
|
|
totalCents += itemTotal
|
|
|
|
createOrder(ctx, db, &domain.Order{
|
|
ID: orderID,
|
|
BuyerID: pharmacy1ID,
|
|
SellerID: distributor1ID,
|
|
Status: "Faturado", // Ready for "Confirmar Entrega" test
|
|
TotalCents: totalCents,
|
|
CreatedAt: time.Now().AddDate(0, 0, -2),
|
|
UpdatedAt: time.Now(),
|
|
})
|
|
|
|
createOrderItem(ctx, db, &domain.OrderItem{
|
|
ID: uuid.Must(uuid.NewV7()),
|
|
OrderID: orderID,
|
|
ProductID: productIDs[0],
|
|
Quantity: qty,
|
|
UnitCents: price,
|
|
Batch: "BATCH-" + productIDs[0].String()[:8],
|
|
ExpiresAt: time.Now().AddDate(1, 0, 0),
|
|
})
|
|
|
|
}
|
|
|
|
func createCompany(ctx context.Context, db *sqlx.DB, c *domain.Company) {
|
|
now := time.Now().UTC()
|
|
c.CreatedAt = now
|
|
c.UpdatedAt = now
|
|
_, err := db.NamedExecContext(ctx, `
|
|
INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, created_at, updated_at)
|
|
VALUES (:id, :cnpj, :corporate_name, :category, :license_number, :is_verified, :latitude, :longitude, :created_at, :updated_at)
|
|
`, c)
|
|
if err != nil {
|
|
log.Printf("Error creating company %s: %v", c.CorporateName, err)
|
|
}
|
|
}
|
|
|
|
func createUser(ctx context.Context, db *sqlx.DB, u *domain.User, password, pepper string) {
|
|
hashed, _ := bcrypt.GenerateFromPassword([]byte(password+pepper), bcrypt.DefaultCost)
|
|
u.ID = uuid.Must(uuid.NewV7())
|
|
u.PasswordHash = string(hashed)
|
|
u.CreatedAt = time.Now().UTC()
|
|
u.UpdatedAt = time.Now().UTC()
|
|
|
|
// Ensure email/username uniqueness is handled by DB constraint, usually we just insert
|
|
_, err := db.NamedExecContext(ctx, `
|
|
INSERT INTO users (id, company_id, role, name, username, email, password_hash, email_verified, created_at, updated_at)
|
|
VALUES (:id, :company_id, :role, :name, :username, :email, :password_hash, :email_verified, :created_at, :updated_at)
|
|
`, u)
|
|
if err != nil {
|
|
log.Printf("Error creating user %s: %v", u.Username, err)
|
|
}
|
|
}
|
|
|
|
func createProduct(ctx context.Context, db *sqlx.DB, p *domain.Product) {
|
|
now := time.Now().UTC()
|
|
p.CreatedAt = now
|
|
p.UpdatedAt = now
|
|
_, err := db.NamedExecContext(ctx, `
|
|
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)
|
|
`, p)
|
|
if err != nil {
|
|
log.Printf("Error creating product %s: %v", p.Name, err)
|
|
}
|
|
}
|
|
|
|
func createShippingSettings(ctx context.Context, db *sqlx.DB, vendorID uuid.UUID) {
|
|
now := time.Now().UTC()
|
|
settings := &domain.ShippingSettings{
|
|
VendorID: vendorID,
|
|
Active: true,
|
|
MaxRadiusKm: 50,
|
|
PricePerKmCents: 150, // R$ 1.50
|
|
MinFeeCents: 1000, // R$ 10.00
|
|
FreeShippingThresholdCents: nil,
|
|
PickupActive: true,
|
|
PickupAddress: "Rua da Distribuidora, 1000",
|
|
PickupHours: "Seg-Sex 08-18h",
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
Latitude: -23.55052,
|
|
Longitude: -46.633308,
|
|
}
|
|
|
|
_, err := db.NamedExecContext(ctx, `
|
|
INSERT INTO shipping_settings (
|
|
vendor_id, active, max_radius_km, price_per_km_cents, min_fee_cents,
|
|
free_shipping_threshold_cents, pickup_active, pickup_address, pickup_hours,
|
|
latitude, longitude, created_at, updated_at
|
|
) VALUES (
|
|
:vendor_id, :active, :max_radius_km, :price_per_km_cents, :min_fee_cents,
|
|
:free_shipping_threshold_cents, :pickup_active, :pickup_address, :pickup_hours,
|
|
:latitude, :longitude, :created_at, :updated_at
|
|
)
|
|
`, settings)
|
|
if err != nil {
|
|
log.Printf("Error creating shipping settings: %v", err)
|
|
}
|
|
}
|
|
|
|
func createOrder(ctx context.Context, db *sqlx.DB, o *domain.Order) {
|
|
_, err := db.NamedExecContext(ctx, `
|
|
INSERT INTO orders (id, buyer_id, seller_id, status, total_cents, created_at, updated_at)
|
|
VALUES (:id, :buyer_id, :seller_id, :status, :total_cents, :created_at, :updated_at)
|
|
`, o)
|
|
if err != nil {
|
|
log.Printf("Error creating order: %v", err)
|
|
}
|
|
}
|
|
|
|
func createOrderItem(ctx context.Context, db *sqlx.DB, item *domain.OrderItem) {
|
|
_, err := db.NamedExecContext(ctx, `
|
|
INSERT INTO order_items (id, order_id, product_id, quantity, unit_cents, batch, expires_at)
|
|
VALUES (:id, :order_id, :product_id, :quantity, :unit_cents, :batch, :expires_at)
|
|
`, item)
|
|
if err != nil {
|
|
log.Printf("Error creating order item: %v", err)
|
|
}
|
|
}
|