Jul 26, 2024
0
Level 1
Merge guest cart with user cart
<?php
namespace App\Services;
use App\Models\Cart;
use App\Models\ProductVariant;
use App\Models\Coupon;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Exception;
class CartService
{
protected $pricingService;
public function __construct(PricingService $pricingService)
{
$this->pricingService = $pricingService;
}
public function getCart($userId = null)
{
if (Auth::check()) {
// User is authenticated
$userId = Auth::id();
$cart = Cart::where('user_id', $userId)->firstOrCreate(['user_id' => $userId]);
// Check and merge guest cart if exists
$guestCartIdentifier = session('cart_identifier');
if ($guestCartIdentifier) {
$guestCart = Cart::where('cart_identifier', $guestCartIdentifier)->first();
if ($guestCart) {
$this->mergeGuestCart($guestCart, $cart); // Merge guest cart items into user's cart
session()->forget('cart_identifier'); // Remove guest cart identifier from session
$guestCart->delete(); // Optionally, delete the guest cart
}
}
return $cart;
} else {
// Guest user
$cartIdentifier = session('cart_identifier') ?: Cookie::get('cart_identifier');
if ($cartIdentifier) {
$cart = Cart::where('cart_identifier', $cartIdentifier)->first();
if (!$cart) {
// If no cart exists for the given identifier, create a new cart
$cart = Cart::create(['cart_identifier' => $cartIdentifier]);
}
} else {
// If no cart identifier found in session or cookie, create a new cart and identifier
$cart = Cart::create();
}
// Ensure the session and cookie are set with the cart identifier
session(['cart_identifier' => $cart->cart_identifier]);
Cookie::queue('cart_identifier', $cart->cart_identifier, 60 * 24 * 7); // 7 days
return $cart;
}
}
protected function mergeGuestCart($guestCart, $userCart)
{
// Ensure both carts are valid
if (!$guestCart || !$userCart) {
return;
}
foreach ($guestCart->items as $guestCartItem) {
$existingItem = $userCart->items()->where('variant_id', $guestCartItem->variant_id)->first();
if ($existingItem) {
// Item exists in user's cart, merge quantities and update price
$existingItem->quantity += $guestCartItem->quantity;
$existingItem->price = $guestCartItem->price; // Update the price if needed
$existingItem->save();
} else {
// Item does not exist in user's cart, move it
$guestCartItem->cart_id = $userCart->id;
$guestCartItem->save();
}
}
// apply coupons from guest cart to user cart
// #### THIS IS MY PROBLEM
foreach ($guestCart->coupons as $coupon) {
if (!$userCart->coupons->contains($coupon->id)) {
$userCart->coupons()->attach($coupon->id);
}
}
// #### END OF PROBLEM SECTION
// Apply cart rules after merging
// $this->updateCart($userCart); // DOING THIS DOESN'T WORK EITHER
$this->applyCartRules($userCart);
}
public function addItem($cart, $variantId, $quantity)
{
$variant = ProductVariant::find($variantId);
if (!$variant) {
throw new Exception('Variant not found.');
}
if ($variant->stock->quantity < $quantity) {
throw new Exception('Insufficient stock.');
}
$cartItem = $cart->items()->firstOrNew(['variant_id' => $variantId]);
$cartItem->quantity += $quantity;
$cartItem->variant_id = $variantId;
$cartItem->price = $variant->price;
$cartItem->save();
$this->updateCart($cart);
}
public function removeItem($cart, $variantId)
{
$variant = ProductVariant::find($variantId);
if (!$variant) {
throw new Exception('Variant not found.');
}
$cart->items()->where('variant_id', $variantId)->delete();
$this->updateCart($cart);
}
public function updateQuantity($cart, $variantId, $quantity)
{
$variant = ProductVariant::find($variantId);
if (!$variant) {
throw new Exception('Variant not found.');
}
$cartItem = $cart->items()->where('variant_id', $variantId)->first();
if ($cartItem) {
$cartItem->quantity = $quantity;
$cartItem->price = $variant->price; // Update the price
$cartItem->save();
$this->updateCart($cart);
}
}
public function applyCoupon(Cart $cart, $couponCode)
{
// Check if the coupon is already applied
if ($this->pricingService->hasCoupon($cart, $couponCode)) {
Session::flash('error', 'Coupon is already applied.');
return false;
}
// Find the coupon by code
$coupon = Coupon::where('code', $couponCode)->first();
// Check if the coupon exists
if (!$coupon) {
Session::flash('error', 'Invalid coupon code.');
return false;
}
// Check for minimum purchase amount
if ($cart->subtotal < $coupon->couponable->minimum_purchase_amount) {
Session::flash('error', 'Coupon cannot be applied. Minimum purchase amount not met.');
return false;
}
// Apply the coupon to the cart
$couponApplied = $coupon->couponable->apply($cart);
if ($couponApplied) {
// Attach the coupon to the cart if it was successfully applied
$cart->coupons()->attach($coupon->id);
$this->pricingService->applyCouponsToCart($cart); // Apply the coupon
Session::flash('success', 'Coupon applied successfully.');
return true;
} else {
Session::flash('error', 'Failed to apply the coupon.');
return false;
}
}
public function removeCoupon(Cart $cart, $couponCode)
{
// Find the coupon by code
$coupon = Coupon::where('code', $couponCode)->first();
// Check if the coupon exists
if (!$coupon) {
Session::flash('error', 'Invalid coupon code.');
return false;
}
if ($coupon->couponable instanceof \App\Contracts\Applicable) {
$coupon->couponable->remove($cart);
}
// Detach the coupon from the cart
$cart->coupons()->detach($coupon->id);
// Save the updated cart
$cart->save();
Session::flash('success', 'Coupon removed successfully.');
return true;
}
protected function validateCoupons(Cart $cart)
{
$cartCoupons = $cart->coupons;
foreach ($cartCoupons as $coupon) {
if ($cart->subtotal < $coupon->couponable->minimum_purchase_amount) {
$cart->coupons()->detach($coupon->id);
if ($coupon->couponable instanceof \App\Contracts\Applicable) {
$coupon->couponable->remove($cart);
}
Session::flash('warning', 'Coupon removed due to insufficient cart value.');
}
}
}
public function applyCartRules($cart)
{
$cart->discount = 0;
$cart->tax = 0;
$cart->shipping_cost = 0;
$this->validateCoupons($cart);
// $pricingService = app(PricingService::class);
$this->pricingService->applyDiscounts($cart);
$this->pricingService->calculateTax($cart, config('cart.tax_rate'));
$this->pricingService->calculateShipping($cart);
$cart->save();
}
public function updateCart($cart)
{
$cart->discount = 0;
$cart->tax = 0;
$cart->shipping_cost = 0;
$this->validateCoupons($cart);
// $pricingService = app(PricingService::class);
$this->pricingService->calculateTax($cart, config('cart.tax_rate'));
$this->pricingService->calculateShipping($cart);
$this->pricingService->updateCartCoupons($cart);
$cart->save();
}
}
trying to merge guest cart with user's cart and transfer coupons from the guest cart to the user's cart. everything works fine except when i add the code to transfer the coupons, the coupon gets attached to the user's cart but not calculated or stored and the guest cart doesn't get deleted either.
Please or to participate in this conversation.