invoicing

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrRuleNameRequired    = &ValidationError{Field: "name", Message: "rule name is required"}
	ErrTriggerTypeRequired = &ValidationError{Field: "trigger_type", Message: "trigger type is required"}
	ErrInvalidTriggerType  = &ValidationError{Field: "trigger_type", Message: "invalid trigger type"}
	ErrInvalidDaysOffset   = &ValidationError{Field: "days_offset", Message: "days offset cannot be negative"}
	ErrRuleNotFound        = &NotFoundError{Entity: "reminder rule"}
)

Errors

View Source
var ErrInvoiceNotFound = fmt.Errorf("invoice not found")

ErrInvoiceNotFound is returned when an invoice is not found

Functions

This section is empty.

Types

type AutomatedReminderResult

type AutomatedReminderResult struct {
	TenantID      string    `json:"tenant_id"`
	RuleID        string    `json:"rule_id"`
	RuleName      string    `json:"rule_name"`
	InvoicesFound int       `json:"invoices_found"`
	RemindersSent int       `json:"reminders_sent"`
	Skipped       int       `json:"skipped"`
	Failed        int       `json:"failed"`
	Errors        []string  `json:"errors,omitempty"`
	RunAt         time.Time `json:"run_at"`
}

AutomatedReminderResult represents the result of an automated reminder run

type AutomatedReminderService

type AutomatedReminderService struct {
	// contains filtered or unexported fields
}

AutomatedReminderService handles scheduled reminder processing

func NewAutomatedReminderService

func NewAutomatedReminderService(db *pgxpool.Pool, emailService *email.Service) *AutomatedReminderService

NewAutomatedReminderService creates a new automated reminder service

func NewAutomatedReminderServiceWithRepository

func NewAutomatedReminderServiceWithRepository(ruleRepo ReminderRuleRepository, emailService *email.Service) *AutomatedReminderService

NewAutomatedReminderServiceWithRepository creates a service with custom repository (for testing)

func (*AutomatedReminderService) CreateRule

func (s *AutomatedReminderService) CreateRule(ctx context.Context, tenantID, schemaName string, req *CreateReminderRuleRequest) (*ReminderRule, error)

CreateRule creates a new reminder rule

func (*AutomatedReminderService) DeleteRule

func (s *AutomatedReminderService) DeleteRule(ctx context.Context, tenantID, schemaName, ruleID string) error

DeleteRule deletes a rule

func (*AutomatedReminderService) GetRule

func (s *AutomatedReminderService) GetRule(ctx context.Context, tenantID, schemaName, ruleID string) (*ReminderRule, error)

GetRule returns a single rule

func (*AutomatedReminderService) ListRules

func (s *AutomatedReminderService) ListRules(ctx context.Context, tenantID, schemaName string) ([]ReminderRule, error)

ListRules returns all reminder rules for a tenant

func (*AutomatedReminderService) ProcessRemindersForTenant

func (s *AutomatedReminderService) ProcessRemindersForTenant(ctx context.Context, tenantID, schemaName, companyName string) ([]AutomatedReminderResult, error)

ProcessRemindersForTenant processes all reminder rules for a tenant

func (*AutomatedReminderService) UpdateRule

func (s *AutomatedReminderService) UpdateRule(ctx context.Context, tenantID, schemaName, ruleID string, req *UpdateReminderRuleRequest) (*ReminderRule, error)

UpdateRule updates an existing rule

type BulkReminderResult

type BulkReminderResult struct {
	TotalRequested int              `json:"total_requested"`
	Successful     int              `json:"successful"`
	Failed         int              `json:"failed"`
	Results        []ReminderResult `json:"results"`
}

BulkReminderResult represents the results of sending multiple reminders

type CreateInvoiceLineRequest

type CreateInvoiceLineRequest struct {
	Description     string          `json:"description"`
	Quantity        decimal.Decimal `json:"quantity"`
	Unit            string          `json:"unit,omitempty"`
	UnitPrice       decimal.Decimal `json:"unit_price"`
	DiscountPercent decimal.Decimal `json:"discount_percent,omitempty"`
	VATRate         decimal.Decimal `json:"vat_rate"`
	VATTreatment    VATTreatment    `json:"vat_treatment,omitempty"`
	AccountID       *string         `json:"account_id,omitempty"`
	ProductID       *string         `json:"product_id,omitempty"`
}

CreateInvoiceLineRequest is a line in the create invoice request

type CreateInvoiceRequest

type CreateInvoiceRequest struct {
	InvoiceType  InvoiceType                `json:"invoice_type"`
	ContactID    string                     `json:"contact_id"`
	IssueDate    time.Time                  `json:"issue_date"`
	DueDate      time.Time                  `json:"due_date"`
	Currency     string                     `json:"currency,omitempty"`
	ExchangeRate decimal.Decimal            `json:"exchange_rate,omitempty"`
	Reference    string                     `json:"reference,omitempty"`
	Notes        string                     `json:"notes,omitempty"`
	Lines        []CreateInvoiceLineRequest `json:"lines"`
	UserID       string                     `json:"-"`
}

