model

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AcctCash              = "1000" // Cash & Cash Equivalents   (asset)
	AcctInventory         = "1300" // Inventory Asset            (asset)
	AcctAccountsPayable   = "2100" // Accounts Payable           (liability)
	AcctSalesRevenue      = "4000" // Sales Revenue              (revenue)
	AcctSalesDiscount     = "4100" // Sales Discounts            (expense/contra-revenue)
	AcctCOGS              = "5000" // Cost of Goods Sold         (expense)
	AcctInventoryWriteoff = "5100" // Inventory Write-off/Waste  (expense)
	AcctOperatingExpenses = "6000" // Operating Expenses         (expense)
	AcctSupplierCosts     = "6100" // Supplier / Purchase Costs  (expense)
)

Standard COA codes — seeded by migration 000024.

Variables

View Source
var DefaultCashDrawerMethods = []PaymentMethod{PaymentCash}

DefaultCashDrawerMethods controls which payment methods count toward the physical cash drawer for session reconciliation. QRIS/ewallet settle digitally — override via WithCashDrawerMethods().

DefaultPaymentMethods is the OSS allowed set. Pro injects additional methods (e.g. qris, ewallet) via WithPaymentMethods().

Functions

This section is empty.

Types

type APIError

type APIError struct {
	// Code is the HTTP status code.
	Code int
	// Internal is the original error (logged but never sent to clients).
	Internal error
	// Public is the human-readable message sent to clients.
	Public string
}

APIError represents an HTTP error returned from a handler. It implements the error interface so it can be returned directly from Echo handlers.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

type APIResponse

type APIResponse struct {
	RequestID uuid.UUID `json:"request_id,omitempty"`
	Status    int       `json:"status"`
	Data      any       `json:"data,omitempty"`
	Error     string    `json:"error,omitempty"`
}

APIResponse is the standard envelope for all JSON API responses.

type Account

type Account struct {
	ID   uuid.UUID
	Code string
	Name string
	Type AccountType
}

Account is a node in the chart of accounts. The OSS COA is system-wide (not per-company); rows are seeded in migration 000024.

type AccountBalance

type AccountBalance struct {
	AccountCode string
	AccountName string
	AccountType AccountType
	TotalDebit  int64
	TotalCredit int64
}

AccountBalance summarizes debits and credits for one account within a company.

type AccountType

type AccountType string

AccountType classifies a chart-of-accounts entry.

const (
	AccountAsset     AccountType = "asset"
	AccountLiability AccountType = "liability"
	AccountEquity    AccountType = "equity"
	AccountRevenue   AccountType = "revenue"
	AccountExpense   AccountType = "expense"
)

type Branch

type Branch struct {
	ID        uuid.UUID
	CompanyID uuid.UUID
	Name      string
	Address   string
	CreatedAt time.Time
	UpdatedAt time.Time
}

Branch represents a physical location (shop/outlet) belonging to a company. A company may have multiple branches sharing a single inventory.

type Company

type Company struct {
	ID        uuid.UUID
	OwnerID   uuid.UUID
	Name      string
	Handle    string // URL slug, globally unique, lowercase alphanum + hyphens
	Currency  string // ISO 4217, e.g. "USD", "IDR"
	CreatedAt time.Time
	UpdatedAt time.Time
	// LogoFileID references the company's current logo, if any, in the
	// files table. nil means no logo has been uploaded.
	LogoFileID *uuid.UUID
}

Company represents a business entity owned by a user with the owner role. Currency is an ISO 4217 code (e.g. "USD", "IDR") stored as display metadata; all monetary values are integers in that currency's smallest unit. Handle is a globally-unique URL slug (e.g. "acme-coffee") used in /@handle/ routes.

type Customer

type Customer struct {
	ID        uuid.UUID
	CompanyID uuid.UUID
	Name      string
	Email     string
	Phone     string
	CreatedAt time.Time
	UpdatedAt time.Time
}

Customer represents a buyer registered in the company's contact book.

type Discount

