stockAmount = new StockAmount(10); $this->campaignCode = new CampaignCode('AAA01'); $this->processingCode = new ProcessingCode('PC1'); $this->stockAdjustment = [new StockAdjustment(5, 'Inventory correction', ActorId::generate())]; }); it('hydrates a stock', function (): void { // GIVEN $id = StockId::generate(); // WHEN $stock = Stock::hydrate( $id, $this->stockAmount, $this->campaignCode, $this->processingCode, $this->stockAdjustment ); // THEN expect($stock->id())->toBe($id) ->and($stock->stockAmount)->toBe($this->stockAmount) ->and($stock->campaignCode)->toBe($this->campaignCode) ->and($stock->processingCode)->toBe($this->processingCode) ->and($stock->stockAdjustment)->toBe($this->stockAdjustment) ->and($stock->updatedAt)->toBeNull() ->and($stock->updatedAt())->toBeNull(); }); it('hydrates a stock with several stock adjustments', function (): void { // GIVEN $id = StockId::generate(); $stockAdjustment = [ new StockAdjustment(5, 'Inventory correction', ActorId::generate()), new StockAdjustment(10, 'Inventory correction', ActorId::generate()), ]; // WHEN $stock = Stock::hydrate( $id, $this->stockAmount, $this->campaignCode, $this->processingCode, $stockAdjustment, ); // THEN expect($stock->id())->toBe($id) ->and($stock->stockAmount)->toBe($this->stockAmount) ->and($stock->campaignCode)->toBe($this->campaignCode) ->and($stock->processingCode)->toBe($this->processingCode) ->and($stock->stockAdjustment)->toBe($stockAdjustment) ->and($stock->updatedAt)->toBeNull() ->and($stock->updatedAt())->toBeNull(); }); it('hydrates a stock without stock adjustement', function (): void { // GIVEN $id = StockId::generate(); // WHEN $stock = Stock::hydrate( $id, $this->stockAmount, $this->campaignCode, $this->processingCode ); // THEN expect($stock->id())->toBe($id) ->and($stock->stockAmount)->toBe($this->stockAmount) ->and($stock->campaignCode)->toBe($this->campaignCode) ->and($stock->processingCode)->toBe($this->processingCode) ->and($stock->stockAdjustment)->toBe([]) ->and($stock->updatedAt)->toBeNull() ->and($stock->updatedAt())->toBeNull(); }); it('rejects a stock with a non-stock-adjustment element', function (): void { // GIVEN $id = StockId::generate(); $stockAdjustment = [new StockAmount(5)]; // WHEN / THEN expect(fn (): Stock => Stock::hydrate( $id, $this->stockAmount, $this->campaignCode, $this->processingCode, $stockAdjustment, ))->toThrow(\DomainException::class, 'Stock adjustment must be StockAdjustment instances.'); }); it('hydrates a stock with an explicit updatedAt date', function (): void { // GIVEN $updatedAt = new \DateTimeImmutable('2026-06-15 12:00:00', new \DateTimeZone('UTC')); // WHEN $stock = Stock::hydrate( StockId::generate(), $this->stockAmount, $this->campaignCode, $this->processingCode, $this->stockAdjustment, $updatedAt, ); // THEN expect($stock->updatedAt)->toBe($updatedAt) ->and($stock->updatedAt())->toBe($updatedAt); }); it('returns the creation date extracted from the id', function (): void { // GIVEN $expected = new \DateTimeImmutable('2024-06-15 12:34:56.789000', new \DateTimeZone('UTC')); $id = new StockId(Uuid::uuid7($expected)); $stock = Stock::hydrate( $id, $this->stockAmount, $this->campaignCode, $this->processingCode, $this->stockAdjustment ); // WHEN $result = $stock->createdAt(); // THEN expect($result->format('Y-m-d H:i:s.v'))->toBe($expected->format('Y-m-d H:i:s.v')); }); });