Domain Models
Go structs in internal/models/ that represent the core domain objects.
Invoice
type Invoice struct {
ID uuid.UUID `json:"id"`
InvoiceNumber int `json:"invoice_number"`
DisplayNumber string `json:"display_number"`
ApplicationKey string `json:"application_key"`
CustomerKey string `json:"customer_key"`
PeriodStart time.Time `json:"period_start"`
PeriodEnd time.Time `json:"period_end"`
InvoiceDate time.Time `json:"invoice_date"`
DealType string `json:"deal_type"`
Currency string `json:"currency"`
BaseAmount decimal.Decimal `json:"base_amount"`
OvertimeHours decimal.Decimal `json:"overtime_hours"`
OvertimeAmount decimal.Decimal `json:"overtime_amount"`
TotalAmount decimal.Decimal `json:"total_amount"`
TotalHours decimal.Decimal `json:"total_hours"`
IsOvertime bool `json:"is_overtime"`
MonthlyLimitHours *decimal.Decimal `json:"monthly_limit_hours,omitempty"`
Status string `json:"status"`
ApprovedAt *time.Time `json:"approved_at,omitempty"`
ApprovedBy *string `json:"approved_by,omitempty"`
DeclinedAt *time.Time `json:"declined_at,omitempty"`
DeclinedBy *string `json:"declined_by,omitempty"`
DeclineReason *string `json:"decline_reason,omitempty"`
RejectedAt *time.Time `json:"rejected_at,omitempty"`
RejectedBy *string `json:"rejected_by,omitempty"`
RejectReason *string `json:"reject_reason,omitempty"`
SentAt *time.Time `json:"sent_at,omitempty"`
PaidAt *time.Time `json:"paid_at,omitempty"`
R2StorageKey *string `json:"r2_storage_key,omitempty"`
R2PublicURL *string `json:"r2_public_url,omitempty"`
PlanFactShipmentID *string `json:"planfact_shipment_id,omitempty"`
PDFStoragePath *string `json:"pdf_storage_path,omitempty"`
HTMLTemplateHash *string `json:"html_template_hash,omitempty"`
HTMLOverride *string `json:"html_override,omitempty"`
Version int `json:"version"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CreatedBy *string `json:"created_by,omitempty"`
}
Status Constants
const (
StatusDraft = "draft"
StatusNeedsReview = "needs_review"
StatusApproved = "approved"
StatusDeclined = "declined"
StatusSent = "sent"
StatusAccepted = "accepted"
StatusRejected = "rejected"
StatusPaid = "paid"
)
Allowed Transitions
var AllowedTransitions = map[string][]string{
StatusDraft: {StatusNeedsReview},
StatusNeedsReview: {StatusApproved, StatusDeclined},
StatusDeclined: {StatusDraft},
StatusApproved: {StatusDraft, StatusSent},
StatusSent: {StatusAccepted, StatusRejected},
StatusRejected: {StatusDraft},
StatusAccepted: {StatusPaid},
}
InvoiceLineItem
type InvoiceLineItem struct {
ID uuid.UUID `json:"id"`
InvoiceID uuid.UUID `json:"invoice_id"`
LineType string `json:"line_type"`
Description string `json:"description"`
JiraKey *string `json:"jira_key,omitempty"`
TimeSeconds int `json:"time_seconds"`
BillableSeconds int `json:"billable_seconds"`
UnitPrice decimal.Decimal `json:"unit_price"`
Quantity decimal.Decimal `json:"quantity"`
LineTotal decimal.Decimal `json:"line_total"`
RateTier string `json:"rate_tier"`
RateMultiplier decimal.Decimal `json:"rate_multiplier"`
Source string `json:"source"`
IsAutoGenerated bool `json:"is_auto_generated"`
OriginalDescription *string `json:"original_description,omitempty"`
OriginalTimeSeconds *int `json:"original_time_seconds,omitempty"`
OriginalLineTotal *decimal.Decimal `json:"original_line_total,omitempty"`
SortOrder int `json:"sort_order"`
LinkedIssueKey *string `json:"linked_issue_key,omitempty"`
Contributors json.RawMessage `json:"contributors,omitempty"`
WorklogDate *time.Time `json:"worklog_date,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
RateRule
type RateRule struct {
ID uuid.UUID `json:"id"`
ApplicationKey string `json:"application_key"`
BaseHourlyRate decimal.Decimal `json:"base_hourly_rate"`
MonthlyLimitHours *decimal.Decimal `json:"monthly_limit_hours"`
SLATier string `json:"sla_tier"`
CoverageType string `json:"coverage_type"`
OvertimeMultiplier decimal.Decimal `json:"overtime_multiplier"`
P1P3Multiplier decimal.Decimal `json:"p1_p3_multiplier"`
OffHoursMultiplier decimal.Decimal `json:"off_hours_multiplier"`
P1P3OffHoursMultiplier decimal.Decimal `json:"p1_p3_off_hours_multiplier"`
BusinessHoursStart string `json:"business_hours_start"`
BusinessHoursEnd string `json:"business_hours_end"`
BusinessHoursTZ string `json:"business_hours_tz"`
WeekendDays []int `json:"weekend_days"`
EffectiveFrom time.Time `json:"effective_from"`
EffectiveTo *time.Time `json:"effective_to,omitempty"`
}
Financials
Calculated financial summary returned by the generator.
type Financials struct {
BaseAmount decimal.Decimal `json:"base_amount"`
OvertimeHours decimal.Decimal `json:"overtime_hours"`
OvertimeAmount decimal.Decimal `json:"overtime_amount"`
TotalAmount decimal.Decimal `json:"total_amount"`
TotalHours decimal.Decimal `json:"total_hours"`
IsOvertime bool `json:"is_overtime"`
RateTiers []RateTier `json:"rate_tiers"`
}
const MinBillableSeconds = 1800
Client Models (from ClickHouse)
type Application struct {
ApplicationKey string `json:"application_key"`
CustomerKey string `json:"customer_key"`
ApplicationName string `json:"application_name"`
DealType string `json:"deal_type"`
DealAmount float64 `json:"deal_amount"`
MonthlyLimit float64 `json:"monthly_limit"`
HourlyRate float64 `json:"hourly_rate"`
Currency string `json:"currency"`
InvoiceAmount float64 `json:"invoice_amount"`
}
type Customer struct {
CustomerKey string `json:"customer_key"`
CompanyName string `json:"company_name"`
CompanyType string `json:"company_type"`
TIN string `json:"tin"`
SwiftBIC string `json:"swift_bic"`
SignerFullName string `json:"signer_full_name"`
Country string `json:"country"`
}
type Worklog struct {
IssueKey string `json:"issue_key"`
IssueSummary string `json:"issue_summary"`
IssueTypeName string `json:"issue_type_name"`
PriorityName string `json:"priority_name"`
TimeSpentSeconds uint32 `json:"time_spent_seconds"`
Started time.Time `json:"started"`
}
Event Models
type InvoiceEvent struct {
ID uuid.UUID `json:"id"`
InvoiceID uuid.UUID `json:"invoice_id"`
EventType string `json:"event_type"`
FromStatus *string `json:"from_status,omitempty"`
ToStatus *string `json:"to_status,omitempty"`
Actor string `json:"actor"`
Metadata *json.RawMessage `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type EditHistory struct {
ID uuid.UUID `json:"id"`
InvoiceID uuid.UUID `json:"invoice_id"`
LineItemID *uuid.UUID `json:"line_item_id,omitempty"`
EditType string `json:"edit_type"`
FieldName *string `json:"field_name,omitempty"`
OldValue *string `json:"old_value,omitempty"`
NewValue *string `json:"new_value,omitempty"`
EditedBy string `json:"edited_by"`
EditedAt time.Time `json:"edited_at"`
}
GenerateRequest
Input for creating a draft invoice.
type GenerateRequest struct {
ApplicationKey string `json:"application_key"`
PeriodStart string `json:"period_start"`
PeriodEnd string `json:"period_end"`
DealType string `json:"deal_type"`
Currency string `json:"currency"`
BaseAmount decimal.Decimal `json:"base_amount"`
TotalAmount decimal.Decimal `json:"total_amount"`
TotalHours decimal.Decimal `json:"total_hours"`
OvertimeHours decimal.Decimal `json:"overtime_hours"`
OvertimeAmount decimal.Decimal `json:"overtime_amount"`
IsOvertime bool `json:"is_overtime"`
LineItems []LineItemInput `json:"line_items"`
}