| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- <?php
- namespace Tests\Unit\Models;
- use App\Models\InventoryMovement;
- use App\Models\Reclamation;
- use App\Models\Shortage;
- use App\Models\SparePart;
- use App\Models\SparePartOrder;
- use App\Models\User;
- use Illuminate\Foundation\Testing\RefreshDatabase;
- use Tests\TestCase;
- class InventoryMovementTest extends TestCase
- {
- use RefreshDatabase;
- protected $seed = true;
- // ==================== Type Constants ====================
- public function test_type_constants_are_defined(): void
- {
- $this->assertEquals('receipt', InventoryMovement::TYPE_RECEIPT);
- $this->assertEquals('reserve', InventoryMovement::TYPE_RESERVE);
- $this->assertEquals('issue', InventoryMovement::TYPE_ISSUE);
- $this->assertEquals('reserve_cancel', InventoryMovement::TYPE_RESERVE_CANCEL);
- $this->assertEquals('correction_plus', InventoryMovement::TYPE_CORRECTION_PLUS);
- $this->assertEquals('correction_minus', InventoryMovement::TYPE_CORRECTION_MINUS);
- }
- public function test_type_names_are_defined(): void
- {
- $this->assertEquals('Поступление', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_RECEIPT]);
- $this->assertEquals('Резервирование', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_RESERVE]);
- $this->assertEquals('Списание', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_ISSUE]);
- $this->assertEquals('Отмена резерва', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_RESERVE_CANCEL]);
- $this->assertEquals('Коррекция (+)', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_CORRECTION_PLUS]);
- $this->assertEquals('Коррекция (-)', InventoryMovement::TYPE_NAMES[InventoryMovement::TYPE_CORRECTION_MINUS]);
- }
- // ==================== Source Type Constants ====================
- public function test_source_type_constants_are_defined(): void
- {
- $this->assertEquals('order', InventoryMovement::SOURCE_ORDER);
- $this->assertEquals('reclamation', InventoryMovement::SOURCE_RECLAMATION);
- $this->assertEquals('manual', InventoryMovement::SOURCE_MANUAL);
- $this->assertEquals('shortage_fulfillment', InventoryMovement::SOURCE_SHORTAGE_FULFILLMENT);
- $this->assertEquals('inventory', InventoryMovement::SOURCE_INVENTORY);
- }
- // ==================== Accessors ====================
- public function test_type_name_attribute_returns_readable_name(): void
- {
- // Arrange
- $movement = InventoryMovement::factory()->receipt()->create();
- // Assert
- $this->assertEquals('Поступление', $movement->type_name);
- }
- public function test_type_name_attribute_returns_raw_for_unknown_type(): void
- {
- // Arrange
- $movement = new InventoryMovement(['movement_type' => 'unknown']);
- // Assert
- $this->assertEquals('unknown', $movement->type_name);
- }
- public function test_source_attribute_returns_reclamation(): void
- {
- // Arrange
- $reclamation = Reclamation::factory()->create();
- $movement = InventoryMovement::factory()
- ->forReclamation($reclamation->id)
- ->create();
- // Act
- $source = $movement->source;
- // Assert
- $this->assertInstanceOf(Reclamation::class, $source);
- $this->assertEquals($reclamation->id, $source->id);
- }
- public function test_source_attribute_returns_null_for_manual(): void
- {
- // Arrange
- $movement = InventoryMovement::factory()->create([
- 'source_type' => InventoryMovement::SOURCE_MANUAL,
- 'source_id' => null,
- ]);
- // Assert
- $this->assertNull($movement->source);
- }
- public function test_source_attribute_returns_null_when_no_source_id(): void
- {
- // Arrange
- $movement = InventoryMovement::factory()->create([
- 'source_type' => InventoryMovement::SOURCE_RECLAMATION,
- 'source_id' => null,
- ]);
- // Assert
- $this->assertNull($movement->source);
- }
- // ==================== Relationships ====================
- public function test_movement_belongs_to_spare_part_order(): void
- {
- // Arrange
- $order = SparePartOrder::factory()->create();
- $movement = InventoryMovement::factory()
- ->fromOrder($order)
- ->create();
- // Assert
- $this->assertInstanceOf(SparePartOrder::class, $movement->sparePartOrder);
- $this->assertEquals($order->id, $movement->sparePartOrder->id);
- }
- public function test_movement_belongs_to_spare_part(): void
- {
- // Arrange
- $sparePart = SparePart::factory()->create();
- $movement = InventoryMovement::factory()->create([
- 'spare_part_id' => $sparePart->id,
- ]);
- // Assert
- $this->assertInstanceOf(SparePart::class, $movement->sparePart);
- $this->assertEquals($sparePart->id, $movement->sparePart->id);
- }
- public function test_movement_belongs_to_user(): void
- {
- // Arrange
- $user = User::factory()->create();
- $movement = InventoryMovement::factory()->create([
- 'user_id' => $user->id,
- ]);
- // Assert
- $this->assertInstanceOf(User::class, $movement->user);
- $this->assertEquals($user->id, $movement->user->id);
- }
- // ==================== Scopes ====================
- public function test_scope_of_type_filters_by_movement_type(): void
- {
- // Arrange
- InventoryMovement::factory()->receipt()->count(2)->create();
- InventoryMovement::factory()->issue()->create();
- InventoryMovement::factory()->reserve()->create();
- // Act
- $receipts = InventoryMovement::ofType(InventoryMovement::TYPE_RECEIPT)->get();
- $issues = InventoryMovement::ofType(InventoryMovement::TYPE_ISSUE)->get();
- // Assert
- $this->assertCount(2, $receipts);
- $this->assertCount(1, $issues);
- }
- public function test_scope_for_spare_part_filters_by_spare_part_id(): void
- {
- // Arrange
- $sparePart1 = SparePart::factory()->create();
- $sparePart2 = SparePart::factory()->create();
- InventoryMovement::factory()->count(3)->create([
- 'spare_part_id' => $sparePart1->id,
- ]);
- InventoryMovement::factory()->create([
- 'spare_part_id' => $sparePart2->id,
- ]);
- // Act
- $movements = InventoryMovement::forSparePart($sparePart1->id)->get();
- // Assert
- $this->assertCount(3, $movements);
- }
- public function test_scope_with_documents_filters_by_with_documents(): void
- {
- // Arrange
- InventoryMovement::factory()->count(2)->create([
- 'with_documents' => true,
- ]);
- InventoryMovement::factory()->create([
- 'with_documents' => false,
- ]);
- // Act
- $withDocs = InventoryMovement::withDocuments(true)->get();
- $withoutDocs = InventoryMovement::withDocuments(false)->get();
- // Assert
- $this->assertCount(2, $withDocs);
- $this->assertCount(1, $withoutDocs);
- }
- public function test_scope_increasing_returns_correct_types(): void
- {
- // Arrange
- InventoryMovement::factory()->receipt()->create();
- InventoryMovement::factory()->reserveCancel()->create();
- InventoryMovement::factory()->create([
- 'movement_type' => InventoryMovement::TYPE_CORRECTION_PLUS,
- ]);
- InventoryMovement::factory()->issue()->create();
- InventoryMovement::factory()->reserve()->create();
- // Act
- $increasing = InventoryMovement::increasing()->get();
- // Assert
- $this->assertCount(3, $increasing);
- $types = $increasing->pluck('movement_type')->toArray();
- $this->assertContains(InventoryMovement::TYPE_RECEIPT, $types);
- $this->assertContains(InventoryMovement::TYPE_RESERVE_CANCEL, $types);
- $this->assertContains(InventoryMovement::TYPE_CORRECTION_PLUS, $types);
- }
- public function test_scope_decreasing_returns_correct_types(): void
- {
- // Arrange
- InventoryMovement::factory()->receipt()->create();
- InventoryMovement::factory()->reserve()->create();
- InventoryMovement::factory()->issue()->create();
- InventoryMovement::factory()->create([
- 'movement_type' => InventoryMovement::TYPE_CORRECTION_MINUS,
- ]);
- // Act
- $decreasing = InventoryMovement::decreasing()->get();
- // Assert
- $this->assertCount(3, $decreasing);
- $types = $decreasing->pluck('movement_type')->toArray();
- $this->assertContains(InventoryMovement::TYPE_RESERVE, $types);
- $this->assertContains(InventoryMovement::TYPE_ISSUE, $types);
- $this->assertContains(InventoryMovement::TYPE_CORRECTION_MINUS, $types);
- }
- // ==================== Methods ====================
- public function test_is_correction_returns_true_for_correction_types(): void
- {
- // Arrange
- $correctionPlus = new InventoryMovement([
- 'movement_type' => InventoryMovement::TYPE_CORRECTION_PLUS,
- ]);
- $correctionMinus = new InventoryMovement([
- 'movement_type' => InventoryMovement::TYPE_CORRECTION_MINUS,
- ]);
- $receipt = new InventoryMovement([
- 'movement_type' => InventoryMovement::TYPE_RECEIPT,
- ]);
- // Assert
- $this->assertTrue($correctionPlus->isCorrection());
- $this->assertTrue($correctionMinus->isCorrection());
- $this->assertFalse($receipt->isCorrection());
- }
- // ==================== Casts ====================
- public function test_qty_is_cast_to_integer(): void
- {
- // Arrange
- $movement = InventoryMovement::factory()->create(['qty' => 10]);
- // Assert
- $this->assertIsInt($movement->qty);
- }
- public function test_with_documents_is_cast_to_boolean(): void
- {
- // Arrange
- $movement = InventoryMovement::factory()->create(['with_documents' => true]);
- // Assert
- $this->assertIsBool($movement->with_documents);
- }
- public function test_source_id_is_cast_to_integer(): void
- {
- // Arrange
- $reclamation = Reclamation::factory()->create();
- $movement = InventoryMovement::factory()
- ->forReclamation($reclamation->id)
- ->create();
- // Assert
- $this->assertIsInt($movement->source_id);
- }
- // ==================== Factory ====================
- public function test_factory_creates_valid_movement(): void
- {
- // Act
- $movement = InventoryMovement::factory()->create();
- // Assert
- $this->assertDatabaseHas('inventory_movements', [
- 'id' => $movement->id,
- ]);
- $this->assertNotNull($movement->spare_part_id);
- $this->assertNotNull($movement->spare_part_order_id);
- $this->assertNotNull($movement->qty);
- $this->assertNotNull($movement->movement_type);
- }
- public function test_factory_receipt_state(): void
- {
- // Act
- $movement = InventoryMovement::factory()->receipt()->create();
- // Assert
- $this->assertEquals(InventoryMovement::TYPE_RECEIPT, $movement->movement_type);
- }
- public function test_factory_reserve_state(): void
- {
- // Act
- $movement = InventoryMovement::factory()->reserve()->create();
- // Assert
- $this->assertEquals(InventoryMovement::TYPE_RESERVE, $movement->movement_type);
- }
- public function test_factory_issue_state(): void
- {
- // Act
- $movement = InventoryMovement::factory()->issue()->create();
- // Assert
- $this->assertEquals(InventoryMovement::TYPE_ISSUE, $movement->movement_type);
- }
- }
|