repo

package
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const TimestampLayout = "2006-01-02T15:04:05.000000000Z07:00"

TimestampLayout is a fixed-width variant of time.RFC3339Nano, used whenever this package persists a time.Time to a SQLite TEXT column.

time.RFC3339Nano trims trailing zero digits from the fractional-second component (e.g. ".5" instead of ".500000000"). That breaks plain lexicographic string comparison in SQL (<=, >=, ORDER BY): a timestamp ending in zeros can sort as "greater than" a slightly later timestamp whose un-trimmed digits happen to start lower, because the trimmed string's terminator ('Z' or '+') compares greater than any digit character. Always emitting all 9 fractional digits keeps every stored timestamp the same length, so string order always matches chronological order.

Parsing is unaffected — time.Parse(time.RFC3339Nano, ...) accepts both this fixed-width format and the old trimmed one, so existing rows written before this fix remain readable.

Variables

This section is empty.

Functions

func DefaultStorageDir

func DefaultStorageDir() (string, error)

DefaultStorageDir returns the OS-appropriate default base directory for local file storage, used when config.StorageLocalPath isn't set.

func NewAccountingRepo

func NewAccountingRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.AccountingRepoer

NewAccountingRepo returns an AccountingRepoer backed by SQLite.

func NewAssetRepo added in v0.5.1

func NewAssetRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.AssetRepoer

NewAssetRepo returns an AssetRepoer backed by SQLite.

func NewBranchRepo

func NewBranchRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.BranchRepoer

func NewCompanyRepo

func NewCompanyRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.CompanyRepoer

func NewCustomerRepo

func NewCustomerRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.CustomerRepoer

func NewDiscountRepo

func NewDiscountRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.DiscountRepoer

NewDiscountRepo returns a DiscountRepoer backed by SQLite.

func NewExpenseRepo

func NewExpenseRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.ExpenseRepoer

func NewFileRepo

func NewFileRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.FileRepoer

NewFileRepo returns a FileRepoer backed by SQLite.

func NewOrderRepo

func NewOrderRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.OrderRepoer

NewOrderRepo constructs an OrderRepo.

func NewPOSStationRepo

func NewPOSStationRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.POSStationRepoer

func NewProductRepo

func NewProductRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.ProductRepoer

func NewReportsRepo

func NewReportsRepo(database *sql.DB) data.ReportsQuerier

NewReportsRepo returns a ReportsQuerier backed by SQLite.

func NewSQLiteDB

func NewSQLiteDB(path string) (*sql.DB, error)

NewSQLiteDB opens a SQLite database at path and configures recommended pragmas. Use ":memory:" for an in-process test database.

func NewSessionRepo

func NewSessionRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.SessionRepoer

NewSessionRepo constructs a SessionRepo.

func NewSupplierPaymentRepo

func NewSupplierPaymentRepo(
	database *sql.DB, q *db.Queries, clk clock.Clock,
) data.SupplierPaymentRepoer

func NewSupplierRepo

func NewSupplierRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.SupplierRepoer

func NewUserRepo

func NewUserRepo(database *sql.DB, q *db.Queries, clk clock.Clock) data.UserRepoer

NewUserRepo creates a new UserRepo backed by the given database and queries. Pass a tx-scoped *db.Queries (via testhelpers.WithTxRollback) for test isolation.

Types

type AccountingRepo

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

AccountingRepo persists COA accounts and double-entry journal entries.

func (*AccountingRepo) BalanceByAccount

func (r *AccountingRepo) BalanceByAccount(
	ctx context.Context,
	companyID uuid.UUID,
) ([]model.AccountBalance, error)

BalanceByAccount returns running debit/credit totals per COA account for the company. It executes a raw SQL query because sqlc cannot express the LEFT JOIN / GROUP BY pattern cleanly with a per-company filter on the joined table.

func (*AccountingRepo) CountDepreciationPeriods added in v0.5.1

func (r *AccountingRepo) CountDepreciationPeriods(
	ctx context.Context,
	assetID uuid.UUID,
) (int, error)

CountDepreciationPeriods counts posted "AssetDepreciationPosted" journal entries referencing assetID — see the doc comment on data.AccountingRepoer.CountDepreciationPeriods for why this is the authoritative source rather than a cached counter.

func (*AccountingRepo) CreateJournalEntry

func (r *AccountingRepo) CreateJournalEntry(
	ctx context.Context,
	entry *model.JournalEntry,
) error

CreateJournalEntry persists the entry header and all its lines atomically. It sets entry.ID, entry.CreatedAt, and each line's ID and EntryID.

func (*AccountingRepo) GetAccountByCode

func (r *AccountingRepo) GetAccountByCode(
	ctx context.Context,
	code string,
) (*model.Account, error)

func (*AccountingRepo) HasOpeningBalanceEntry added in v0.5.1

func (r *AccountingRepo) HasOpeningBalanceEntry(
	ctx context.Context,
	companyID, branchID uuid.UUID,
) (bool, error)

HasOpeningBalanceEntry reports whether an opening-balance entry has already been posted for this branch, guarding against accidental duplicate postings that would double-count cash and equity.

func (*AccountingRepo) ListAccounts

func (r *AccountingRepo) ListAccounts(ctx context.Context) ([]model.Account, error)

func (*AccountingRepo) ListJournalEntriesByCompany

func (r *AccountingRepo) ListJournalEntriesByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.JournalEntry], error)

func (*AccountingRepo) ListJournalEntriesByCompanyFiltered added in v0.5.1