CreateInvoiceRequest is the request to create an invoice

type CreateReminderRuleRequest

type CreateReminderRuleRequest struct {
	Name              string      `json:"name"`
	TriggerType       TriggerType `json:"trigger_type"`
	DaysOffset        int         `json:"days_offset"`
	EmailTemplateType string      `json:"email_template_type,omitempty"`
	IsActive          bool        `json:"is_active"`
}

CreateReminderRuleRequest is the request to create a reminder rule

func (*CreateReminderRuleRequest) Validate

func (r *CreateReminderRuleRequest) Validate() error

Validate validates the create rule request

type GORMRepository

type GORMRepository struct {
	// contains filtered or unexported fields
}

GORMRepository implements Repository using GORM

func NewGORMRepository

func NewGORMRepository(db *gorm.DB) *GORMRepository

NewGORMRepository creates a new GORM invoicing repository

func (*GORMRepository) ApplyPayment

func (r *GORMRepository) ApplyPayment(ctx context.Context, schemaName, tenantID, invoiceID string, amount decimal.Decimal) error

ApplyPayment atomically applies a payment delta while holding the invoice row lock. This prevents concurrent allocations or reversals from losing a previously recorded payment amount.

func (*GORMRepository) Create

func (r *GORMRepository) Create(ctx context.Context, schemaName string, invoice *Invoice) error

Create inserts a new invoice with its lines

func (*GORMRepository) GenerateNumber

func (r *GORMRepository) GenerateNumber(ctx context.Context, schemaName, tenantID string, invoiceType InvoiceType) (string, error)

GenerateNumber generates a new invoice number

func (*GORMRepository) GetByID

func (r *GORMRepository) GetByID(ctx context.Context, schemaName, tenantID, invoiceID string) (*Invoice, error)

GetByID retrieves an invoice by ID with its lines

func (*GORMRepository) List

func (r *GORMRepository) List(ctx context.Context, schemaName, tenantID string, filter *InvoiceFilter) ([]Invoice, error)

List retrieves invoices with optional filtering

func (*GORMRepository) UpdateOverdueStatus

func (r *GORMRepository) UpdateOverdueStatus(ctx context.Context, schemaName, tenantID string) (int, error)

UpdateOverdueStatus updates the status of overdue invoices

func (*GORMRepository) UpdatePayment

func (r *GORMRepository) UpdatePayment(ctx context.Context, schemaName, tenantID, invoiceID string, amountPaid decimal.Decimal, status InvoiceStatus) error

UpdatePayment updates the amount paid and status of an invoice

func (*GORMRepository) UpdateStatus

func (r *GORMRepository) UpdateStatus(ctx context.Context, schemaName, tenantID, invoiceID string, status InvoiceStatus) error

UpdateStatus updates the status of an invoice

func (*GORMRepository) VoidInvoice

func (r *GORMRepository) VoidInvoice(ctx context.Context, schemaName, tenantID, invoiceID string) error

VoidInvoice atomically voids an unpaid invoice. The payment and status predicates are part of the update so a concurrent payment cannot be followed by a stale void operation.

type ImportEInvoiceRequest

type ImportEInvoiceRequest struct {
	XMLContent  string      `json:"xml_content"`
	FileName    string      `json:"file_name,omitempty"`
	InvoiceType InvoiceType `json:"invoice_type,omitempty"`
	UserID      string      `json:"-"`
}

ImportEInvoiceRequest contains Estonian e-invoice XML for manual invoice import.

type ImportInvoicesRequest

type ImportInvoicesRequest struct {
	CSVContent string `json:"csv_content"`
	FileName   string `json:"file_name,omitempty"`
	UserID     string `json:"-"`
}

ImportInvoicesRequest contains CSV payload for bulk invoice import.

type ImportInvoicesResult

type ImportInvoicesResult struct {
	FileName        string                   `json:"file_name,omitempty"`
	RowsProcessed   int                      `json:"rows_processed"`
	InvoicesCreated int                      `json:"invoices_created"`
	LinesImported   int                      `json:"lines_imported"`
	RowsSkipped     int                      `json:"rows_skipped"`
	Errors          []ImportInvoicesRowError `json:"errors,omitempty"`
}

ImportInvoicesResult summarizes a bulk invoice import.

type ImportInvoicesRowError

type ImportInvoicesRowError struct {
	Row           int    `json:"row"`
	InvoiceNumber string `json:"invoice_number,omitempty"`
	Message       string `json:"message"`
}

ImportInvoicesRowError describes a row-level import failure.

type InterestCalculationResult

type InterestCalculationResult struct {
	InvoiceID         string          `json:"invoice_id"`
	InvoiceNumber     string          `json:"invoice_number"`
	DueDate           time.Time       `json:"due_date"`
	DaysOverdue       int             `json:"days_overdue"`
	OutstandingAmount decimal.Decimal `json:"outstanding_amount"`
	InterestRate      decimal.Decimal `json:"interest_rate"`
	DailyInterest     decimal.Decimal `json:"daily_interest"`
	TotalInterest     decimal.Decimal `json:"total_interest"`
	TotalWithInterest decimal.Decimal `json:"total_with_interest"`
	CalculatedAt      time.Time       `json:"calculated_at"`
	Currency          string          `json:"currency"`
}