type Discount struct {
	ID        uuid.UUID
	CompanyID uuid.UUID
	Name      string
	Type      DiscountType
	// Value is cents for fixed discounts and 1–100 (integer %) for percentage discounts.
	Value     int64
	Active    bool
	CreatedAt time.Time
	// Code, when set, lets this discount be redeemed by a cashier-entered
	// coupon code at POS checkout instead of being picked from the list.
	Code *string
	// ValidFrom/ValidUntil optionally bound when this discount can be
	// applied. Nil means no bound on that side.
	ValidFrom  *time.Time
	ValidUntil *time.Time
	// MaxRedemptions optionally caps how many orders may redeem this
	// discount in total. Nil means unlimited.
	MaxRedemptions *int
}

Discount is a named, reusable discount rule stored per company. A Discount with Code set can be redeemed by a cashier-entered coupon code instead of being picked from the discount list; ValidFrom/ValidUntil and MaxRedemptions are independent of Code and apply to any discount.

type DiscountRedemption added in v0.1.4

type DiscountRedemption struct {
	ID         uuid.UUID
	DiscountID uuid.UUID
	OrderID    uuid.UUID
	CompanyID  uuid.UUID
	CreatedAt  time.Time
}

DiscountRedemption records one order's redemption of a discount that has a MaxRedemptions cap, so the cap can be enforced and freed correctly when a discount is removed from an order.

type DiscountType

type DiscountType string

DiscountType determines how a discount value is applied.

const (
	// DiscountFixed applies a fixed amount in the smallest currency unit.
	DiscountFixed DiscountType = "fixed"

	// DiscountPercentage applies an integer percentage (1–100) of the basis amount.
	DiscountPercentage DiscountType = "percentage"
)

type Expense

type Expense struct {
	ID          uuid.UUID
	CompanyID   uuid.UUID
	Description string
	Amount      int64  // smallest currency unit, > 0
	AccountCode string // COA debit account (default "6000")
	PaidFrom    string // COA credit account representing payment source (default "1000")
	CreatedAt   time.Time
}

Expense is a general business expense record (rent, utilities, etc.).

type File

type File struct {
	ID         uuid.UUID
	CompanyID  uuid.UUID
	Intent     string
	StorageKey string
	MimeType   string
	SizeBytes  int64
	UploadedBy *uuid.UUID
	CreatedAt  time.Time
}

File is an uploaded object tracked by the File API, scoped to one company. StorageKey never contains an absolute path — it is relative to the storage backend's root (e.g. "<companyID>/avatars/<uuid>.webp").

type InventoryLine

type InventoryLine struct {
	ProductID         uuid.UUID `json:"product_id"`
	ProductName       string    `json:"product_name"`
	ProductType       string    `json:"product_type"`
	CurrentStock      float64   `json:"current_stock"`
	LastPurchasePrice int64     `json:"last_purchase_price"`
	StockValue        int64     `json:"stock_value"`
	LowStock          bool      `json:"low_stock"`
}

InventoryLine holds the current stock position for a single product.

type InventoryReport

type InventoryReport struct {
	Items []InventoryLine `json:"items"`
}

InventoryReport is the full inventory snapshot response.

type JournalEntry

type JournalEntry struct {
	ID          uuid.UUID
	CompanyID   uuid.UUID
	Description string
	EventName   string // originating domain event, for audit/filtering
	Reference   string // e.g. order_id, expense_id
	Lines       []JournalLine
	CreatedAt   time.Time
}

JournalEntry is an immutable double-entry accounting record. ∑(Lines[i].Debit) must equal ∑(Lines[i].Credit) before the entry is persisted.

type JournalLine

type JournalLine struct {
	ID        uuid.UUID
	EntryID   uuid.UUID
	AccountID uuid.UUID
	Debit     int64 // amount in smallest currency unit; 0 when this is a credit leg
	Credit    int64 // amount in smallest currency unit; 0 when this is a debit leg
}

JournalLine is one leg of a journal entry. Exactly one of Debit or Credit should be non-zero per line.

type MovementReason

type MovementReason string

MovementReason is the type of a stock movement.