func (r *AccountingRepo) ListJournalEntriesByCompanyFiltered(
	ctx context.Context,
	companyID uuid.UUID,
	filter data.JournalEntryFilter,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.JournalEntry], error)

ListJournalEntriesByCompanyFiltered is the filterable counterpart to ListJournalEntriesByCompany, backing the ledger UI's journal-entries page.

type AssetRepo added in v0.5.1

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

AssetRepo persists fixed-asset registry rows.

func (*AssetRepo) Create added in v0.5.1

func (r *AssetRepo) Create(ctx context.Context, asset *model.FixedAsset) error

func (*AssetRepo) GetByID added in v0.5.1

func (r *AssetRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.FixedAsset, error)

func (*AssetRepo) HasAssetsForCompany added in v0.5.1

func (r *AssetRepo) HasAssetsForCompany(ctx context.Context, companyID uuid.UUID) (bool, error)

HasAssetsForCompany reports whether companyID has any fixed_assets row, active or disposed — backs the enable_asset_tracking disable guard.

func (*AssetRepo) ListActiveByBranch added in v0.5.1

func (r *AssetRepo) ListActiveByBranch(
	ctx context.Context,
	companyID, branchID uuid.UUID,
) ([]model.FixedAsset, error)

func (*AssetRepo) ListByCompany added in v0.5.1

func (r *AssetRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
) ([]model.FixedAsset, error)

func (*AssetRepo) Update added in v0.5.1

func (r *AssetRepo) Update(ctx context.Context, asset *model.FixedAsset) error

Update persists the full row — used for both editing an unlocked asset's fields and flipping Status/DisposedAt on disposal.

type BranchRepo

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

func (*BranchRepo) Create

func (r *BranchRepo) Create(ctx context.Context, entity *model.Branch) error

func (*BranchRepo) Delete

func (r *BranchRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*BranchRepo) GetByID

func (r *BranchRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Branch, error)

func (*BranchRepo) ListByCompany

func (r *BranchRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Branch], error)

func (*BranchRepo) Update

func (r *BranchRepo) Update(ctx context.Context, entity *model.Branch) error

func (*BranchRepo) WithTx

func (r *BranchRepo) WithTx(ctx context.Context, fn func(data.BranchRepoer) error) error

type CompanyRepo

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

func (*CompanyRepo) Create

func (r *CompanyRepo) Create(ctx context.Context, entity *model.Company) error

func (*CompanyRepo) Delete

func (r *CompanyRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*CompanyRepo) GetByHandle

func (r *CompanyRepo) GetByHandle(ctx context.Context, handle string) (*model.Company, error)

func (*CompanyRepo) GetByID

func (r *CompanyRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Company, error)

func (*CompanyRepo) ListByOwner

func (*CompanyRepo) Update

func (r *CompanyRepo) Update(ctx context.Context, entity *model.Company) error

func (*CompanyRepo) WithTx

func (r *CompanyRepo) WithTx(ctx context.Context, fn func(data.CompanyRepoer) error) error

type CustomerRepo

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

func (*CustomerRepo) Create

func (r *CustomerRepo) Create(ctx context.Context, entity *model.Customer) error

func (*CustomerRepo) Delete

func (r *CustomerRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*CustomerRepo) GetByCompanyAndEmail added in v0.1.2

func (r *CustomerRepo) GetByCompanyAndEmail(
	ctx context.Context,
	companyID uuid.UUID,
	email string,
) (*model.Customer, error)

func (*CustomerRepo) GetByCompanyAndPhone added in v0.1.2

func (r *CustomerRepo) GetByCompanyAndPhone(
	ctx context.Context,
	companyID uuid.UUID,
	phone string,
) (*model.Customer, error)

func (*CustomerRepo) GetByID

func (r *CustomerRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Customer, error)

func (*CustomerRepo) ListByCompany

func (r *CustomerRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Customer], error)

func (*CustomerRepo) Update

func (r *CustomerRepo) Update(ctx context.Context, entity *model.Customer) error

func (*CustomerRepo) WithTx

func (r *CustomerRepo) WithTx(ctx context.Context, fn func(data.CustomerRepoer) error) error

type DiscountRepo

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

DiscountRepo persists named discount rules.

func (*DiscountRepo) CountRedemptions added in v0.1.4

func (r *DiscountRepo) CountRedemptions(ctx context.Context, discountID uuid.UUID) (int, error)

CountRedemptions returns how many orders have redeemed a discount.

func (*DiscountRepo) Create

func (r *DiscountRepo) Create(ctx context.Context, entity *model.Discount) error

Create persists a new discount. Sets ID and CreatedAt.

func (*DiscountRepo) CreateRedemption added in v0.1.4

func (r *DiscountRepo) CreateRedemption(
	ctx context.Context,
	entity *model.DiscountRedemption,
) error

CreateRedemption records an order's redemption of a discount. Sets ID.

func (*DiscountRepo) Delete

func (r *DiscountRepo) Delete(ctx context.Context, id uuid.UUID) error

Delete removes a discount by ID.

func (*DiscountRepo) DeleteRedemptionByOrder added in v0.1.4

func (r *DiscountRepo) DeleteRedemptionByOrder(ctx context.Context, orderID uuid.UUID) error

DeleteRedemptionByOrder clears any redemption tied to an order — a no-op if none exists.

func (*DiscountRepo) GetByCode added in v0.1.4

