Skip to content

Release Billplz 6.0 with Money objects, bundled Codex internals, and updated CI#59

Merged
abdusfauzi merged 22 commits intojomweb:6.xfrom
abdusfauzi:6.x
Mar 11, 2026
Merged

Release Billplz 6.0 with Money objects, bundled Codex internals, and updated CI#59
abdusfauzi merged 22 commits intojomweb:6.xfrom
abdusfauzi:6.x

Conversation

@abdusfauzi
Copy link
Collaborator

PR Draft For jomweb/billplz

Title

Release Billplz 6.0 with Money objects, bundled Codex internals, and updated CI

Body

Summary

  1. Prepare the 6.x line for Billplz 6.0.0
  2. Replace old money assumptions with \Money\Money
  3. Bundle Codex internals in-package
  4. Move CI and tests to the current toolchain

Changes

  1. Raise minimum PHP to 8.3
  2. Remove the hard dependency on jomweb/ringgit
  3. Remove external laravie/codex and laravie/codex-filter dependencies
  4. Migrate tests to Pest v4
  5. Add PHPStan and Pint checks for the 6.x line
  6. Refresh README, changelog, and release docs

Upgrade Notes

  1. Response money values now hydrate to \Money\Money
  2. Request payloads can use \Money\Money::MYR(...) or integer minor units
  3. Existing \Duit\MYR integrations should convert from the returned Money amount

Verification

  1. composer validate --strict
  2. composer run qa
  3. GitHub Actions:
    • tests
    • analyse
    • coveralls

Copilot AI review requested due to automatic review settings March 10, 2026 16:09
@coveralls
Copy link

coveralls commented Mar 10, 2026

Pull Request Test Coverage Report for Build 22936394180

Details

  • 445 of 445 (100.0%) changed or added relevant lines in 27 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+2.5%) to 100.0%

Totals Coverage Status
Change from base Build 22910823317: 2.5%
Covered Lines: 681
Relevant Lines: 681

💛 - Coveralls

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prepares the 6.x line for Billplz 6.0 by migrating money handling to Money\Money, bundling Codex internals into the package, and modernizing QA/CI (Pest v4, PHPStan, Pint, repo-managed git hooks).

Changes:

  • Migrates the test suite from PHPUnit test classes to Pest tests + shared “register tests” helpers.
  • Bundles Laravie\Codex internals under src/Internal/Codex and updates autoloading accordingly.
  • Updates project tooling: raises PHP requirement to ^8.3, adds Composer QA scripts and aligns GitHub Actions to run them.

Reviewed changes

