Files
Paymenter-Version-Tracks/app/Classes/Cart.php
Muhammad Tamir b3933b9960 v1.4.0
2025-11-14 10:59:24 +07:00

211 lines
6.2 KiB
PHP

<?php
namespace App\Classes;
use App\Exceptions\DisplayException;
use App\Models\Coupon;
use App\Models\Plan;
use App\Models\Product;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Session;
class Cart
{
public static function getOnce()
{
if (!Cookie::has('cart') || !$cart = \App\Models\Cart::where('ulid', Cookie::get('cart'))->first()) {
return new \App\Models\Cart;
}
return $cart->load('items.plan', 'items.product', 'items.product.configOptions.children.plans.prices');
}
public static function get()
{
return once(fn () => self::getOnce());
}
public static function clear()
{
if (Cookie::has('cart')) {
\App\Models\Cart::where('ulid', Cookie::get('cart'))->delete();
Cookie::queue(Cookie::forget('cart'));
}
}
public static function items()
{
return self::get()->items;
}
public static function createCart()
{
$cart = self::getOnce();
if (!$cart->exists) {
$cart->user_id = Auth::id();
$cart->currency_code = session('currency', session('currency', config('settings.default_currency')));
$cart->save();
Cookie::queue('cart', $cart->ulid, 60 * 24 * 30); // 30 days
$cart = \App\Models\Cart::find($cart->id);
}
return $cart;
}
public static function add(Product $product, Plan $plan, $configOptions, $checkoutConfig, $quantity = 1, $key = null)
{
// Match on key
$cart = self::createCart();
$item = $cart->items()->updateOrCreate([
'id' => $key,
], [
'product_id' => $product->id,
'plan_id' => $plan->id,
'config_options' => $configOptions,
'checkout_config' => $checkoutConfig,
'quantity' => $quantity,
]);
$cart->load('items.plan', 'items.product', 'items.product.configOptions.children.plans.prices');
if ($cart->coupon_id) {
// Reapply coupon to the cart
try {
self::validateCoupon($cart->coupon->code);
// Check if any of the items have gotten a discount
if ($cart->items->filter(fn ($item) => $item->price->hasDiscount())->isEmpty()) {
$cart->coupon_id = null;
$cart->save();
}
} catch (DisplayException $e) {
// Coupon is invalid, remove it
$cart->coupon_id = null;
$cart->save();
}
}
// Return index of the newly added item
return $item->id;
}
public static function remove($index)
{
$cart = self::get();
$item = $cart->items()->where('id', $index)->first();
if ($item) {
$item->delete(); // We also want to trigger Eloquent events
}
$cart->load('items.plan', 'items.product', 'items.product.configOptions.children.plans.prices');
}
public static function updateQuantity($index, $quantity)
{
$cart = self::get();
if ($item = $cart->items()->where('id', $index)->first()) {
if ($item->product->allow_quantity !== 'combined') {
return;
}
} else {
return;
}
if ($quantity < 1) {
self::remove($index);
return;
}
$item->quantity = $quantity;
$item->save();
$cart->load('items');
}
/**
* Validate if a coupon is valid for the current user and cart
*
* @param string $coupon_code
* @return Coupon
*
* @throws DisplayException
*/
public static function validateCoupon($coupon_code)
{
$coupon = Coupon::where('code', $coupon_code)->first();
if (!$coupon) {
throw new DisplayException('Coupon code not found');
}
if ($coupon->expires_at && $coupon->expires_at->isPast()) {
throw new DisplayException('Coupon code has expired');
}
if ($coupon->starts_at && $coupon->starts_at->isFuture()) {
throw new DisplayException('Coupon code is not active yet');
}
if ($coupon->max_uses && $coupon->services->count() >= $coupon->max_uses) {
throw new DisplayException('Coupon code has reached its maximum uses');
}
if (Auth::check() && $coupon->hasExceededMaxUsesPerUser(Auth::id())) {
throw new DisplayException('You have already used this coupon the maximum number of times allowed');
}
return $coupon;
}
public static function applyCoupon($code)
{
$coupon = self::validateCoupon($code);
$wasSuccessful = false;
$cart = self::createCart();
$cart->coupon_id = $coupon->id;
$cart->save();
// Check if any of the items have gotten a discount, if empty also set succesful because it's valid for future use (will get rechecked on checkout
if ($cart->items->filter(fn ($item) => $item->price->hasDiscount())->isNotEmpty() || $cart->items->isEmpty()) {
$wasSuccessful = true;
} else {
$cart->coupon_id = null;
}
if ($wasSuccessful) {
$cart->save();
} else {
$cart->coupon_id = null;
$cart->save();
throw new DisplayException('Coupon code is not valid for any items in your cart');
}
}
/**
* Validates and refreshes the coupon in the session
*
* @return bool True if coupon is valid, false otherwise
*/
public static function validateAndRefreshCoupon()
{
if (!self::get()->coupon_id || !self::get()->coupon) {
return true;
}
try {
$coupon = self::get()->coupon;
self::validateCoupon($coupon->code);
return true;
} catch (DisplayException $e) {
// Coupon is invalid, remove it
self::removeCoupon();
return false;
}
}
public static function removeCoupon()
{
self::get()->update(['coupon_id' => null]);
self::get()->load('coupon');
}
}