func (r *DiscountRepo) GetByCode(
	ctx context.Context, companyID uuid.UUID, code string,
) (*model.Discount, error)

GetByCode retrieves a discount by its company-scoped coupon code.

func (*DiscountRepo) GetByID

func (r *DiscountRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Discount, error)

GetByID retrieves a discount by its ID.

func (*DiscountRepo) ListByCompany

func (r *DiscountRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Discount], error)

ListByCompany returns paginated discounts for a company, optionally filtered by a name search keyword.

func (*DiscountRepo) ListSelectable added in v0.1.4

func (r *DiscountRepo) ListSelectable(
	ctx context.Context, companyID uuid.UUID, at time.Time,
) ([]model.Discount, error)

ListSelectable returns active, uncoded, currently-in-window discounts for a company — what the POS dropdown may offer.

func (*DiscountRepo) Update

func (r *DiscountRepo) Update(ctx context.Context, entity *model.Discount) error

Update persists mutable discount fields.

type ExpenseRepo

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

func (*ExpenseRepo) Create

func (r *ExpenseRepo) Create(ctx context.Context, entity *model.Expense) error

func (*ExpenseRepo) GetByID

func (r *ExpenseRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Expense, error)

func (*ExpenseRepo) ListByCompany

func (r *ExpenseRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Expense], error)

type FileRepo

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

FileRepo persists uploaded file metadata.

func (*FileRepo) Create

func (r *FileRepo) Create(ctx context.Context, entity *model.File) error

Create persists a new file record. Sets ID and CreatedAt.

func (*FileRepo) Delete

func (r *FileRepo) Delete(ctx context.Context, id, companyID uuid.UUID) error

Delete removes a file record by ID, scoped to the owning company.

func (*FileRepo) GetByID

func (r *FileRepo) GetByID(ctx context.Context, id, companyID uuid.UUID) (*model.File, error)

GetByID retrieves a file by ID, scoped to the owning company.

type GoqiteEnqueuer

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

GoqiteEnqueuer implements data.Enqueuer using a goqite SQLite-backed queue. All jobs share the single "okpos" queue; the job name routes to the correct handler.

func NewGoqiteEnqueuer

func NewGoqiteEnqueuer(database *sql.DB) *GoqiteEnqueuer

NewGoqiteEnqueuer creates an enqueuer backed by the given *sql.DB. The database must already contain the goqite schema (migration 000023).

func (*GoqiteEnqueuer) Enqueue added in v0.2.0

func (e *GoqiteEnqueuer) Enqueue(ctx context.Context, job data.BackgroundJob) error

Enqueue enqueues a job non-transactionally.

func (*GoqiteEnqueuer) Queue

func (e *GoqiteEnqueuer) Queue() *goqite.Queue

Queue returns the underlying goqite.Queue, used by worker.NewRunner.

type InventoryRepo

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

func NewInventoryRepo

func NewInventoryRepo(database *sql.DB, q *db.Queries, clk clock.Clock) *InventoryRepo

func (*InventoryRepo) CreateInvoice added in v0.5.1

func (r *InventoryRepo) CreateInvoice(ctx context.Context, entity *model.ProcurementInvoice) error

CreateInvoice persists a procurement invoice. See data.InventoryRepoer's doc comment for why this lives here rather than only on InvoiceRepoer.

func (*InventoryRepo) CurrentStock

func (r *InventoryRepo) CurrentStock(ctx context.Context, productID uuid.UUID) (float64, error)

func (*InventoryRepo) GetByID

func (r *InventoryRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.StockMovement, error)

func (*InventoryRepo) GetInvoiceByID added in v0.5.1

func (r *InventoryRepo) GetInvoiceByID(
	ctx context.Context,
	id uuid.UUID,
) (*model.ProcurementInvoice, error)

GetInvoiceByID exists here for CorrectMovement's transactionally-consistent re-check — see data.InventoryRepoer's doc comment.

func (*InventoryRepo) HasMovements

func (r *InventoryRepo) HasMovements(ctx context.Context, productID uuid.UUID) (bool, error)

func (*InventoryRepo) IsReversed added in v0.1.2

func (r *InventoryRepo) IsReversed(ctx context.Context, movementID uuid.UUID) (bool, error)

IsReversed reports whether a correction movement already reverses movementID.

func (*InventoryRepo) LPP

func (r *InventoryRepo) LPP(ctx context.Context, productID uuid.UUID) (int64, error)

func (*InventoryRepo) LPPTrend added in v0.5.1

func (r *InventoryRepo) LPPTrend(
	ctx context.Context,
	productID uuid.UUID,
) (current int64, previous *int64, err error)

LPPTrend returns the most recent procurement unit_cost (same value as LPP) and the one before it, if any. previous is nil when there's no earlier procurement to compare against. Returns ErrNoProcurementPrice when no procurement exists at all, same condition as LPP.

func (*InventoryRepo) ListByCompany

func (*InventoryRepo) ListByProduct

func (r *InventoryRepo) ListByProduct(
	ctx context.Context,
	productID, companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.StockMovement], error)

func (*InventoryRepo) Record

func (r *InventoryRepo) Record(ctx context.Context, entity *model.StockMovement) error

func (*InventoryRepo) StockAt

func (r *InventoryRepo) StockAt(
	ctx context.Context,
	productID uuid.UUID,
	at time.Time,
) (float64, error)

func (*InventoryRepo) UpdateInvoiceTotalAmount added in v0.5.1