const (
	// ReasonProcurement is stock received from a supplier (unit_cost required).
	ReasonProcurement MovementReason = "procurement"

	// ReasonOpeningBalance is the initial stock level recorded at system setup
	// (unit_cost required).
	ReasonOpeningBalance MovementReason = "opening_balance"

	// ReasonWaste is stock lost due to spoilage, spillage, or expiry.
	// LPP is resolved at the moment of recording to compute valueLost.
	ReasonWaste MovementReason = "waste"

	// ReasonAdjustmentUp increases stock to correct a discrepancy found during
	// an audit (no unit_cost; no accounting event).
	ReasonAdjustmentUp MovementReason = "adjustment_up"

	// ReasonAdjustmentDown decreases stock to correct a discrepancy found during
	// an audit (no unit_cost; no accounting event).
	ReasonAdjustmentDown MovementReason = "adjustment_down"

	// ReasonCorrection reverses a specific prior movement that was recorded
	// incorrectly (e.g. a typo'd quantity or unit cost). Always paired with a
	// ReversesMovementID pointing at the movement it cancels out.
	ReasonCorrection MovementReason = "correction"

	// ReasonPosSale is a negative movement created at POS checkout.
	ReasonPosSale MovementReason = "pos_sale"

	// ReasonPosVoid is a positive movement that restores stock when a paid order
	// is voided.
	ReasonPosVoid MovementReason = "pos_void"

	// ReasonPosReturn is a positive movement that restores stock when items are
	// returned.
	ReasonPosReturn MovementReason = "pos_return"
)

type Order

