package service import ( "Portifolio/internal/model" "database/sql" "fmt" "time" _ "github.com/mattn/go-sqlite3" ) func InsertRevenue(db *sql.DB, companyID, currencyID int, category, label string, value float64, period model.Period) error { periodID, err := InsertPeriod(db, period) if err != nil { return err } reportID, err := getOrCreateReport(db, companyID, periodID) if err != nil { return err } _, err = db.Exec( `INSERT INTO revenue_entries (report_id, currency_id, category, label, value) VALUES (?, ?, ?, ?, ?)`, reportID, currencyID, category, label, value, ) return err } func InsertPeriod(db *sql.DB, p model.Period) (int, error) { res, err := db.Exec( `INSERT INTO periods (type, year, idx, start_date, end_date) VALUES (?, ?, ?, ?, ?) ON CONFLICT(type, year, idx) DO UPDATE SET start_date=excluded.start_date`, string(p.Type), p.Year, p.Index, p.Start.Format("2006-01-02"), p.End.Format("2006-01-02"), ) if err != nil { return 0, err } id, err := res.LastInsertId() return int(id), err } func getOrCreateReport(db *sql.DB, companyID, periodID int) (int, error) { var id int err := db.QueryRow( `SELECT id FROM revenue_reports WHERE company_id = ? AND period_id = ?`, companyID, periodID, ).Scan(&id) if err == sql.ErrNoRows { res, err := db.Exec( `INSERT INTO revenue_reports (company_id, period_id) VALUES (?, ?)`, companyID, periodID, ) if err != nil { return 0, err } lid, _ := res.LastInsertId() return int(lid), nil } return id, err } func GetRevenue(db *sql.DB, companyID int, periodType model.PeriodType, year, idx int) ([]model.Revenue, error) { rows, err := db.Query(` SELECT e.id, e.category, e.label, e.value, p.type, p.year, p.idx, p.start_date, p.end_date FROM revenue_entries e JOIN revenue_reports r ON e.report_id = r.id JOIN periods p ON r.period_id = p.id WHERE r.company_id = ? AND p.type = ? AND p.year = ? AND p.idx = ?`, companyID, string(periodType), year, idx, ) if err != nil { return nil, err } defer rows.Close() var entries []model.Revenue for rows.Next() { var e model.Revenue var p model.Period var start, end string if err := rows.Scan(&e.ID, &e.Category, &e.Label, &e.Value, &p.Type, &p.Year, &p.Index, &start, &end); err != nil { return nil, err } p.Start, _ = time.Parse("2006-01-02", start) p.End, _ = time.Parse("2006-01-02", end) e.Period = p entries = append(entries, e) } return entries, rows.Err() } func SumRevenue(db *sql.DB, companyID int, periodType model.PeriodType, year int) (*model.RevSum, error) { rows, err := db.Query(` SELECT e.category, e.label, e.value, p.type, p.year, p.idx FROM revenue_entries e JOIN revenue_reports r ON e.report_id = r.id JOIN periods p ON r.period_id = p.id WHERE r.company_id = ? AND p.type = ? AND p.year = ?`, companyID, string(periodType), year, ) if err != nil { return nil, err } defer rows.Close() rs := &model.RevSum{ Categories: make(map[model.RevenueCategory]float64), Labels: make(map[string]float64), } seen := map[string]bool{} for rows.Next() { var category, label string var value float64 var pType model.PeriodType var pYear, pIdx int if err := rows.Scan(&category, &label, &value, &pType, &pYear, &pIdx); err != nil { return nil, err } key := fmt.Sprintf("%s-%d-%d", pType, pYear, pIdx) if !seen[key] { rs.Periods = append(rs.Periods, model.Period{Type: pType, Year: pYear, Index: pIdx}) seen[key] = true } if category == model.CategoryTotal { rs.Total += value } else { rs.Categories[category] += value rs.Labels[label] += value } } return rs, rows.Err() }