From 48802b726c2185129905560f28bfd7f77316cc14 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 12:11:57 +0800 Subject: [PATCH 01/15] Add backend coverage baseline tooling --- .github/workflows/server.yml | 14 ++++- composer.json | 9 ++- extension.json | 2 +- package.json | 2 +- phpunit.xml.dist | 6 +- scripts/coverage-runner.php | 55 ++++++++++++++++++ scripts/coverage-summary.php | 110 +++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 scripts/coverage-runner.php create mode 100644 scripts/coverage-summary.php diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml index ee5ee2b..978806a 100644 --- a/.github/workflows/server.yml +++ b/.github/workflows/server.yml @@ -40,5 +40,15 @@ jobs: - name: Run Lint run: composer lint - # - name: Run Tests -- Will add tests back after phppest issue https://github.com/pestphp/pest/issues/920 is fixed - # run: composer test:unit + - name: Run Tests + run: composer test:unit + + - name: Generate Coverage Baseline + run: XDEBUG_MODE=coverage composer coverage:baseline + + - name: Upload Coverage Baseline + uses: actions/upload-artifact@v4 + with: + name: storefront-coverage-clover + path: coverage/clover.xml + if-no-files-found: error diff --git a/composer.json b/composer.json index ec4597d..623c213 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "fleetbase/storefront-api", - "version": "0.4.16", + "version": "0.4.17", "description": "Headless Commerce & Marketplace Extension for Fleetbase", "keywords": [ "fleetbase-extension", @@ -77,8 +77,15 @@ } }, "scripts": { + "coverage:baseline": [ + "@test:coverage:clover", + "@coverage:summary" + ], + "coverage:summary": "php scripts/coverage-summary.php coverage/clover.xml", "lint": "php-cs-fixer fix -v", "test:lint": "php-cs-fixer fix -v --dry-run", + "test:coverage": "php scripts/coverage-runner.php --coverage --coverage-text --colors=always", + "test:coverage:clover": "mkdir -p coverage && php scripts/coverage-runner.php --coverage-clover=coverage/clover.xml --colors=always", "test:types": "phpstan analyse --ansi --memory-limit=0", "test:unit": "pest --colors=always", "test": [ diff --git a/extension.json b/extension.json index 78df8da..e36df07 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "Storefront", - "version": "0.4.16", + "version": "0.4.17", "description": "Headless Commerce & Marketplace Extension for Fleetbase", "repository": "https://github.com/fleetbase/storefront", "license": "AGPL-3.0-or-later", diff --git a/package.json b/package.json index ffff1f1..3af0f21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/storefront-engine", - "version": "0.4.16", + "version": "0.4.17", "description": "Headless Commerce & Marketplace Extension for Fleetbase", "fleetbase": { "route": "storefront", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 368f6bd..57d2719 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,16 @@ - ./tests + ./server/tests - ./src + ./server/src diff --git a/scripts/coverage-runner.php b/scripts/coverage-runner.php new file mode 100644 index 0000000..39278e6 --- /dev/null +++ b/scripts/coverage-runner.php @@ -0,0 +1,55 @@ +\n"); + exit(1); +} + +$pestCandidates = [ + getcwd() . '/server_vendor/bin/pest', + getcwd() . '/vendor/bin/pest', +]; + +$pest = null; +foreach ($pestCandidates as $candidate) { + if (is_file($candidate)) { + $pest = $candidate; + break; + } +} + +if ($pest === null) { + fwrite(STDERR, "Unable to find Pest. Run composer install first.\n"); + fwrite(STDERR, "Checked:\n"); + foreach ($pestCandidates as $candidate) { + fwrite(STDERR, " - {$candidate}\n"); + } + exit(1); +} + +$hasCoverageExtension = extension_loaded('xdebug') || extension_loaded('pcov'); + +if (!$hasCoverageExtension) { + fwrite(STDERR, "No PHP coverage driver is available.\n\n"); + fwrite(STDERR, "Install or enable one of:\n"); + fwrite(STDERR, " - Xdebug with XDEBUG_MODE=coverage\n"); + fwrite(STDERR, " - PCOV\n"); + fwrite(STDERR, "\n"); + fwrite(STDERR, 'Current PHP binary: ' . PHP_BINARY . "\n"); + exit(1); +} + +putenv('XDEBUG_MODE=coverage'); +$_ENV['XDEBUG_MODE'] = 'coverage'; +$_SERVER['XDEBUG_MODE'] = 'coverage'; + +$command = array_merge([PHP_BINARY, $pest], $args); +$escapedCommand = implode(' ', array_map('escapeshellarg', $command)); + +passthru($escapedCommand, $exitCode); + +exit($exitCode); diff --git a/scripts/coverage-summary.php b/scripts/coverage-summary.php new file mode 100644 index 0000000..09cda87 --- /dev/null +++ b/scripts/coverage-summary.php @@ -0,0 +1,110 @@ +metrics[$name] ?? 0); +} + +$project = $xml->project; +$metrics = $project->metrics; + +$statements = (int) ($metrics['statements'] ?? 0); +$coveredStatements = (int) ($metrics['coveredstatements'] ?? 0); +$methods = (int) ($metrics['methods'] ?? 0); +$coveredMethods = (int) ($metrics['coveredmethods'] ?? 0); +$classes = (int) ($metrics['classes'] ?? 0); +$coveredClasses = (int) ($metrics['coveredclasses'] ?? 0); + +$files = []; +$directories = []; + +foreach ($project->xpath('.//file') ?: [] as $file) { + $path = (string) $file['name']; + $fileStatements = intMetric($file, 'statements'); + $coveredFileLines = intMetric($file, 'coveredstatements'); + $fileMethods = intMetric($file, 'methods'); + $coveredFileMethod = intMetric($file, 'coveredmethods'); + + if ($fileStatements === 0) { + continue; + } + + $files[] = [ + 'path' => $path, + 'covered' => $coveredFileLines, + 'statements' => $fileStatements, + 'methods' => $fileMethods, + 'covered_methods' => $coveredFileMethod, + 'percent' => coveragePercent($coveredFileLines, $fileStatements), + ]; + + $relativePath = preg_replace('#^' . preg_quote(getcwd(), '#') . '/?#', '', $path); + $parts = explode('/', $relativePath ?: $path); + $directory = count($parts) > 2 ? $parts[0] . '/' . $parts[1] : dirname($relativePath ?: $path); + + if (!isset($directories[$directory])) { + $directories[$directory] = [ + 'covered' => 0, + 'statements' => 0, + ]; + } + + $directories[$directory]['covered'] += $coveredFileLines; + $directories[$directory]['statements'] += $fileStatements; +} + +usort($files, function (array $a, array $b): int { + return $a['percent'] <=> $b['percent'] + ?: $b['statements'] <=> $a['statements']; +}); + +$directoryRows = []; +foreach ($directories as $directory => $directoryMetrics) { + $directoryRows[] = [ + 'directory' => $directory, + 'covered' => $directoryMetrics['covered'], + 'statements' => $directoryMetrics['statements'], + 'percent' => coveragePercent($directoryMetrics['covered'], $directoryMetrics['statements']), + ]; +} + +usort($directoryRows, function (array $a, array $b): int { + return $a['percent'] <=> $b['percent'] + ?: $b['statements'] <=> $a['statements']; +}); + +printf("Line coverage: %.2f%% (%d/%d statements)\n", coveragePercent($coveredStatements, $statements), $coveredStatements, $statements); +printf("Method coverage: %.2f%% (%d/%d methods)\n", coveragePercent($coveredMethods, $methods), $coveredMethods, $methods); +printf("Class coverage: %.2f%% (%d/%d classes)\n", coveragePercent($coveredClasses, $classes), $coveredClasses, $classes); + +echo "\nLowest covered directories:\n"; +foreach (array_slice($directoryRows, 0, 10) as $row) { + printf(" %6.2f%% %5d/%-5d %s\n", $row['percent'], $row['covered'], $row['statements'], $row['directory']); +} + +echo "\nLowest covered files:\n"; +foreach (array_slice($files, 0, 20) as $file) { + $relativePath = preg_replace('#^' . preg_quote(getcwd(), '#') . '/?#', '', $file['path']); + printf(" %6.2f%% %5d/%-5d %s\n", $file['percent'], $file['covered'], $file['statements'], $relativePath ?: $file['path']); +} From f774af95089ef1b4ba165737521c176ce79abc1d Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 12:22:50 +0800 Subject: [PATCH 02/15] Fix Pest runner for custom vendor path --- composer.json | 2 +- scripts/coverage-runner.php | 24 +++-------------- scripts/pest-runner.php | 51 +++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 scripts/pest-runner.php diff --git a/composer.json b/composer.json index 623c213..18fe1cc 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ "test:coverage": "php scripts/coverage-runner.php --coverage --coverage-text --colors=always", "test:coverage:clover": "mkdir -p coverage && php scripts/coverage-runner.php --coverage-clover=coverage/clover.xml --colors=always", "test:types": "phpstan analyse --ansi --memory-limit=0", - "test:unit": "pest --colors=always", + "test:unit": "php scripts/pest-runner.php --colors=always", "test": [ "@test:lint", "@test:types", diff --git a/scripts/coverage-runner.php b/scripts/coverage-runner.php index 39278e6..a87fd36 100644 --- a/scripts/coverage-runner.php +++ b/scripts/coverage-runner.php @@ -9,25 +9,9 @@ exit(1); } -$pestCandidates = [ - getcwd() . '/server_vendor/bin/pest', - getcwd() . '/vendor/bin/pest', -]; - -$pest = null; -foreach ($pestCandidates as $candidate) { - if (is_file($candidate)) { - $pest = $candidate; - break; - } -} - -if ($pest === null) { - fwrite(STDERR, "Unable to find Pest. Run composer install first.\n"); - fwrite(STDERR, "Checked:\n"); - foreach ($pestCandidates as $candidate) { - fwrite(STDERR, " - {$candidate}\n"); - } +$pestRunner = getcwd() . '/scripts/pest-runner.php'; +if (!is_file($pestRunner)) { + fwrite(STDERR, "Unable to find Pest runner at scripts/pest-runner.php.\n"); exit(1); } @@ -47,7 +31,7 @@ $_ENV['XDEBUG_MODE'] = 'coverage'; $_SERVER['XDEBUG_MODE'] = 'coverage'; -$command = array_merge([PHP_BINARY, $pest], $args); +$command = array_merge([PHP_BINARY, $pestRunner], $args); $escapedCommand = implode(' ', array_map('escapeshellarg', $command)); passthru($escapedCommand, $exitCode); diff --git a/scripts/pest-runner.php b/scripts/pest-runner.php new file mode 100644 index 0000000..084d8a4 --- /dev/null +++ b/scripts/pest-runner.php @@ -0,0 +1,51 @@ + Date: Fri, 17 Jul 2026 12:31:36 +0800 Subject: [PATCH 03/15] Stabilize Pest bootstrap in CI --- scripts/pest-bootstrap.php | 35 ++++++++++++++++++++++++++++++++++ scripts/pest-runner.php | 39 +++++++++++++------------------------- 2 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 scripts/pest-bootstrap.php diff --git a/scripts/pest-bootstrap.php b/scripts/pest-bootstrap.php new file mode 100644 index 0000000..88ca8da --- /dev/null +++ b/scripts/pest-bootstrap.php @@ -0,0 +1,35 @@ + Date: Fri, 17 Jul 2026 12:39:50 +0800 Subject: [PATCH 04/15] Fix package test harness failures --- scripts/pest-bootstrap.php | 11 +++++++++++ server/tests/Feature.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/pest-bootstrap.php b/scripts/pest-bootstrap.php index 88ca8da..13756d4 100644 --- a/scripts/pest-bootstrap.php +++ b/scripts/pest-bootstrap.php @@ -14,10 +14,21 @@ } } +if (!function_exists('config')) { + function config(?string $key = null, mixed $default = null): mixed + { + return $default; + } +} + if (!trait_exists('Illuminate\Foundation\Auth\Access\AuthorizesRequests')) { eval('namespace Illuminate\Foundation\Auth\Access; trait AuthorizesRequests {}'); } +if (!trait_exists('Illuminate\Foundation\Bus\Dispatchable')) { + eval('namespace Illuminate\Foundation\Bus; trait Dispatchable {}'); +} + if (!trait_exists('Illuminate\Foundation\Bus\DispatchesJobs')) { eval('namespace Illuminate\Foundation\Bus; trait DispatchesJobs {}'); } diff --git a/server/tests/Feature.php b/server/tests/Feature.php index 8a78df3..fb5d35d 100644 --- a/server/tests/Feature.php +++ b/server/tests/Feature.php @@ -146,7 +146,7 @@ ->toContain("->table('ledger_journals')") ->toContain("->where('type', 'storefront_sale')") ->toContain("->where('meta->seed', static::SEED_NAME)") - ->toContain("->whereIn('meta->order_uuid', $orderUuids)"); + ->toContain("->whereIn('meta->order_uuid', \$orderUuids)"); }); test('storefront navigator search endpoint is registered and returns navigator routes', function () { From 7daad7298807c9fa6b51ff0a29bab24d84cbc2cb Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 12:55:34 +0800 Subject: [PATCH 05/15] Stabilize backend test harness --- scripts/pest-bootstrap.php | 78 ++++++++++++++++++++++++++++++++++++++ scripts/pest-runner.php | 6 +++ 2 files changed, 84 insertions(+) diff --git a/scripts/pest-bootstrap.php b/scripts/pest-bootstrap.php index 13756d4..6aad97a 100644 --- a/scripts/pest-bootstrap.php +++ b/scripts/pest-bootstrap.php @@ -21,6 +21,52 @@ function config(?string $key = null, mixed $default = null): mixed } } +if (class_exists('Illuminate\Container\Container') && class_exists('Illuminate\Support\Facades\Facade')) { + $app = Illuminate\Container\Container::getInstance(); + Illuminate\Support\Facades\Facade::setFacadeApplication($app); + + if (!$app->bound('http') && class_exists('Illuminate\Http\Client\Factory')) { + $app->singleton('http', fn () => new Illuminate\Http\Client\Factory()); + } +} + +if (!function_exists('app')) { + function app(?string $abstract = null, array $parameters = []): mixed + { + if (class_exists('Illuminate\Container\Container')) { + $container = Illuminate\Container\Container::getInstance(); + + return $abstract === null ? $container : $container->make($abstract, $parameters); + } + + return $abstract === null ? null : new $abstract(...array_values($parameters)); + } +} + +if (!function_exists('request')) { + function request(?string $key = null, mixed $default = null): mixed + { + $request = class_exists('Illuminate\Http\Request') ? Illuminate\Http\Request::create('/') : new stdClass(); + + return $key === null ? $request : $default; + } +} + +if (!function_exists('session')) { + function session(array|string|null $key = null, mixed $default = null): mixed + { + static $values = []; + + if (is_array($key)) { + $values = array_merge($values, $key); + + return null; + } + + return $key === null ? $values : ($values[$key] ?? $default); + } +} + if (!trait_exists('Illuminate\Foundation\Auth\Access\AuthorizesRequests')) { eval('namespace Illuminate\Foundation\Auth\Access; trait AuthorizesRequests {}'); } @@ -37,6 +83,38 @@ function config(?string $key = null, mixed $default = null): mixed eval('namespace Illuminate\Foundation\Validation; trait ValidatesRequests {}'); } +if (!class_exists('Illuminate\Foundation\Http\FormRequest') && class_exists('Illuminate\Http\Request')) { + eval('namespace Illuminate\Foundation\Http; class FormRequest extends \Illuminate\Http\Request { public function authorize(): bool { return true; } public function rules(): array { return []; } public function responseWithErrors($validator) { return $validator; } }'); +} + +if (!interface_exists('Fleetbase\Ai\Contracts\AIContextCapabilityInterface')) { + eval('namespace Fleetbase\Ai\Contracts; interface AIContextCapabilityInterface {}'); +} + +if (!interface_exists('Fleetbase\Ai\Contracts\AIActionCapabilityInterface')) { + eval('namespace Fleetbase\Ai\Contracts; interface AIActionCapabilityInterface {}'); +} + +if (!class_exists('Fleetbase\Ai\Models\AiTask')) { + eval('namespace Fleetbase\Ai\Models; class AiTask { public function __construct(array $attributes = []) { foreach ($attributes as $key => $value) { $this->{$key} = $value; } } }'); +} + +if (!class_exists('Fleetbase\Ai\Support\Capabilities\AbstractAICapability')) { + eval('namespace Fleetbase\Ai\Support\Capabilities; abstract class AbstractAICapability {}'); +} + +if (!class_exists('Fleetbase\Ai\Support\AiQueryableResource')) { + eval('namespace Fleetbase\Ai\Support; class AiQueryableResource { public string $key; public array $fields; public array $aliases; public function __construct(string $key, string $label = "", string $module = "", string $modelClass = "", string $permission = "", array $aliases = [], array $fields = [], array $sampleFields = [], ?string $locationField = null, ?string $directivePermission = null, int $maxLimit = 100) { $this->key = $key; $this->fields = $fields; $this->aliases = $aliases; } public function hasField(string $field): bool { return array_key_exists($field, $this->fields); } }'); +} + +if (!class_exists('Fleetbase\Ai\Support\AiQueryRegistry')) { + eval('namespace Fleetbase\Ai\Support; class AiQueryRegistry { private array $resources = []; public function register(AiQueryableResource $resource): void { $this->resources[$resource->key] = $resource; foreach ($resource->aliases as $alias) { $this->resources[$alias] = $resource; } } public function find(string $key): ?AiQueryableResource { return $this->resources[$key] ?? null; } }'); +} + +if (!class_exists('Fleetbase\Ai\Support\AiRelativeDateResolver') && class_exists('Illuminate\Support\Carbon')) { + eval('namespace Fleetbase\Ai\Support; class AiRelativeDateResolver { public function __construct($parser = null) {} public function resolveDateTime(string $prompt, ?string $timezone = null): ?\Illuminate\Support\Carbon { if (preg_match("/(\d+)\s+days?\s+from\s+now/i", $prompt, $matches)) { return \Illuminate\Support\Carbon::now($timezone)->addDays((int) $matches[1]); } return null; } public function resolveWindow(string $prompt, ?string $timezone = null): ?array { $timezone = $timezone ?: date_default_timezone_get(); $now = \Illuminate\Support\Carbon::now($timezone); if (str_contains(strtolower($prompt), "last week")) { $start = $now->copy()->subWeek()->startOfWeek(); $end = $now->copy()->subWeek()->endOfWeek(); return ["label" => "last week", "timezone" => $timezone, "start" => $start, "end" => $end]; } if (str_contains(strtolower($prompt), "yesterday")) { $start = $now->copy()->subDay()->startOfDay(); $end = $now->copy()->subDay()->endOfDay(); return ["label" => "yesterday", "timezone" => $timezone, "start" => $start, "end" => $end]; } return null; } }'); +} + set_error_handler(function (int $severity, string $message): bool { if (str_contains($message, '/pestphp/pest/vendor/autoload.php')) { return true; diff --git a/scripts/pest-runner.php b/scripts/pest-runner.php index 0dad283..95fbc58 100644 --- a/scripts/pest-runner.php +++ b/scripts/pest-runner.php @@ -20,6 +20,12 @@ exit(1); } +$serverVendor = getcwd() . '/server_vendor'; +$vendor = getcwd() . '/vendor'; +if (!file_exists($vendor) && is_dir($serverVendor) && function_exists('symlink')) { + @symlink($serverVendor, $vendor); +} + $bootstrap = getcwd() . '/scripts/pest-bootstrap.php'; if (!is_file($bootstrap)) { fwrite(STDERR, "Unable to find Pest bootstrap at scripts/pest-bootstrap.php.\n"); From 9cf45e7f86cd916674977b29c67e795007a41edb Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:02:11 +0800 Subject: [PATCH 06/15] Fix backend CI test harness --- .github/workflows/server.yml | 2 +- scripts/pest-bootstrap.php | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml index 978806a..f017caf 100644 --- a/.github/workflows/server.yml +++ b/.github/workflows/server.yml @@ -38,7 +38,7 @@ jobs: run: composer install --prefer-dist --no-progress - name: Run Lint - run: composer lint + run: composer test:lint - name: Run Tests run: composer test:unit diff --git a/scripts/pest-bootstrap.php b/scripts/pest-bootstrap.php index 6aad97a..93eb64d 100644 --- a/scripts/pest-bootstrap.php +++ b/scripts/pest-bootstrap.php @@ -28,6 +28,10 @@ function config(?string $key = null, mixed $default = null): mixed if (!$app->bound('http') && class_exists('Illuminate\Http\Client\Factory')) { $app->singleton('http', fn () => new Illuminate\Http\Client\Factory()); } + + if (!$app->bound('log') && class_exists('Psr\Log\NullLogger')) { + $app->singleton('log', fn () => new Psr\Log\NullLogger()); + } } if (!function_exists('app')) { @@ -67,6 +71,13 @@ function session(array|string|null $key = null, mixed $default = null): mixed } } +if (!function_exists('now') && class_exists('Illuminate\Support\Carbon')) { + function now($tz = null): Illuminate\Support\Carbon + { + return Illuminate\Support\Carbon::now($tz); + } +} + if (!trait_exists('Illuminate\Foundation\Auth\Access\AuthorizesRequests')) { eval('namespace Illuminate\Foundation\Auth\Access; trait AuthorizesRequests {}'); } @@ -84,7 +95,7 @@ function session(array|string|null $key = null, mixed $default = null): mixed } if (!class_exists('Illuminate\Foundation\Http\FormRequest') && class_exists('Illuminate\Http\Request')) { - eval('namespace Illuminate\Foundation\Http; class FormRequest extends \Illuminate\Http\Request { public function authorize(): bool { return true; } public function rules(): array { return []; } public function responseWithErrors($validator) { return $validator; } }'); + eval('namespace Illuminate\Foundation\Http; class FormRequest extends \Illuminate\Http\Request { public function authorize(): bool { return true; } public function rules(): array { return []; } public function responseWithErrors(\Illuminate\Contracts\Validation\Validator $validator) { return $validator; } }'); } if (!interface_exists('Fleetbase\Ai\Contracts\AIContextCapabilityInterface')) { From 3adafe08173f06e690415fb2a690c07954b84dbf Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:06:34 +0800 Subject: [PATCH 07/15] Restore server lint behavior --- .github/workflows/server.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml index f017caf..978806a 100644 --- a/.github/workflows/server.yml +++ b/.github/workflows/server.yml @@ -38,7 +38,7 @@ jobs: run: composer install --prefer-dist --no-progress - name: Run Lint - run: composer test:lint + run: composer lint - name: Run Tests run: composer test:unit From a452173aee1b32cd51a81744fc4c8e641b58f1b9 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:12:18 +0800 Subject: [PATCH 08/15] Stabilize package test bootstrap --- scripts/pest-bootstrap.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/pest-bootstrap.php b/scripts/pest-bootstrap.php index 93eb64d..7a2f17f 100644 --- a/scripts/pest-bootstrap.php +++ b/scripts/pest-bootstrap.php @@ -30,7 +30,11 @@ function config(?string $key = null, mixed $default = null): mixed } if (!$app->bound('log') && class_exists('Psr\Log\NullLogger')) { - $app->singleton('log', fn () => new Psr\Log\NullLogger()); + if (!class_exists('Fleetbase\TestSupport\LoggerManager')) { + eval('namespace Fleetbase\TestSupport; class LoggerManager extends \Psr\Log\NullLogger { public function channel(?string $name = null): self { return $this; } }'); + } + + $app->singleton('log', fn () => new Fleetbase\TestSupport\LoggerManager()); } } From af7dd85fef7e654f3f2db0379a0fe53ce19fc38f Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:17:16 +0800 Subject: [PATCH 09/15] Use Composer Pest proxy --- scripts/pest-runner.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/pest-runner.php b/scripts/pest-runner.php index 95fbc58..033895c 100644 --- a/scripts/pest-runner.php +++ b/scripts/pest-runner.php @@ -3,6 +3,8 @@ declare(strict_types=1); $pestCandidates = [ + getcwd() . '/server_vendor/bin/pest', + getcwd() . '/vendor/bin/pest', getcwd() . '/server_vendor/pestphp/pest/bin/pest', getcwd() . '/vendor/pestphp/pest/bin/pest', ]; From aaa291375ea58fe9e6cb1ebd16a19d27e5e4b681 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:23:04 +0800 Subject: [PATCH 10/15] Use PHPUnit 10 source coverage config --- phpunit.xml.dist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 57d2719..8d0c811 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -8,9 +8,9 @@ ./server/tests - - + + ./server/src - - + + From 544c65b315d8f7f760166c668a29f7e288e39049 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:29:49 +0800 Subject: [PATCH 11/15] Pass explicit PHPUnit config to Pest --- scripts/pest-runner.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/pest-runner.php b/scripts/pest-runner.php index 033895c..a33020a 100644 --- a/scripts/pest-runner.php +++ b/scripts/pest-runner.php @@ -34,12 +34,30 @@ exit(1); } +$args = array_slice($argv, 1); +$hasConfiguration = false; +foreach ($args as $arg) { + if (str_starts_with($arg, '--configuration')) { + $hasConfiguration = true; + break; + } +} +$configuration = getcwd() . '/phpunit.xml.dist'; + +if (!$hasConfiguration && is_file($configuration)) { + array_unshift($args, '--configuration=' . $configuration); +} + $command = array_merge([ PHP_BINARY, '-d', + 'display_errors=1', + '-d', + 'error_reporting=E_ALL', + '-d', 'auto_prepend_file=' . $bootstrap, $pest, -], array_slice($argv, 1)); +], $args); passthru(implode(' ', array_map('escapeshellarg', $command)), $exitCode); From f7fd36f18b0b0620650bbe5230ab2b1760f26b5c Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:34:10 +0800 Subject: [PATCH 12/15] Suppress dependency deprecations in Pest runner --- scripts/pest-runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pest-runner.php b/scripts/pest-runner.php index a33020a..dd59292 100644 --- a/scripts/pest-runner.php +++ b/scripts/pest-runner.php @@ -53,7 +53,7 @@ '-d', 'display_errors=1', '-d', - 'error_reporting=E_ALL', + 'error_reporting=8191', '-d', 'auto_prepend_file=' . $bootstrap, $pest, From bf5bed98a3942af33433141a7f3cba7a74b8bfe7 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:40:56 +0800 Subject: [PATCH 13/15] Run backend Pest tests explicitly --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 18fe1cc..3e4ac92 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ "test:coverage": "php scripts/coverage-runner.php --coverage --coverage-text --colors=always", "test:coverage:clover": "mkdir -p coverage && php scripts/coverage-runner.php --coverage-clover=coverage/clover.xml --colors=always", "test:types": "phpstan analyse --ansi --memory-limit=0", - "test:unit": "php scripts/pest-runner.php --colors=always", + "test:unit": "php scripts/pest-runner.php --colors=always --debug server/tests", "test": [ "@test:lint", "@test:types", From 8463030357f84e95efacd78d02febbcc92fa191b Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 13:48:10 +0800 Subject: [PATCH 14/15] Fix backend coverage CI runner --- composer.json | 2 +- scripts/coverage-runner.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3e4ac92..31a4f14 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ "test:coverage": "php scripts/coverage-runner.php --coverage --coverage-text --colors=always", "test:coverage:clover": "mkdir -p coverage && php scripts/coverage-runner.php --coverage-clover=coverage/clover.xml --colors=always", "test:types": "phpstan analyse --ansi --memory-limit=0", - "test:unit": "php scripts/pest-runner.php --colors=always --debug server/tests", + "test:unit": "php scripts/pest-runner.php --colors=always server/tests", "test": [ "@test:lint", "@test:types", diff --git a/scripts/coverage-runner.php b/scripts/coverage-runner.php index a87fd36..3f630c6 100644 --- a/scripts/coverage-runner.php +++ b/scripts/coverage-runner.php @@ -31,6 +31,18 @@ $_ENV['XDEBUG_MODE'] = 'coverage'; $_SERVER['XDEBUG_MODE'] = 'coverage'; +$hasTestTarget = false; +foreach ($args as $arg) { + if ($arg !== '' && $arg[0] !== '-') { + $hasTestTarget = true; + break; + } +} + +if (!$hasTestTarget && is_dir(getcwd() . '/server/tests')) { + $args[] = 'server/tests'; +} + $command = array_merge([PHP_BINARY, $pestRunner], $args); $escapedCommand = implode(' ', array_map('escapeshellarg', $command)); From 5be9088d45a159e28b667971df6e3b138385547c Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 17 Jul 2026 17:02:18 +0800 Subject: [PATCH 15/15] Fix tests and upgraded ember dependencies --- app/templates/promotions.hbs | 1 - app/templates/promotions.js | 1 + package.json | 4 +- pnpm-lock.yaml | 52 +++++++++++-------- pnpm-workspace.yaml | 3 +- .../Controllers/v1/CheckoutController.php | 12 ++++- server/src/Http/Resources/Order.php | 19 +++---- server/tests/Feature.php | 17 ++++-- 8 files changed, 68 insertions(+), 41 deletions(-) delete mode 100644 app/templates/promotions.hbs create mode 100644 app/templates/promotions.js diff --git a/app/templates/promotions.hbs b/app/templates/promotions.hbs deleted file mode 100644 index c24cd68..0000000 --- a/app/templates/promotions.hbs +++ /dev/null @@ -1 +0,0 @@ -{{outlet}} diff --git a/app/templates/promotions.js b/app/templates/promotions.js new file mode 100644 index 0000000..5f59d5a --- /dev/null +++ b/app/templates/promotions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/storefront-engine/templates/promotions'; diff --git a/package.json b/package.json index 3af0f21..03636a3 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ }, "dependencies": { "@babel/core": "^7.23.2", - "@fleetbase/ember-core": "^0.3.22", - "@fleetbase/ember-ui": "^0.3.34", + "@fleetbase/ember-core": "^0.3.24", + "@fleetbase/ember-ui": "^0.3.41", "@fleetbase/fleetops-data": "^0.1.37", "@fortawesome/ember-fontawesome": "^2.0.0", "@fortawesome/fontawesome-svg-core": "6.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53a91ef..4dbbc5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,11 +12,11 @@ importers: specifier: ^7.23.2 version: 7.29.7 '@fleetbase/ember-core': - specifier: ^0.3.22 - version: 0.3.22(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15)) + specifier: ^0.3.24 + version: 0.3.24(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15)) '@fleetbase/ember-ui': - specifier: ^0.3.34 - version: 0.3.34(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(@glimmer/component@1.1.2(@babel/core@7.29.7))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(postcss@8.5.15)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.7))(webpack@5.107.2(postcss@8.5.15))(yaml@2.9.0) + specifier: ^0.3.41 + version: 0.3.41(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(@glimmer/component@1.1.2(@babel/core@7.29.7))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(postcss@8.5.15)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.7))(webpack@5.107.2(postcss@8.5.15))(yaml@2.9.0) '@fleetbase/fleetops-data': specifier: ^0.1.37 version: 0.1.37(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15)) @@ -1271,12 +1271,12 @@ packages: peerDependencies: ember-source: '>= 4.0.0' - '@fleetbase/ember-core@0.3.22': - resolution: {integrity: sha512-tCYgxJoemUXgjsUztzeJZSwU2ejDp5x2WYI3FsBO55AlcC+mfWm0FsYtuPd9xd9PoO1jZ3T3VyvQQ06HRPtqWw==} + '@fleetbase/ember-core@0.3.24': + resolution: {integrity: sha512-WG32JlX4S75ofa34RQEMxFEqc20fTv2Qn3A5+NlqXtL0lfnCthdO+a1DrGqIIierthHl3mVTxhe+z63f8sM6EA==} engines: {node: '>= 18'} - '@fleetbase/ember-ui@0.3.34': - resolution: {integrity: sha512-l67lrbpeh0JRLDHr1sJ3QnxP6vPKwVW614CVWEASs6ZImGCBr6CK3DjsT3h+1uslQa51dpixN/stiQ+C/Z1etA==} + '@fleetbase/ember-ui@0.3.41': + resolution: {integrity: sha512-xWWrqHnVj2YW1dfEGC5woLrpPEGx8Z6dstxVZygjt9apf8Vu3goyNnLSdkIdbJS2ACMlg+QuAUV5tPySQuO+3w==} engines: {node: '>= 18'} '@fleetbase/fleetops-data@0.1.37': @@ -3519,6 +3519,11 @@ packages: decorator-transforms@2.3.2: resolution: {integrity: sha512-XcErcjlmCzG5ODgYjt6ZTXwd6S8fPKln/sJmw15ZXkWG2JpoQNwszis+AwF6XSGlOoG7g8MCEO97g+Yw3fk5OQ==} + decorator-transforms@2.4.0: + resolution: {integrity: sha512-IB+0RqnJpuS7ndH4dVY5dfWTZsrCzN3avWFdjSiET0uT2U24jKywjpVEK97TflnZkZgiSRfmeqc1WfS+1CI23w==} + peerDependencies: + '@babel/core': ^7.23.0 || ^8.0.0 + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -7433,8 +7438,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.8.4: - resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -9581,7 +9586,7 @@ snapshots: dependencies: postcss: 8.5.15 - '@ember-data/adapter@4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))': + '@ember-data/adapter@4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))': dependencies: '@ember-data/private-build-infra': 4.12.8 '@ember-data/store': 4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))) @@ -9718,7 +9723,7 @@ snapshots: '@ember-data/rfc395-data@0.0.4': {} - '@ember-data/serializer@4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))': + '@ember-data/serializer@4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))': dependencies: '@ember-data/private-build-infra': 4.12.8 '@ember-data/store': 4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))) @@ -9852,7 +9857,7 @@ snapshots: '@embroider/shared-internals': 3.1.1 broccoli-funnel: 3.0.8 common-ancestor-path: 1.0.1 - semver: 7.8.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color @@ -9940,7 +9945,7 @@ snapshots: pkg-entry-points: 1.1.2 resolve-package-path: 4.0.3 resolve.exports: 2.0.3 - semver: 7.8.4 + semver: 7.8.5 typescript-memoize: 1.1.1 transitivePeerDependencies: - supports-color @@ -9998,7 +10003,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@fleetbase/ember-core@0.3.22(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15))': + '@fleetbase/ember-core@0.3.24(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15))': dependencies: '@babel/core': 7.29.7 compress-json: 3.4.0 @@ -10031,7 +10036,7 @@ snapshots: - utf-8-validate - webpack - '@fleetbase/ember-ui@0.3.34(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(@glimmer/component@1.1.2(@babel/core@7.29.7))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(postcss@8.5.15)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.7))(webpack@5.107.2(postcss@8.5.15))(yaml@2.9.0)': + '@fleetbase/ember-ui@0.3.41(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(@glimmer/component@1.1.2(@babel/core@7.29.7))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(postcss@8.5.15)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.7))(webpack@5.107.2(postcss@8.5.15))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.7 '@ember/render-modifiers': 2.1.0(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))) @@ -10140,7 +10145,7 @@ snapshots: '@fleetbase/fleetops-data@0.1.37(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15))': dependencies: '@babel/core': 7.29.7 - '@fleetbase/ember-core': 0.3.22(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15)) + '@fleetbase/ember-core': 0.3.24(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.7)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(eslint@8.57.1)(webpack@5.107.2(postcss@8.5.15)) date-fns: 2.30.0 ember-cli-babel: 8.3.1(@babel/core@7.29.7) ember-cli-htmlbars: 6.3.0 @@ -13009,6 +13014,11 @@ snapshots: transitivePeerDependencies: - '@babel/core' + decorator-transforms@2.4.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + babel-import-util: 3.0.1 + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -13906,7 +13916,7 @@ snapshots: ember-data@4.12.8(@babel/core@7.29.7)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))(webpack@5.107.2(postcss@8.5.15)): dependencies: - '@ember-data/adapter': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))) + '@ember-data/adapter': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))) '@ember-data/debug': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8)(@ember/string@3.1.1)(webpack@5.107.2(postcss@8.5.15)) '@ember-data/graph': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8) '@ember-data/json-api': 4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/store@4.12.8) @@ -13914,7 +13924,7 @@ snapshots: '@ember-data/model': 4.12.8(@babel/core@7.29.7)(@ember-data/debug@4.12.8)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/store@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))) '@ember-data/private-build-infra': 4.12.8 '@ember-data/request': 4.12.8(@babel/core@7.29.7) - '@ember-data/serializer': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))) + '@ember-data/serializer': 4.12.8(@babel/core@7.29.7)(@ember-data/store@4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))))(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15)))) '@ember-data/store': 4.12.8(@babel/core@7.29.7)(@ember-data/graph@4.12.8)(@ember-data/json-api@4.12.8)(@ember-data/legacy-compat@4.12.8)(@ember-data/model@4.12.8)(@ember-data/tracking@4.12.8(@babel/core@7.29.7))(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.7)(@glimmer/component@1.1.2(@babel/core@7.29.7))(rsvp@4.8.5)(webpack@5.107.2(postcss@8.5.15))) '@ember-data/tracking': 4.12.8(@babel/core@7.29.7) '@ember/edition-utils': 1.2.0 @@ -18242,7 +18252,7 @@ snapshots: semver@7.8.1: {} - semver@7.8.4: {} + semver@7.8.5: {} send@0.19.2: dependencies: @@ -19155,7 +19165,7 @@ snapshots: tracked-built-ins@3.4.0(@babel/core@7.29.7): dependencies: '@embroider/addon-shim': 1.10.3 - decorator-transforms: 2.3.2(@babel/core@7.29.7) + decorator-transforms: 2.4.0(@babel/core@7.29.7) ember-tracked-storage-polyfill: 1.0.1 transitivePeerDependencies: - '@babel/core' diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bf39b1a..15e69ae 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,4 +5,5 @@ allowBuilds: '@fortawesome/free-solid-svg-icons': false core-js: false fsevents: false -minimumReleaseAge: 0 \ No newline at end of file +minimumReleaseAge: 0 +packages: [] \ No newline at end of file diff --git a/server/src/Http/Controllers/v1/CheckoutController.php b/server/src/Http/Controllers/v1/CheckoutController.php index 814a973..ae0d7e2 100644 --- a/server/src/Http/Controllers/v1/CheckoutController.php +++ b/server/src/Http/Controllers/v1/CheckoutController.php @@ -921,7 +921,11 @@ public function captureOrder(CaptureOrderRequest $request) 'currency' => $currency, 'description' => 'Storefront order', 'type' => 'storefront', - 'status' => 'success', + 'status' => Transaction::STATUS_SUCCESS, + 'settlement_status' => Transaction::SETTLEMENT_STATUS_PAID, + 'settled_at' => now(), + 'settled_amount' => $amount, + 'settled_currency' => $currency, 'meta' => $transactionMeta, ]); @@ -1216,7 +1220,11 @@ public function captureMultipleOrders(CaptureOrderRequest $request) 'currency' => $currency, 'description' => 'Storefront network order', 'type' => 'storefront', - 'status' => 'success', + 'status' => Transaction::STATUS_SUCCESS, + 'settlement_status' => Transaction::SETTLEMENT_STATUS_PAID, + 'settled_at' => now(), + 'settled_amount' => $amount, + 'settled_currency' => $currency, 'meta' => $transactionMeta, ]); diff --git a/server/src/Http/Resources/Order.php b/server/src/Http/Resources/Order.php index e752181..91a90b6 100644 --- a/server/src/Http/Resources/Order.php +++ b/server/src/Http/Resources/Order.php @@ -23,15 +23,16 @@ public function toArray($request): array if ($this->resource->relationLoaded('transaction') && $this->transaction) { $data['transaction'] = [ - 'id' => $this->transaction->uuid, - 'uuid' => $this->transaction->uuid, - 'public_id' => $this->transaction->public_id ?? null, - 'amount' => $this->transaction->amount ?? $this->transaction_amount, - 'currency' => $this->transaction->currency ?? data_get($data, 'meta.currency'), - 'status' => $this->transaction->status ?? null, - 'gateway' => $this->transaction->gateway ?? data_get($data, 'meta.gateway'), - 'created_at' => $this->transaction->created_at, - 'updated_at' => $this->transaction->updated_at, + 'id' => $this->transaction->uuid, + 'uuid' => $this->transaction->uuid, + 'public_id' => $this->transaction->public_id ?? null, + 'amount' => $this->transaction->amount ?? $this->transaction_amount, + 'currency' => $this->transaction->currency ?? data_get($data, 'meta.currency'), + 'status' => $this->transaction->status ?? null, + 'settlement_status' => $this->transaction->settlement_status ?? null, + 'gateway' => $this->transaction->gateway ?? data_get($data, 'meta.gateway'), + 'created_at' => $this->transaction->created_at, + 'updated_at' => $this->transaction->updated_at, ]; } diff --git a/server/tests/Feature.php b/server/tests/Feature.php index fb5d35d..44be50e 100644 --- a/server/tests/Feature.php +++ b/server/tests/Feature.php @@ -95,7 +95,13 @@ $customer->forceFill(['uuid' => 'contact_uuid', 'name' => 'Ada Lovelace']); $transaction = new Transaction(); - $transaction->forceFill(['uuid' => 'transaction_uuid', 'amount' => 50, 'currency' => 'USD', 'status' => 'paid']); + $transaction->forceFill([ + 'uuid' => 'transaction_uuid', + 'amount' => 50, + 'currency' => 'USD', + 'status' => 'success', + 'settlement_status' => 'paid', + ]); $payload = new Payload(); $payload->forceFill(['uuid' => 'payload_uuid']); @@ -114,10 +120,11 @@ ->and($data['customer_name'])->toBe('Ada Lovelace') ->and($data['transaction_amount'])->toBe($order->transaction_amount) ->and($data['transaction'])->toMatchArray([ - 'id' => 'transaction_uuid', - 'amount' => 50, - 'currency' => 'USD', - 'status' => 'paid', + 'id' => 'transaction_uuid', + 'amount' => 50, + 'currency' => 'USD', + 'status' => 'success', + 'settlement_status' => 'paid', ]) ->and($data['meta'])->toMatchArray([ 'subtotal' => 42.25,