type Order struct {
	ID             uuid.UUID
	CompanyID      uuid.UUID
	BranchID       uuid.UUID // denormalized from session at create time
	StationID      uuid.UUID // denormalized from session at create time
	SessionID      uuid.UUID
	CustomerID     *uuid.UUID
	ReceiptNumber  string // stamped during checkout; empty while open
	Status         OrderStatus
	Total          int64      // net total = ∑(item.Subtotal) − DiscountAmount
	DiscountAmount int64      // order-level discount in smallest currency unit; 0 when none
	DiscountID     *uuid.UUID // optional reference to the named Discount applied at order level
	VoidedBy       *uuid.UUID
	VoidedAt       *time.Time
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

Order is a sales transaction within a POS session. An order starts open, transitions to paid on checkout, or voided.

type OrderItem

type OrderItem struct {
	ID             uuid.UUID
	OrderID        uuid.UUID
	ProductID      uuid.UUID
	Quantity       int64      // whole units only
	UnitPrice      int64      // snapshot of Product.BasePrice at AddItem time
	DiscountAmount int64      // item-level discount in smallest currency unit; 0 when none
	DiscountID     *uuid.UUID // optional reference to the named Discount applied at item level
	Subtotal       int64      // (UnitPrice × Quantity) − DiscountAmount
}

OrderItem is one product line on an order.

type OrderReturn

type OrderReturn struct {
	ID              uuid.UUID
	CompanyID       uuid.UUID
	OriginalOrderID uuid.UUID
	RefundAmount    int64
	RefundMethod    PaymentMethod
	Reason          string
	CreatedBy       uuid.UUID
	CreatedAt       time.Time
}

OrderReturn records a return against a previously paid order.

type OrderReturnItem

type OrderReturnItem struct {
	ID          uuid.UUID
	ReturnID    uuid.UUID
	OrderItemID uuid.UUID
	ProductID   uuid.UUID
	Quantity    int64
	UnitPrice   int64
	Subtotal    int64
}

OrderReturnItem is one returned product line within an OrderReturn.

type OrderStatus

type OrderStatus string

OrderStatus represents the lifecycle state of an order.

const (
	OrderOpen   OrderStatus = "open"
	OrderPaid   OrderStatus = "paid"
	OrderVoided OrderStatus = "voided"
)

type PLReport

type PLReport struct {
	Summary PLSummary `json:"summary"`
}

PLReport is the full profit-and-loss response.

type PLSummary

type PLSummary struct {
	Revenue   int64 `json:"revenue"`
	Expenses  int64 `json:"expenses"`
	NetProfit int64 `json:"net_profit"`
}

PLSummary holds period profit-and-loss totals.

type POSSession

type POSSession struct {
	ID          uuid.UUID
	CompanyID   uuid.UUID
	BranchID    uuid.UUID // denormalized from station at open time
	StationID   uuid.UUID
	UserID      uuid.UUID // user who opened the session
	Status      SessionStatus
	OpeningCash int64 // cash float placed in drawer before trading; default 0
	OpenedAt    time.Time
	ClosedAt    *time.Time
}

POSSession represents a cashier's shift at a specific POS station. A station may have at most one open session at a time.

type POSStation

type POSStation struct {
	ID        uuid.UUID
	CompanyID uuid.UUID // denormalized from branch for efficient queries
	BranchID  uuid.UUID
	Name      string
	CreatedAt time.Time
	UpdatedAt time.Time
}

POSStation represents a physical point-of-sale terminal within a branch. Multiple stations may be active simultaneously in the same branch.

type Payment

type Payment struct {
	ID        uuid.UUID
	OrderID   uuid.UUID
	Amount    int64
	Method    PaymentMethod
	Status    PaymentStatus
	CreatedAt time.Time
	// TenderedAmount is what the customer physically handed over for a cash
	// payment (nil for card/transfer, or for a cash leg submitted without
	// one). Change given = TenderedAmount - Amount.
	TenderedAmount *int64
}

Payment is one payment leg on an order (supports split payments).

type PaymentMethod

type PaymentMethod string

PaymentMethod is the tender type used for a payment leg.

const (
	PaymentCash     PaymentMethod = "cash"
	PaymentCard     PaymentMethod = "card"
	PaymentTransfer PaymentMethod = "transfer"
)

type PaymentMethodRevenue

type PaymentMethodRevenue struct {
	Method  string `json:"method"`
	Revenue int64  `json:"revenue"`
}

PaymentMethodRevenue holds revenue totals broken down by payment method.

type PaymentStatus

type PaymentStatus string

PaymentStatus tracks whether a payment is completed or refunded.

const (
	PaymentCompleted PaymentStatus = "completed"
	PaymentRefunded  PaymentStatus = "refunded"
)

type Product

type Product struct {
	ID        uuid.UUID
	CompanyID uuid.UUID
	Type      ProductType
	Name      string
	BasePrice int64  // smallest currency unit; must be 0 for ingredients
	Unit      string // "kg", "ml", "pcs" — must be used consistently throughout
	// LowStockThreshold flags CurrentStock at or below this level (but above
	// zero) as "low" on the Inventory page and dashboard. Not meaningful for
	// recipe products, which have no stock of their own.
	LowStockThreshold int64
	// SKU is the barcode/lookup code used at the POS. Unique per company.
	// Defaults to the product's own ID (as a string) when not explicitly set.
	SKU         string
	CreatedAt   time.Time
	UpdatedAt   time.Time
	ImageFileID *uuid.UUID // nil = no image
}

Product represents an item in the company's product catalog.

type ProductType

type ProductType string

ProductType classifies how a product is made and sold.

const (
	// ProductTypeIngredient is a raw material used in recipes.
	// It has BasePrice = 0 and is never sold directly at the POS.
	ProductTypeIngredient ProductType = "ingredient"

	// ProductTypeSimple is a finished good sold as-is with stock tracked directly.
	ProductTypeSimple ProductType = "simple"

	// ProductTypeRecipe is a manufactured product sold at the POS.
	// Its stock is derived from the ingredient stock of its components.
	ProductTypeRecipe ProductType = "recipe"
)

type RecipeComponent

type RecipeComponent struct {
	ID           uuid.UUID
	RecipeID     uuid.UUID
	IngredientID uuid.UUID
	Quantity     float64 // NUMERIC(12,4); same unit as the ingredient's Unit field
}

RecipeComponent links a recipe product to one of its ingredient products.

type RecipeOverhead

type RecipeOverhead struct {
	ID          uuid.UUID
	RecipeID    uuid.UUID
	Description string
	Cost        int64 // smallest currency unit
}

RecipeOverhead is a fixed cost line added to a recipe's COGS (e.g. packaging, labor allocation).

type SalesPeriod

type SalesPeriod struct {
	Period  string `json:"period"` // "2026-01-15" | "2026-W03" | "2026-01"
	Revenue int64  `json:"revenue"`
	Orders  int64  `json:"orders"`
}

SalesPeriod holds aggregated sales data for a single time bucket.

type SalesReport

type SalesReport struct {
	Summary         SalesSummary           `json:"summary"`
	ByPeriod        []SalesPeriod          `json:"by_period"`
	ByPaymentMethod []PaymentMethodRevenue `json:"by_payment_method"`
	TopProducts     []TopProduct           `json:"top_products"`
}

SalesReport is the full sales analytics response.

type SalesSummary

type SalesSummary struct {
	TotalRevenue int64 `json:"total_revenue"`
	TotalOrders  int64 `json:"total_orders"`
	TotalReturns int64 `json:"total_returns"`
	NetRevenue   int64 `json:"net_revenue"`
}

SalesSummary aggregates top-level sales metrics for a date range.

type SessionReconciliation

type SessionReconciliation struct {
	SessionID    uuid.UUID
	CompanyID    uuid.UUID
	ExpectedCash int64 // OpeningCash + SUM of cash-method payments in the session
	DeclaredCash int64 // physically counted by the cashier at close
	Difference   int64 // DeclaredCash − ExpectedCash; negative = shortage
	ReconciledBy uuid.UUID
	ReconciledAt time.Time
}

SessionReconciliation is written when a cashier closes a session and declares their cash count. The system computes ExpectedCash and records the difference.

type SessionStatus

type SessionStatus string

SessionStatus represents the lifecycle state of a POS session.

const (
	SessionOpen   SessionStatus = "open"
	SessionClosed SessionStatus = "closed"
)

type StockMovement

type StockMovement struct {
	ID         uuid.UUID
	CompanyID  uuid.UUID
	ProductID  uuid.UUID
	Reason     MovementReason
	Delta      float64 // signed quantity in the product's unit
	UnitCost   *int64  // smallest currency unit; non-nil only for procurement/opening_balance
	Notes      string
	CreatedAt  time.Time  // immutable; no UpdatedAt
	SupplierID *uuid.UUID // optional; set only for procurement movements

	// ReversesMovementID is set only when Reason is ReasonCorrection, pointing
	// at the movement this one cancels out.
	ReversesMovementID *uuid.UUID
}

StockMovement is an immutable append-only record of a change in stock for a single ingredient or simple product.

Delta is signed: positive for in-flow (procurement, opening_balance, adjustment_up), negative for out-flow (waste, adjustment_down). CurrentStock = SUM(delta) for a given product_id.

type Supplier

type Supplier struct {
	ID        uuid.UUID
	CompanyID uuid.UUID
	Name      string
	Contact   string
	Phone     string
	Email     string
	Address   string
	CreatedAt time.Time
	UpdatedAt time.Time
}

Supplier represents a vendor that provides raw materials or goods to the company.

type SupplierPayment

type SupplierPayment struct {
	ID         uuid.UUID
	CompanyID  uuid.UUID
	SupplierID uuid.UUID
	Amount     int64 // smallest currency unit, > 0
	Notes      string
	PaidFrom   string // COA credit account representing payment source (default "1000")
	CreatedAt  time.Time
}

SupplierPayment records a cash or transfer payment made to a supplier.

type TopProduct

type TopProduct struct {
	ProductID   uuid.UUID `json:"product_id"`
	ProductName string    `json:"product_name"`
	Revenue     int64     `json:"revenue"`
	UnitsSold   int64     `json:"units_sold"`
}

TopProduct holds revenue and units-sold for a single product.

type User

type User struct {
	ID           uuid.UUID
	Email        string
	Name         string
	Role         auth.UserRole
	PasswordHash string
	CompanyID    *uuid.UUID // nil for owners; required for managers and cashiers
	CreatedAt    time.Time
	UpdatedAt    time.Time
	// TokenValidAfter, when set, invalidates any JWT issued (iat) before this
	// time for this user — checked in handler.JWTParserMiddleware and
	// AuthService.RefreshTokens. nil means no restriction.
	TokenValidAfter *time.Time
}

User represents a registered user of the system.

Jump to

Keyboard shortcuts

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