func (r *InventoryRepo) UpdateInvoiceTotalAmount(
	ctx context.Context,
	id uuid.UUID,
	totalAmount int64,
) error

func (*InventoryRepo) WithTx

func (r *InventoryRepo) WithTx(ctx context.Context, fn func(data.InventoryRepoer) error) error

type InvoiceRepo added in v0.5.1

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

func NewInvoiceRepo added in v0.5.1

func NewInvoiceRepo(database *sql.DB, q *db.Queries) *InvoiceRepo

func (*InvoiceRepo) GetByID added in v0.5.1

func (r *InvoiceRepo) GetByID(
	ctx context.Context,
	id uuid.UUID,
) (*model.ProcurementInvoice, error)

func (*InvoiceRepo) ListByCompany added in v0.5.1

func (*InvoiceRepo) ListBySupplier added in v0.5.1

func (*InvoiceRepo) ListOpenBySupplier added in v0.5.1

func (r *InvoiceRepo) ListOpenBySupplier(
	ctx context.Context,
	supplierID uuid.UUID,
) ([]model.ProcurementInvoice, error)

type LocalFSStorage

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

LocalFSStorage stores file bytes on the local filesystem, rooted at baseDir. It does not implement data.URLPresigner — a private local directory has no native presign mechanism, so read access is instead brokered through a short-lived file-access JWT (see service.FileService).

func NewLocalFSStorage

func NewLocalFSStorage(baseDir string) (*LocalFSStorage, error)

NewLocalFSStorage returns a FileStorage backed by baseDir, creating it (privately, mode 0700) if it doesn't already exist.

func (*LocalFSStorage) Delete

func (s *LocalFSStorage) Delete(_ context.Context, key string) error

Delete removes baseDir/key. Deleting an already-absent key is a no-op, matching typical object-storage delete semantics.

func (*LocalFSStorage) Get

Get opens baseDir/key for reading. Returns data.ErrNotFound if it doesn't exist.

func (*LocalFSStorage) Put

func (s *LocalFSStorage) Put(_ context.Context, key string, r io.Reader, _ int64) error

Put writes r to baseDir/key, creating parent directories as needed.

type OrderRepo

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

OrderRepo implements data.OrderRepoer using SQLite.

func (*OrderRepo) CountOrdersByCompanyAndDate

func (r *OrderRepo) CountOrdersByCompanyAndDate(
	ctx context.Context,
	companyID uuid.UUID,
	date string,
) (int64, error)

CountOrdersByCompanyAndDate returns the number of orders created by the company on the given date (format "YYYY-MM-DD"). Used for receipt sequence generation.

func (*OrderRepo) CreateOrder

func (r *OrderRepo) CreateOrder(ctx context.Context, entity *model.Order) error

CreateOrder persists a new open order. Sets ID, CreatedAt, UpdatedAt.

func (*OrderRepo) CreateOrderItem

func (r *OrderRepo) CreateOrderItem(ctx context.Context, entity *model.OrderItem) error

CreateOrderItem persists a new order item. Sets ID.

func (*OrderRepo) CreateOrderReturn

func (r *OrderRepo) CreateOrderReturn(ctx context.Context, entity *model.OrderReturn) error

CreateOrderReturn persists a return record. Sets ID.

func (*OrderRepo) CreateOrderReturnItem

func (r *OrderRepo) CreateOrderReturnItem(
	ctx context.Context,
	entity *model.OrderReturnItem,
) error

CreateOrderReturnItem persists a return item line. Sets ID.

func (*OrderRepo) CreatePayment

func (r *OrderRepo) CreatePayment(ctx context.Context, entity *model.Payment) error

CreatePayment persists a payment leg. Sets ID.

func (*OrderRepo) DeleteOrder

func (r *OrderRepo) DeleteOrder(ctx context.Context, id uuid.UUID) error

DeleteOrder removes an order record entirely.

func (*OrderRepo) DeleteOrderItem

func (r *OrderRepo) DeleteOrderItem(ctx context.Context, id uuid.UUID) error

DeleteOrderItem removes an order item.

func (*OrderRepo) GetOpenOrderBySession added in v0.5.1

func (r *OrderRepo) GetOpenOrderBySession(
	ctx context.Context,
	sessionID uuid.UUID,
) (*model.Order, error)

GetOpenOrderBySession retrieves the session's current open order directly by status — see data.OrderRepoer's doc comment for why this exists alongside ListOrdersBySession.

func (*OrderRepo) GetOrderByID

func (r *OrderRepo) GetOrderByID(ctx context.Context, id uuid.UUID) (*model.Order, error)

GetOrderByID retrieves an order by its ID.

func (*OrderRepo) GetOrderItemByID

func (r *OrderRepo) GetOrderItemByID(ctx context.Context, id uuid.UUID) (*model.OrderItem, error)

GetOrderItemByID retrieves an order item by its ID.

func (*OrderRepo) GetOrderReturnByID

func (r *OrderRepo) GetOrderReturnByID(
	ctx context.Context,
	id uuid.UUID,
) (*model.OrderReturn, error)

GetOrderReturnByID retrieves a return by its ID.

func (*OrderRepo) ListOrderItemsByOrder

func (r *OrderRepo) ListOrderItemsByOrder(
	ctx context.Context,
	orderID uuid.UUID,
) ([]model.OrderItem, error)

ListOrderItemsByOrder returns all items for an order.

func (*OrderRepo) ListOrderReturnItemsByReturn

