Documentation
¶
Overview ¶
Package service contains the business logic for okpos. Service methods depend only on data.*Repoer interfaces and domain types; they never import database-specific packages (pgx, sqlite, etc.).
Index ¶
- func ComputeDiscountAmount(d *model.Discount, basisCents int64) int64
- type AuthService
- func (s *AuthService) Login(ctx context.Context, email, password string) (*auth.JWTTokens, error)
- func (s *AuthService) Logout(ctx context.Context, userID uuid.UUID) error
- func (s *AuthService) RefreshTokens(ctx context.Context, refreshToken string) (*auth.JWTTokens, error)
- func (s *AuthService) Register(ctx context.Context, req *dto.RegisterDTO) (*model.User, *auth.JWTTokens, error)
- type BranchService
- func (s *BranchService) Create(ctx context.Context, req *dto.CreateBranchDTO) (*model.Branch, error)
- func (s *BranchService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *BranchService) GetByID(ctx context.Context, id uuid.UUID) (*model.Branch, error)
- func (s *BranchService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Branch, error)
- func (s *BranchService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Branch], error)
- func (s *BranchService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateBranchDTO) (*model.Branch, error)
- type CompanyService
- func (s *CompanyService) Create(ctx context.Context, ownerID uuid.UUID, req *dto.CreateCompanyDTO) (*model.Company, error)
- func (s *CompanyService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *CompanyService) GetByID(ctx context.Context, id uuid.UUID) (*model.Company, error)
- func (s *CompanyService) GetByIDForOwner(ctx context.Context, id, ownerID uuid.UUID) (*model.Company, error)
- func (s *CompanyService) ListByOwner(ctx context.Context, ownerID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Company], error)
- func (s *CompanyService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateCompanyDTO) (*model.Company, error)
- type CustomerService
- func (s *CustomerService) Create(ctx context.Context, req *dto.CreateCustomerDTO) (*model.Customer, error)
- func (s *CustomerService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *CustomerService) GetByID(ctx context.Context, id uuid.UUID) (*model.Customer, error)
- func (s *CustomerService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Customer, error)
- func (s *CustomerService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Customer], error)
- func (s *CustomerService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateCustomerDTO) (*model.Customer, error)
- type DiscountService
- func (s *DiscountService) Create(ctx context.Context, req *dto.CreateDiscountDTO) (*model.Discount, error)
- func (s *DiscountService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *DiscountService) GetByID(ctx context.Context, id uuid.UUID) (*model.Discount, error)
- func (s *DiscountService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Discount, error)
- func (s *DiscountService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Discount], error)
- func (s *DiscountService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateDiscountDTO) (*model.Discount, error)
- type ExpenseService
- func (s *ExpenseService) GetByID(ctx context.Context, id uuid.UUID) (*model.Expense, error)
- func (s *ExpenseService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Expense, error)
- func (s *ExpenseService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Expense], error)
- func (s *ExpenseService) Record(ctx context.Context, req *dto.CreateExpenseDTO) (*model.Expense, error)
- type FileService
- func (s *FileService) Delete(ctx context.Context, id, companyID uuid.UUID) error
- func (s *FileService) Open(ctx context.Context, id, companyID uuid.UUID) (*model.File, io.ReadCloser, error)
- func (s *FileService) PresignedURL(ctx context.Context, file *model.File) (string, error)
- func (s *FileService) Upload(ctx context.Context, companyID, uploaderID uuid.UUID, intent data.UploadIntent, ...) (*model.File, string, error)
- type InventoryService
- func (s *InventoryService) CurrentStock(ctx context.Context, productID uuid.UUID) (float64, error)
- func (s *InventoryService) GetByID(ctx context.Context, id uuid.UUID) (*model.StockMovement, error)
- func (s *InventoryService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.StockMovement, error)
- func (s *InventoryService) LPP(ctx context.Context, productID uuid.UUID) (int64, error)
- func (s *InventoryService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.StockMovement], error)
- func (s *InventoryService) ListByProduct(ctx context.Context, productID, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.StockMovement], error)
- func (s *InventoryService) RecordAdjustmentDown(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) RecordAdjustmentUp(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) RecordMovement(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) RecordOpeningBalance(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) RecordProcurement(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) RecordWaste(ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO) (*model.StockMovement, error)
- func (s *InventoryService) StockAt(ctx context.Context, productID uuid.UUID, at time.Time) (float64, error)
- type OrderService
- func (s *OrderService) AddItem(ctx context.Context, orderID uuid.UUID, req *dto.AddOrderItemDTO) (*model.OrderItem, error)
- func (s *OrderService) ApplyOrderDiscount(ctx context.Context, orderID uuid.UUID, req *dto.ApplyOrderDiscountDTO) (*model.Order, error)
- func (s *OrderService) Checkout(ctx context.Context, orderID uuid.UUID, userID uuid.UUID, req *dto.CheckoutDTO) (*model.Order, error)
- func (s *OrderService) CreateOrder(ctx context.Context, companyID uuid.UUID, _ uuid.UUID, req *dto.CreateOrderDTO) (*model.Order, error)
- func (s *OrderService) DecrementItem(ctx context.Context, orderID, itemID uuid.UUID) error
- func (s *OrderService) GetOrderByID(ctx context.Context, id uuid.UUID) (*model.Order, error)
- func (s *OrderService) GetOrderByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Order, error)
- func (s *OrderService) ListItemsByOrder(ctx context.Context, orderID uuid.UUID) ([]model.OrderItem, error)
- func (s *OrderService) ListOrdersByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Order], error)
- func (s *OrderService) ListOrdersByCompanyFiltered(ctx context.Context, companyID uuid.UUID, filter *data.OrderFilter, ...) (*dto.PaginationResults[model.Order], error)
- func (s *OrderService) ListOrdersBySession(ctx context.Context, sessionID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Order], error)
- func (s *OrderService) RemoveItem(ctx context.Context, orderID, itemID uuid.UUID) error
- func (s *OrderService) RemoveOrderDiscount(ctx context.Context, orderID uuid.UUID) (*model.Order, error)
- func (s *OrderService) Return(ctx context.Context, orderID uuid.UUID, returnedBy uuid.UUID, ...) (*model.OrderReturn, error)
- func (s *OrderService) Void(ctx context.Context, orderID uuid.UUID, voidedBy uuid.UUID, ...) (*model.Order, error)
- type POSStationService
- func (s *POSStationService) Create(ctx context.Context, req *dto.CreatePOSStationDTO) (*model.POSStation, error)
- func (s *POSStationService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *POSStationService) GetByID(ctx context.Context, id uuid.UUID) (*model.POSStation, error)
- func (s *POSStationService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.POSStation, error)
- func (s *POSStationService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.POSStation], error)
- func (s *POSStationService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdatePOSStationDTO) (*model.POSStation, error)
- type ProductService
- func (s *ProductService) AvailableUnits(ctx context.Context, recipeID uuid.UUID) (float64, error)
- func (s *ProductService) ComputeCOGS(ctx context.Context, recipeID uuid.UUID) (int64, error)
- func (s *ProductService) Create(ctx context.Context, req *dto.CreateProductDTO) (*model.Product, error)
- func (s *ProductService) CurrentStock(ctx context.Context, id uuid.UUID) (float64, error)
- func (s *ProductService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *ProductService) GetByID(ctx context.Context, id uuid.UUID) (*model.Product, error)
- func (s *ProductService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Product, error)
- func (s *ProductService) GetBySKU(ctx context.Context, companyID uuid.UUID, sku string) (*model.Product, error)
- func (s *ProductService) GetRecipe(ctx context.Context, recipeID uuid.UUID) (*dto.RecipeDTO, error)
- func (s *ProductService) LPP(ctx context.Context, id uuid.UUID) (int64, error)
- func (s *ProductService) ListByCompany(ctx context.Context, companyID uuid.UUID, productType string, ...) (*dto.PaginationResults[model.Product], error)
- func (s *ProductService) SetRecipe(ctx context.Context, recipeID uuid.UUID, req *dto.SetRecipeDTO) error
- func (s *ProductService) StockAt(ctx context.Context, id uuid.UUID, at time.Time) (float64, error)
- func (s *ProductService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateProductDTO) (*model.Product, error)
- type ReportsService
- func (s *ReportsService) InventoryReport(ctx context.Context, q *dto.InventoryReportQuery) (*model.InventoryReport, error)
- func (s *ReportsService) PLReport(ctx context.Context, q *dto.PLReportQuery) (*model.PLReport, error)
- func (s *ReportsService) SalesReport(ctx context.Context, q *dto.SalesReportQuery) (*model.SalesReport, error)
- type SessionService
- func (s *SessionService) Close(ctx context.Context, sessionID uuid.UUID, closerID uuid.UUID, ...) (*model.SessionReconciliation, error)
- func (s *SessionService) ForceClose(ctx context.Context, sessionID, companyID, actorID uuid.UUID) (*model.SessionReconciliation, error)
- func (s *SessionService) GetByID(ctx context.Context, id uuid.UUID) (*model.POSSession, error)
- func (s *SessionService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.POSSession, error)
- func (s *SessionService) GetOpenByUser(ctx context.Context, companyID, userID uuid.UUID) (*model.POSSession, error)
- func (s *SessionService) GetReconciliation(ctx context.Context, sessionID uuid.UUID) (*model.SessionReconciliation, error)
- func (s *SessionService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.POSSession], error)
- func (s *SessionService) ListOpenByCompanyFiltered(ctx context.Context, companyID uuid.UUID, filter *data.SessionFilter, ...) (*dto.PaginationResults[model.POSSession], error)
- func (s *SessionService) Open(ctx context.Context, companyID uuid.UUID, userID uuid.UUID, ...) (*model.POSSession, error)
- type SupplierPaymentService
- func (s *SupplierPaymentService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.SupplierPayment], error)
- func (s *SupplierPaymentService) ListBySupplier(ctx context.Context, supplierID, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.SupplierPayment], error)
- func (s *SupplierPaymentService) RecordPayment(ctx context.Context, supplierID uuid.UUID, companyID uuid.UUID, ...) (*model.SupplierPayment, error)
- type SupplierService
- func (s *SupplierService) Create(ctx context.Context, req *dto.CreateSupplierDTO) (*model.Supplier, error)
- func (s *SupplierService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *SupplierService) GetByID(ctx context.Context, id uuid.UUID) (*model.Supplier, error)
- func (s *SupplierService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.Supplier, error)
- func (s *SupplierService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.Supplier], error)
- func (s *SupplierService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateSupplierDTO) (*model.Supplier, error)
- type UserService
- func (s *UserService) Create(ctx context.Context, req *dto.CreateUserDTO) (*model.User, error)
- func (s *UserService) Delete(ctx context.Context, id uuid.UUID) error
- func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*model.User, error)
- func (s *UserService) GetByIDForCompany(ctx context.Context, id, companyID uuid.UUID) (*model.User, error)
- func (s *UserService) List(ctx context.Context, q *dto.PaginationDTO) (*dto.PaginationResults[model.User], error)
- func (s *UserService) ListByCompany(ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO) (*dto.PaginationResults[model.User], error)
- func (s *UserService) Update(ctx context.Context, id uuid.UUID, req *dto.UpdateUserDTO) (*model.User, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeDiscountAmount ¶
ComputeDiscountAmount returns the discount in cents for the given basis amount. For fixed discounts, returns d.Value directly. For percentage discounts, returns (basisCents * d.Value) / 100 (integer division).
Types ¶
type AuthService ¶
type AuthService struct {
// contains filtered or unexported fields
}
AuthService handles login and token refresh.
func NewAuthService ¶
func NewAuthService(userRepo data.UserRepoer, a *auth.Auth) *AuthService
NewAuthService creates an AuthService.
func (*AuthService) Logout ¶
Logout revokes every access and refresh token already issued to the user by advancing their token_valid_after cutoff (UserRepoer.InvalidateTokens), so a token that was merely discarded client-side (or stolen) can no longer be used to authenticate or refresh. There's no per-device session store, so this revokes all of the user's sessions, not just the caller's.
func (*AuthService) RefreshTokens ¶
func (s *AuthService) RefreshTokens( ctx context.Context, refreshToken string, ) (*auth.JWTTokens, error)
RefreshTokens validates a refresh token and issues a new access+refresh pair.
type BranchService ¶
type BranchService struct {
// contains filtered or unexported fields
}
BranchService handles branch-related business operations.
func NewBranchService ¶
func NewBranchService(repo data.BranchRepoer, companyRepo data.CompanyRepoer) *BranchService
func (*BranchService) Create ¶
func (s *BranchService) Create( ctx context.Context, req *dto.CreateBranchDTO, ) (*model.Branch, error)
Create registers a new branch. Validates that the company exists.
func (*BranchService) GetByIDForCompany ¶
func (s *BranchService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Branch, error)
GetByIDForCompany fetches a branch and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*BranchService) ListByCompany ¶
func (s *BranchService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Branch], error)
type CompanyService ¶
type CompanyService struct {
// contains filtered or unexported fields
}
CompanyService handles company-related business operations.
func NewCompanyService ¶
func NewCompanyService(repo data.CompanyRepoer) *CompanyService
func (*CompanyService) Create ¶
func (s *CompanyService) Create( ctx context.Context, ownerID uuid.UUID, req *dto.CreateCompanyDTO, ) (*model.Company, error)
Create registers a new company. ownerID is taken from the caller's JWT, not the DTO.
func (*CompanyService) GetByIDForOwner ¶
func (s *CompanyService) GetByIDForOwner( ctx context.Context, id, ownerID uuid.UUID, ) (*model.Company, error)
GetByIDForOwner fetches a company and verifies ownerID actually owns it. Returns data.ErrForbidden if the company exists but belongs to someone else — companies have no CompanyID of their own to compare (they're the tenant root), so ownership is checked via OwnerID instead.
func (*CompanyService) ListByOwner ¶
func (s *CompanyService) ListByOwner( ctx context.Context, ownerID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Company], error)
type CustomerService ¶
type CustomerService struct {
// contains filtered or unexported fields
}
CustomerService handles customer-related business operations.
func NewCustomerService ¶
func NewCustomerService(repo data.CustomerRepoer) *CustomerService
func (*CustomerService) Create ¶
func (s *CustomerService) Create( ctx context.Context, req *dto.CreateCustomerDTO, ) (*model.Customer, error)
func (*CustomerService) GetByIDForCompany ¶
func (s *CustomerService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Customer, error)
GetByIDForCompany fetches a customer and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*CustomerService) ListByCompany ¶
func (s *CustomerService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Customer], error)
type DiscountService ¶
type DiscountService struct {
// contains filtered or unexported fields
}
DiscountService handles CRUD operations on the named discount catalog.
func NewDiscountService ¶
func NewDiscountService(repo data.DiscountRepoer) *DiscountService
NewDiscountService constructs a DiscountService.
func (*DiscountService) Create ¶
func (s *DiscountService) Create( ctx context.Context, req *dto.CreateDiscountDTO, ) (*model.Discount, error)
Create persists a new discount. Validates type and value range.
func (*DiscountService) GetByIDForCompany ¶
func (s *DiscountService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Discount, error)
GetByIDForCompany fetches a discount and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*DiscountService) ListByCompany ¶
func (s *DiscountService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Discount], error)
ListByCompany returns paginated discounts for a company.
type ExpenseService ¶
type ExpenseService struct {
// contains filtered or unexported fields
}
ExpenseService handles expense-related business operations.
func NewExpenseService ¶
func NewExpenseService(repo data.ExpenseRepoer, emitter data.EventEmitter) *ExpenseService
func (*ExpenseService) GetByIDForCompany ¶
func (s *ExpenseService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Expense, error)
GetByIDForCompany fetches an expense and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*ExpenseService) ListByCompany ¶
func (s *ExpenseService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Expense], error)
func (*ExpenseService) Record ¶
func (s *ExpenseService) Record( ctx context.Context, req *dto.CreateExpenseDTO, ) (*model.Expense, error)
type FileService ¶
type FileService struct {
// contains filtered or unexported fields
}
FileService validates and persists uploaded files against the intent registry, delegating byte storage to a data.FileStorage backend and producing presigned download URLs for either backend transparently.
func NewFileService ¶
func NewFileService( repo data.FileRepoer, storage data.FileStorage, a *auth.Auth, fileAccessTTL time.Duration, ) *FileService
NewFileService constructs a FileService.
func (*FileService) Delete ¶
Delete removes both the storage object and the metadata row for a file, scoped to companyID. Storage is deleted first so a failure leaves the DB row (and thus the file) intact for a retry, rather than orphaning bytes with no record pointing at them.
func (*FileService) Open ¶
func (s *FileService) Open( ctx context.Context, id, companyID uuid.UUID, ) (*model.File, io.ReadCloser, error)
Open retrieves a file's metadata and a reader over its bytes, scoped to companyID. Used by the public download handler.
func (*FileService) PresignedURL ¶
PresignedURL returns a time-limited download URL for file, using the storage backend's native presign when available (S3), or a file-access JWT pointing back at this app's own download route otherwise (local FS).
func (*FileService) Upload ¶
func (s *FileService) Upload( ctx context.Context, companyID, uploaderID uuid.UUID, intent data.UploadIntent, declaredMIME string, size int64, r io.Reader, ) (*model.File, string, error)
Upload validates r against intent's registered constraints, stores it, records a files row, and returns the record plus a presigned download URL.
type InventoryService ¶
type InventoryService struct {
// contains filtered or unexported fields
}
InventoryService handles stock movement operations. It also implements data.InventoryQuerier (LPP + CurrentStock) so it can be passed directly to ProductService.
func NewInventoryService ¶
func NewInventoryService( repo data.InventoryRepoer, productRepo data.ProductRepoer, emitter data.EventEmitter, ) *InventoryService
func (*InventoryService) CurrentStock ¶
CurrentStock returns the signed sum of stock deltas for the product. Returns ErrInsufficientStock if no movements have been recorded yet.
func (*InventoryService) GetByID ¶
func (s *InventoryService) GetByID( ctx context.Context, id uuid.UUID, ) (*model.StockMovement, error)
func (*InventoryService) GetByIDForCompany ¶
func (s *InventoryService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.StockMovement, error)
GetByIDForCompany fetches a stock movement and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*InventoryService) ListByCompany ¶
func (s *InventoryService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.StockMovement], error)
func (*InventoryService) ListByProduct ¶
func (s *InventoryService) ListByProduct( ctx context.Context, productID, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.StockMovement], error)
func (*InventoryService) RecordAdjustmentDown ¶
func (s *InventoryService) RecordAdjustmentDown( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordAdjustmentDown records a negative stock adjustment. UnitCost must be nil.
func (*InventoryService) RecordAdjustmentUp ¶
func (s *InventoryService) RecordAdjustmentUp( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordAdjustmentUp records a positive stock adjustment. UnitCost must be nil.
func (*InventoryService) RecordMovement ¶
func (s *InventoryService) RecordMovement( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordMovement dispatches to the appropriate method based on Reason.
func (*InventoryService) RecordOpeningBalance ¶
func (s *InventoryService) RecordOpeningBalance( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordOpeningBalance records an opening balance movement. UnitCost is required.
func (*InventoryService) RecordProcurement ¶
func (s *InventoryService) RecordProcurement( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordProcurement records an incoming stock movement of type "procurement". UnitCost is required.
func (*InventoryService) RecordWaste ¶
func (s *InventoryService) RecordWaste( ctx context.Context, companyID uuid.UUID, req *dto.RecordStockMovementDTO, ) (*model.StockMovement, error)
RecordWaste records a waste movement (negative delta). UnitCost must be nil. Resolves LPP to compute valueLost and optionally emits an event.
type OrderService ¶
type OrderService struct {
// contains filtered or unexported fields
}
OrderService handles the order lifecycle: create, add items, checkout, void, return.
func NewOrderService ¶
func NewOrderService( repo data.OrderRepoer, productRepo data.ProductRepoer, sessionRepo data.SessionRepoer, discountRepo data.DiscountRepoer, paymentMethods []model.PaymentMethod, cashDrawerMethods []model.PaymentMethod, emitter data.EventEmitter, ) *OrderService
NewOrderService constructs an OrderService. Pass nil for paymentMethods to use model.DefaultPaymentMethods. Pass nil for cashDrawerMethods to use model.DefaultCashDrawerMethods.
func (*OrderService) AddItem ¶
func (s *OrderService) AddItem( ctx context.Context, orderID uuid.UUID, req *dto.AddOrderItemDTO, ) (*model.OrderItem, error)
AddItem adds a product to an open order. Returns ErrOrderNotOpen if the order is not open. Returns ErrInvalidProductType if the product is an ingredient.
func (*OrderService) ApplyOrderDiscount ¶
func (s *OrderService) ApplyOrderDiscount( ctx context.Context, orderID uuid.UUID, req *dto.ApplyOrderDiscountDTO, ) (*model.Order, error)
ApplyOrderDiscount applies a named or ad-hoc discount to the order total. Replaces any previously applied order-level discount. Returns ErrOrderNotOpen if the order is not open. Returns ErrDiscountExceedsTotal if the discount would wipe out the order total.
func (*OrderService) Checkout ¶
func (s *OrderService) Checkout( ctx context.Context, orderID uuid.UUID, userID uuid.UUID, req *dto.CheckoutDTO, ) (*model.Order, error)
Checkout finalizes a paid order in a single transaction: validates payment total and methods, deducts stock, records payments, generates a receipt number, and marks the order paid.
func (*OrderService) CreateOrder ¶
func (s *OrderService) CreateOrder( ctx context.Context, companyID uuid.UUID, _ uuid.UUID, req *dto.CreateOrderDTO, ) (*model.Order, error)
CreateOrder creates a new open order within the given session. Returns ErrNotFound if the session does not exist. Returns ErrOrderNotOpen if the session is already closed.
func (*OrderService) DecrementItem ¶
DecrementItem decreases an item's quantity by 1. If the quantity reaches 0, the item is removed entirely.
func (*OrderService) GetOrderByID ¶
GetOrderByID retrieves an order by ID.
func (*OrderService) GetOrderByIDForCompany ¶
func (s *OrderService) GetOrderByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Order, error)
GetOrderByIDForCompany fetches an order and verifies it belongs to companyID, returning data.ErrForbidden otherwise. Order items and payments have no CompanyID of their own — verifying the parent order here is what scopes them too, since every item/payment action is keyed on an orderID first.
func (*OrderService) ListItemsByOrder ¶
func (s *OrderService) ListItemsByOrder( ctx context.Context, orderID uuid.UUID, ) ([]model.OrderItem, error)
ListItemsByOrder returns all items on an order.
func (*OrderService) ListOrdersByCompany ¶
func (s *OrderService) ListOrdersByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Order], error)
ListOrdersByCompany returns paginated orders for a company.
func (*OrderService) ListOrdersByCompanyFiltered ¶
func (s *OrderService) ListOrdersByCompanyFiltered( ctx context.Context, companyID uuid.UUID, filter *data.OrderFilter, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Order], error)
ListOrdersByCompanyFiltered returns paginated orders for a company, narrowed by filter.
func (*OrderService) ListOrdersBySession ¶
func (s *OrderService) ListOrdersBySession( ctx context.Context, sessionID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Order], error)
ListOrdersBySession returns paginated orders for a session.
func (*OrderService) RemoveItem ¶
RemoveItem removes an item from an open order. Returns ErrOrderNotOpen if the order is not open. Returns ErrNotFound if the item does not belong to this order.
func (*OrderService) RemoveOrderDiscount ¶
func (s *OrderService) RemoveOrderDiscount( ctx context.Context, orderID uuid.UUID, ) (*model.Order, error)
RemoveOrderDiscount removes an order-level discount, restoring the full items total. Returns ErrOrderNotOpen if the order is not open.
func (*OrderService) Return ¶
func (s *OrderService) Return( ctx context.Context, orderID uuid.UUID, returnedBy uuid.UUID, req *dto.ReturnOrderDTO, ) (*model.OrderReturn, error)
Return processes a partial or full return against a paid order. Manager/owner only. Returns ErrOrderNotPaid if the order is not paid.
func (*OrderService) Void ¶
func (s *OrderService) Void( ctx context.Context, orderID uuid.UUID, voidedBy uuid.UUID, req *dto.VoidOrderDTO, ) (*model.Order, error)
Void voids a paid order, restoring stock. Manager/owner only. Returns ErrOrderNotPaid if the order is not in paid status. Returns ErrOrderAlreadyVoided if already voided.
type POSStationService ¶
type POSStationService struct {
// contains filtered or unexported fields
}
POSStationService handles POS station-related business operations.
func NewPOSStationService ¶
func NewPOSStationService( repo data.POSStationRepoer, branchRepo data.BranchRepoer, ) *POSStationService
func (*POSStationService) Create ¶
func (s *POSStationService) Create( ctx context.Context, req *dto.CreatePOSStationDTO, ) (*model.POSStation, error)
Create registers a new POS station. Validates that the branch belongs to the given company.
func (*POSStationService) GetByID ¶
func (s *POSStationService) GetByID(ctx context.Context, id uuid.UUID) (*model.POSStation, error)
func (*POSStationService) GetByIDForCompany ¶
func (s *POSStationService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.POSStation, error)
GetByIDForCompany fetches a station and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*POSStationService) ListByCompany ¶
func (s *POSStationService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.POSStation], error)
func (*POSStationService) Update ¶
func (s *POSStationService) Update( ctx context.Context, id uuid.UUID, req *dto.UpdatePOSStationDTO, ) (*model.POSStation, error)
type ProductService ¶
type ProductService struct {
// contains filtered or unexported fields
}
ProductService handles product-related business operations including recipes, COGS computation, and available units calculation.
func NewProductService ¶
func NewProductService(repo data.ProductRepoer, inventory data.InventoryQuerier) *ProductService
func (*ProductService) AvailableUnits ¶
AvailableUnits returns how many complete units of a recipe product can be made given current ingredient stock levels. Returns ErrInsufficientStock if the inventory querier is nil or any ingredient has no stock record yet.
func (*ProductService) ComputeCOGS ¶
ComputeCOGS returns the cost of goods sold for a recipe product. Returns ErrNoProcurementPrice if the inventory querier is nil or any ingredient has no procurement price recorded.
func (*ProductService) Create ¶
func (s *ProductService) Create( ctx context.Context, req *dto.CreateProductDTO, ) (*model.Product, error)
func (*ProductService) CurrentStock ¶
CurrentStock returns the current stock level for a product. Returns ErrInsufficientStock if inventory is nil or no movements have been recorded.
func (*ProductService) GetByIDForCompany ¶
func (s *ProductService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Product, error)
GetByIDForCompany fetches a product and verifies it belongs to companyID, returning data.ErrForbidden otherwise. Recipe components/overheads have no CompanyID of their own — verifying their parent product here is what scopes them too, since they're never reached except via their product ID.
func (*ProductService) GetBySKU ¶
func (s *ProductService) 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 (*ProductService) GetRecipe ¶
func (s *ProductService) GetRecipe( ctx context.Context, recipeID uuid.UUID, ) (*dto.RecipeDTO, error)
GetRecipe returns the recipe components and overheads for a recipe product.
func (*ProductService) LPP ¶
LPP returns the last procurement price for a product. Returns ErrNoProcurementPrice if inventory is nil or no procurement exists.
func (*ProductService) ListByCompany ¶
func (s *ProductService) ListByCompany( ctx context.Context, companyID uuid.UUID, productType string, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Product], error)
func (*ProductService) SetRecipe ¶
func (s *ProductService) SetRecipe( ctx context.Context, recipeID uuid.UUID, req *dto.SetRecipeDTO, ) error
SetRecipe atomically replaces all recipe components and overheads for a recipe product.
type ReportsService ¶
type ReportsService struct {
// contains filtered or unexported fields
}
ReportsService assembles management reports from aggregate repo queries.
func NewReportsService ¶
func NewReportsService(repo data.ReportsQuerier) *ReportsService
NewReportsService returns a ReportsService backed by the given querier.
func (*ReportsService) InventoryReport ¶
func (s *ReportsService) InventoryReport( ctx context.Context, q *dto.InventoryReportQuery, ) (*model.InventoryReport, error)
InventoryReport returns a stock snapshot with last-purchase-price and low-stock flags.
func (*ReportsService) PLReport ¶
func (s *ReportsService) PLReport( ctx context.Context, q *dto.PLReportQuery, ) (*model.PLReport, error)
PLReport returns a profit-and-loss summary for the requested period.
func (*ReportsService) SalesReport ¶
func (s *ReportsService) SalesReport( ctx context.Context, q *dto.SalesReportQuery, ) (*model.SalesReport, error)
SalesReport returns a full sales analytics report for the requested period.
type SessionService ¶
type SessionService struct {
// contains filtered or unexported fields
}
SessionService handles POS session lifecycle operations.
func NewSessionService ¶
func NewSessionService( repo data.SessionRepoer, stationRepo data.POSStationRepoer, emitter data.EventEmitter, ) *SessionService
NewSessionService constructs a SessionService.
func (*SessionService) Close ¶
func (s *SessionService) Close( ctx context.Context, sessionID uuid.UUID, closerID uuid.UUID, req *dto.CloseSessionDTO, ) (*model.SessionReconciliation, error)
Close closes a POS session and writes a SessionReconciliation record. Returns ErrNotFound if the session does not exist, ErrSessionAlreadyClosed if it is already closed, and ErrOpenOrdersExist if there are open orders (Phase 6 stub: never returns this error until the orders table exists).
func (*SessionService) ForceClose ¶
func (s *SessionService) ForceClose( ctx context.Context, sessionID, companyID, actorID uuid.UUID, ) (*model.SessionReconciliation, error)
ForceClose forcibly closes a session on an admin's behalf: any open (unpaid) order on the session is hard-deleted first — safe because stock is only decremented at Checkout, never when an item is merely added to an open order — and then the session is closed exactly like a normal Close, with DeclaredCash set to the computed expected cash (there is no cashier present to physically count the drawer, so the resulting reconciliation always has a zero Difference). Returns ErrNotFound if the session does not exist, ErrForbidden if it belongs to a different company, and ErrSessionAlreadyClosed if it is already closed.
func (*SessionService) GetByID ¶
func (s *SessionService) GetByID(ctx context.Context, id uuid.UUID) (*model.POSSession, error)
GetByID retrieves a session by ID.
func (*SessionService) GetByIDForCompany ¶
func (s *SessionService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.POSSession, error)
GetByIDForCompany fetches a session and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*SessionService) GetOpenByUser ¶
func (s *SessionService) GetOpenByUser( ctx context.Context, companyID, userID uuid.UUID, ) (*model.POSSession, error)
GetOpenByUser retrieves the open session opened by userID within companyID, if any.
func (*SessionService) GetReconciliation ¶
func (s *SessionService) GetReconciliation( ctx context.Context, sessionID uuid.UUID, ) (*model.SessionReconciliation, error)
GetReconciliation retrieves the reconciliation record for a session.
func (*SessionService) ListByCompany ¶
func (s *SessionService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.POSSession], error)
ListByCompany returns paginated sessions for a company.
func (*SessionService) ListOpenByCompanyFiltered ¶
func (s *SessionService) ListOpenByCompanyFiltered( ctx context.Context, companyID uuid.UUID, filter *data.SessionFilter, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.POSSession], error)
ListOpenByCompanyFiltered returns paginated open sessions for a company, optionally narrowed by branch.
func (*SessionService) Open ¶
func (s *SessionService) Open( ctx context.Context, companyID uuid.UUID, userID uuid.UUID, req *dto.OpenSessionDTO, ) (*model.POSSession, error)
Open creates a new POS session for the given station. Only cashier and owner roles may call this — enforced at the handler layer. Returns ErrNotFound if the station does not exist, ErrStationBusy if an open session already exists for that station.
type SupplierPaymentService ¶
type SupplierPaymentService struct {
// contains filtered or unexported fields
}
SupplierPaymentService handles payments made to suppliers.
func NewSupplierPaymentService ¶
func NewSupplierPaymentService( repo data.SupplierPaymentRepoer, supplierRepo data.SupplierRepoer, emitter data.EventEmitter, ) *SupplierPaymentService
func (*SupplierPaymentService) ListByCompany ¶
func (s *SupplierPaymentService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.SupplierPayment], error)
func (*SupplierPaymentService) ListBySupplier ¶
func (s *SupplierPaymentService) ListBySupplier( ctx context.Context, supplierID, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.SupplierPayment], error)
ListBySupplier returns a supplier's payment history, scoped to companyID — verifies the supplier actually belongs to the caller before listing its (potentially sensitive) payment history.
func (*SupplierPaymentService) RecordPayment ¶
func (s *SupplierPaymentService) RecordPayment( ctx context.Context, supplierID uuid.UUID, companyID uuid.UUID, req *dto.RecordSupplierPaymentDTO, ) (*model.SupplierPayment, error)
type SupplierService ¶
type SupplierService struct {
// contains filtered or unexported fields
}
SupplierService handles supplier-related business operations.
func NewSupplierService ¶
func NewSupplierService(repo data.SupplierRepoer) *SupplierService
func (*SupplierService) Create ¶
func (s *SupplierService) Create( ctx context.Context, req *dto.CreateSupplierDTO, ) (*model.Supplier, error)
func (*SupplierService) GetByIDForCompany ¶
func (s *SupplierService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.Supplier, error)
GetByIDForCompany fetches a supplier and verifies it belongs to companyID, returning data.ErrForbidden otherwise.
func (*SupplierService) ListByCompany ¶
func (s *SupplierService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.Supplier], error)
type UserService ¶
type UserService struct {
// contains filtered or unexported fields
}
UserService implements all user-related business operations.
func NewUserService ¶
func NewUserService(repo data.UserRepoer) *UserService
NewUserService creates a new UserService backed by the given repo.
func (*UserService) Create ¶
func (s *UserService) Create(ctx context.Context, req *dto.CreateUserDTO) (*model.User, error)
Create registers a new user. The entity's ID and timestamps are set by the repo layer. CompanyID is required when Role is manager or cashier.
func (*UserService) Delete ¶
Delete removes a user by ID. Returns data.ErrNotFound if the user does not exist.
func (*UserService) GetByID ¶
GetByID fetches a single user by its UUID. Returns data.ErrNotFound if absent.
func (*UserService) GetByIDForCompany ¶
func (s *UserService) GetByIDForCompany( ctx context.Context, id, companyID uuid.UUID, ) (*model.User, error)
GetByIDForCompany fetches a user and verifies it belongs to companyID, returning data.ErrForbidden otherwise. Owner-role users have a nil CompanyID and never match here — this is only for company team members.
func (*UserService) List ¶
func (s *UserService) List( ctx context.Context, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.User], error)
List returns a paginated list of users.
func (*UserService) ListByCompany ¶
func (s *UserService) ListByCompany( ctx context.Context, companyID uuid.UUID, q *dto.PaginationDTO, ) (*dto.PaginationResults[model.User], error)
ListByCompany returns a paginated list of users belonging to companyID.