InterestCalculationResult represents the result of an interest calculation

type InterestGORMRepository

type InterestGORMRepository struct {
	// contains filtered or unexported fields
}

InterestGORMRepository stores interest data through the shared ORM layer.

func NewInterestGORMRepository

func NewInterestGORMRepository(db *gorm.DB) *InterestGORMRepository

func NewInterestRepository

func NewInterestRepository(db *pgxpool.Pool) *InterestGORMRepository

func (*InterestGORMRepository) CreateInterest

func (r *InterestGORMRepository) CreateInterest(ctx context.Context, schemaName string, interest *InvoiceInterest) error

func (*InterestGORMRepository) GetInvoiceForInterest

func (r *InterestGORMRepository) GetInvoiceForInterest(ctx context.Context, schemaName, tenantID, invoiceID string) (*interestInvoice, error)

func (*InterestGORMRepository) GetLatestInterest

func (r *InterestGORMRepository) GetLatestInterest(ctx context.Context, schemaName, invoiceID string) (*InvoiceInterest, error)

func (*InterestGORMRepository) ListInterestHistory

func (r *InterestGORMRepository) ListInterestHistory(ctx context.Context, schemaName, invoiceID string) ([]InvoiceInterest, error)

func (*InterestGORMRepository) ListOverdueInvoices

func (r *InterestGORMRepository) ListOverdueInvoices(ctx context.Context, schemaName, tenantID string, asOfDate time.Time) ([]interestInvoice, error)

type InterestRepository

type InterestRepository interface {
	GetInvoiceForInterest(ctx context.Context, schemaName, tenantID, invoiceID string) (*interestInvoice, error)
	CreateInterest(ctx context.Context, schemaName string, interest *InvoiceInterest) error
	GetLatestInterest(ctx context.Context, schemaName, invoiceID string) (*InvoiceInterest, error)
	ListInterestHistory(ctx context.Context, schemaName, invoiceID string) ([]InvoiceInterest, error)
	ListOverdueInvoices(ctx context.Context, schemaName, tenantID string, asOfDate time.Time) ([]interestInvoice, error)
}

type InterestService

type InterestService struct {
	// contains filtered or unexported fields
}

InterestService handles interest calculations for overdue invoices.

func NewInterestService

func NewInterestService(db *pgxpool.Pool) *InterestService

NewInterestService creates a new interest service.

func NewInterestServiceWithRepository

func NewInterestServiceWithRepository(repo InterestRepository) *InterestService

func (*InterestService) CalculateInterest

func (s *InterestService) CalculateInterest(ctx context.Context, schemaName, tenantID, invoiceID string, interestRate float64, asOfDate time.Time) (*InterestCalculationResult, error)

CalculateInterest calculates current interest for an invoice.

func (*InterestService) CalculateInterestForOverdueInvoices

func (s *InterestService) CalculateInterestForOverdueInvoices(ctx context.Context, schemaName, tenantID string, interestRate float64) ([]InterestCalculationResult, error)

CalculateInterestForOverdueInvoices calculates interest for all overdue invoices of a tenant.

func (*InterestService) GetLatestInterest

func (s *InterestService) GetLatestInterest(ctx context.Context, schemaName, invoiceID string) (*InvoiceInterest, error)

GetLatestInterest gets the most recent interest calculation for an invoice.

func (*InterestService) ListInterestHistory

func (s *InterestService) ListInterestHistory(ctx context.Context, schemaName, invoiceID string) ([]InvoiceInterest, error)

ListInterestHistory gets all interest calculations for an invoice.

func (*InterestService) SaveInterestCalculation

func (s *InterestService) SaveInterestCalculation(ctx context.Context, schemaName string, result *InterestCalculationResult) (*InvoiceInterest, error)

SaveInterestCalculation saves an interest calculation record.

type InterestSettings

type InterestSettings struct {
	Rate        float64 `json:"rate"`        // Daily interest rate (e.g., 0.0005 = 0.05%)
	AnnualRate  float64 `json:"annual_rate"` // Annualized rate for display (rate * 365)
	Description string  `json:"description"` // Human-readable description
	IsEnabled   bool    `json:"is_enabled"`  // Whether interest calculation is enabled
}

InterestSettings represents the interest configuration for a tenant

type Invoice