Copilot reviewed 107 out of 109 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/Three/OpenCollectionTest.php Migrates v3 open collection tests to Pest + shared registration helper.
tests/Three/CollectionTest.php Migrates v3 collection tests to Pest + shared registration helper.
tests/Three/Collection/PaymentMethodTest.php Migrates v3 payment-method tests to Pest + shared registration helper.
tests/Three/BillTest.php Migrates v3 bill tests to Pest + shared registration helper.
tests/Three/Bill/TransactionTest.php Migrates v3 transaction tests to Pest + shared registration helper.
tests/Three/BankAccountTest.php Migrates v3 bank-account tests to Pest + shared registration helper.
tests/SignatureTest.php Migrates signature verification tests to Pest.
tests/SanitizerTest.php Migrates sanitizer signature test to Pest.
tests/Pest.php Adds Pest bootstrap + shared billplz_register_tests() helper and requires shared test definitions.
tests/PaymentCompletionTest.php Migrates payment completion tests to Pest.
tests/Four/WebhookTest.php Migrates v4 webhook tests to Pest.
tests/Four/PayoutTest.php Migrates v4 payout tests to Pest.
tests/Four/PaymentGatewayTest.php Migrates v4 payment gateway tests to Pest.
tests/Four/OpenCollectionTest.php Migrates v4 open collection tests to Pest + shared registration helper.
tests/Four/CollectionTest.php Migrates v4 collection tests to Pest and adds hook-based proxy version setup.
tests/Four/Collection/PayoutTest.php Migrates v4 collection payout tests to Pest.
tests/Four/Collection/PaymentMethodTest.php Migrates v4 payment-method tests to Pest + shared registration helper.
tests/Four/CardTest.php Migrates v4 card tests to Pest.
tests/Four/BillTest.php Migrates v4 bill tests to Pest; updates assertions to Money\Money.
tests/Four/Bill/TransactionTest.php Migrates v4 transaction tests to Pest + shared registration helper.
tests/Four/BankAccountTest.php Migrates v4 bank account tests to Pest + shared registration helper.
tests/Five/WebhookTest.php Migrates v5 webhook tests to Pest.
tests/Five/PayoutTest.php Migrates v5 payout tests to Pest.
tests/Five/PaymentOrderTest.php Adds Pest tests covering v5 PaymentOrder endpoints.
tests/Five/PaymentOrderCollectionTest.php Adds Pest tests covering v5 PaymentOrderCollection endpoints.
tests/Five/BankAccountTest.php Migrates v5 bank account tests to Pest + shared registration helper.
tests/ClientTest.php Migrates client tests to Pest and extends shared TestCase.
tests/Casts/DateTimeTest.php Migrates DateTime cast tests to Pest.
tests/Base/OpenCollectionTests.php Introduces shared open-collection test registration helper.
tests/Base/OpenCollectionTestCase.php Removes PHPUnit base test-case class in favor of Pest helper registration.
tests/Base/CollectionTests.php Introduces shared collection test registration helper.
tests/Base/CollectionTestCase.php Removes PHPUnit base test-case class in favor of Pest helper registration.
tests/Base/Collection/PaymentMethodTests.php Introduces shared payment-method test registration helper.
tests/Base/Collection/PaymentMethodTestCase.php Removes PHPUnit base test-case class in favor of Pest helper registration.
tests/Base/BillTestCase.php Removes large PHPUnit base test-case class in favor of Pest helper registration.
tests/Base/Bill/TransactionTests.php Introduces shared bill-transaction test registration helper.
tests/Base/Bill/TransactionTestCase.php Removes PHPUnit transaction test-case class in favor of Pest helper registration.
tests/Base/BankAccountTests.php Introduces shared bank-account test registration helper.
tests/Base/BankAccountTestCase.php Removes PHPUnit base test-case class in favor of Pest helper registration.
tests/ArraySubsetTest.php Adds test for updated ArraySubset exporter behavior.
src/Sanitizer.php Switches default money caster from Ringgit to Money.
src/Request.php Minor style change (new Sanitizer without parentheses).
src/Internal/Codex/Testing/Faker.php Bundles Codex testing Faker implementation used by tests.
src/Internal/Codex/Testing/Assert.php Bundles Codex assert compatibility layer (array subset).
src/Internal/Codex/Testing/ArraySubset.php Bundles Codex ArraySubset constraint with PHPUnit version branching.
src/Internal/Codex/Support/Versioning.php Bundles Codex versioning + proxy-version request helper.
src/Internal/Codex/Support/Responsable.php Bundles Codex response interaction helper for requests.
src/Internal/Codex/Support/HttpClient.php Bundles Codex HttpClient trait wrapper.
src/Internal/Codex/Response.php Bundles Codex Response wrapper class.
src/Internal/Codex/Request.php Bundles Codex base Request implementation.
src/Internal/Codex/Payload.php Bundles Codex Payload wrapper class.
src/Internal/Codex/Filter/WithSanitizer.php Bundles Codex filterable sanitizer trait.
src/Internal/Codex/Filter/Sanitizer.php Bundles Codex sanitizer implementation.
src/Internal/Codex/Filter/Cast.php Bundles Codex cast base class.
src/Internal/Codex/Exceptions/UnauthorizedException.php Bundles Codex Unauthorized exception.
src/Internal/Codex/Exceptions/NotFoundException.php Bundles Codex NotFound exception.
src/Internal/Codex/Exceptions/HttpException.php Bundles Codex HttpException base.
src/Internal/Codex/Endpoint.php Bundles Codex Endpoint wrapper class.
src/Internal/Codex/Discovery.php Bundles Codex discovery wrapper class.
src/Internal/Codex/Contracts/Sanitizer.php Bundles Codex sanitizer contract.
src/Internal/Codex/Contracts/Response.php Bundles Codex response contract.
src/Internal/Codex/Contracts/Request.php Bundles Codex request contract.
src/Internal/Codex/Contracts/Filterable.php Bundles Codex filterable contract.
src/Internal/Codex/Contracts/Endpoint.php Bundles Codex endpoint contract.
src/Internal/Codex/Contracts/Client.php Bundles Codex client contract.
src/Internal/Codex/Contracts/Cast.php Bundles Codex cast contract.
src/Internal/Codex/Concerns/Request/Multipart.php Bundles Codex multipart request concern.
src/Internal/Codex/Concerns/Request/Json.php Bundles Codex JSON request concern.
src/Internal/Codex/Concerns/Passport.php Bundles Codex “Passport” credential helpers.
src/Internal/Codex/Common/Response.php Bundles Codex common response implementation.
src/Internal/Codex/Common/Request.php Bundles Codex common request implementation.
src/Internal/Codex/Common/Payload.php Bundles Codex common payload implementation.
src/Internal/Codex/Common/HttpClient.php Bundles Codex HTTP client behavior (payload prep + query handling).
src/Internal/Codex/Common/Endpoint.php Bundles Codex endpoint implementation.
src/Internal/Codex/Common/Discovery.php Bundles Codex HTTP discovery.
src/Internal/Codex/Client.php Bundles Codex base client implementation (uses()/version selection).
src/Four/Bill.php Updates docblock amount type to `Money\Money
src/Five/PaymentOrder.php Removes identity number parameter from create() signature/payload.
src/Contracts/PaymentOrder.php Updates contract to match PaymentOrder::create() signature change.
src/Contracts/OpenCollection.php Updates docblock amount type to `Money\Money
src/Contracts/Bill.php Updates docblock amount type to `Money\Money
src/Checksum.php Fixes comment spacing.
src/Casts/Ringgit.php Removes Ringgit caster (Duit integration).
src/Casts/Money.php Updates money cast validation/docblocks to only accept Money\Money.
src/Base/PaymentCompletion.php Minor style change when throwing exception.
src/Base/OpenCollection.php Updates docblock amount type to `Money\Money
src/Base/Bill.php Updates docblock amount type to `Money\Money
phpunit.xml Updates PHPUnit config schema to PHPUnit 12.5 format.
phpstan.neon.dist Removes checkMissingIterableValueType override.
examples/v5/creating-payment-order.php Updates example to match PaymentOrder signature change.
docs/release-notes-v6.0.0.md Adds v6.0.0 release notes draft.
docs/release-6.0.0.md Adds maintainer release checklist.
docs/pr-jomweb-billplz-6x.md Adds upstream PR draft.
docs/plans/2026-03-11-ci-alignment-and-release-drafts-plan.md Adds CI alignment + draft docs plan.
docs/plans/2026-03-10-release-docs-implementation-plan.md Adds release docs implementation plan.
docs/plans/2026-03-10-release-docs-design.md Adds release docs design notes.
docs/plans/2026-03-10-git-hooks-qa-plan.md Adds repo-managed git hooks QA plan.
composer.json Updates dependencies (PHP 8.3+, Money, bundled Codex), adds scripts and autoload mapping for internal Codex.
README.md Updates badges/installation/upgrade notes + replaces Duit examples with Money.
CONTRIBUTING.md Updates contributor workflow to use Composer scripts + repo git hooks; updates CI reference.
CHANGELOG-6.x.md Adds v6.x changelog and upgrade notes.
.gitignore Adds PHPUnit cache directory.
.github/workflows/tests.yml Updates CI matrix (PHP versions) and runs tests via Composer script.
.github/workflows/coveralls.yml Runs coverage via Composer script.
.github/workflows/analyse.yml Aligns Pint/PHPStan steps to Composer scripts and updates PHP matrix.
.githooks/pre-push Adds repo-managed pre-push hook to run analyse + parallel tests.
.githooks/pre-commit Adds repo-managed pre-commit hook to run Pint lint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +19 to +33
it('can create payment order collection', function (): void {
$title = 'My First API Payment Order Collection';
$epoch = time();
$expected = '{"id":"8f4e331f-ac71-435e-a870-72fe520b4563","title":"My First API Payment Order Collection","callback_url":"https:\/\/example.com\/payment-orders\/callback"}';

$payload = [
'title' => $title,
'epoch' => $epoch,
'checksum' => Checksum::create(TestCase::X_SIGNATURE, [
$title,
'https://example.com/payment-orders/callback',
$epoch,
]),
'callback_url' => 'https://example.com/payment-orders/callback',
];
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test computes $epoch = time() and a checksum based on it, but the PaymentOrderCollection implementation also calls time() internally to build the request. That makes the expected request payload fragile/flaky if time advances between the two calls. Make the request deterministic by allowing a caller-supplied epoch (and computing checksum from that), or by injecting a clock that can be controlled in tests.

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +111
/** @var class-string<\Laravie\Codex\Contracts\Request> $class */
$class = sprintf('%s\%s\%s', $this->getResourceNamespace(), $this->supportedVersions[$version], $name);

if (! class_exists($class)) {
throw new InvalidArgumentException("Resource [{$service}] for version [{$version}] is not available.");
}

return $this->via(new $class($this));
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uses() instantiates the request with new $class($this), but the request classes (e.g. Billplz\Request / Laravie\Codex\Request) don’t accept a client argument in their constructors. This will trigger an ArgumentCountError the first time any resource is resolved. Instantiate with new $class() and rely on via() to call setClient(), or update the request base class constructor signature consistently across resources.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +16
'can check bill transaction' => function (): void {
$expected = '{"bill_id":"inbmmepb","transactions":[{"id":"60793D4707CD","status":"completed","completed_at":"2017-02-23T12:49:23.612+08:00","payment_channel":"FPX"},{"id":"28F3D3194138","status":"failed","completed_at":,"payment_channel":"FPX"}],"page":1}';

Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $expected response body is invalid JSON ("completed_at":,). If any code calls toArray()/getContent() on this response (now using JSON_THROW_ON_ERROR), it will throw. Update the fixture to valid JSON (e.g. "completed_at":null) to avoid decoding failures.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +40
it('can create payment order', function (): void {
$paymentOrderCollectionId = '8f4e331f-ac71-435e-a870-72fe520b4563';
$bankAccountNumber = '543478924652';
$total = 2000;
$epoch = time();
$expected = '{"id":"cc92738f-dfda-4969-91dc-22a44afc7e26","payment_order_collection_id":"8f4e331f-ac71-435e-a870-72fe520b4563","bank_code":"MBBEMYKL","bank_account_number":"543478924652","name":"Michael Yap","description":"Maecenas eu placerat ante.","total":"2000","status":"pending"}';

$payload = [
'payment_order_collection_id' => $paymentOrderCollectionId,
'bank_code' => 'MBBEMYKL',
'bank_account_number' => $bankAccountNumber,
'name' => 'Michael Yap',
'description' => 'Maecenas eu placerat ante.',
'total' => $total,
'epoch' => $epoch,
'checksum' => Checksum::create(TestCase::X_SIGNATURE, [
$paymentOrderCollectionId,
$bankAccountNumber,
$total,
$epoch,
]),
];
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests build an expected payload/query using $epoch = time(), but the underlying PaymentOrder methods also call time() internally when computing epoch/checksum. If the second ticks over between the test’s time() and the method’s time(), the expected request won’t match and the test becomes flaky. Prefer passing a fixed epoch (and deriving checksum from it) via method parameters/optional overrides, or inject/mock the clock in the implementation so tests can be deterministic.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +39
public function send(string $method, EndpointContract $uri, array $headers = [], $body = []): ResponseInterface
{
$method = strtoupper($method);

if ($method === 'GET' && ! $body instanceof StreamInterface) {
$uri->addQuery($body);
$body = null;
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In send(), GET requests call $uri->addQuery($body) for any non-stream body. If $body is a Laravie\Codex\Common\Payload (allowed by the phpdoc), Endpoint::addQuery() will receive an object and can throw (illegal offset type / unexpected key). Consider unwrapping Payload to an array before addQuery(), or restrict GET bodies to arrays and enforce it with a runtime check.

Copilot uses AI. Check for mistakes.
Comment on lines +206 to +210
'can check bill transaction' => function (): void {
$expected = '{"bill_id":"inbmmepb","transactions":[{"id":"60793D4707CD","status":"completed","completed_at":"2017-02-23T12:49:23.612+08:00","payment_channel":"FPX"},{"id":"28F3D3194138","status":"failed","completed_at":,"payment_channel":"FPX"}],"page":1}';

$faker = $this->expectRequest('GET', 'bills/inbmmepb/transactions')
->shouldResponseWithJson(200, $expected);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $expected fixture is invalid JSON ("completed_at":,). With responses now decoded using json_decode(..., JSON_THROW_ON_ERROR), calling toArray() on this response would throw a JsonException. Update the fixture to valid JSON (e.g. "completed_at":null) so it reflects a realistic API response and won’t break decoding.

Copilot uses AI. Check for mistakes.
@abdusfauzi
Copy link
Collaborator Author

Added a small coverage pass on the Codex internals that Coveralls flagged most heavily.

Changes in this push:

  1. Added focused tests for:
  • Laravie\Codex\Concerns\Request\Json
  • Laravie\Codex\Concerns\Passport
  • Laravie\Codex\Common\Discovery
  • Laravie\Codex\Testing\Assert
  • one request integration path covering filter setup, merged payloads, and endpoint query handling
  1. Fixed current PHPUnit compatibility in Laravie\Codex\Testing\Assert
  • Version::series()[0] was mis-detecting PHPUnit 10+ and falling into the legacy branch
  • PHPUnit\Framework\InvalidArgumentException::create() / PHPUnit\Util\InvalidArgumentHelper::factory() are not available in the current setup
  1. Removed the stale PHPStan baseline entries tied to those old code paths

Local verification:

  1. composer run qa passes
  2. tests/CodexCoverageTest.php passes

Coveralls may still report a large delta here because this bootstrap 6.x PR introduces the bundled src/Internal/Codex/* surface against a base branch that does not have that code yet.

If the branch checks are otherwise acceptable, please consider ignoring or relaxing the Coveralls gate for this initial 6.x bootstrap PR, then tightening coverage incrementally in follow-up PRs.

@abdusfauzi abdusfauzi merged commit 1b8c18f into jomweb:6.x Mar 11, 2026
14 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants