diff --git a/app/Http/Controllers/CustomOrderController.php b/app/Http/Controllers/CustomOrderController.php index 3c01ef8..5b052a0 100644 --- a/app/Http/Controllers/CustomOrderController.php +++ b/app/Http/Controllers/CustomOrderController.php @@ -164,36 +164,58 @@ class CustomOrderController extends Controller */ public function depositPayment(Request $request) { + Log::info('Deposit payment initiated', [ + 'request_data' => $request->all(), + 'user_id' => auth()->id(), + ]); $validated = $request->validate([ 'custom_order_id' => 'required|exists:custom_orders,id', ]); + Log::info('Deposit payment validation passed', $validated); $customOrder = CustomOrder::findOrFail($validated['custom_order_id']); // Check authorization if ($customOrder->user_id !== auth()->id()) { + Log::warning('Unauthorized deposit payment attempt', [ + 'custom_order_id' => $customOrder->id, + 'user_id' => auth()->id(), + ]); abort(403); } // Check if already paid if ($customOrder->deposit_status === 'paid') { + Log::info('Deposit already paid for custom order', [ + 'custom_order_id' => $customOrder->id, + ]); return redirect()->route('custom-orders.show', $customOrder) ->with('info', 'Deposit already paid for this order.'); } // Initiate Yoco payment for deposit + Log::info('Initiating Yoco payment for custom order deposit', [ + 'custom_order_id' => $customOrder->id, + 'deposit_amount' => $customOrder->deposit_amount, + ]); $yocoResponse = $this->initiateYocoPayment( amount: (int)($customOrder->deposit_amount * 100), // Convert to cents - orderId: $customOrder->uuid, + customOrder: $customOrder, orderType: 'custom_deposit', - description: "Deposit for Custom {$customOrder->type} Order #{$customOrder->order_number}" + description: "Deposit for Order #{$customOrder->order_number}" ); if (!$yocoResponse) { + Log::error('Failed to initiate Yoco payment for custom order deposit', [ + 'custom_order_id' => $customOrder->id, + ]); return redirect()->route('custom-orders.show', $customOrder) ->with('error', 'Failed to initiate payment. Please try again.'); } - + Log::info('Yoco payment initiated successfully for custom order deposit', [ + 'custom_order_id' => $customOrder->id, + 'checkout_url' => $yocoResponse['checkout_url'], + ]); return redirect($yocoResponse['checkout_url']); } @@ -207,11 +229,11 @@ class CustomOrderController extends Controller abort(403); } - // Update order status - $customOrder->update([ - 'deposit_status' => 'paid', - 'status' => 'submitted', - ]); + // // Update order status + // $customOrder->update([ + // 'deposit_status' => 'paid', + // 'status' => 'submitted', + // ]); return view('custom-orders.deposit-success', [ 'customOrder' => $customOrder, @@ -250,67 +272,143 @@ class CustomOrderController extends Controller /** * Initiate Yoco payment */ - private function initiateYocoPayment($amount, $orderId, $orderType, $description) + private function initiateYocoPayment($amount, $customOrder, $orderType, $description) { - $yocoSecret = config('services.yoco.secret_key'); + + Log::info('Initiating Yoco payment', [ + 'order_id' => $customOrder->uuid, + 'order_type' => $orderType, + 'amount' => $amount, + 'description' => $description, + ]); - if (!$yocoSecret) { + if (!$customOrder) { + Log::error('Custom order not found for Yoco payment', [ + 'order_id' => $customOrder->uuid ?? 'unknown', + ]); + return null; + } + Log::info('Custom order found for Yoco payment', [ + 'order_id' => $customOrder->uuid, + 'custom_order_data' => $customOrder->toArray(), + ]); + // Get configuration + $secretKey = config('services.yoco.secret_key'); + $mode = config('services.yoco.mode'); + + Log::info('Yoco configuration', [ + 'mode' => $mode, + 'secret_key_set' => !empty($secretKey) && $secretKey !== 'sk_test_your_key_here', + ]); + + // Check if API key is configured + if (empty($secretKey) || $secretKey === 'sk_test_your_key_here') { Log::error('Yoco secret key not configured'); return null; } - - $payload = [ + + $baseUrl = $mode === 'live' + ? 'https://payments.yoco.com/api/checkouts' + : 'https://payments.yoco.com/api/checkouts'; + + $checkoutData = [ 'amount' => $amount, 'currency' => 'ZAR', - 'successUrl' => route('yoco-custom-deposit-success', ['customOrder' => $orderId]), - 'failureUrl' => route('custom-orders.show', ['customOrder' => $orderId]), - 'cancelUrl' => route('custom-orders.show', ['customOrder' => $orderId]), + 'successUrl' => route('yoco-custom-deposit-success', ['customOrder' => $customOrder->uuid]), + 'cancelUrl' => route('custom-orders.show', ['customOrder' => $customOrder->uuid]), + 'failureUrl' => route('custom-orders.show', ['customOrder' => $customOrder->uuid]), 'metadata' => [ - 'order_uuid' => $orderId, + 'order_uuid' => $customOrder->uuid, 'order_type' => $orderType, - ], - 'description' => $description, + 'site' => 'additional_design', + 'description' => $description + ] ]; + Log::info('Yoco checkout data prepared', [ + 'order_id' => $customOrder->uuid, + 'checkout_data' => $checkoutData, + ]); + + // Make API request to Yoco + try { - Log::info('Initiating Yoco payment', [ - 'amount' => $amount, - 'orderId' => $orderId, - 'description' => $description - ]); - $response = Http::withHeaders([ - 'Authorization' => 'Bearer ' . $yocoSecret, + 'Authorization' => 'Bearer ' . $secretKey, 'Content-Type' => 'application/json', - ])->post('https://payments.yoco.com/api/checkouts', $payload); - - Log::info('Yoco API response', [ - 'status' => $response->status(), - 'body' => $response->body() - ]); - + ])->post($baseUrl, $checkoutData); + if ($response->successful()) { - $data = $response->json(); - Log::info('Yoco payment success', [ - 'checkout_url' => $data['redirectUrl'] ?? 'N/A', - 'checkout_id' => $data['id'] ?? 'N/A' + $checkout = $response->json(); + + $checkoutId = $checkout['id'] ?? null; + $redirectUrl = $checkout['redirectUrl'] ?? null; + + Log::info('Yoco checkout created for custom order', [ + 'order_uuid' => $customOrder->uuid, + 'checkout_id' => $checkoutId, + 'redirect_url' => $redirectUrl, ]); + + if (!$checkoutId || !$redirectUrl) { + Log::error('Invalid Yoco checkout response: missing id or redirectUrl', [ + 'order_uuid' => $customOrder->uuid, + 'response' => $checkout, + ]); + throw new \Exception('Invalid Yoco checkout response: missing id or redirectUrl'); + } + + // Persist checkout info to database + try { + $customOrder->update([ + 'yoco_checkout_id' => $checkoutId, + 'yoco_redirect_url' => $redirectUrl, + 'yoco_checkout_response' => json_encode($checkout), + ]); + + // Reload the model to verify update + $customOrder->refresh(); + + if ($customOrder->yoco_checkout_id) { + Log::info('Yoco checkout info saved successfully for custom order', [ + 'order_uuid' => $customOrder->uuid, + 'yoco_checkout_id' => $customOrder->yoco_checkout_id, + ]); + } else { + Log::warning('Yoco checkout ID not saved after update for custom order', [ + 'order_uuid' => $customOrder->uuid, + 'order_data' => $customOrder->toArray(), + ]); + } + } catch (\Exception $dbException) { + Log::error('Database error while saving Yoco checkout info for custom order', [ + 'order_uuid' => $customOrder->uuid, + 'error_message' => $dbException->getMessage(), + 'error_code' => $dbException->getCode(), + 'checkout_id' => $checkoutId, + 'redirect_url' => $redirectUrl, + ]); + throw $dbException; + } + return [ - 'checkout_url' => $data['redirectUrl'], - 'checkout_id' => $data['id'], + 'checkout_url' => $redirectUrl, + 'checkout_id' => $checkoutId, ]; } else { - Log::error('Yoco payment API error', [ + Log::error('Yoco API Error for custom order', [ + 'order_uuid' => $customOrder->uuid, 'status' => $response->status(), 'body' => $response->body() ]); + return null; } } catch (\Exception $e) { - Log::error('Yoco payment exception: ' . $e->getMessage(), [ - 'trace' => $e->getTraceAsString() + Log::error('Yoco Payment Exception for custom order', [ + 'order_uuid' => $customOrder->uuid, + 'message' => $e->getMessage() ]); + return null; } - - return null; } } diff --git a/app/Http/Controllers/OrderController.php b/app/Http/Controllers/OrderController.php index 2f8cd66..1a033e2 100644 --- a/app/Http/Controllers/OrderController.php +++ b/app/Http/Controllers/OrderController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\CustomOrder; use App\Models\Order; use App\Models\OrderItem; use App\Models\Product; @@ -267,6 +268,7 @@ class OrderController extends Controller 'metadata' => [ 'order_uuid' => $order->uuid, 'order_number' => $order->order_number, + 'order_type' => 'standard', 'site' => 'additional_design', ], ]; @@ -477,6 +479,7 @@ class OrderController extends Controller $metadata = $payload['metadata'] ?? []; $orderUuid = $metadata['order_uuid'] ?? null; + $orderType = $metadata['order_type'] ?? null; $site = $metadata['site'] ?? null; $paymentId = $payload['id'] ?? null; $status = $payload['status'] ?? null; @@ -484,6 +487,7 @@ class OrderController extends Controller \Log::info('Yoco Webhook: Payload extracted', [ 'type' => $type, 'site' => $site, + 'order_type' => $orderType, 'order_uuid' => $orderUuid, 'payment_id' => $paymentId, 'status' => $status, @@ -506,49 +510,107 @@ class OrderController extends Controller return response()->json(['error' => 'Invalid payload'], 400); } - // 7. Update Payment State - $order = Order::where('uuid', $orderUuid)->first(); + // 7. Update Payment State where orderType is 'standard' + if ($orderType === 'standard') { - if (!$order) { - \Log::warning('Yoco Webhook: Order not found', ['order_uuid' => $orderUuid]); - return response()->json(['error' => 'Order not found'], 404); - } - - if ($status === 'succeeded') { - \Log::info('Yoco Webhook: Processing successful payment', [ - 'order_uuid' => $orderUuid, - 'payment_id' => $paymentId, - ]); + $order = Order::where('uuid', $orderUuid)->first(); - if ($order->payment_status !== 'paid') { - $order->update([ - 'payment_status' => 'paid', - 'status' => 'processing', - 'yoco_checkout_response' => json_encode($payload), + if (!$order) { + \Log::warning('Yoco Webhook: Order not found', ['order_uuid' => $orderUuid]); + return response()->json(['error' => 'Order not found'], 404); + } + + if ($status === 'succeeded') { + \Log::info('Yoco Webhook: Processing successful payment', [ + 'order_uuid' => $orderUuid, + 'payment_id' => $paymentId, ]); - // Reduce stock - foreach ($order->items as $item) { - $product = $item->product; - $product->stock -= $item->quantity; - $product->save(); + if ($order->payment_status !== 'paid') { + $order->update([ + 'payment_status' => 'paid', + 'status' => 'processing', + 'yoco_checkout_response' => json_encode($payload), + ]); + + // Reduce stock + foreach ($order->items as $item) { + $product = $item->product; + $product->stock -= $item->quantity; + $product->save(); + } + + \Log::info('Yoco Webhook: Order updated for successful payment', [ + 'order_uuid' => $orderUuid, + 'order_id' => $order->id, + ]); } - - \Log::info('Yoco Webhook: Order updated for successful payment', [ + } elseif ($status === 'failed' || $status === 'cancelled') { + \Log::info('Yoco Webhook: Processing failed/cancelled payment', [ 'order_uuid' => $orderUuid, - 'order_id' => $order->id, + 'payment_id' => $paymentId, + 'status' => $status, + ]); + + $order->update([ + 'payment_status' => 'failed', ]); } - } elseif ($status === 'failed' || $status === 'cancelled') { - \Log::info('Yoco Webhook: Processing failed/cancelled payment', [ - 'order_uuid' => $orderUuid, - 'payment_id' => $paymentId, - 'status' => $status, - ]); + } elseif ($orderType === 'custom_deposit' || $orderType === 'custom_balance') { - $order->update([ - 'payment_status' => 'failed', - ]); + $order = CustomOrder::where('uuid', $orderUuid)->first(); + + if (!$order) { + \Log::warning('Yoco Webhook: Order not found', ['order_uuid' => $orderUuid]); + return response()->json(['error' => 'Order not found'], 404); + } + + if ($status === 'succeeded') { + \Log::info('Yoco Webhook: Processing successful payment', [ + 'order_uuid' => $orderUuid, + 'payment_id' => $paymentId, + 'order_type' => $orderType, + ]); + + if ($orderType === 'custom_deposit' && $order->deposit_status !== 'paid') { + $order->update([ + 'deposit_status' => 'paid', + 'status' => 'submitted', + 'yoco_checkout_response' => json_encode($payload), + ]); + + \Log::info('Yoco Webhook: Order updated for successful deposit payment', [ + 'order_uuid' => $orderUuid, + 'order_id' => $order->id, + 'order_type' => $orderType, + ]); + + } elseif ($orderType === 'custom_balance' && $order->balance_status !== 'paid') { + $order->update([ + 'balance_status' => 'paid', + 'status' => 'in production', + 'yoco_checkout_response' => json_encode($payload), + ]); + + \Log::info('Yoco Webhook: Order updated for successful balance payment', [ + 'order_uuid' => $orderUuid, + 'order_id' => $order->id, + 'order_type' => $orderType, + ]); + } + } elseif ($status === 'failed' || $status === 'cancelled') { + \Log::info('Yoco Webhook: Processing failed/cancelled payment', [ + 'order_uuid' => $orderUuid, + 'payment_id' => $paymentId, + 'status' => $status, + ]); + + if ($orderType === 'custom_deposit') { + $order->update(['deposit_status' => 'failed']); + } elseif ($orderType === 'custom_balance') { + $order->update(['balance_status' => 'failed']); + } + } } \Log::info('Yoco Webhook: Processed successfully', [ diff --git a/app/Models/CustomOrder.php b/app/Models/CustomOrder.php index c70372c..74b8138 100644 --- a/app/Models/CustomOrder.php +++ b/app/Models/CustomOrder.php @@ -23,6 +23,9 @@ class CustomOrder extends Model 'balance_amount', 'deposit_status', 'balance_status', + 'yoco_checkout_id', + 'yoco_redirect_url', + 'yoco_checkout_response', 'customer_brief', 'admin_notes', 'submitted_at', diff --git a/public/css/styles.css b/public/css/styles.css index 4b20791..49d8ae3 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -163,7 +163,8 @@ a:hover { header { background-color: var(--bg-primary); - padding: var(--spacing-md) 0; + /* backdrop-filter: blur(10px); */ + padding: var(--spacing-xs) 0; border-bottom: 1px solid var(--border-color); position: sticky; top: 0; @@ -306,6 +307,35 @@ nav a:hover { /* ===== CARDS ===== */ .card { + background-color: white; + padding: var(--spacing-lg); + border-radius: 20px; + border: 1px solid var(--border-color); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + margin-bottom: var(--spacing-lg); + transition: var(--transition); +} + +.card:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); +} + +.card--pink { + background-color: var(--accent-light); + padding: var(--spacing-lg); + border-radius: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + margin-bottom: var(--spacing-lg); + /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */ + transition: var(--transition); +} + +.card--pink:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); +} + +/* Product cards (with image on top) */ +.product-card { background-color: white; overflow: hidden; transition: var(--transition); @@ -313,7 +343,7 @@ nav a:hover { border-radius: 20px; } -.card:hover { +.product-card:hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); } diff --git a/resources/views/account/orders.blade.php b/resources/views/account/orders.blade.php index ea856d9..d3c66b8 100644 --- a/resources/views/account/orders.blade.php +++ b/resources/views/account/orders.blade.php @@ -50,10 +50,8 @@ } .table-container { - background: white; - border-radius: 8px; + border-radius: 20px; overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } table { @@ -114,10 +112,7 @@ } .empty-state { - background-color: var(--bg-secondary); - border-radius: 8px; - padding: var(--spacing-xl); - text-align: center; + border-radius: 20px; } .empty-state p { @@ -184,7 +179,7 @@
You haven't placed any standard orders yet.
Browse ProductsYou haven't created any custom orders yet.
Create Custom OrderContact us for assistance with your account or orders.
support@example.com diff --git a/resources/views/cart.blade.php b/resources/views/cart.blade.php index e75c215..b39d7eb 100644 --- a/resources/views/cart.blade.php +++ b/resources/views/cart.blade.php @@ -18,11 +18,7 @@ margin-bottom: 3rem; } - .cart-items { - background: white; - padding: 2rem; - border-radius: 8px; - } + .empty-cart { text-align: center; @@ -111,9 +107,6 @@ } .summary { - background: white; - padding: 2rem; - border-radius: 8px; height: fit-content; } @@ -221,7 +214,7 @@ @if(count($items) > 0)