func (r *OrderRepo) ListOrderReturnItemsByReturn(
	ctx context.Context,
	returnID uuid.UUID,
) ([]model.OrderReturnItem, error)

ListOrderReturnItemsByReturn returns all item lines for a return.

func (*OrderRepo) ListOrderReturnsByOrder

func (r *OrderRepo) ListOrderReturnsByOrder(
	ctx context.Context,
	orderID uuid.UUID,
) ([]model.OrderReturn, error)

ListOrderReturnsByOrder returns all return records for an order.

func (*OrderRepo) ListOrdersByCompany

func (r *OrderRepo) ListOrdersByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Order], error)

ListOrdersByCompany returns paginated orders for a company.

func (*OrderRepo) ListOrdersByCompanyFiltered

func (r *OrderRepo) ListOrdersByCompanyFiltered(
	ctx context.Context,
	companyID uuid.UUID,
	filter *data.OrderFilter,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Order], error)

ListOrdersByCompanyFiltered returns paginated orders for a company, narrowed by filter. Built as hand-rolled dynamic SQL (bypassing sqlc, same approach as ReportsRepo's multi-filter queries) since sqlc's static query generation doesn't cleanly express several independently-optional, mixed-type conditions in one query.

func (*OrderRepo) ListOrdersBySession

func (r *OrderRepo) ListOrdersBySession(
	ctx context.Context,
	sessionID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Order], error)

ListOrdersBySession returns paginated orders for a session.

func (*OrderRepo) ListPaymentsByOrder

func (r *OrderRepo) ListPaymentsByOrder(
	ctx context.Context,
	orderID uuid.UUID,
) ([]model.Payment, error)

ListPaymentsByOrder returns all payment legs for an order.

func (*OrderRepo) SumPaymentsByOrder

func (r *OrderRepo) SumPaymentsByOrder(ctx context.Context, orderID uuid.UUID) (int64, error)

SumPaymentsByOrder returns the total of completed payments for an order.

func (*OrderRepo) UpdateOrder

func (r *OrderRepo) UpdateOrder(ctx context.Context, entity *model.Order) error

UpdateOrder persists mutable order fields.

func (*OrderRepo) UpdateOrderItem

func (r *OrderRepo) UpdateOrderItem(ctx context.Context, entity *model.OrderItem) error

UpdateOrderItem updates the quantity and subtotal of an existing order item.

func (*OrderRepo) WithTx

func (r *OrderRepo) WithTx(
	ctx context.Context,
	fn func(orders data.OrderRepoer, inv data.InventoryRepoer) error,
) error

WithTx runs fn inside a single database transaction with transactional views of both the order repo and the inventory repo.

type POSStationRepo

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

func (*POSStationRepo) Create

func (r *POSStationRepo) Create(ctx context.Context, entity *model.POSStation) error

func (*POSStationRepo) Delete

func (r *POSStationRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*POSStationRepo) GetByID

func (r *POSStationRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.POSStation, error)

func (*POSStationRepo) ListByCompany

func (*POSStationRepo) Update

func (r *POSStationRepo) Update(ctx context.Context, entity *model.POSStation) error

func (*POSStationRepo) WithTx

func (r *POSStationRepo) WithTx(ctx context.Context, fn func(data.POSStationRepoer) error) error

type ProductRepo

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

func (*ProductRepo) Create

func (r *ProductRepo) Create(ctx context.Context, entity *model.Product) error

Create persists a new product. Sets CreatedAt/UpdatedAt, and generates an ID only if entity.ID is not already set — ProductService.Create pre-generates it when it needs to default SKU to the product's own ID, so the row can be inserted once with its final SKU rather than requiring a separate backfill update (which would race against the SKU uniqueness constraint under concurrent creates).

func (*ProductRepo) Delete

func (r *ProductRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*ProductRepo) GetByID

func (r *ProductRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Product, error)

func (*ProductRepo) GetBySKU

func (r *ProductRepo) GetBySKU(
	ctx context.Context,
	companyID uuid.UUID,
	sku string,
) (*model.Product, error)

GetBySKU retrieves a product by its SKU, scoped to companyID. Used by the POS barcode-scan-to-cart flow.

func (*ProductRepo) GetBySKUForBranch added in v0.5.1

func (r *ProductRepo) GetBySKUForBranch(
	ctx context.Context,
	companyID, branchID uuid.UUID,
	sku string,
) (*model.Product, error)

GetBySKUForBranch is GetBySKU further filtered to products visible at branchID, used by the POS barcode-scan-to-cart flow so scanning enforces the same branch restriction as the product grid.

func (*ProductRepo) GetOrCreateCategories added in v0.1.7

func (r *ProductRepo) GetOrCreateCategories(
	ctx context.Context,
	companyID uuid.UUID,
	names []string,
) ([]model.Category, error)

GetOrCreateCategories resolves each name to a company-scoped category via an atomic upsert (see UpsertCategory), so concurrent creates of the same normalized name can't race into duplicate rows. Blank names are skipped.

func (*ProductRepo) GetProductBranches added in v0.5.1

func (r *ProductRepo) GetProductBranches(
	ctx context.Context,
	productID uuid.UUID,
) ([]model.Branch, error)

GetProductBranches returns the branches a product is restricted to. An empty slice means the product is unrestricted (sellable at every branch of its company).

func (*ProductRepo) GetProductCategories added in v0.1.7

func (r *ProductRepo) GetProductCategories(
	ctx context.Context,
	productID uuid.UUID,
) ([]model.Category, error)

