Codebase Overview
June 12, 2026 · View on GitHub
Directory Map
src/
├── action/ Action entity, ActionState (NEW/FINISHED/FAILED), UsageInterval (pro-rating),
│ TemporaryAction (runtime-only, never persisted), mux/ (ActionMuxInterface)
├── bill/ Bill entity — aggregated invoice line item; BillState, BillRequisite
├── charge/ Charge entity, ChargeModifier interface, modifier classes and addons;
│ ChargeState (NEW/FINISHED); derivative/ (ChargeDerivative copy-with pattern)
├── customer/ Customer entity — billable party with seller hierarchy
├── event/ Domain events (e.g., InstallmentWasCharged)
├── Exception/ Shared exceptions (CannotReassignException, etc.)
├── formula/ FormulaEngine — parses DSL strings into ChargeModifier objects
├── helpers/ Utility classes
├── Money/ Money value object, MultipliedMoney for sub-cent prices
├── order/ Order (action collection), Calculator (main billing pipeline),
│ Billing (top-level orchestrator: calculate + aggregate + persist),
│ Collector (normalizes Order/Action/Action[] input)
├── plan/ Plan entity — tariff containing a collection of Prices
├── price/ Price implementations (SinglePrice, EnumPrice, RatePrice, ProgressivePrice)
├── product/ Higher-level product/tariff registry: TariffTypeDefinition, BillingRegistry,
│ behavior system, invoice representations, quantity formatters
├── sale/ Sale entity — subscription binding Customer → Target → Plan
├── statement/ Statement — billing snapshot for a period (balance, total, bills, plans)
├── target/ Target entity — object being billed
├── tools/ Aggregator (Charge → Bill grouping), Generalizer (Charge → Bill mapping)
├── type/ Type entity — classification of actions and charges
└── usage/ Usage tracking classes
Key Patterns
- Interface + Implementation: core entities define interfaces (e.g.,
PriceInterface,BillInterface) - Value Objects: Money, Quantity, Target, Type are immutable value objects
- Trait Composition:
HasMoney,HasQuantity,SettableChargeModifierTrait, fluentWith*traits for modifier addons - Factory:
ModifierFactoryfor formula context, static::fromAction()/::fromActions()on Order - Strategy: Price types implement different calculation strategies via
calculateSum()/calculateUsage() - Immutability Guards:
CannotReassignExceptionprevents mutation of billing-critical fields
Testing
- Behat features in
tests/behat/— living documentation for the formula DSL (FixedDiscount, GrowingDiscount, Installment, MonthlyCap, Combination) - PHPUnit tests in
tests/unit/— unit tests for prices, formulas, modifiers, and entities
Further Reading
- For formula DSL and charge modifiers, see docs/formula-and-modifiers.md
- For core entities and execution flow, see docs/domain-model.md
- For price type algorithms, see docs/price-types.md
- For the product/tariff registry subsystem, see docs/product-subsystem.md