type Invoice struct {
	ID             string            `json:"id"`
	TenantID       string            `json:"tenant_id"`
	InvoiceNumber  string            `json:"invoice_number"`
	InvoiceType    InvoiceType       `json:"invoice_type"`
	ContactID      string            `json:"contact_id"`
	Contact        *contacts.Contact `json:"contact,omitempty"`
	IssueDate      time.Time         `json:"issue_date"`
	DueDate        time.Time         `json:"due_date"`
	Currency       string            `json:"currency"`
	ExchangeRate   decimal.Decimal   `json:"exchange_rate"`
	Subtotal       decimal.Decimal   `json:"subtotal"`
	VATAmount      decimal.Decimal   `json:"vat_amount"`
	Total          decimal.Decimal   `json:"total"`
	BaseSubtotal   decimal.Decimal   `json:"base_subtotal"`
	BaseVATAmount  decimal.Decimal   `json:"base_vat_amount"`
	BaseTotal      decimal.Decimal   `json:"base_total"`
	AmountPaid     decimal.Decimal   `json:"amount_paid"`
	Status         InvoiceStatus     `json:"status"`
	Reference      string            `json:"reference,omitempty"`
	Notes          string            `json:"notes,omitempty"`
	Lines          []InvoiceLine     `json:"lines"`
	JournalEntryID *string           `json:"journal_entry_id,omitempty"`
	EInvoiceSentAt *time.Time        `json:"einvoice_sent_at,omitempty"`
	EInvoiceID     *string           `json:"einvoice_id,omitempty"`
	CreatedAt      time.Time         `json:"created_at"`
	CreatedBy      string            `json:"created_by"`
	UpdatedAt      time.Time         `json:"updated_at"`
}

Invoice represents a sales or purchase invoice

func (*Invoice) AmountDue

func (inv *Invoice) AmountDue() decimal.Decimal

AmountDue returns the amount still owed

func (*Invoice) Calculate

func (inv *Invoice) Calculate()

Calculate computes the invoice totals from lines

func (*Invoice) IsOverdue

func (inv *Invoice) IsOverdue() bool

IsOverdue returns true if the invoice is past due and not fully paid

func (*Invoice) IsPaid

func (inv *Invoice) IsPaid() bool

IsPaid returns true if the invoice is fully paid

func (*Invoice) Validate

func (inv *Invoice) Validate() error

Validate validates the invoice

type InvoiceFilter

type InvoiceFilter struct {
	InvoiceType InvoiceType
	Status      InvoiceStatus
	ContactID   string
	FromDate    *time.Time
	ToDate      *time.Time
	Search      string
}

InvoiceFilter provides filtering options

type InvoiceForReminder

type InvoiceForReminder struct {
	ID                string `json:"id"`
	InvoiceNumber     string `json:"invoice_number"`
	ContactID         string `json:"contact_id"`
	ContactName       string `json:"contact_name"`
	ContactEmail      string `json:"contact_email,omitempty"`
	IssueDate         string `json:"issue_date"`
	DueDate           string `json:"due_date"`
	Total             string `json:"total"`
	AmountPaid        string `json:"amount_paid"`
	OutstandingAmount string `json:"outstanding_amount"`
	Currency          string `json:"currency"`
	DaysUntilDue      int    `json:"days_until_due"` // Negative if overdue
	DaysOverdue       int    `json:"days_overdue"`   // 0 if not overdue
}

InvoiceForReminder represents an invoice that may need a reminder

type InvoiceInterest

type InvoiceInterest struct {
	ID                string          `json:"id"`
	InvoiceID         string          `json:"invoice_id"`
	CalculatedAt      time.Time       `json:"calculated_at"`
	DaysOverdue       int             `json:"days_overdue"`
	PrincipalAmount   decimal.Decimal `json:"principal_amount"`
	InterestRate      decimal.Decimal `json:"interest_rate"`
	InterestAmount    decimal.Decimal `json:"interest_amount"`
	TotalWithInterest decimal.Decimal `json:"total_with_interest"`
	CreatedAt         time.Time       `json:"created_at"`
}

InvoiceInterest represents a calculated interest record for an invoice

type InvoiceLine

type InvoiceLine struct {
	ID              string          `json:"id"`
	TenantID        string          `json:"tenant_id"`
	InvoiceID       string          `json:"invoice_id"`
	LineNumber      int             `json:"line_number"`
	Description     string          `json:"description"`
	Quantity        decimal.Decimal `json:"quantity"`
	Unit            string          `json:"unit,omitempty"`
	UnitPrice       decimal.Decimal `json:"unit_price"`
	DiscountPercent decimal.Decimal `json:"discount_percent"`
	VATRate         decimal.Decimal `json:"vat_rate"`
	VATTreatment    VATTreatment    `json:"vat_treatment"`
	LineSubtotal    decimal.Decimal `json:"line_subtotal"`
	LineVAT         decimal.Decimal `json:"line_vat"`
	LineTotal       decimal.Decimal `json:"line_total"`
	AccountID       *string         `json:"account_id,omitempty"`
	ProductID       *string         `json:"product_id,omitempty"`
}

InvoiceLine represents a line item on an invoice

func (*InvoiceLine) Calculate

func (l *InvoiceLine) Calculate()

Calculate computes the line totals

func (InvoiceLine) ReverseChargeVAT

func (l InvoiceLine) ReverseChargeVAT() decimal.Decimal

ReverseChargeVAT calculates the self-assessed VAT amount for reverse-charge reporting.

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus represents the status of an invoice

