136 lines
3.6 KiB
Go
136 lines
3.6 KiB
Go
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()
|
|
}
|