Deposit Payment Successful!
-Your deposit payment has been received and processed successfully.
- - -diff --git a/app/Http/Controllers/CartController.php b/app/Http/Controllers/CartController.php index 6535acd..979f539 100644 --- a/app/Http/Controllers/CartController.php +++ b/app/Http/Controllers/CartController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\Product; +use App\Services\ShippingService; use Illuminate\Http\Request; class CartController extends Controller @@ -30,30 +31,36 @@ class CartController extends Controller $product = Product::find($productId); if ($product) { $quantity = is_array($cartItem) ? ($cartItem['quantity'] ?? 1) : $cartItem; + $isSample = is_array($cartItem) ? ($cartItem['is_sample'] ?? false) : false; $stockCost = 0; $stock = null; - // Get print stock if available - if ($printStockId) { - $stock = $product->printStocks()->find($printStockId); - if ($stock) { - $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; - } - } - - // Calculate price based on stock cost only (no base design cost) - $basePrice = $stockCost; - - if ($type === 'wallpaper') { - $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; - $itemTotal = $basePrice * $length * $quantity; - } elseif ($type === 'mural') { - $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; - $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; - $m2 = $width * $height; - $itemTotal = $basePrice * $m2 * $quantity; + // For samples, use fixed sample cost + if ($isSample) { + $itemTotal = ShippingService::getSampleCost() * $quantity; } else { - $itemTotal = $basePrice * $quantity; + // Get print stock if available + if ($printStockId) { + $stock = $product->printStocks()->find($printStockId); + if ($stock) { + $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; + } + } + + // Calculate price based on stock cost only (no base design cost) + $basePrice = $stockCost; + + if ($type === 'wallpaper') { + $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; + $itemTotal = $basePrice * $length * $quantity; + } elseif ($type === 'mural') { + $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; + $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; + $m2 = $width * $height; + $itemTotal = $basePrice * $m2 * $quantity; + } else { + $itemTotal = $basePrice * $quantity; + } } $total += $itemTotal; @@ -63,6 +70,7 @@ class CartController extends Controller 'stock' => $stock, 'quantity' => $quantity, 'type' => $type, + 'is_sample' => $isSample, 'length' => is_array($cartItem) ? ($cartItem['length'] ?? null) : null, 'width' => is_array($cartItem) ? ($cartItem['width'] ?? null) : null, 'height' => is_array($cartItem) ? ($cartItem['height'] ?? null) : null, @@ -72,9 +80,14 @@ class CartController extends Controller } } + $shippingFee = ShippingService::calculateShippingFee($total); + $shippingLabel = ShippingService::getShippingLabel($total); + return view('cart', [ 'items' => $items, 'total' => $total, + 'shippingFee' => $shippingFee, + 'shippingLabel' => $shippingLabel, 'itemCount' => count($cart) ]); } @@ -151,4 +164,43 @@ class CartController extends Controller session()->forget('cart'); return redirect()->back()->with('success', 'Cart cleared!'); } + + /** + * Order a sample of a product + */ + public function orderSample(Request $request, Product $product) + { + $request->validate([ + 'print_stock_id' => 'required|exists:print_stocks,id', + ]); + + // Create a sample cart item + $cart = session()->get('cart', []); + $sampleSize = 0.3; + + $cartItemKey = $product->id . '_sample_' . $request->input('print_stock_id') . '_' . uniqid(); + + $cartItem = [ + 'product_id' => $product->id, + 'print_stock_id' => $request->input('print_stock_id'), + 'quantity' => 1, + 'type' => $product->type, + 'is_sample' => true, + ]; + + if ($product->type === 'wallpaper') { + // For wallpaper samples: use 30cm length (0.3m) with default width + $cartItem['width'] = 0.3; + $cartItem['height'] = 0.3; + } elseif ($product->type === 'mural') { + // For mural samples: use 6cm × 5cm (0.06m × 0.05m = 0.003m²) + $cartItem['width'] = 0.3; + $cartItem['height'] = 0.3; + } + + $cart[$cartItemKey] = $cartItem; + session()->put('cart', $cart); + + return redirect()->route('cart')->with('success', 'Sample added to cart!'); + } } diff --git a/app/Http/Controllers/OrderController.php b/app/Http/Controllers/OrderController.php index 1a033e2..d432b73 100644 --- a/app/Http/Controllers/OrderController.php +++ b/app/Http/Controllers/OrderController.php @@ -7,6 +7,7 @@ use App\Models\Order; use App\Models\OrderItem; use App\Models\Product; use App\Models\PrintStock; +use App\Services\ShippingService; use Illuminate\Http\Request; class OrderController extends Controller @@ -28,49 +29,59 @@ class OrderController extends Controller $productId = $cartItem['product_id'] ?? null; $type = $cartItem['type'] ?? 'wallpaper'; $printStockId = $cartItem['print_stock_id'] ?? null; + $isSample = $cartItem['is_sample'] ?? false; } else { $productId = $itemKey; $type = 'wallpaper'; $printStockId = null; + $isSample = false; } if ($productId) { $product = Product::find($productId); if ($product) { $quantity = is_array($cartItem) ? ($cartItem['quantity'] ?? 1) : $cartItem; - $stockCost = 0; - $stock = null; - // Get print stock if available - if ($printStockId) { - $stock = $product->printStocks()->find($printStockId); - if ($stock) { - $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; - } - } - - // Calculate price based on stock cost only (no base design cost) - $basePrice = $stockCost; - - if ($type === 'wallpaper') { - $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; - $subtotal = $basePrice * $length * $quantity; - } elseif ($type === 'mural') { - $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; - $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; - $m2 = $width * $height; - $subtotal = $basePrice * $m2 * $quantity; + // For samples, use fixed sample cost + if ($isSample) { + $subtotal = ShippingService::getSampleCost() * $quantity; } else { - $subtotal = $basePrice * $quantity; + $stockCost = 0; + $stock = null; + + // Get print stock if available + if ($printStockId) { + $stock = $product->printStocks()->find($printStockId); + if ($stock) { + $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; + } + } + + // Calculate price based on stock cost only (no base design cost) + $basePrice = $stockCost; + + if ($type === 'wallpaper') { + $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; + $subtotal = $basePrice * $length * $quantity; + } elseif ($type === 'mural') { + $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; + $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; + $m2 = $width * $height; + $subtotal = $basePrice * $m2 * $quantity; + } else { + $subtotal = $basePrice * $quantity; + } + $stock = null; } $total += $subtotal; $items[] = [ 'key' => $itemKey, 'product' => $product, - 'stock' => $stock, + 'stock' => isset($stock) ? $stock : null, 'quantity' => $quantity, 'type' => $type, + 'is_sample' => $isSample, 'length' => is_array($cartItem) ? ($cartItem['length'] ?? null) : null, 'width' => is_array($cartItem) ? ($cartItem['width'] ?? null) : null, 'height' => is_array($cartItem) ? ($cartItem['height'] ?? null) : null, @@ -80,9 +91,16 @@ class OrderController extends Controller } } + $shippingFee = ShippingService::calculateShippingFee($total); + $shippingLabel = ShippingService::getShippingLabel($total); + $grandTotal = $total + $shippingFee; + return view('checkout', [ 'items' => $items, 'total' => $total, + 'shippingFee' => $shippingFee, + 'shippingLabel' => $shippingLabel, + 'grandTotal' => $grandTotal, 'itemCount' => count($cart) ]); } @@ -114,11 +132,13 @@ class OrderController extends Controller $quantity = $cartItem['quantity'] ?? 1; $type = $cartItem['type'] ?? 'wallpaper'; $printStockId = $cartItem['print_stock_id'] ?? null; + $isSample = $cartItem['is_sample'] ?? false; } else { $productId = $itemKey; $quantity = $cartItem; $type = 'wallpaper'; $printStockId = null; + $isSample = false; } $product = Product::find($productId); @@ -130,30 +150,36 @@ class OrderController extends Controller return redirect()->route('cart')->with('error', "Insufficient stock for {$product->name}"); } - $stockCost = 0; - $stock = null; - - // Get print stock if available - if ($printStockId) { - $stock = $product->printStocks()->find($printStockId); - if ($stock) { - $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; - } - } - - // Calculate price based on stock cost only (no base design cost) - $basePrice = $stockCost; - - if ($type === 'wallpaper') { - $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; - $subtotal = $basePrice * $length * $quantity; - } elseif ($type === 'mural') { - $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; - $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; - $m2 = $width * $height; - $subtotal = $basePrice * $m2 * $quantity; + // For samples, use fixed sample cost + if ($isSample) { + $subtotal = ShippingService::getSampleCost() * $quantity; + $stockCost = ShippingService::getSampleCost(); } else { - $subtotal = $basePrice * $quantity; + $stockCost = 0; + $stock = null; + + // Get print stock if available + if ($printStockId) { + $stock = $product->printStocks()->find($printStockId); + if ($stock) { + $stockCost = ($type === 'wallpaper') ? $stock->cost_per_meter : $stock->cost_per_m2; + } + } + + // Calculate price based on stock cost only (no base design cost) + $basePrice = $stockCost; + + if ($type === 'wallpaper') { + $length = is_array($cartItem) ? ($cartItem['length'] ?? 0) : 0; + $subtotal = $basePrice * $length * $quantity; + } elseif ($type === 'mural') { + $width = is_array($cartItem) ? ($cartItem['width'] ?? 0) : 0; + $height = is_array($cartItem) ? ($cartItem['height'] ?? 0) : 0; + $m2 = $width * $height; + $subtotal = $basePrice * $m2 * $quantity; + } else { + $subtotal = $basePrice * $quantity; + } } $total += $subtotal; @@ -164,6 +190,7 @@ class OrderController extends Controller 'stock_cost' => $stockCost, 'print_stock_id' => $printStockId, 'type' => $type, + 'is_sample' => $isSample, 'length' => is_array($cartItem) ? ($cartItem['length'] ?? null) : null, 'width' => is_array($cartItem) ? ($cartItem['width'] ?? null) : null, 'height' => is_array($cartItem) ? ($cartItem['height'] ?? null) : null, @@ -171,6 +198,9 @@ class OrderController extends Controller ]; } + // Calculate shipping + $shippingFee = ShippingService::calculateShippingFee($total); + // Create order $orderNumber = 'ORD-' . date('Ymd') . '-' . strtoupper(uniqid()); @@ -178,6 +208,7 @@ class OrderController extends Controller 'user_id' => auth()->check() ? auth()->id() : null, 'order_number' => $orderNumber, 'total' => $total, + 'shipping_fee' => $shippingFee, 'status' => 'pending', 'payment_method' => 'yoco', 'payment_status' => 'pending', @@ -204,6 +235,7 @@ class OrderController extends Controller 'price' => $data['price'], 'print_stock_id' => $data['print_stock_id'], 'type' => $data['type'], + 'is_sample' => $data['is_sample'], 'length' => $data['length'], 'width' => $data['width'], 'height' => $data['height'] @@ -260,7 +292,7 @@ class OrderController extends Controller : 'https://payments.yoco.com/api/checkouts'; $checkoutData = [ - 'amount' => (int)($order->total * 100), // Amount in cents + 'amount' => (int)(($order->total + $order->shipping_fee) * 100), // Amount in cents, including shipping 'currency' => 'ZAR', 'successUrl' => route('yoco-success', ['order' => $order->uuid]), 'cancelUrl' => route('yoco-cancel', ['order' => $order->uuid]), diff --git a/app/Models/Order.php b/app/Models/Order.php index bf82e09..6b54d95 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -17,6 +17,7 @@ class Order extends Model 'user_id', 'order_number', 'total', + 'shipping_fee', 'status', 'payment_method', 'payment_status', diff --git a/app/Models/OrderItem.php b/app/Models/OrderItem.php index 34e80d3..4878578 100644 --- a/app/Models/OrderItem.php +++ b/app/Models/OrderItem.php @@ -13,6 +13,7 @@ class OrderItem extends Model 'quantity', 'price', 'type', + 'is_sample', 'length', 'width', 'height' diff --git a/app/Services/ShippingService.php b/app/Services/ShippingService.php new file mode 100644 index 0000000..0c90285 --- /dev/null +++ b/app/Services/ShippingService.php @@ -0,0 +1,45 @@ += $freeShippingThreshold) { + return 0; + } + + $localShipping = AppSetting::get('local_shipping', 200); + return $localShipping; + } + + /** + * Get shipping label based on order subtotal + */ + public static function getShippingLabel(float $subtotal): string + { + $freeShippingThreshold = AppSetting::get('free_shipping_threshold', 2000); + + if ($subtotal >= $freeShippingThreshold) { + return 'Free Shipping'; + } + + return 'Local Delivery'; + } + + /** + * Get sample cost + */ + public static function getSampleCost(): float + { + return AppSetting::get('sample_cost', 80); + } +} diff --git a/database/migrations/2025_12_30_add_is_sample_to_order_items_table.php b/database/migrations/2025_12_30_add_is_sample_to_order_items_table.php new file mode 100644 index 0000000..32cc961 --- /dev/null +++ b/database/migrations/2025_12_30_add_is_sample_to_order_items_table.php @@ -0,0 +1,22 @@ +boolean('is_sample')->default(false)->after('type'); + }); + } + + public function down(): void + { + Schema::table('order_items', function (Blueprint $table) { + $table->dropColumn('is_sample'); + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_12_30_add_shipping_fee_to_orders_table.php b/database/migrations/2025_12_30_add_shipping_fee_to_orders_table.php new file mode 100644 index 0000000..fec0252 --- /dev/null +++ b/database/migrations/2025_12_30_add_shipping_fee_to_orders_table.php @@ -0,0 +1,22 @@ +decimal('shipping_fee', 10, 2)->default(0)->nullable()->after('total'); + }); + } + + public function down(): void + { + Schema::table('orders', function (Blueprint $table) { + $table->dropColumn('shipping_fee'); + }); + } +}; \ No newline at end of file diff --git a/resources/views/cart.blade.php b/resources/views/cart.blade.php index b39d7eb..67bdf3f 100644 --- a/resources/views/cart.blade.php +++ b/resources/views/cart.blade.php @@ -224,28 +224,34 @@ @endif
{{ $item['product']->category->name }}
@php $stockCost = 0; $stockUnit = $item['type'] === 'wallpaper' ? '/m' : '/m²'; - if ($item['stock']) { + if (!$item['is_sample'] && $item['stock']) { $stockCost = $item['type'] === 'wallpaper' ? $item['stock']->cost_per_meter : $item['stock']->cost_per_m2; } @endphp - @if($item['stock']) + @if($item['is_sample']) ++ Sample - Fixed Price: R{{ number_format(\App\Services\ShippingService::getSampleCost(), 2) }} +
+ @elseif($item['stock']){{ $item['stock']->name }}: R{{ number_format($stockCost, 2) }}{{ $stockUnit }}
@endif - @if($item['type'] === 'wallpaper') -Length: {{ $item['length'] }}m
- @elseif($item['type'] === 'mural') -Dimensions: {{ $item['width'] }}m × {{ $item['height'] }}m ({{ number_format($item['width'] * $item['height'], 2) }}m²)
+ @if(!$item['is_sample']) + @if($item['type'] === 'wallpaper') +Length: {{ $item['length'] }}m
+ @elseif($item['type'] === 'mural') +Dimensions: {{ $item['width'] }}m × {{ $item['height'] }}m ({{ number_format($item['width'] * $item['height'], 2) }}m²)
+ @endif @endifSubtotal: R{{ number_format($item['subtotal'], 2) }}
@@ -277,20 +283,14 @@ Subtotal: R{{ number_format($total, 2) }}Showing all designs
+No products available
+ ++ Schedule a free consultation with our design experts. We'll help you find the perfect wallpaper for your space. +
+ +Your deposit payment has been received and processed successfully.
- - -category->name); ?>
cost_per_meter : $item['stock']->cost_per_m2; } ?> - + ++ Sample - Fixed Price: R +
+name); ?>: R
- -Length: m
- -Dimensions: m × m (m²)
+ + +Length: m
+ +Dimensions: m × m (m²)
+Subtotal: R
@@ -279,20 +285,14 @@ Subtotal: R