php-commerce/tests/Feature/CompoundSkuTest.php

237 lines
8 KiB
PHP
Raw Normal View History

2026-01-27 00:24:22 +00:00
<?php
declare(strict_types=1);
use Core\Mod\Commerce\Data\BundleItem;
use Core\Mod\Commerce\Data\ParsedItem;
use Core\Mod\Commerce\Data\SkuOption;
use Core\Mod\Commerce\Services\SkuBuilderService;
use Core\Mod\Commerce\Services\SkuParserService;
2026-01-27 00:24:22 +00:00
describe('Compound SKU Parser', function () {
beforeEach(function () {
$this->parser = app(SkuParserService::class);
});
test('parses simple SKU without options', function () {
$result = $this->parser->parse('LAPTOP');
expect($result->count())->toBe(1);
expect($result->items[0])->toBeInstanceOf(ParsedItem::class);
expect($result->items[0]->baseSku)->toBe('LAPTOP');
expect($result->items[0]->options)->toBeEmpty();
});
test('parses SKU with single option', function () {
$result = $this->parser->parse('LAPTOP-ram~16gb');
expect($result->count())->toBe(1);
expect($result->items[0]->baseSku)->toBe('LAPTOP');
expect($result->items[0]->options)->toHaveCount(1);
expect($result->items[0]->options[0]->code)->toBe('ram');
expect($result->items[0]->options[0]->value)->toBe('16gb');
expect($result->items[0]->options[0]->quantity)->toBe(1);
});
test('parses SKU with multiple options', function () {
$result = $this->parser->parse('LAPTOP-ram~16gb-ssd~512gb-color~silver');
expect($result->count())->toBe(1);
expect($result->items[0]->options)->toHaveCount(3);
expect($result->items[0]->getOption('ram')->value)->toBe('16gb');
expect($result->items[0]->getOption('ssd')->value)->toBe('512gb');
expect($result->items[0]->getOption('color')->value)->toBe('silver');
});
test('parses option with quantity', function () {
$result = $this->parser->parse('LAPTOP-cover~black*2');
expect($result->items[0]->options[0]->code)->toBe('cover');
expect($result->items[0]->options[0]->value)->toBe('black');
expect($result->items[0]->options[0]->quantity)->toBe(2);
});
test('parses multiple comma-separated items', function () {
$result = $this->parser->parse('LAPTOP-ram~16gb,MOUSE,PAD-size~xl');
expect($result->count())->toBe(3);
expect($result->items[0]->baseSku)->toBe('LAPTOP');
expect($result->items[1]->baseSku)->toBe('MOUSE');
expect($result->items[2]->baseSku)->toBe('PAD');
expect($result->hasBundles())->toBeFalse();
});
test('parses pipe-separated bundle', function () {
$result = $this->parser->parse('LAPTOP-ram~16gb|MOUSE|PAD');
expect($result->count())->toBe(1);
expect($result->hasBundles())->toBeTrue();
expect($result->items[0])->toBeInstanceOf(BundleItem::class);
$bundle = $result->items[0];
expect($bundle->count())->toBe(3);
expect($bundle->getBaseSkus())->toBe(['LAPTOP', 'MOUSE', 'PAD']);
});
test('bundle hash is consistent regardless of order', function () {
$result1 = $this->parser->parse('LAPTOP|MOUSE|PAD');
$result2 = $this->parser->parse('PAD|LAPTOP|MOUSE');
expect($result1->items[0]->hash)->toBe($result2->items[0]->hash);
});
test('parses mixed bundles and singles', function () {
$result = $this->parser->parse('LAPTOP|MOUSE,HDMI-length~2m');
expect($result->count())->toBe(2);
expect($result->items[0])->toBeInstanceOf(BundleItem::class);
expect($result->items[1])->toBeInstanceOf(ParsedItem::class);
});
test('preserves entity lineage in base SKU', function () {
// SKU with lineage: ORGORG-WBUTS-PROD500
$result = $this->parser->parse('ORGORG-WBUTS-PROD500-ram~16gb');
expect($result->items[0]->baseSku)->toBe('ORGORG-WBUTS-PROD500');
expect($result->items[0]->options)->toHaveCount(1);
});
test('validates SKU format', function () {
$valid = $this->parser->validate('LAPTOP-ram~16gb');
expect($valid['valid'])->toBeTrue();
$invalid = $this->parser->validate('');
expect($invalid['valid'])->toBeFalse();
});
test('round trips through parse and toString', function () {
$original = 'LAPTOP-ram~16gb-ssd~512gb';
$result = $this->parser->parse($original);
expect($result->toString())->toBe($original);
});
});
describe('Compound SKU Builder', function () {
beforeEach(function () {
$this->builder = app(SkuBuilderService::class);
});
test('builds simple item', function () {
$sku = $this->builder->build([
['base_sku' => 'laptop'],
]);
expect($sku)->toBe('LAPTOP');
});
test('builds item with options', function () {
$sku = $this->builder->build([
[
'base_sku' => 'laptop',
'options' => [
['code' => 'ram', 'value' => '16gb'],
['code' => 'ssd', 'value' => '512gb'],
],
],
]);
expect($sku)->toBe('LAPTOP-ram~16gb-ssd~512gb');
});
test('builds item with quantity on option', function () {
$sku = $this->builder->build([
[
'base_sku' => 'laptop',
'options' => [
['code' => 'cover', 'value' => 'black', 'quantity' => 2],
],
],
]);
expect($sku)->toBe('LAPTOP-cover~black*2');
});
test('builds multiple items comma-separated', function () {
$sku = $this->builder->build([
['base_sku' => 'laptop'],
['base_sku' => 'mouse'],
]);
expect($sku)->toBe('LAPTOP,MOUSE');
});
test('builds bundle with same group', function () {
$sku = $this->builder->build([
['base_sku' => 'laptop', 'bundle_group' => 'cyber'],
['base_sku' => 'mouse', 'bundle_group' => 'cyber'],
['base_sku' => 'hdmi'], // standalone
]);
expect($sku)->toBe('LAPTOP|MOUSE,HDMI');
});
test('adds entity lineage', function () {
$sku = $this->builder->addLineage('PROD500', ['ORGORG', 'WBUTS']);
expect($sku)->toBe('ORGORG-WBUTS-PROD500');
});
test('builds with lineage', function () {
$sku = $this->builder->buildWithLineage(
['ORGORG', 'WBUTS'],
[
[
'base_sku' => 'PROD500',
'options' => [['code' => 'size', 'value' => 'xl']],
],
]
);
expect($sku)->toBe('ORGORG-WBUTS-PROD500-size~xl');
});
test('generates bundle hash', function () {
$hash = $this->builder->generateBundleHash(['laptop', 'mouse', 'pad']);
// Hash is deterministic
expect($hash)->toBe($this->builder->generateBundleHash(['PAD', 'LAPTOP', 'MOUSE']));
expect(strlen($hash))->toBe(64); // SHA256
});
test('creates option and item helpers', function () {
$option = $this->builder->option('ram', '16gb', 2);
expect($option)->toBeInstanceOf(SkuOption::class);
expect($option->toString())->toBe('ram~16gb*2');
$item = $this->builder->item('LAPTOP', [$option]);
expect($item)->toBeInstanceOf(ParsedItem::class);
expect($item->toString())->toBe('LAPTOP-ram~16gb*2');
});
});
describe('SKU Parse Result', function () {
test('collects all base SKUs', function () {
$parser = app(SkuParserService::class);
$result = $parser->parse('LAPTOP|MOUSE,HDMI,PAD');
expect($result->getAllBaseSkus())->toBe(['LAPTOP', 'MOUSE', 'HDMI', 'PAD']);
});
test('counts products correctly', function () {
$parser = app(SkuParserService::class);
$result = $parser->parse('LAPTOP|MOUSE|PAD,HDMI');
expect($result->count())->toBe(2); // 1 bundle + 1 single
expect($result->productCount())->toBe(4); // 3 in bundle + 1 single
});
test('extracts bundle hashes', function () {
$parser = app(SkuParserService::class);
$result = $parser->parse('LAPTOP|MOUSE,KEYBOARD|PAD');
$hashes = $result->getBundleHashes();
expect($hashes)->toHaveCount(2);
});
});