102 lines
2.3 KiB
Go
102 lines
2.3 KiB
Go
package model
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// PeriodType defines the granularity of the revenue entry
|
|
type PeriodType string
|
|
|
|
const (
|
|
PeriodQuarter PeriodType = "Q"
|
|
PeriodHalfYear PeriodType = "H"
|
|
PeriodYear PeriodType = "Y"
|
|
)
|
|
|
|
// Period holds the actual time range for a revenue entry
|
|
type Period struct {
|
|
ID int
|
|
Type PeriodType
|
|
Year int
|
|
Index int // Q1=1 Q2=2 Q3=3 Q4=4 | H1=1 H2=2 | FY=1
|
|
Start time.Time
|
|
End time.Time
|
|
}
|
|
|
|
func (p *Period) Insert(db *sql.DB) error {
|
|
_, 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, end_date=excluded.end_date`,
|
|
string(p.Type), p.Year, p.Index, p.Start.Format("2006-01-02"), p.End.Format("2006-01-02"),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert period: %w", err)
|
|
}
|
|
|
|
var id int
|
|
err = db.QueryRow(
|
|
`SELECT id FROM periods WHERE type = ? AND year = ? AND idx = ?`,
|
|
string(p.Type), p.Year, p.Index,
|
|
).Scan(&id)
|
|
if err != nil {
|
|
return fmt.Errorf("select period: %w", err)
|
|
}
|
|
p.ID = id
|
|
return nil
|
|
}
|
|
|
|
type RevenueCategory struct {
|
|
ID int
|
|
CompanyID int
|
|
ParentID *int
|
|
Name string // e.g. "product", "location", "segment"
|
|
}
|
|
|
|
func (rc *RevenueCategory) Validate() error {
|
|
if rc.ID == 0 {
|
|
return fmt.Errorf("No ID Set")
|
|
} else if rc.Name == "" {
|
|
return fmt.Errorf("No Name found")
|
|
} else if rc.CompanyID == 0 {
|
|
return fmt.Errorf("No Company Set")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rc *RevenueCategory) Insert(db *sql.DB) error {
|
|
if err := rc.Validate(); err != nil {
|
|
return fmt.Errorf("failed to insert: %w", err)
|
|
}
|
|
|
|
_, err := db.Exec(
|
|
`INSERT INTO category (company_id, parent_id, name) VALUES (?, ?, ?)
|
|
ON CONFLICT(company_id, name) DO UPDATE SET parent_id=excluded.parent_id`,
|
|
rc.CompanyID, rc.ParentID, rc.Name,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert category: %w", err)
|
|
}
|
|
|
|
err = db.QueryRow(
|
|
`SELECT id FROM category WHERE company_id = ? AND name = ?`,
|
|
rc.CompanyID, rc.Name,
|
|
).Scan(&rc.ID)
|
|
if err != nil {
|
|
return fmt.Errorf("select category id: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Revenue is a single line in a financial report
|
|
type Revenue struct {
|
|
ID int
|
|
Company *Company
|
|
Currency *Currency
|
|
Category *RevenueCategory
|
|
Period *Period
|
|
Value float64
|
|
}
|