From eaae8b9be98c6152b2b4fb510a696c676e7054de Mon Sep 17 00:00:00 2001 From: Nurmuhammet Allanov Date: Thu, 5 Feb 2026 01:29:10 +0500 Subject: [PATCH] Refactor order creation logic by introducing CreateOrderService and removing the create method from OrderRepository. Update ProductRepository with stricter type declarations and fix minor typos in comments. --- .../Controllers/Api/V1/OrderController.php | 5 +- .../Ecommerce/Order/OrderRepository.php | 49 +----------- .../Ecommerce/Product/ProductRepository.php | 22 ++++-- app/Services/Order/CreateOrderService.php | 62 +++++++++++++++ .../Services/Order/CreateOrderServiceTest.php | 76 +++++++++++++++++++ 5 files changed, 160 insertions(+), 54 deletions(-) create mode 100644 app/Services/Order/CreateOrderService.php create mode 100644 tests/Feature/Services/Order/CreateOrderServiceTest.php diff --git a/app/Http/Controllers/Api/V1/OrderController.php b/app/Http/Controllers/Api/V1/OrderController.php index 0f6f1eb..01c641e 100644 --- a/app/Http/Controllers/Api/V1/OrderController.php +++ b/app/Http/Controllers/Api/V1/OrderController.php @@ -7,6 +7,7 @@ use App\Http\Requests\CheckoutOrderRequest; use App\Http\Resources\Api\V1\Order\OrderIndexResource; use App\Models\Ecommerce\Product\Order\Order; use App\Repositories\Ecommerce\Order\OrderRepository; +use App\Services\Order\CreateOrderService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -35,9 +36,9 @@ class OrderController extends Controller /** * (*) Store order */ - public function store(CheckoutOrderRequest $request): JsonResponse + public function store(CheckoutOrderRequest $request, CreateOrderService $service): JsonResponse { - $order = (new OrderRepository($request->all()))->create(); + $order = $service->execute(auth()->user(), $request->validated()); $url = null; if ($request->payment_type_id == 3) { diff --git a/app/Repositories/Ecommerce/Order/OrderRepository.php b/app/Repositories/Ecommerce/Order/OrderRepository.php index 55e6b4c..72be193 100644 --- a/app/Repositories/Ecommerce/Order/OrderRepository.php +++ b/app/Repositories/Ecommerce/Order/OrderRepository.php @@ -1,58 +1,17 @@ data); - - auth()->user()->carts()->with(['product' => [ - 'media', - 'channels', - ]])->get()->each(function ($cart) use ($order) { - DB::table('order_items')->insert([ - 'product_name' => $cart->product->name, - 'product_id' => $cart->product_id, - 'order_id' => $order->id, - 'channel_id' => $cart->product->channels->first()?->id ?? tmpostChannel()->id, - 'quantity' => $cart->product_quantity, - 'unit_price_amount' => $cart->product->price_amount, - 'unit_cost_amount' => $cart->product->cost_amount, - 'created_at' => now(), - 'updated_at' => now(), - ]); - - $cart->product->update([ - 'stock' => $cart->product->stock - $cart->product_quantity, - ]); - }); - - auth()->user()->carts()->delete(); - - OrderCreated::dispatch($order); - - return $order; - } - /** * Available times + * + * @return array */ public static function availableTimes(): array { diff --git a/app/Repositories/Ecommerce/Product/ProductRepository.php b/app/Repositories/Ecommerce/Product/ProductRepository.php index d309646..00e0e0c 100644 --- a/app/Repositories/Ecommerce/Product/ProductRepository.php +++ b/app/Repositories/Ecommerce/Product/ProductRepository.php @@ -1,11 +1,15 @@ + * @var array */ protected array $with = []; @@ -54,6 +58,8 @@ class ProductRepository /** * Update query builder with resource relationship + * + * @param mixed $resource */ public function queryAsFromResource($resource): self { @@ -119,7 +125,7 @@ class ProductRepository public function applySearchQueries(): self { if (request()->filled('q')) { - $searcQuery = str_replace([ + $searchQuery = str_replace([ '\\', '(', ')', @@ -128,7 +134,7 @@ class ProductRepository ], '', request('q')); // Search by name - $this->queryBuilder->where('products.name', '~*', $searcQuery); + $this->queryBuilder->where('products.name', '~*', $searchQuery); } return $this; @@ -145,7 +151,7 @@ class ProductRepository } /** - * "Where IN" clouse + * "Where IN" clause */ public function whereIn(string $attribute, array $value): self { @@ -155,7 +161,7 @@ class ProductRepository } /** - * "where integer in raw" clouse + * "where integer in raw" clause */ public function whereIntegerInRaw(string $attribute, array $value): self { @@ -180,7 +186,7 @@ class ProductRepository /** * Get the results */ - public function get() + public function get(): Collection { $this->eagerLoadRelationships(); @@ -257,6 +263,8 @@ class ProductRepository /** * Ajax paginate + * + * @param mixed $products */ public static function ajaxPaginate($products): JsonResponse { diff --git a/app/Services/Order/CreateOrderService.php b/app/Services/Order/CreateOrderService.php new file mode 100644 index 0000000..b264376 --- /dev/null +++ b/app/Services/Order/CreateOrderService.php @@ -0,0 +1,62 @@ +carts() + ->with(['product' => function ($query) { + $query->with(['media', 'channels']); + }]) + ->get() + ->each(function ($cart) use ($order) { + // Create Order Item + DB::table('order_items')->insert([ + 'product_name' => $cart->product->name, + 'product_id' => $cart->product_id, + 'order_id' => $order->id, + 'channel_id' => $cart->product->channels->first()?->id ?? tmpostChannel()->id, + 'quantity' => $cart->product_quantity, + 'unit_price_amount' => $cart->product->price_amount, + 'unit_cost_amount' => $cart->product->cost_amount, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + // Update Stock + $cart->product->update([ + 'stock' => $cart->product->stock - $cart->product_quantity, + ]); + }); + + // 3. Clear User Cart + $user->carts()->delete(); + + // 4. Dispatch Event + OrderCreated::dispatch($order); + + return $order; + }); + } +} diff --git a/tests/Feature/Services/Order/CreateOrderServiceTest.php b/tests/Feature/Services/Order/CreateOrderServiceTest.php new file mode 100644 index 0000000..b051097 --- /dev/null +++ b/tests/Feature/Services/Order/CreateOrderServiceTest.php @@ -0,0 +1,76 @@ +create(); + $product = Product::factory()->create([ + 'stock' => 10, + 'price_amount' => 100, + 'cost_amount' => 50, + 'name' => 'Test Product' + ]); + + // Create Cart Item + Cart::factory()->create([ + 'user_id' => $user->id, + 'product_id' => $product->id, + 'product_quantity' => 2 + ]); + + $service = new CreateOrderService(); + $orderData = [ + 'user_id' => $user->id, + 'status' => 'pending', + 'total_amount' => 200 + ]; + + // 2. Act + $order = $service->execute($user, $orderData); + + // 3. Assert + + // Check Order Created + $this->assertDatabaseHas('orders', [ + 'id' => $order->id, + 'user_id' => $user->id, + 'total_amount' => 200 + ]); + + // Check Order Items Created + $this->assertDatabaseHas('order_items', [ + 'order_id' => $order->id, + 'product_id' => $product->id, + 'quantity' => 2, + 'product_name' => 'Test Product' + ]); + + // Check Stock Deducted (10 - 2 = 8) + $this->assertEquals(8, $product->fresh()->stock); + + // Check Cart Cleared + $this->assertDatabaseMissing('carts', [ + 'user_id' => $user->id + ]); + + // Check Event Dispatched + Event::assertDispatched(OrderCreated::class); + } +}