* Include domain name in invoice lines and order titles (#4286)
* Reject multi-label and overlong ACE SLDs in isSldValid
* Build longest-valid-label fixture dynamically for spellcheck
* Reject overlong own-domain values in getDomainFromConfig
* Resolve owndomain tuple from flat config with nested fallback
* ✨ Allow custom recurring billing periods
Products were limited to a fixed set of 7 hardcoded recurring billing
periods (1W/1M/3M/6M/1Y/2Y/3Y), stored as fixed columns on
product_payment. Admins can now configure any number of arbitrary
periods per product (e.g. 45 days, 18 months, 5 years) within
Box_Period's existing valid ranges, while the original 7 periods
remain as pre-filled defaults and one-click quick-add presets.
- Replace product_payment's fixed w/m/q/b/a/bia/tria columns with a
new product_payment_period table (one row per configured period),
migrated via UpdatePatcher::patch98().
- Rework the admin product pricing UI to add/remove billing periods
by quantity + unit (day/week/month/year), in addition to the
existing presets.
- Fix Box_Period's constructor, which only ever accepted a
single-digit quantity (e.g. "9Y" but not "24M" or "45D") despite
its own unit bounds implying otherwise.
- Fix period labels silently disappearing in the client checkout,
admin order form, and admin subscription edit screens for any
period outside Box_Period's 9 presets, by having the API return a
precomputed title per period instead of relying on a second lookup.
- Fix the Stripe adapter dropping the period quantity entirely when
creating recurring prices (e.g. quarterly/biannual products were
silently billed monthly), and reject periods that exceed Stripe's
own interval_count caps instead of mis-billing them.
Closes#4098
* Address review feedback on custom billing periods
- Make patch98's period migration INSERT idempotent with ON DUPLICATE
KEY UPDATE, so a rerun after a partial failure doesn't hit the
(product_payment_id, code) unique constraint.
- Order ProductPayment::$periods by sortOrder so the admin's edit
order is preserved on reload, matching the pattern already used by
ServiceDownloadable's ordered collection.
- Wrap the Box_Period parsing failure in
getEnabledProductPaymentPeriod() so a malformed/missing period
raises FOSSBilling\InformationException instead of a raw exception,
matching applyPricingToProductPayment()'s handling.
- Fix the Stripe adapter reusing a wrong-cadence price: Stripe's price
list filter only supports 'interval', not 'interval_count', so the
existing-price match now also compares interval_count explicitly.
- Stop the admin pricing form from resurrecting default periods an
admin had deliberately removed - defaults are now only used when a
product has no configured periods at all.
- Drop the redundant product_payment_id_idx index, since the unique
key on (product_payment_id, code) already covers lookups on
product_payment_id via its leftmost prefix.
* Fix quantity validation and i18n in the add-period JS
- Use Number() + Number.isInteger() instead of parseInt() to validate
the custom period quantity, so a fractional value like "5.7" is
rejected instead of silently truncated to 5.
- Replace the English-only '(s)' suffix hack for pluralizing the unit
label with translated data-singular/data-plural attributes on each
unit option, selected based on quantity.
* Improve type safety, auth checks and PHPStan fixes (#3250)
* Improve type safety, auth checks and PHPStan fixes
* Remove @phpstan-ignore annotations
* Improve type safety, auth checks and PHPStan fixes
* Remove @phpstan-ignore annotations
* Remove redundant @phpstan-ignore comment
* Improve code robustness and reliability (#3248)
* Harden code against null/undefined values
* Update dependency lockfiles
* Sanitize ticket input and use IDs in email list
* Restructure tests and add test utilities
* Move E2E tests to `Library\E2E` namespace
* Update `php-build` action ref in workflows
* Switch tests to Pest and add test scaffolding
* Refactor E2E tests to Pest-style tests
m
Skip E2E tests when env not configured
* Refactor Unit tests and update test config
Add test datasets and refine test helpers
* Add DEBUG guard, fix API JSON decode, update tests
* Refactor tests: add types and Mockery expectations
* Adjust tests, phpstan config, and composer script
* Instantiate test APIs locally, remove beforeEach
* Refactor runtime checks, types & logging
* Apply PHP Code Styling Changes
m
* Add PHPStan ignores, test renames & small fixes
* Enable Pest tests in CI workflow
* Remove legacy tests; add new unit tests/config
* Avoid undefined index in fingerprint comparison
* Ignore properties absent in both fingerprints
* Remove public_ticket_create API method
* Add Fingerprint unit tests
* Remove em dash from fingerprint test name
* Switch to Pest; assorted bug fixes & refactors
* Prefer getDi() and guard DEBUG define
* Refactor tests: DBAL, Antispam rename, helpers
* Refactor email tests to use Doctrine entities
* Update tests, use DBAL mocks & improve Formbuilder admin
* Validate plan_id and update unit tests
* Replace error_log with DI logger and update tests
* Expect db->store in Invoice Service test
* Use DI logger instead of error_log; fix tests
* Fix typo in Hook Service test
* Fix Staff test spelling fixture
* Complete Pest test migration
* Fix Product test spelling fixtures
* Fix Product test spelling fixtures
* Run live tests with Pest and load helpers
* Migrate tests to ApiClient; remove legacy APIHelper
* Fix Email test spelling
* Remove unused PHPUnit bridge
* Organize Cypress end-to-end tests
* Document Pest test directory root
* Remove noisy Pest comments