const (
	StatusDraft         InvoiceStatus = "DRAFT"
	StatusSent          InvoiceStatus = "SENT"
	StatusPartiallyPaid InvoiceStatus = "PARTIALLY_PAID"
	StatusPaid          InvoiceStatus = "PAID"
	StatusOverdue       InvoiceStatus = "OVERDUE"
	StatusVoided        InvoiceStatus = "VOIDED"
)

type InvoiceType

type InvoiceType string

InvoiceType represents the type of invoice

const (
	InvoiceTypeSales      InvoiceType = "SALES"
	InvoiceTypePurchase   InvoiceType = "PURCHASE"
	InvoiceTypeCreditNote InvoiceType = "CREDIT_NOTE"
)

type MockReminderRepository

type MockReminderRepository struct {
	OverdueInvoices []OverdueInvoice
	Reminders       map[string][]PaymentReminder
	GetOverdueErr   error
}

MockReminderRepository for testing.

func NewMockReminderRepository

func NewMockReminderRepository() *MockReminderRepository

NewMockReminderRepository creates a new mock reminder repository.

func (*MockReminderRepository) AddMockOverdueInvoice

func (m *MockReminderRepository) AddMockOverdueInvoice(id, invoiceNumber, contactID, contactName, contactEmail, currency string, total, amountPaid decimal.Decimal, daysOverdue int)

AddMockOverdueInvoice adds a mock overdue invoice for testing.

func (*MockReminderRepository) CreateReminder

func (m *MockReminderRepository) CreateReminder(ctx context.Context, schemaName string, reminder *PaymentReminder) error

CreateReminder creates a mock reminder.

func (*MockReminderRepository) GetOverdueInvoices

func (m *MockReminderRepository) GetOverdueInvoices(ctx context.Context, schemaName, tenantID string, asOfDate time.Time) ([]OverdueInvoice, error)

GetOverdueInvoices returns mock overdue invoices.

func (*MockReminderRepository) GetReminderCount

func (m *MockReminderRepository) GetReminderCount(ctx context.Context, schemaName, tenantID, invoiceID string) (int, *time.Time, error)

GetReminderCount returns mock reminder count.

func (*MockReminderRepository) GetRemindersByInvoice

func (m *MockReminderRepository) GetRemindersByInvoice(ctx context.Context, schemaName, tenantID, invoiceID string) ([]PaymentReminder, error)

GetRemindersByInvoice returns mock reminders for an invoice.

func (*MockReminderRepository) UpdateReminderStatus

func (m *MockReminderRepository) UpdateReminderStatus(ctx context.Context, schemaName, reminderID string, status ReminderStatus, sentAt *time.Time, errorMsg string) error

UpdateReminderStatus updates mock reminder status.

type NotFoundError

type NotFoundError struct {
	Entity string
}

NotFoundError represents a not found error

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type OverdueInvoice

type OverdueInvoice struct {
	ID                string          `json:"id"`
	InvoiceNumber     string          `json:"invoice_number"`
	ContactID         string          `json:"contact_id"`
	ContactName       string          `json:"contact_name"`
	ContactEmail      string          `json:"contact_email,omitempty"`
	IssueDate         string          `json:"issue_date"`
	DueDate           string          `json:"due_date"`
	Total             decimal.Decimal `json:"total"`
	AmountPaid        decimal.Decimal `json:"amount_paid"`
	OutstandingAmount decimal.Decimal `json:"outstanding_amount"`
	Currency          string          `json:"currency"`
	DaysOverdue       int             `json:"days_overdue"`
	ReminderCount     int             `json:"reminder_count"`
	LastReminderAt    *time.Time      `json:"last_reminder_at,omitempty"`
}

OverdueInvoice represents an overdue invoice with reminder info

type OverdueInvoicesSummary

type OverdueInvoicesSummary struct {
	TotalOverdue       decimal.Decimal  `json:"total_overdue"`
	InvoiceCount       int              `json:"invoice_count"`
	ContactCount       int              `json:"contact_count"`
	AverageDaysOverdue int              `json:"average_days_overdue"`
	Invoices           []OverdueInvoice `json:"invoices"`
	GeneratedAt        time.Time        `json:"generated_at"`
}

OverdueInvoicesSummary represents a summary of overdue invoices

type PaymentReminder

type PaymentReminder struct {
	ID             string         `json:"id"`
	TenantID       string         `json:"tenant_id"`
	InvoiceID      string         `json:"invoice_id"`
	InvoiceNumber  string         `json:"invoice_number"`
	ContactID      string         `json:"contact_id"`
	ContactName    string         `json:"contact_name"`
	ContactEmail   string         `json:"contact_email"`
	RuleID         *string        `json:"rule_id,omitempty"`      // Link to reminder rule
	TriggerType    string         `json:"trigger_type,omitempty"` // BEFORE_DUE, ON_DUE, AFTER_DUE
	DaysOffset     int            `json:"days_offset,omitempty"`  // Days from due date
	ReminderNumber int            `json:"reminder_number"`        // 1st, 2nd, 3rd reminder etc.
	Status         ReminderStatus `json:"status"`
	SentAt         *time.Time     `json:"sent_at,omitempty"`
	ErrorMessage   string         `json:"error_message,omitempty"`
	CreatedAt      time.Time      `json:"created_at"`
	UpdatedAt      time.Time      `json:"updated_at"`
}

PaymentReminder represents a payment reminder for an overdue invoice

type ReminderGORMRepository

type ReminderGORMRepository struct {
	// contains filtered or unexported fields
}

ReminderGORMRepository implements ReminderRepository with the shared ORM layer.

func NewReminderGORMRepository

func NewReminderGORMRepository(db *gorm.DB) *ReminderGORMRepository

func NewReminderRepository

func NewReminderRepository(db *pgxpool.Pool) *ReminderGORMRepository

func (*ReminderGORMRepository) CreateReminder

func (r *ReminderGORMRepository) CreateReminder(ctx context.Context, schemaName string, reminder *PaymentReminder) error

CreateReminder creates a new payment reminder record.

func (*ReminderGORMRepository) GetOverdueInvoices

func (r *ReminderGORMRepository) GetOverdueInvoices(ctx context.Context, schemaName, tenantID string, asOfDate time.Time) ([]OverdueInvoice, error)

GetOverdueInvoices retrieves all overdue sales invoices.

func (*ReminderGORMRepository) GetReminderCount

func (r *ReminderGORMRepository) GetReminderCount(ctx context.Context, schemaName, tenantID, invoiceID string) (int, *time.Time, error)

GetReminderCount gets the number of reminders sent for an invoice.

func (*ReminderGORMRepository) GetRemindersByInvoice

func (r *ReminderGORMRepository) GetRemindersByInvoice(ctx context.Context, schemaName, tenantID, invoiceID string) ([]PaymentReminder, error)

GetRemindersByInvoice gets all reminders for an invoice.

func (*ReminderGORMRepository) UpdateReminderStatus

func (r *ReminderGORMRepository) UpdateReminderStatus(ctx context.Context, schemaName, reminderID string, status ReminderStatus, sentAt *time.Time, errorMsg string) error

UpdateReminderStatus updates the status of a reminder.

type ReminderRepository

type ReminderRepository interface {
	// GetOverdueInvoices retrieves all overdue sales invoices
	GetOverdueInvoices(ctx context.Context, schemaName, tenantID string, asOfDate time.Time) ([]OverdueInvoice, error)

	// GetReminderCount gets the number of reminders sent for an invoice
	GetReminderCount(ctx context.Context, schemaName, tenantID, invoiceID string) (int, *time.Time, error)

	// CreateReminder creates a new payment reminder record
	CreateReminder(ctx context.Context, schemaName string, reminder *PaymentReminder) error

	// UpdateReminderStatus updates the status of a reminder
	UpdateReminderStatus(ctx context.Context, schemaName, reminderID string, status ReminderStatus, sentAt *time.Time, errorMsg string) error

	// GetRemindersByInvoice gets all reminders for an invoice
	GetRemindersByInvoice(ctx context.Context, schemaName, tenantID, invoiceID string) ([]PaymentReminder, error)
}

ReminderRepository defines the interface for payment reminder data access

type ReminderResult

type ReminderResult struct {
	InvoiceID     string `json:"invoice_id"`
	InvoiceNumber string `json:"invoice_number"`
	Success       bool   `json:"success"`
	Message       string `json:"message"`
	ReminderID    string `json:"reminder_id,omitempty"`
}

ReminderResult represents the result of sending a reminder

type ReminderRule

type ReminderRule struct {
	ID                string      `json:"id"`
	TenantID          string      `json:"tenant_id"`
	Name              string      `json:"name"`
	TriggerType       TriggerType `json:"trigger_type"`
	DaysOffset        int         `json:"days_offset"`
	EmailTemplateType string      `json:"email_template_type"`
	IsActive          bool        `json:"is_active"`
	CreatedAt         time.Time   `json:"created_at"`
	UpdatedAt         time.Time   `json:"updated_at"`
}

ReminderRule defines when automated reminders should be sent

type ReminderRuleGORMRepository

type ReminderRuleGORMRepository struct {
	// contains filtered or unexported fields
}

ReminderRuleGORMRepository implements ReminderRuleRepository with the shared ORM layer.

func NewReminderRuleGORMRepository

func NewReminderRuleGORMRepository(db *gorm.DB) *ReminderRuleGORMRepository

func NewReminderRuleRepository

func NewReminderRuleRepository(db *pgxpool.Pool) *ReminderRuleGORMRepository

func (*ReminderRuleGORMRepository) CreateRule

func (r *ReminderRuleGORMRepository) CreateRule(ctx context.Context, schemaName string, rule *ReminderRule) error

func (*ReminderRuleGORMRepository) DeleteRule

func (r *ReminderRuleGORMRepository) DeleteRule(ctx context.Context, schemaName, tenantID, ruleID string) error

func (*ReminderRuleGORMRepository) GetInvoicesForRule

func (r *ReminderRuleGORMRepository) GetInvoicesForRule(ctx context.Context, schemaName, tenantID string, rule *ReminderRule, asOfDate time.Time) ([]InvoiceForReminder, error)

