user = User::factory()->create([ 'password' => 'password', 'phone_number' => 61929248, ]); // Create tmpost channel required by OrderRepository if (Channel::where('slug', 'tmpost')->doesntExist()) { Channel::create(['slug' => 'tmpost', 'name' => 'TM Post']); } // Mock default payment type for OrderPayment::default() if (PaymentType::count() === 0) { $paymentType = new PaymentType; $paymentType->forceFill([ 'id' => 1, 'code' => 'cash', 'name' => ['en' => 'Cash'], 'tax' => 0, 'is_enabled' => true, ]); $paymentType->save(); } }); test('authenticated user can list their orders', function () { $order = new Order; $order->forceFill([ 'user_id' => $this->user->id, 'number' => 'ORD-123', 'customer_name' => 'John Doe', 'customer_phone' => 61929248, 'customer_address' => 'Test Address', 'shipping_method' => OrderShipping::STANDART, 'shipping_price' => 20, 'payment_type_id' => 1, // Assuming ID 1 exists or mocked 'region' => Region::AG, 'delivery_at' => now(), 'status' => OrderStatus::PENDING, ]); $order->save(); $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->getJson('/api/v1/orders'); $response->assertOk() ->assertJsonStructure([ 'data' => [ '*' => [ 'id', 'number', // Add other fields from OrderIndexResource ], ], ]); }); test('unauthenticated user cannot list orders', function () { $this->withHeaders(['Api-Token' => 'test-token']) ->getJson('/api/v1/orders') ->assertUnauthorized(); }); test('can place an order', function () { // Setup prerequisites $product = Product::create([ 'name' => 'Test Product', 'slug' => 'test-product', 'price_amount' => 100, 'cost_amount' => 80, 'stock' => 10, 'is_visible' => true, ]); // Add item to cart CartItem::create([ 'user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 2, ]); // Mock PaymentType if needed (OrderPayment::values() uses DB) PaymentType::create([ 'code' => 'card', 'name' => ['en' => 'Card'], 'tax' => 0, 'is_enabled' => true, ]); $paymentTypeId = PaymentType::where('code', 'card')->first()->id; $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->postJson('/api/v1/orders', [ 'customer_name' => 'John Doe', 'customer_phone' => 61929248, 'customer_address' => '123 Main St', 'shipping_method' => OrderShipping::STANDART, 'payment_type_id' => $paymentTypeId, 'region' => Region::AG, 'notes' => 'Test order', ]); $response->assertCreated() ->assertJsonStructure(['data' => ['order_id']]); // Verify order created $this->assertDatabaseHas('orders', [ 'user_id' => $this->user->id, 'customer_name' => 'John Doe', 'notes' => 'Test order', ]); // Verify cart cleared $this->assertDatabaseMissing('cart_items', [ 'user_id' => $this->user->id, ]); // Verify stock reduced $this->assertEquals(8, $product->fresh()->stock); }); test('cannot place order with empty cart', function () { // Ensure cart is empty $this->user->carts()->delete(); // Mock PaymentType PaymentType::create([ 'code' => 'online', // unique code 'name' => ['en' => 'Online'], 'tax' => 0, 'is_enabled' => true, ]); $paymentTypeId = PaymentType::where('code', 'online')->first()->id; $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->postJson('/api/v1/orders', [ 'customer_name' => 'John Doe', 'customer_phone' => 61929248, 'customer_address' => '123 Main St', 'shipping_method' => OrderShipping::STANDART, 'payment_type_id' => $paymentTypeId, 'region' => Region::AG, ]); // The validation 'user_without_product_in_cart' should fail $response->assertStatus(422) ->assertJsonValidationErrors(['user_without_product_in_cart']); }); test('order validation fails with invalid data', function () { // Add item to cart to pass that check $product = Product::create(['name' => 'P', 'slug' => 'p', 'stock' => 1]); CartItem::create(['user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 1]); $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->postJson('/api/v1/orders', [ 'customer_name' => '', // Required 'shipping_method' => 'invalid_method', // Invalid enum ]); $response->assertStatus(422) ->assertJsonValidationErrors(['customer_name', 'shipping_method']); }); test('can show specific order', function () { $order = new Order; $order->forceFill([ 'user_id' => $this->user->id, 'number' => 'ORD-SHOW', 'customer_name' => 'John Doe', 'customer_phone' => 61929248, 'customer_address' => 'Address', 'shipping_method' => OrderShipping::STANDART, 'shipping_price' => 20, 'payment_type_id' => 1, 'region' => Region::AG, 'delivery_at' => now(), 'status' => OrderStatus::PENDING, ]); $order->save(); $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->getJson("/api/v1/orders/{$order->id}"); $response->assertOk() ->assertJsonPath('data.id', $order->id) ->assertJsonPath('data.number', 'ORD-SHOW'); }); test('can delete order (if allowed)', function () { // Note: The controller destroy method is basically empty: return response()->rest(); // But the route exists. Let's test it returns 200 at least. $order = new Order; $order->forceFill([ 'user_id' => $this->user->id, 'number' => 'ORD-DEL', 'customer_name' => 'John Doe', 'customer_phone' => 61929248, 'customer_address' => 'Address', 'shipping_method' => OrderShipping::STANDART, 'shipping_price' => 20, 'payment_type_id' => 1, 'region' => Region::AG, 'delivery_at' => now(), 'status' => OrderStatus::PENDING, ]); $order->save(); $response = $this->actingAs($this->user, 'sanctum') ->withHeaders(['Api-Token' => 'test-token']) ->deleteJson("/api/v1/orders/{$order->id}"); $response->assertOk(); $this->assertSoftDeleted('orders', [ 'id' => $order->id, ]); });