70 lines
1.7 KiB
Go
70 lines
1.7 KiB
Go
package model
|
|
|
|
import "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 {
|
|
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
|
|
}
|
|
|
|
// RevenueCategory is what the revenue is broken down by
|
|
type RevenueCategory string
|
|
|
|
const (
|
|
CategoryProduct RevenueCategory = "product"
|
|
CategoryLocation RevenueCategory = "location"
|
|
CategoryTotal RevenueCategory = "total"
|
|
)
|
|
|
|
// Revenue is a single line in a financial report
|
|
type Revenue struct {
|
|
ID int
|
|
Company *Company
|
|
Currency *Currency
|
|
Category RevenueCategory
|
|
Label string // e.g. "North America", "iPhone", "Total"
|
|
Value float64
|
|
Period Period
|
|
}
|
|
|
|
// RevenueReport groups revenue lines for a company/period
|
|
// and verifies that sub-categories sum to total
|
|
type RevenueReport struct {
|
|
Company *Company
|
|
Period Period
|
|
Entries []Revenue
|
|
}
|
|
|
|
// Total returns the sum of all entries matching a category
|
|
func (r *RevenueReport) Total(category RevenueCategory) float64 {
|
|
var sum float64
|
|
for _, e := range r.Entries {
|
|
if e.Category == category {
|
|
sum += e.Value
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
// Validate checks that product + location sums match the total entry
|
|
func (r *RevenueReport) Validate() (bool, float64, float64) {
|
|
total := r.Total(CategoryTotal)
|
|
products := r.Total(CategoryProduct)
|
|
locations := r.Total(CategoryLocation)
|
|
// both breakdowns should equal the total
|
|
return products == total && locations == total, products, locations
|
|
}
|