Adds seed script
This commit is contained in:
parent
37b45ee4db
commit
7f1ea8ba72
224
cmd/seed/main.go
Normal file
224
cmd/seed/main.go
Normal file
@ -0,0 +1,224 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"erp_system/internal/database"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dbPath := "erp.db"
|
||||
if len(os.Args) > 1 {
|
||||
dbPath = os.Args[1]
|
||||
}
|
||||
|
||||
log.Printf("Connecting to database at %s...", dbPath)
|
||||
// We can use the internal database package to initialize (runs migrations)
|
||||
db, err := database.Initialize(dbPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Configuration for generation
|
||||
const (
|
||||
numCustomers = 500
|
||||
maxOrdersPerCust = 15
|
||||
maxLinesPerOrder = 8
|
||||
numJournalEntries = 100
|
||||
)
|
||||
|
||||
log.Println("Starting data generation...")
|
||||
start := time.Now()
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to begin transaction: %v", err)
|
||||
}
|
||||
|
||||
// 1. Customers
|
||||
customerIDs := make([]int64, 0, numCustomers)
|
||||
for i := 0; i < numCustomers; i++ {
|
||||
name := fmt.Sprintf("Customer %s %s", randomString(5), randomString(7))
|
||||
email := fmt.Sprintf("%s.%s@example.com", randomString(4), randomString(5))
|
||||
phone := fmt.Sprintf("555-%04d", rand.Intn(10000))
|
||||
address := fmt.Sprintf("%d %s St, City %s", rand.Intn(999), randomString(6), randomString(4))
|
||||
|
||||
res, err := tx.Exec("INSERT INTO customers (name, email, phone, address) VALUES (?, ?, ?, ?)", name, email, phone, address)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert customer: %v", err)
|
||||
}
|
||||
id, _ := res.LastInsertId()
|
||||
customerIDs = append(customerIDs, id)
|
||||
}
|
||||
log.Printf("Generated %d customers", numCustomers)
|
||||
|
||||
// 2. Orders and Lines and Invoices
|
||||
var orderCount, lineCount, invoiceCount int
|
||||
for _, custID := range customerIDs {
|
||||
numOrders := rand.Intn(maxOrdersPerCust)
|
||||
for j := 0; j < numOrders; j++ {
|
||||
// Create Order
|
||||
status := "draft"
|
||||
r := rand.Float32()
|
||||
if r > 0.7 {
|
||||
status = "fulfilled"
|
||||
} else if r > 0.4 {
|
||||
status = "confirmed"
|
||||
} else if r > 0.3 {
|
||||
status = "cancelled"
|
||||
}
|
||||
|
||||
// Random date in last year
|
||||
orderDate := time.Now().AddDate(0, 0, -rand.Intn(365))
|
||||
|
||||
res, err := tx.Exec("INSERT INTO orders (customer_id, status, order_date, notes) VALUES (?, ?, ?, ?)",
|
||||
custID, status, orderDate.Format("2006-01-02"), "Generated order")
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert order: %v", err)
|
||||
}
|
||||
orderID, _ := res.LastInsertId()
|
||||
orderCount++
|
||||
|
||||
// Create Order Lines
|
||||
numLines := rand.Intn(maxLinesPerOrder) + 1
|
||||
var totalAmount float64
|
||||
for k := 0; k < numLines; k++ {
|
||||
qty := float64(rand.Intn(10) + 1)
|
||||
price := float64(rand.Intn(100) + 10)
|
||||
desc := fmt.Sprintf("Product %s-%d", randomString(3), rand.Intn(100))
|
||||
lineTotal := qty * price
|
||||
totalAmount += lineTotal
|
||||
|
||||
_, err := tx.Exec("INSERT INTO order_lines (order_id, description, quantity, unit_price, line_total) VALUES (?, ?, ?, ?, ?)",
|
||||
orderID, desc, qty, price, lineTotal)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert order line: %v", err)
|
||||
}
|
||||
lineCount++
|
||||
}
|
||||
|
||||
// Update Order Total
|
||||
_, err = tx.Exec("UPDATE orders SET total_amount = ? WHERE id = ?", totalAmount, orderID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to update order total: %v", err)
|
||||
}
|
||||
|
||||
// Create Invoice if order is confirmed or fulfilled
|
||||
if status == "confirmed" || status == "fulfilled" {
|
||||
invoiceStatus := "pending"
|
||||
if rand.Float32() > 0.5 {
|
||||
invoiceStatus = "paid"
|
||||
}
|
||||
|
||||
invNum := fmt.Sprintf("INV-%d-%d", orderID, rand.Intn(10000))
|
||||
dueDate := orderDate.AddDate(0, 1, 0) // Due in 30 days
|
||||
var paidDate interface{} = nil
|
||||
if invoiceStatus == "paid" {
|
||||
pd := dueDate.AddDate(0, 0, -rand.Intn(10))
|
||||
paidDate = pd.Format("2006-01-02")
|
||||
}
|
||||
|
||||
_, err := tx.Exec("INSERT INTO invoices (order_id, customer_id, invoice_number, status, amount, due_date, paid_date) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
orderID, custID, invNum, invoiceStatus, totalAmount, dueDate.Format("2006-01-02"), paidDate)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert invoice: %v", err)
|
||||
}
|
||||
invoiceCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("Generated %d orders, %d lines, %d invoices", orderCount, lineCount, invoiceCount)
|
||||
|
||||
// 3. Journal Entries
|
||||
// Fetch account IDs first
|
||||
rows, err := tx.Query("SELECT id, code, type FROM gl_accounts")
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to fetch accounts: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type Account struct {
|
||||
ID int64
|
||||
Code string
|
||||
Type string
|
||||
}
|
||||
var accounts []Account
|
||||
for rows.Next() {
|
||||
var a Account
|
||||
if err := rows.Scan(&a.ID, &a.Code, &a.Type); err != nil {
|
||||
log.Fatalf("Failed to scan account: %v", err)
|
||||
}
|
||||
accounts = append(accounts, a)
|
||||
}
|
||||
|
||||
if len(accounts) >= 2 {
|
||||
for i := 0; i < numJournalEntries; i++ {
|
||||
date := time.Now().AddDate(0, 0, -rand.Intn(60)).Format("2006-01-02")
|
||||
desc := fmt.Sprintf("Journal Entry %d", i+1)
|
||||
|
||||
res, err := tx.Exec("INSERT INTO journal_entries (entry_date, description, reference) VALUES (?, ?, ?)",
|
||||
date, desc, "GEN-"+strconv.Itoa(i))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert journal entry: %v", err)
|
||||
}
|
||||
jeID, _ := res.LastInsertId()
|
||||
|
||||
// Simple balanced entry: 2 lines
|
||||
amount := float64(rand.Intn(5000) + 100)
|
||||
|
||||
// Pick 2 random accounts
|
||||
idx1 := rand.Intn(len(accounts))
|
||||
idx2 := rand.Intn(len(accounts))
|
||||
for idx1 == idx2 {
|
||||
idx2 = rand.Intn(len(accounts))
|
||||
}
|
||||
|
||||
// Debit line
|
||||
_, err = tx.Exec("INSERT INTO journal_lines (journal_entry_id, account_id, debit, credit) VALUES (?, ?, ?, ?)",
|
||||
jeID, accounts[idx1].ID, amount, 0)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert journal line 1: %v", err)
|
||||
}
|
||||
|
||||
// Credit line
|
||||
_, err = tx.Exec("INSERT INTO journal_lines (journal_entry_id, account_id, debit, credit) VALUES (?, ?, ?, ?)",
|
||||
jeID, accounts[idx2].ID, 0, amount)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
log.Fatalf("Failed to insert journal line 2: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("Generated %d journal entries", numJournalEntries)
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
log.Fatalf("Failed to commit transaction: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Seeding completed in %v", time.Since(start))
|
||||
}
|
||||
|
||||
func randomString(n int) string {
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
BIN
erp.db-wal
BIN
erp.db-wal
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user