/
itp_practice
/
itp_backend
Обзор
Документация
Войти
/
itp_practice
/
itp_backend
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
app/Services/OrderService.php
231 строка
7 KB
vivanenko
fix taps and others structure
27 май 2025, 18:06
27 май 2025, 18:06
8cdc7d9
Код
Авторство
О чём код?
<?php namespace App\Services; use App\Models\Cart; use App\Models\Coupon; use App\Models\Order; use App\Models\OrderStatus; use App\Models\Transaction; use App\Models\User; use App\Services\PaymentGatewayManagerService; use Illuminate\Database\Eloquent\Collection; /** * Сервис для управления заказами * Реализует бизнес-логику создания и обработки заказов */ class OrderService { public function __construct( private readonly CartService $cartService, private readonly PaymentGatewayManagerService $paymentGatewayManager ) {} /** * Create order from user's cart */ public function createOrderFromCart( int $userId, string $paymentGateway, array $orderData = [], ?string $couponCode = null ): array { $user = User::find($userId); if (!$user) { throw new \InvalidArgumentException('User not found'); } $checkoutData = $this->cartService->prepareCartForCheckout($userId); $cart = $checkoutData['cart']; // Apply coupon if provided $couponDiscount = 0; $couponUsage = null; if ($couponCode) { $coupon = Coupon::findValidByCode($couponCode); if ($coupon && $coupon->canBeUsedByUser($userId)) { $couponDiscount = $coupon->calculateDiscount($checkoutData['total_amount']); } } // Calculate final amounts $finalTotal = $checkoutData['total_amount'] - $couponDiscount; // Create order $order = Order::createFromCart($cart, array_merge([ 'payment_gateway' => $paymentGateway, 'discount_amount' => $checkoutData['quantity_discount'] + $couponDiscount, 'total_amount' => $finalTotal, ], $orderData)); // Apply coupon if used if ($couponCode && isset($coupon) && $couponDiscount > 0) { $couponUsage = $coupon->applyToOrder($userId, $order->id, $couponDiscount); } // Create payment transaction $paymentData = $this->createPaymentTransaction($order, $paymentGateway); return [ 'order' => $order->load(['items.itemable', 'status', 'couponUsages']), 'payment' => $paymentData, 'coupon_usage' => $couponUsage, ]; } /** * Get user orders */ public function getUserOrders(int $userId, int $page = 1, int $perPage = 15): array { $user = User::find($userId); if (!$user) { throw new \InvalidArgumentException('User not found'); } $orders = Order::where('user_id', $userId) ->with(['items.itemable', 'status', 'transactions', 'couponUsages']) ->orderBy('created_at', 'desc') ->paginate($perPage, ['*'], 'page', $page); return [ 'orders' => $orders->items(), 'meta' => [ 'current_page' => $orders->currentPage(), 'per_page' => $orders->perPage(), 'total' => $orders->total(), 'last_page' => $orders->lastPage(), ], ]; } /** * Get order by ID */ public function getOrder(int $orderId, int $userId): Order { $order = Order::where('id', $orderId) ->where('user_id', $userId) ->with(['items.itemable', 'status', 'transactions', 'couponUsages']) ->first(); if (!$order) { throw new \InvalidArgumentException('Order not found'); } return $order; } /** * Cancel order */ public function cancelOrder(int $orderId, int $userId): bool { $order = $this->getOrder($orderId, $userId); if ($order->isFinal()) { throw new \InvalidArgumentException('Cannot cancel order in final status'); } $order->markAsCancelled()->save(); // Cancel any pending transactions $order->transactions() ->where('status', Transaction::STATUS_PENDING) ->update([ 'status' => Transaction::STATUS_CANCELLED, 'processed_at' => now(), ]); return true; } /** * Process payment callback */ public function processPaymentCallback(array $callbackData): bool { $transaction = Transaction::where('transaction_id', $callbackData['transaction_id']) ->where('gateway', $callbackData['gateway']) ->first(); if (!$transaction) { throw new \InvalidArgumentException('Transaction not found'); } $order = $transaction->order; // Verify payment with gateway $gateway = $this->paymentGatewayManager->getGateway($callbackData['gateway']); $isValid = $gateway->verifyCallback($callbackData); if (!$isValid) { $transaction->markAsFailed()->save(); $order->markAsFailed()->save(); return false; } // Update transaction and order status $transaction->markAsCompleted()->save(); $order->markAsPaid()->save(); return true; } /** * Get order statistics for user */ public function getOrderStats(int $userId): array { $user = User::find($userId); if (!$user) { throw new \InvalidArgumentException('User not found'); } $stats = Order::where('user_id', $userId) ->selectRaw(' COUNT(*) as total_orders, SUM(CASE WHEN status_code = ? THEN 1 ELSE 0 END) as paid_orders, SUM(CASE WHEN status_code = ? THEN total_amount ELSE 0 END) as total_spent, AVG(CASE WHEN status_code = ? THEN total_amount ELSE NULL END) as avg_order_value ', [OrderStatus::PAID, OrderStatus::PAID, OrderStatus::PAID]) ->first(); return [ 'total_orders' => $stats->total_orders ?? 0, 'paid_orders' => $stats->paid_orders ?? 0, 'total_spent' => $stats->total_spent ?? 0, 'avg_order_value' => $stats->avg_order_value ?? 0, ]; } /** * Create payment transaction for order */ private function createPaymentTransaction(Order $order, string $gateway): array { $paymentGateway = $this->paymentGatewayManager->getGateway($gateway); $transactionId = $paymentGateway->generateTransactionId($order); $transaction = Transaction::create([ 'order_id' => $order->id, 'gateway' => $gateway, 'transaction_id' => $transactionId, 'amount' => $order->total_amount, 'currency' => $order->currency, 'status' => Transaction::STATUS_PENDING, ]); $paymentUrl = $paymentGateway->createPaymentUrl($order, $transaction); return [ 'transaction_id' => $transaction->transaction_id, 'payment_url' => $paymentUrl, 'gateway' => $gateway, 'amount' => $order->total_amount, 'currency' => $order->currency, ]; } }