dodil/erp-brick-pos
DODIL ERP brick: point of sale
src/brick_pos/domain/values.py
"""Value objects: the states each lifecycle may be in, and the attributes with a fixed set of values.
Stored as their plain strings; naming them here makes a typo a NameError, not a new state.
"""
from enum import Enum
class SessionState(str, Enum):
"""session: its lifecycle states (module.yaml workflows). A session only moves forward."""
OPEN = "open"
COUNTED = "counted"
CLOSED = "closed"
FORCE_CLOSED = "force_closed"
POSTED = "posted"
class ReceiptState(str, Enum):
"""receipt: its lifecycle states (module.yaml workflows). A finalised receipt never reopens."""
OPEN = "open"
FINALISED = "finalised"
QUARANTINED = "quarantined"
VOIDED = "voided" # void_open_receipt: kept as a void record with its lines (the workflow's "to: none")
class ReceiptKind(str, Enum):
SALE = "sale"
REFUND = "refund"
class PaymentMethod(str, Enum):
CASH = "cash"
CARD = "card"
VOUCHER = "voucher"
class TerminalStatus(str, Enum):
PENDING = "pending"
AUTHORISED = "authorised"
DECLINED = "declined"
REVERSED = "reversed"
class CashMoveKind(str, Enum):
SAFE_DROP = "safe_drop"
PAID_IN = "paid_in"
PAID_OUT = "paid_out"
FLOAT_TOP_UP = "float_top_up"
class VoucherOperation(str, Enum):
"""voucher_claim: what a claim row did to the balance (the operation is part of what is claimed)."""
ISSUE = "issue"
REDEEM = "redeem"
REFUND_TO_VOUCHER = "refund_to_voucher"
EXPIRE = "expire"
class DepositState(str, Enum):
"""cash_deposit: sealed -> handed_over -> matched (payments reports the bank credit: a later slice). A bag never goes back."""
SEALED = "sealed"
HANDED_OVER = "handed_over"
MATCHED = "matched"
class OutboxStatus(str, Enum):
"""outbox: pending -> sent | failed, and failed -> sent. A sent row never goes back to pending."""
PENDING = "pending"
SENT = "sent"
FAILED = "failed"
# Fiscal profiles that need a certified device before a register may sell (POS-01, gate fiscal_device_ready).
DEVICE_PROFILES = ("de_kassensichv", "at_rksv")
FISCAL_PROFILES = ("none", "de_kassensichv", "fr_nf525", "at_rksv")
# module.yaml config_rows: pos_settings. key -> (kind, default, controls, what it changes). `controls` = held by the
# owner (pos:settings:controls), never by the people the control binds. business_timezone is the bucket's ONE zone
# (shared.yaml conventions): kept here until the platform owns it, read through SettingsRepository.timezone() only.
SETTING_DEFS = {
"difference_threshold": ("decimal", "5.00", True, "a cash difference above this needs a second person"),
"blind_close": ("bool", True, True, "the cashier counts before seeing the expected amount"),
"paid_out_limit": ("decimal", "50.00", True, "a paid-out above this needs a shift lead"),
"day_cutoff_time": ("time", "04:00", False, "sales before this time belong to the previous business date"),
"tips_treatment": ("choice:liability|revenue", "liability", False,
"liability (tips_payable, passed to staff) | revenue; the UK Employment (Allocation of Tips) Act 2023 says liability"),
"voucher_validity_months": ("int", 24, False, "months a gift voucher is valid from the day it is sold (UK policy: 24)"),
"recipe_source": ("choice:pos|manufacturing", "pos", False, "pos: the recipes kept here; manufacturing: its usage-sale bills of materials"),
"cash_refund_limit": ("decimal", "20.00", True, "a cash refund above this needs a shift lead"),
"business_timezone": ("zone", "Europe/London", True, "the IANA time zone in which 'today' is counted (one per bucket)"),
}