func (*ProductRepo) GetRecipeComponents

func (r *ProductRepo) GetRecipeComponents(
	ctx context.Context,
	recipeID uuid.UUID,
) ([]model.RecipeComponent, error)

func (*ProductRepo) GetRecipeOverheads

func (r *ProductRepo) GetRecipeOverheads(
	ctx context.Context,
	recipeID uuid.UUID,
) ([]model.RecipeOverhead, error)

func (*ProductRepo) HasRecipeOrIngredientProducts added in v0.5.1

func (r *ProductRepo) HasRecipeOrIngredientProducts(
	ctx context.Context,
	companyID uuid.UUID,
) (bool, error)

HasRecipeOrIngredientProducts reports whether a company has any product of type recipe or ingredient.

func (*ProductRepo) ListByCompany

func (r *ProductRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Product], error)

func (*ProductRepo) ListByCompanyAndType

func (r *ProductRepo) ListByCompanyAndType(
	ctx context.Context,
	companyID uuid.UUID,
	t model.ProductType,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Product], error)

func (*ProductRepo) ListByCompanyFiltered added in v0.5.1

func (r *ProductRepo) ListByCompanyFiltered(
	ctx context.Context,
	companyID uuid.UUID,
	productType *model.ProductType,
	categoryID, branchID *uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Product], error)

ListByCompanyFiltered lists products for a company with type, category, and branch as independent optional filters (nil = don't filter on that dimension). Backs the product list page's filter row. Branch filtering uses the same unrestricted-OR-explicit-match semantics as ListSellableByCompanyForBranch.

func (*ProductRepo) ListCategoriesByCompany added in v0.1.7

func (r *ProductRepo) ListCategoriesByCompany(
	ctx context.Context,
	companyID uuid.UUID,
) ([]model.Category, error)

func (*ProductRepo) ListSellableByCompany

func (r *ProductRepo) ListSellableByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Product], error)

ListSellableByCompany returns paginated Simple+Recipe products for the POS product grid, as one correctly-ordered and counted set.

func (*ProductRepo) ListSellableByCompanyForBranch added in v0.5.1

func (r *ProductRepo) ListSellableByCompanyForBranch(
	ctx context.Context,
	companyID, branchID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Product], error)

ListSellableByCompanyForBranch is ListSellableByCompany further filtered to products visible at branchID: unrestricted products (zero product_branches rows) plus products explicitly restricted to branchID.

func (*ProductRepo) SetProductBranches added in v0.5.1

func (r *ProductRepo) SetProductBranches(
	ctx context.Context,
	productID uuid.UUID,
	branchIDs []uuid.UUID,
) error

SetProductBranches replaces a product's full branch-restriction set (delete-then-reinsert, same pattern as SetProductCategories). An empty/nil slice clears all restrictions, making the product unrestricted.

func (*ProductRepo) SetProductCategories added in v0.1.7

func (r *ProductRepo) SetProductCategories(
	ctx context.Context,
	productID uuid.UUID,
	categoryIDs []uuid.UUID,
) error

func (*ProductRepo) SetRecipeComponents

func (r *ProductRepo) SetRecipeComponents(
	ctx context.Context,
	recipeID uuid.UUID,
	components []model.RecipeComponent,
) error

func (*ProductRepo) SetRecipeOverheads

func (r *ProductRepo) SetRecipeOverheads(
	ctx context.Context,
	recipeID uuid.UUID,
	overheads []model.RecipeOverhead,
) error

func (*ProductRepo) Update

func (r *ProductRepo) Update(ctx context.Context, entity *model.Product) error

func (*ProductRepo) WithTx

func (r *ProductRepo) WithTx(
	ctx context.Context,
	fn func(products data.ProductRepoer, inv data.InventoryRepoer) error,
) error

WithTx runs fn inside a single database transaction with transactional views of both the product repo and the inventory repo — mirrors OrderRepo.WithTx, so a product write and a stock movement (e.g. initial stock at creation) can commit atomically.

type ReportsRepo

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

ReportsRepo provides aggregate report queries using raw SQL. It does not use sqlc; all queries are executed via database.QueryContext.

func (*ReportsRepo) ExpiringSoon added in v0.5.1

func (r *ReportsRepo) ExpiringSoon(
	ctx context.Context,
	companyID uuid.UUID,
) ([]model.ExpiringBatch, error)

ExpiringSoon returns procurement batches whose expiry_date falls within their product's own expiry_warning_days. See data.ReportsQuerier's doc comment for the CurrentStock filtering note.

func (*ReportsRepo) InventorySnapshot

func (r *ReportsRepo) InventorySnapshot(
	ctx context.Context,
	companyID uuid.UUID,
) ([]model.InventoryLine, error)

InventorySnapshot returns current stock and last-purchase-price per product.

func (*ReportsRepo) InventorySnapshotPaged

func (r *ReportsRepo) InventorySnapshotPaged(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	productType string,
	categoryID *uuid.UUID,
	stockStatus string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.InventoryLine], error)

InventorySnapshotPaged is the paginated, searchable counterpart to InventorySnapshot, used by the web Inventory list page.

The stock-status filter ("low"/"out"/"ok") applies to the aggregated current_stock (a SUM over stock_movements), so it must be a HAVING clause evaluated after GROUP BY — it can't be a plain WHERE. That in turn means the count query can't stay a flat `count(*) FROM products`; it wraps the same grouped/filtered query as a subquery instead.