func (*ReminderRuleGORMRepository) GetRule

func (r *ReminderRuleGORMRepository) GetRule(ctx context.Context, schemaName, tenantID, ruleID string) (*ReminderRule, error)

func (*ReminderRuleGORMRepository) HasReminderBeenSent

func (r *ReminderRuleGORMRepository) HasReminderBeenSent(ctx context.Context, schemaName, tenantID, invoiceID, ruleID string) (bool, error)

func (*ReminderRuleGORMRepository) ListActiveRules

func (r *ReminderRuleGORMRepository) ListActiveRules(ctx context.Context, schemaName, tenantID string) ([]ReminderRule, error)

func (*ReminderRuleGORMRepository) ListRules

func (r *ReminderRuleGORMRepository) ListRules(ctx context.Context, schemaName, tenantID string) ([]ReminderRule, error)

func (*ReminderRuleGORMRepository) RecordReminderSent

func (r *ReminderRuleGORMRepository) RecordReminderSent(ctx context.Context, schemaName string, reminder *PaymentReminder) error

func (*ReminderRuleGORMRepository) UpdateRule

func (r *ReminderRuleGORMRepository) UpdateRule(ctx context.Context, schemaName string, rule *ReminderRule) error

type ReminderRuleRepository

type ReminderRuleRepository interface {
	ListRules(ctx context.Context, schemaName, tenantID string) ([]ReminderRule, error)
	ListActiveRules(ctx context.Context, schemaName, tenantID string) ([]ReminderRule, error)
	GetRule(ctx context.Context, schemaName, tenantID, ruleID string) (*ReminderRule, error)
	CreateRule(ctx context.Context, schemaName string, rule *ReminderRule) error
	UpdateRule(ctx context.Context, schemaName string, rule *ReminderRule) error
	DeleteRule(ctx context.Context, schemaName, tenantID, ruleID string) error
	GetInvoicesForRule(ctx context.Context, schemaName, tenantID string, rule *ReminderRule, asOfDate time.Time) ([]InvoiceForReminder, error)
	HasReminderBeenSent(ctx context.Context, schemaName, tenantID, invoiceID, ruleID string) (bool, error)
	RecordReminderSent(ctx context.Context, schemaName string, reminder *PaymentReminder) error
}

ReminderRuleRepository defines the interface for reminder rule data access.

type ReminderService

type ReminderService struct {
	// contains filtered or unexported fields
}

ReminderService provides payment reminder operations

func NewReminderService

func NewReminderService(db *pgxpool.Pool, emailService *email.Service) *ReminderService

NewReminderService creates a new reminder service

func NewReminderServiceWithRepository

func NewReminderServiceWithRepository(repo ReminderRepository, emailService *email.Service) *ReminderService

NewReminderServiceWithRepository creates a reminder service with custom repository

func (*ReminderService) GetOverdueInvoicesSummary

func (s *ReminderService) GetOverdueInvoicesSummary(ctx context.Context, tenantID, schemaName string) (*OverdueInvoicesSummary, error)

GetOverdueInvoicesSummary retrieves a summary of all overdue invoices

func (*ReminderService) GetReminderHistory

func (s *ReminderService) GetReminderHistory(ctx context.Context, tenantID, schemaName, invoiceID string) ([]PaymentReminder, error)

GetReminderHistory gets the reminder history for an invoice

func (*ReminderService) SendBulkReminders

func (s *ReminderService) SendBulkReminders(ctx context.Context, tenantID, schemaName string, req *SendBulkRemindersRequest, companyName string) (*BulkReminderResult, error)

SendBulkReminders sends payment reminders for multiple invoices

func (*ReminderService) SendReminder

func (s *ReminderService) SendReminder(ctx context.Context, tenantID, schemaName string, req *SendReminderRequest, companyName string) (*ReminderResult, error)

SendReminder sends a payment reminder for a specific invoice

type ReminderStatus

type ReminderStatus string

ReminderStatus represents the status of a payment reminder

const (
	ReminderStatusPending  ReminderStatus = "PENDING"
	ReminderStatusSent     ReminderStatus = "SENT"
	ReminderStatusFailed   ReminderStatus = "FAILED"
	ReminderStatusCanceled ReminderStatus = "CANCELED"
)

type Repository

type Repository interface {
	Create(ctx context.Context, schemaName string, invoice *Invoice) error
	GetByID(ctx context.Context, schemaName, tenantID, invoiceID string) (*Invoice, error)
	List(ctx context.Context, schemaName, tenantID string, filter *InvoiceFilter) ([]Invoice, error)
	UpdateStatus(ctx context.Context, schemaName, tenantID, invoiceID string, status InvoiceStatus) error
	UpdatePayment(ctx context.Context, schemaName, tenantID, invoiceID string, amountPaid decimal.Decimal, status InvoiceStatus) error
	GenerateNumber(ctx context.Context, schemaName, tenantID string, invoiceType InvoiceType) (string, error)
	UpdateOverdueStatus(ctx context.Context, schemaName, tenantID string) (int, error)
}

