better end points and better tests
This commit is contained in:
82
internal/service/report-service.go
Normal file
82
internal/service/report-service.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"Engine/internal/database"
|
||||
"Engine/internal/model"
|
||||
)
|
||||
|
||||
type ReportService struct {
|
||||
repo *database.ReportRepo
|
||||
}
|
||||
|
||||
func NewReportService(repo *database.ReportRepo) *ReportService {
|
||||
return &ReportService{repo: repo}
|
||||
}
|
||||
|
||||
type PnLFilter struct {
|
||||
FiscalYear int
|
||||
FiscalPeriod int
|
||||
DeptCode string
|
||||
Version model.BudgetVersion
|
||||
}
|
||||
|
||||
func (s *ReportService) CreatePnL(ctx context.Context, f PnLFilter) (*model.PnLReport, error) {
|
||||
// fetch all five GL type buckets in parallel would be nicer, but keeping
|
||||
// it simple and sequential matches the rest of your codebase style.
|
||||
|
||||
revenue, err := s.repo.GetGLRevenueActuals(ctx, f.FiscalYear, f.FiscalPeriod, f.DeptCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreatePnL: revenue actuals: %w", err)
|
||||
}
|
||||
|
||||
cogs, err := s.repo.GetGLCOGSActuals(ctx, f.FiscalYear, f.FiscalPeriod, f.DeptCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreatePnL: cogs actuals: %w", err)
|
||||
}
|
||||
|
||||
opex, err := s.repo.GetGLOpexActuals(ctx, f.FiscalYear, f.FiscalPeriod, f.DeptCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreatePnL: opex actuals: %w", err)
|
||||
}
|
||||
|
||||
headcount, err := s.repo.GetGLHeadcountActuals(ctx, f.FiscalYear, f.FiscalPeriod, f.DeptCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreatePnL: headcount actuals: %w", err)
|
||||
}
|
||||
|
||||
capex, err := s.repo.GetGLCapexActuals(ctx, f.FiscalYear, f.FiscalPeriod, f.DeptCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreatePnL: capex actuals: %w", err)
|
||||
}
|
||||
|
||||
report := &model.PnLReport{
|
||||
Department: f.DeptCode,
|
||||
FiscalYear: f.FiscalYear,
|
||||
FiscalPeriod: f.FiscalPeriod,
|
||||
Version: f.Version,
|
||||
Currency: "DKK",
|
||||
Revenue: toSection(revenue),
|
||||
COGS: toSection(cogs),
|
||||
Opex: toSection(opex),
|
||||
Headcount: toSection(headcount),
|
||||
Capex: toSection(capex),
|
||||
}
|
||||
|
||||
report.GrossProfit = report.Revenue.Total - report.COGS.Total
|
||||
report.EBIT = report.GrossProfit - report.Opex.Total - report.Headcount.Total
|
||||
report.NetIncome = report.EBIT - report.Capex.Total
|
||||
|
||||
return report, nil
|
||||
}
|
||||
|
||||
// toSection sums the rows and packages them into a PnLSection.
|
||||
func toSection(rows []model.GLAmountRow) model.PnLSection {
|
||||
s := model.PnLSection{Lines: rows}
|
||||
for _, r := range rows {
|
||||
s.Total += r.Amount
|
||||
}
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user