Every filter arg is a numbered parameter (?1, ?2, ...) even where the same value is referenced multiple times in the SQL text (e.g. companyID), so each value is only passed once in the Go args slice.

func (*ReportsRepo) PLByPeriod

func (r *ReportsRepo) PLByPeriod(
	ctx context.Context,
	companyID uuid.UUID,
	from, to string,
	branchID *uuid.UUID,
) (model.PLSummary, error)

PLByPeriod returns revenue and expense totals from double-entry journal entries. branchID, when non-nil, restricts to entries posted for that branch — entries with no branch (company-wide postings, e.g. supplier payments or unassigned expenses) are excluded from any specific branch's figures, the same way they're excluded from every other branch's.

func (*ReportsRepo) RevenueByPaymentMethod

func (r *ReportsRepo) RevenueByPaymentMethod(
	ctx context.Context,
	companyID uuid.UUID,
	from, to string,
	branchID *uuid.UUID,
) ([]model.PaymentMethodRevenue, error)

RevenueByPaymentMethod returns completed payment totals grouped by method. branchID, when non-nil, restricts to orders placed at that branch.

func (*ReportsRepo) SalesByPeriod

func (r *ReportsRepo) SalesByPeriod(
	ctx context.Context,
	companyID uuid.UUID,
	from, to, groupBy string,
	branchID *uuid.UUID,
) ([]model.SalesPeriod, error)

SalesByPeriod returns revenue grouped by day, week, or month. branchID, when non-nil, restricts to orders placed at that branch.

func (*ReportsRepo) SalesTotals

func (r *ReportsRepo) SalesTotals(
	ctx context.Context,
	companyID uuid.UUID,
	from, to string,
	branchID *uuid.UUID,
) (model.SalesSummary, error)

SalesTotals returns aggregate sales figures for the given date range. branchID, when non-nil, restricts to orders placed at that branch.

func (*ReportsRepo) TopProductsByRevenue

func (r *ReportsRepo) TopProductsByRevenue(
	ctx context.Context,
	companyID uuid.UUID,
	from, to string,
	branchID *uuid.UUID,
	topN int,
) ([]model.TopProduct, error)

TopProductsByRevenue returns the top N products by order-item subtotal. branchID, when non-nil, restricts to orders placed at that branch.

func (*ReportsRepo) TrialBalanceAsOf added in v0.5.1

func (r *ReportsRepo) TrialBalanceAsOf(
	ctx context.Context,
	companyID uuid.UUID,
	asOf string,
	branchID *uuid.UUID,
) ([]model.AccountBalance, error)

TrialBalanceAsOf returns per-account debit/credit totals as of a given date, optionally scoped to one branch. asOf == "" means no upper bound (lifetime-to-date, matching AccountingRepoer.BalanceByAccount's behavior). Backs both the trial balance and balance sheet views.

type S3Config

type S3Config struct {
	Endpoint  string
	Region    string
	AccessKey string
	SecretKey string
	Bucket    string
	UseSSL    bool
}

S3Config configures an S3-compatible storage backend (AWS S3, MinIO, Cloudflare R2, DigitalOcean Spaces, etc.).

type S3Storage

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

S3Storage stores file bytes in an S3-compatible bucket via minio-go, and caches presigned GET URLs in-memory (keyed by storage key) so repeated reads of the same file within one URL's lifetime don't re-hit the presign endpoint on every request.

func NewS3Storage

func NewS3Storage(ctx context.Context, cfg *S3Config) (*S3Storage, error)

NewS3Storage connects to the configured S3-compatible endpoint and ensures the target bucket exists, creating it if necessary.

func (*S3Storage) Delete

func (s *S3Storage) Delete(ctx context.Context, key string) error

Delete removes the object at key. Deleting an already-absent key is a no-op, matching S3's own delete semantics.

func (*S3Storage) Get

func (s *S3Storage) Get(ctx context.Context, key string) (io.ReadCloser, error)

Get opens the object at key for reading. Returns data.ErrNotFound if it doesn't exist.

func (*S3Storage) PresignGET

func (s *S3Storage) PresignGET(ctx context.Context, key string, ttl time.Duration) (string, error)

PresignGET returns a presigned GET URL for key, valid for ttl. Cached in-memory (TTL-bound to ttl) so repeated calls for the same key within one token's lifetime don't re-hit the S3 presign endpoint.

func (*S3Storage) Put

func (s *S3Storage) Put(ctx context.Context, key string, r io.Reader, size int64) error

Put uploads r to the bucket under key.

type SessionRepo

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

SessionRepo implements data.SessionRepoer using SQLite.

func (*SessionRepo) Close

func (r *SessionRepo) Close(ctx context.Context, sessionID uuid.UUID, closedAt time.Time) error

Close marks a session as closed at the given time.

func (*SessionRepo) Create

func (r *SessionRepo) Create(ctx context.Context, entity *model.POSSession) error

Create persists a new open POS session. Sets ID and OpenedAt.

func (*SessionRepo) CreateReconciliation

func (r *SessionRepo) CreateReconciliation(
	ctx context.Context,
	entity *model.SessionReconciliation,
) error

CreateReconciliation persists a SessionReconciliation. Sets ReconciledAt.

func (*SessionRepo) DeleteOpenOrders

func (r *SessionRepo) DeleteOpenOrders(ctx context.Context, sessionID uuid.UUID) (int64, error)

DeleteOpenOrders hard-deletes every open order for the session (cascading to their items via FK) and returns the number deleted.

func (*SessionRepo) GetByID

func (r *SessionRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.POSSession, error)

GetByID retrieves a session by its ID.

func (*SessionRepo) GetOpenByStation

func (r *SessionRepo) GetOpenByStation(
	ctx context.Context,
	stationID uuid.UUID,
) (*model.POSSession, error)

GetOpenByStation retrieves the open session for a station, if any. Returns ErrNotFound if no open session exists for the station.

func (*SessionRepo) GetOpenByUser

func (r *SessionRepo) GetOpenByUser(
	ctx context.Context,
	companyID, userID uuid.UUID,
) (*model.POSSession, error)

GetOpenByUser retrieves the open session opened by userID within companyID, if any. Returns ErrNotFound if no open session exists.

func (*SessionRepo) GetReconciliationBySession

func (r *SessionRepo) GetReconciliationBySession(
	ctx context.Context,
	sessionID uuid.UUID,
) (*model.SessionReconciliation, error)

GetReconciliationBySession retrieves the reconciliation for a given session.

func (*SessionRepo) HasOpenOrders

func (r *SessionRepo) HasOpenOrders(ctx context.Context, sessionID uuid.UUID) (bool, error)

HasOpenOrders returns true if the session has any orders in open status.

func (*SessionRepo) ListByCompany

func (r *SessionRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.POSSession], error)

ListByCompany returns paginated sessions for a company, ordered by opened_at DESC.

func (*SessionRepo) ListOpenByCompanyFiltered

func (r *SessionRepo) ListOpenByCompanyFiltered(
	ctx context.Context,
	companyID uuid.UUID,
	filter *data.SessionFilter,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.POSSession], error)

ListOpenByCompanyFiltered returns paginated open sessions for a company, optionally narrowed by filter.BranchID. Built as hand-rolled dynamic SQL (bypassing sqlc), same approach as OrderRepo.ListOrdersByCompanyFiltered.

func (*SessionRepo) SumCashPayments

func (r *SessionRepo) SumCashPayments(ctx context.Context, sessionID uuid.UUID) (int64, error)

SumCashPayments returns the total cash-method payments taken in a session.

type SupplierPaymentRepo

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

func (*SupplierPaymentRepo) Create

func (*SupplierPaymentRepo) GetByID

func (*SupplierPaymentRepo) GetInvoiceByID added in v0.5.1

func (r *SupplierPaymentRepo) GetInvoiceByID(
	ctx context.Context,
	id uuid.UUID,
) (*model.ProcurementInvoice, error)

GetInvoiceByID exists here for RecordPayment's transactionally-consistent re-check — see data.SupplierPaymentRepoer's doc comment.

func (*SupplierPaymentRepo) ListByCompany

func (*SupplierPaymentRepo) ListBySupplier

func (*SupplierPaymentRepo) UpdateInvoicePaid added in v0.5.1

func (r *SupplierPaymentRepo) UpdateInvoicePaid(
	ctx context.Context,
	id uuid.UUID,
	paidAmount int64,
	status string,
) error

func (*SupplierPaymentRepo) WithTx added in v0.5.1

type SupplierRepo

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

func (*SupplierRepo) Create

func (r *SupplierRepo) Create(ctx context.Context, entity *model.Supplier) error

func (*SupplierRepo) Delete

func (r *SupplierRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*SupplierRepo) GetByID

func (r *SupplierRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.Supplier, error)

func (*SupplierRepo) ListByCompany

func (r *SupplierRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	search string,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.Supplier], error)

func (*SupplierRepo) Update

func (r *SupplierRepo) Update(ctx context.Context, entity *model.Supplier) error

func (*SupplierRepo) WithTx

func (r *SupplierRepo) WithTx(ctx context.Context, fn func(data.SupplierRepoer) error) error

type UserRepo

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

UserRepo is the SQLite implementation of data.UserRepoer.

func (*UserRepo) CountByCompany

func (r *UserRepo) CountByCompany(ctx context.Context, companyID uuid.UUID) (int64, error)

func (*UserRepo) CountByRole added in v0.1.7

func (r *UserRepo) CountByRole(ctx context.Context, role auth.UserRole) (int64, error)

func (*UserRepo) Create

func (r *UserRepo) Create(ctx context.Context, entity *model.User) error

func (*UserRepo) Delete

func (r *UserRepo) Delete(ctx context.Context, id uuid.UUID) error

func (*UserRepo) GetByEmail

func (r *UserRepo) GetByEmail(ctx context.Context, email string) (*model.User, error)

func (*UserRepo) GetByID

func (r *UserRepo) GetByID(ctx context.Context, id uuid.UUID) (*model.User, error)

func (*UserRepo) InvalidateTokens

func (r *UserRepo) InvalidateTokens(ctx context.Context, userID uuid.UUID) error

InvalidateTokens sets token_valid_after to now, so any JWT already issued to this user (its iat predates this call) is rejected by handler.JWTParserMiddleware and AuthService.RefreshTokens going forward.

func (*UserRepo) ListByCompany

func (r *UserRepo) ListByCompany(
	ctx context.Context,
	companyID uuid.UUID,
	q data.SupportsPagination,
) (*dto.PaginationResults[model.User], error)

func (*UserRepo) Paginate

func (*UserRepo) Update

func (r *UserRepo) Update(ctx context.Context, entity *model.User) error

func (*UserRepo) WithTx

func (r *UserRepo) WithTx(ctx context.Context, fn func(data.UserRepoer) error) error

Jump to

Keyboard shortcuts

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