Repository defines the contract for invoice data access

type SendBulkRemindersRequest

type SendBulkRemindersRequest struct {
	InvoiceIDs []string `json:"invoice_ids"`
	Message    string   `json:"message,omitempty"`
}

SendBulkRemindersRequest represents a request to send multiple reminders

type SendReminderRequest

type SendReminderRequest struct {
	InvoiceID string `json:"invoice_id"`
	Message   string `json:"message,omitempty"` // Optional custom message
}

SendReminderRequest represents a request to send a payment reminder

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides invoicing operations

func NewService

func NewService(db *pgxpool.Pool, accountingService *accounting.Service) *Service

NewService creates a new invoicing service with an ORM-backed repository.

func NewServiceWithRepository

func NewServiceWithRepository(repo Repository, accountingService *accounting.Service) *Service

NewServiceWithRepository creates a new invoicing service with a custom repository

func (*Service) Create

func (s *Service) Create(ctx context.Context, tenantID, schemaName string, req *CreateInvoiceRequest) (*Invoice, error)

Create creates a new invoice

func (*Service) GetByID

func (s *Service) GetByID(ctx context.Context, tenantID, schemaName, invoiceID string) (*Invoice, error)

GetByID retrieves an invoice by ID

func (*Service) ImportCSV

func (s *Service) ImportCSV(
	ctx context.Context,
	tenantID, schemaName string,
	existingContacts []contacts.Contact,
	existingProducts []inventory.Product,
	req *ImportInvoicesRequest,
	validateDate func(time.Time) error,
) (*ImportInvoicesResult, error)

ImportCSV imports invoices from grouped CSV rows. Each row represents one invoice line.

func (*Service) ImportEInvoiceXML

func (s *Service) ImportEInvoiceXML(
	ctx context.Context,
	tenantID, schemaName string,
	existingContacts []contacts.Contact,
	req *ImportEInvoiceRequest,
	validateDate func(time.Time) error,
) (*ImportInvoicesResult, error)

ImportEInvoiceXML imports invoices from Estonian e-invoice XML.

func (*Service) List

func (s *Service) List(ctx context.Context, tenantID, schemaName string, filter *InvoiceFilter) ([]Invoice, error)

List retrieves invoices with optional filtering

func (*Service) RecordPayment

func (s *Service) RecordPayment(ctx context.Context, tenantID, schemaName, invoiceID string, amount decimal.Decimal) error

RecordPayment records a payment against an invoice

func (*Service) ResolveInvoiceIDByNumber

func (s *Service) ResolveInvoiceIDByNumber(ctx context.Context, tenantID, schemaName, invoiceNumber string) (string, error)

ResolveInvoiceIDByNumber returns the unique invoice ID for an invoice number.

func (*Service) Send

func (s *Service) Send(ctx context.Context, tenantID, schemaName, invoiceID string) error

Send marks an invoice as sent and updates status

func (*Service) UpdateOverdueStatus

func (s *Service) UpdateOverdueStatus(ctx context.Context, tenantID, schemaName string) (int, error)

UpdateOverdueStatus updates status of overdue invoices

func (*Service) Void

func (s *Service) Void(ctx context.Context, tenantID, schemaName, invoiceID string) error

Void voids an invoice

func (*Service) WithRepository

func (s *Service) WithRepository(repo Repository) *Service

WithRepository returns a service that keeps this service's domain dependencies while using a repository bound to another transaction.

type TriggerType

type TriggerType string

TriggerType represents when a reminder should be triggered

const (
	TriggerBeforeDue TriggerType = "BEFORE_DUE"
	TriggerOnDue     TriggerType = "ON_DUE"
	TriggerAfterDue  TriggerType = "AFTER_DUE"
)

type UpdateInterestSettingsRequest

type UpdateInterestSettingsRequest struct {
	Rate float64 `json:"rate"` // Daily interest rate
}

UpdateInterestSettingsRequest is the request to update interest settings

func (*UpdateInterestSettingsRequest) Validate

func (r *UpdateInterestSettingsRequest) Validate() error

Validate validates the interest settings update request

type UpdateReminderRuleRequest

type UpdateReminderRuleRequest struct {
	Name              *string `json:"name,omitempty"`
	EmailTemplateType *string `json:"email_template_type,omitempty"`
	IsActive          *bool   `json:"is_active,omitempty"`
}

UpdateReminderRuleRequest is the request to update a reminder rule

type VATTreatment

type VATTreatment string

VATTreatment controls whether VAT is charged on the invoice line or reported separately.

const (
	VATTreatmentStandard      VATTreatment = "STANDARD"
	VATTreatmentReverseCharge VATTreatment = "REVERSE_CHARGE"
)

func NormalizeVATTreatment

func NormalizeVATTreatment(value string) (VATTreatment, error)

NormalizeVATTreatment validates and normalizes VAT treatment values.

type ValidationError

type ValidationError struct {
	Field   string
	Message string
}

ValidationError represents a validation error

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
mappers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL