sarga/packages/Webkul/Checkout/src/Cart.php

1052 lines
34 KiB
PHP
Raw Normal View History

2018-09-11 11:19:40 +00:00
<?php
2018-09-28 13:28:54 +00:00
namespace Webkul\Checkout;
2018-09-11 11:19:40 +00:00
use Exception;
2020-07-23 15:12:11 +00:00
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Event;
2021-06-24 04:51:19 +00:00
use Webkul\Checkout\Models\Cart as CartModel;
2020-03-05 15:16:17 +00:00
use Webkul\Checkout\Models\CartAddress;
2020-07-23 15:12:11 +00:00
use Webkul\Checkout\Models\CartPayment;
2021-06-24 04:51:19 +00:00
use Webkul\Checkout\Repositories\CartAddressRepository;
use Webkul\Checkout\Repositories\CartItemRepository;
2018-09-28 13:28:54 +00:00
use Webkul\Checkout\Repositories\CartRepository;
2021-09-10 04:37:54 +00:00
use Webkul\Checkout\Traits\CartCoupons;
2021-09-09 14:44:04 +00:00
use Webkul\Checkout\Traits\CartTools;
2021-09-10 04:37:54 +00:00
use Webkul\Checkout\Traits\CartValidators;
2021-06-24 04:51:19 +00:00
use Webkul\Customer\Repositories\CustomerAddressRepository;
use Webkul\Customer\Repositories\WishlistRepository;
2018-09-21 10:17:43 +00:00
use Webkul\Product\Repositories\ProductRepository;
2021-06-24 04:51:19 +00:00
use Webkul\Shipping\Facades\Shipping;
use Webkul\Tax\Helpers\Tax;
2018-10-15 10:39:09 +00:00
use Webkul\Tax\Repositories\TaxCategoryRepository;
2018-09-11 11:19:40 +00:00
class Cart
{
2021-09-10 04:37:54 +00:00
use CartCoupons, CartTools, CartValidators;
2021-09-09 14:44:04 +00:00
2018-09-26 04:21:14 +00:00
/**
2021-09-09 14:44:04 +00:00
* Cart repository instance.
2018-09-26 04:21:14 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Checkout\Repositories\CartRepository
2018-09-26 04:21:14 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $cartRepository;
2018-09-26 04:21:14 +00:00
/**
2021-09-09 14:44:04 +00:00
* Cart item repository instance.
2018-09-26 04:21:14 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Checkout\Repositories\CartItemRepository
2018-09-26 04:21:14 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $cartItemRepository;
2018-09-26 04:21:14 +00:00
/**
2021-09-09 14:44:04 +00:00
* Cart address repository instance.
2018-09-26 04:21:14 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Checkout\Repositories\CartAddressRepository
2018-09-26 04:21:14 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $cartAddressRepository;
2018-09-19 07:00:24 +00:00
2018-09-26 04:21:14 +00:00
/**
2021-09-09 14:44:04 +00:00
* Product repository instance.
2018-09-26 04:21:14 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Checkout\Repositories\ProductRepository
2018-09-26 04:21:14 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $productRepository;
2018-10-15 10:39:09 +00:00
/**
2021-09-09 14:44:04 +00:00
* Tax category repository instance.
2018-10-15 10:39:09 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Tax\Repositories\TaxCategoryRepository
2018-10-15 10:39:09 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $taxCategoryRepository;
2018-10-15 10:39:09 +00:00
2018-10-30 04:31:01 +00:00
/**
2021-09-09 14:44:04 +00:00
* Wishlist repository instance.
2018-10-30 04:31:01 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Customer\Repositories\WishlistRepository
2018-10-30 04:31:01 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $wishlistRepository;
2018-10-30 04:31:01 +00:00
2019-02-14 15:50:10 +00:00
/**
2021-09-09 14:44:04 +00:00
* Customer address repository instance.
2019-02-14 15:50:10 +00:00
*
2020-03-05 05:34:57 +00:00
* @var \Webkul\Customer\Repositories\CustomerAddressRepository
2019-02-14 15:50:10 +00:00
*/
2019-07-01 11:33:36 +00:00
protected $customerAddressRepository;
2018-09-26 04:21:14 +00:00
/**
2020-03-05 05:34:57 +00:00
* Create a new class instance.
*
2020-03-05 05:34:57 +00:00
* @param \Webkul\Checkout\Repositories\CartRepository $cartRepository
* @param \Webkul\Checkout\Repositories\CartItemRepository $cartItemRepository
* @param \Webkul\Checkout\Repositories\CartAddressRepository $cartAddressRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Tax\Repositories\TaxCategoryRepository $taxCategoryRepository
* @param \Webkul\Customer\Repositories\WishlistRepository $wishlistRepository
* @param \Webkul\Customer\Repositories\CustomerAddressRepository $customerAddressRepository
2018-09-26 04:21:14 +00:00
* @return void
*/
public function __construct(
2019-07-01 11:33:36 +00:00
CartRepository $cartRepository,
CartItemRepository $cartItemRepository,
CartAddressRepository $cartAddressRepository,
ProductRepository $productRepository,
TaxCategoryRepository $taxCategoryRepository,
WishlistRepository $wishlistRepository,
CustomerAddressRepository $customerAddressRepository
2021-09-09 14:44:04 +00:00
) {
2019-07-01 11:33:36 +00:00
$this->cartRepository = $cartRepository;
2019-07-01 11:33:36 +00:00
$this->cartItemRepository = $cartItemRepository;
2018-09-19 07:00:24 +00:00
2019-07-01 11:33:36 +00:00
$this->cartAddressRepository = $cartAddressRepository;
2018-09-26 04:21:14 +00:00
2019-07-01 11:33:36 +00:00
$this->productRepository = $productRepository;
2018-10-15 10:39:09 +00:00
2019-07-01 11:33:36 +00:00
$this->taxCategoryRepository = $taxCategoryRepository;
2018-10-30 04:31:01 +00:00
2019-07-01 11:33:36 +00:00
$this->wishlistRepository = $wishlistRepository;
2019-07-01 11:33:36 +00:00
$this->customerAddressRepository = $customerAddressRepository;
2018-09-14 13:15:49 +00:00
}
/**
2021-09-09 14:44:04 +00:00
* Return current logged in customer.
*
2020-03-05 05:34:57 +00:00
* @return \Webkul\Customer\Contracts\Customer|bool
*/
public function getCurrentCustomer()
{
2019-04-24 10:35:29 +00:00
$guard = request()->has('token') ? 'api' : 'customer';
2019-04-24 10:35:29 +00:00
return auth()->guard($guard);
}
2018-09-28 12:55:48 +00:00
/**
2021-09-10 04:37:54 +00:00
* Returns cart.
*
* @return \Webkul\Checkout\Contracts\Cart|null
*/
public function getCart(): ?\Webkul\Checkout\Contracts\Cart
{
$cart = null;
if ($this->getCurrentCustomer()->check()) {
$cart = $this->cartRepository->findOneWhere([
'customer_id' => $this->getCurrentCustomer()->user()->id,
'is_active' => 1,
]);
} else if (session()->has('cart')) {
$cart = $this->cartRepository->find(session()->get('cart')->id);
}
$this->removeInactiveItems($cart);
return $cart;
}
/**
* Get cart item by product.
*
* @param array $data
* @return \Webkul\Checkout\Contracts\CartItem|void
*/
public function getItemByProduct($data)
{
$items = $this->getCart()->all_items;
foreach ($items as $item) {
if ($item->product->getTypeInstance()->compareOptions($item->additional, $data['additional'])) {
if (isset($data['additional']['parent_id'])) {
if ($item->parent->product->getTypeInstance()->compareOptions($item->parent->additional, $data['additional'])) {
return $item;
}
} else {
return $item;
}
}
}
}
/**
* Add items in a cart with some cart and item details.
2018-09-28 12:55:48 +00:00
*
2021-09-09 14:44:04 +00:00
* @param int $productId
* @param array $data
* @return \Webkul\Checkout\Contracts\Cart|string|array
* @throws Exception
2019-08-19 09:30:24 +00:00
*/
public function addProduct($productId, $data)
{
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.cart.add.before', $productId);
2019-08-19 09:30:24 +00:00
$cart = $this->getCart();
if (! $cart && ! $cart = $this->create($data)) {
return ['warning' => __('shop::app.checkout.cart.item.error-add')];
}
2019-08-19 09:30:24 +00:00
$product = $this->productRepository->findOneByField('id', $productId);
2020-06-11 06:21:45 +00:00
if ($product->status === 0) {
return ['info' => __('shop::app.checkout.cart.item.inactive-add')];
}
2019-08-19 09:30:24 +00:00
$cartProducts = $product->getTypeInstance()->prepareForCart($data);
if (is_string($cartProducts)) {
2019-10-11 06:41:07 +00:00
$this->collectTotals();
2020-03-05 14:52:20 +00:00
if (count($cart->all_items) <= 0) {
2020-01-23 14:13:03 +00:00
session()->forget('cart');
}
throw new Exception($cartProducts);
2019-08-19 09:30:24 +00:00
} else {
$parentCartItem = null;
foreach ($cartProducts as $cartProduct) {
$cartItem = $this->getItemByProduct($cartProduct);
if (isset($cartProduct['parent_id'])) {
2019-08-19 09:30:24 +00:00
$cartProduct['parent_id'] = $parentCartItem->id;
}
2019-08-19 09:30:24 +00:00
if (! $cartItem) {
2019-08-19 09:30:24 +00:00
$cartItem = $this->cartItemRepository->create(array_merge($cartProduct, ['cart_id' => $cart->id]));
} else {
if (isset($cartProduct['parent_id']) && $cartItem->parent_id !== $parentCartItem->id) {
$cartItem = $this->cartItemRepository->create(array_merge($cartProduct, [
2020-02-27 08:03:03 +00:00
'cart_id' => $cart->id
]));
2019-10-24 10:59:09 +00:00
} else {
2020-09-07 14:30:57 +00:00
// if ($cartItem->product->getTypeInstance()->isMultipleQtyAllowed() === false) {
// return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
// }
2020-02-11 07:40:14 +00:00
2019-10-24 10:59:09 +00:00
$cartItem = $this->cartItemRepository->update($cartProduct, $cartItem->id);
}
2019-08-19 09:30:24 +00:00
}
2020-02-19 12:14:07 +00:00
if (! $parentCartItem) {
2019-08-19 09:30:24 +00:00
$parentCartItem = $cartItem;
2020-02-19 12:14:07 +00:00
}
2019-08-19 09:30:24 +00:00
}
}
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.cart.add.after', $cart);
2019-08-19 09:30:24 +00:00
$this->collectTotals();
2019-10-11 06:41:07 +00:00
return $this->getCart();
2019-08-19 09:30:24 +00:00
}
/**
* Create new cart instance.
2018-09-28 12:55:48 +00:00
*
2020-03-05 05:34:57 +00:00
* @param array $data
* @return \Webkul\Checkout\Contracts\Cart|null
2018-09-28 12:55:48 +00:00
*/
2019-08-19 09:30:24 +00:00
public function create($data)
2018-09-28 12:55:48 +00:00
{
$cartData = [
2020-02-19 12:14:07 +00:00
'channel_id' => core()->getCurrentChannel()->id,
'global_currency_code' => core()->getBaseCurrencyCode(),
'base_currency_code' => core()->getBaseCurrencyCode(),
'channel_currency_code' => core()->getChannelBaseCurrencyCode(),
2020-02-19 12:14:07 +00:00
'cart_currency_code' => core()->getCurrentCurrencyCode(),
'items_count' => 1,
];
2018-10-25 09:56:24 +00:00
2021-09-09 14:44:04 +00:00
/**
* Fill in the customer data, as far as possible.
*/
if ($this->getCurrentCustomer()->check()) {
$cartData['customer_id'] = $this->getCurrentCustomer()->user()->id;
$cartData['is_guest'] = 0;
$cartData['customer_first_name'] = $this->getCurrentCustomer()->user()->first_name;
$cartData['customer_last_name'] = $this->getCurrentCustomer()->user()->last_name;
$cartData['customer_email'] = $this->getCurrentCustomer()->user()->email;
} else {
$cartData['is_guest'] = 1;
2018-09-28 12:55:48 +00:00
}
2018-10-10 10:26:27 +00:00
2019-08-19 09:30:24 +00:00
$cart = $this->cartRepository->create($cartData);
if (! $cart) {
2020-06-05 06:19:13 +00:00
session()->flash('error', __('shop::app.checkout.cart.create-error'));
2018-09-28 12:55:48 +00:00
2019-08-19 09:30:24 +00:00
return;
}
2018-10-11 05:39:17 +00:00
2019-08-19 09:30:24 +00:00
$this->putCart($cart);
2018-10-11 05:39:17 +00:00
2019-08-19 09:30:24 +00:00
return $cart;
}
/**
2021-09-09 14:44:04 +00:00
* Update cart items information.
*
2020-03-05 05:34:57 +00:00
* @param array $data
* @return bool|void|Exception
*/
2019-08-19 09:30:24 +00:00
public function updateItems($data)
{
2019-08-19 09:30:24 +00:00
foreach ($data['qty'] as $itemId => $quantity) {
$item = $this->cartItemRepository->findOneByField('id', $itemId);
2020-02-19 12:14:07 +00:00
if (! $item) {
2019-08-19 09:30:24 +00:00
continue;
2020-02-19 12:14:07 +00:00
}
2018-10-11 05:39:17 +00:00
if ($item->product && $item->product->status === 0) {
throw new Exception(__('shop::app.checkout.cart.item.inactive'));
}
2019-08-19 09:30:24 +00:00
if ($quantity <= 0) {
$this->removeItem($itemId);
2018-10-30 11:22:36 +00:00
2020-06-09 06:35:22 +00:00
throw new Exception(__('shop::app.checkout.cart.quantity.illegal'));
}
2018-10-30 11:22:36 +00:00
$item->quantity = $quantity;
2020-02-19 12:14:07 +00:00
if (! $this->isItemHaveQuantity($item)) {
2020-06-09 06:35:22 +00:00
throw new Exception(__('shop::app.checkout.cart.quantity.inventory_warning'));
2020-02-19 12:14:07 +00:00
}
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.cart.update.before', $item);
2019-06-28 14:18:52 +00:00
2019-08-19 09:30:24 +00:00
$this->cartItemRepository->update([
2020-02-27 08:03:03 +00:00
'quantity' => $quantity,
'total' => core()->convertPrice($item->price * $quantity),
'base_total' => $item->price * $quantity,
'total_weight' => $item->weight * $quantity,
'base_total_weight' => $item->weight * $quantity,
], $itemId);
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.cart.update.after', $item);
}
2018-10-11 05:39:17 +00:00
2019-08-19 09:30:24 +00:00
$this->collectTotals();
2019-08-19 09:30:24 +00:00
return true;
2018-10-11 05:39:17 +00:00
}
/**
2021-09-09 14:44:04 +00:00
* Remove the item from the cart.
*
2020-03-05 05:34:57 +00:00
* @param int $itemId
2020-03-18 07:54:12 +00:00
* @return boolean
*/
public function removeItem($itemId)
{
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.cart.delete.before', $itemId);
2018-09-13 13:40:01 +00:00
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
2019-08-19 09:30:24 +00:00
return false;
2020-02-19 12:14:07 +00:00
}
2018-09-13 13:40:01 +00:00
2021-03-01 05:27:00 +00:00
if ($cartItem = $cart->items()->find($itemId)) {
$cartItem->delete();
2018-09-26 04:21:14 +00:00
if ($cart->items->count() == 0) {
2021-03-01 05:27:00 +00:00
$this->cartRepository->delete($cart->id);
2021-03-01 05:27:00 +00:00
if (session()->has('cart')) {
session()->forget('cart');
}
2019-08-19 09:30:24 +00:00
}
2018-09-14 13:15:49 +00:00
2021-03-01 05:27:00 +00:00
Shipping::collectRates();
2020-07-23 15:12:11 +00:00
2021-03-01 05:27:00 +00:00
Event::dispatch('checkout.cart.delete.after', $itemId);
2019-08-19 09:30:24 +00:00
2021-03-01 05:27:00 +00:00
$this->collectTotals();
2019-08-19 09:30:24 +00:00
2021-03-01 05:27:00 +00:00
return true;
}
return false;
2018-10-10 10:26:27 +00:00
}
/**
2021-09-10 04:37:54 +00:00
* Remove cart items, whose product is inactive.
2018-10-11 05:39:17 +00:00
*
2021-09-10 04:37:54 +00:00
* @param \Webkul\Checkout\Models\Cart|null $cart
* @return \Webkul\Checkout\Models\Cart|null
2018-10-11 05:39:17 +00:00
*/
2021-09-10 04:37:54 +00:00
public function removeInactiveItems(CartModel $cart = null): ?CartModel
2018-10-11 05:39:17 +00:00
{
2021-09-10 04:37:54 +00:00
if (! $cart) {
return $cart;
2018-10-11 05:39:17 +00:00
}
2021-09-10 04:37:54 +00:00
foreach ($cart->items as $item) {
if ($this->isCartItemInactive($item)) {
2018-10-11 05:39:17 +00:00
2021-09-10 04:37:54 +00:00
$this->cartItemRepository->delete($item->id);
2018-10-11 05:39:17 +00:00
2021-09-10 04:37:54 +00:00
if ($cart->items->count() == 0) {
$this->cartRepository->delete($cart->id);
2018-10-11 05:39:17 +00:00
2021-09-10 04:37:54 +00:00
if (session()->has('cart')) {
session()->forget('cart');
}
}
2019-06-28 14:18:52 +00:00
2021-09-10 04:37:54 +00:00
session()->flash('info', __('shop::app.checkout.cart.item.inactive'));
}
2019-06-28 14:18:52 +00:00
}
2018-10-11 05:39:17 +00:00
2021-09-10 04:37:54 +00:00
$cart->save();
2019-04-16 10:10:58 +00:00
2021-09-10 04:37:54 +00:00
return $cart;
2018-10-11 05:39:17 +00:00
}
2018-09-26 04:21:14 +00:00
/**
2021-09-09 14:44:04 +00:00
* Save customer address.
*
2021-09-09 14:44:04 +00:00
* @param array $data
2020-04-28 16:15:40 +00:00
* @return bool
* @throws \Prettus\Validator\Exceptions\ValidatorException
2018-09-26 04:21:14 +00:00
*/
2020-03-05 14:52:20 +00:00
public function saveCustomerAddress($data): bool
2018-09-26 04:21:14 +00:00
{
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
2018-09-26 04:21:14 +00:00
return false;
2020-02-19 12:14:07 +00:00
}
2018-09-26 04:21:14 +00:00
2020-03-05 14:52:20 +00:00
$billingAddressData = $this->gatherBillingAddress($data, $cart);
2019-02-14 15:50:10 +00:00
2020-03-05 14:52:20 +00:00
$shippingAddressData = $this->gatherShippingAddress($data, $cart);
2018-09-26 04:21:14 +00:00
2020-03-05 14:52:20 +00:00
$this->saveAddressesWhenRequested($data, $billingAddressData, $shippingAddressData);
2019-06-28 14:18:52 +00:00
2020-03-05 14:52:20 +00:00
$this->linkAddresses($cart, $billingAddressData, $shippingAddressData);
$this->assignCustomerFields($cart);
2018-10-26 13:43:01 +00:00
$cart->save();
2018-10-15 10:39:09 +00:00
$this->collectTotals();
2018-09-26 04:21:14 +00:00
return true;
}
/**
2021-09-09 14:44:04 +00:00
* Save shipping method for cart.
2018-09-26 04:21:14 +00:00
*
2020-03-05 05:34:57 +00:00
* @param string $shippingMethodCode
* @return bool
2018-09-26 04:21:14 +00:00
*/
2020-03-05 14:52:20 +00:00
public function saveShippingMethod($shippingMethodCode): bool
2018-09-26 04:21:14 +00:00
{
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
2018-09-26 04:21:14 +00:00
return false;
2020-02-19 12:14:07 +00:00
}
2018-09-26 04:21:14 +00:00
2021-11-09 07:54:48 +00:00
if (! Shipping::isMethodCodeExists($shippingMethodCode)) {
return false;
}
2018-09-26 10:19:18 +00:00
$cart->shipping_method = $shippingMethodCode;
$cart->save();
2018-09-26 04:21:14 +00:00
return true;
}
2018-09-26 10:19:18 +00:00
/**
2021-09-09 14:44:04 +00:00
* Save payment method for cart.
2018-09-26 10:19:18 +00:00
*
2020-03-05 05:34:57 +00:00
* @param string $payment
* @return \Webkul\Checkout\Contracts\CartPayment
2018-09-26 10:19:18 +00:00
*/
public function savePaymentMethod($payment)
{
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
2018-09-26 10:19:18 +00:00
return false;
2020-02-19 12:14:07 +00:00
}
2018-09-26 10:19:18 +00:00
if ($cartPayment = $cart->payment) {
2018-09-26 10:19:18 +00:00
$cartPayment->delete();
}
2018-09-26 10:19:18 +00:00
$cartPayment = new CartPayment;
$cartPayment->method = $payment['method'];
$cartPayment->cart_id = $cart->id;
$cartPayment->save();
return $cartPayment;
}
/**
2021-09-09 14:44:04 +00:00
* Updates cart totals.
2018-09-26 10:19:18 +00:00
*
* @return void
*/
public function collectTotals(): void
2018-09-26 10:19:18 +00:00
{
if (! $this->validateItems()) {
return;
2020-02-19 12:14:07 +00:00
}
2018-09-26 10:19:18 +00:00
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
return;
2020-02-19 12:14:07 +00:00
}
Event::dispatch('checkout.cart.collect.totals.before', $cart);
2019-12-21 05:25:32 +00:00
2018-10-15 10:39:09 +00:00
$this->calculateItemsTax();
2020-03-19 11:02:11 +00:00
$cart->refresh();
2018-10-10 10:41:33 +00:00
2018-10-15 10:39:09 +00:00
$cart->grand_total = $cart->base_grand_total = 0;
$cart->sub_total = $cart->base_sub_total = 0;
$cart->tax_total = $cart->base_tax_total = 0;
$cart->discount_amount = $cart->base_discount_amount = 0;
2018-09-26 10:19:18 +00:00
foreach ($cart->items as $item) {
$cart->discount_amount += $item->discount_amount;
$cart->base_discount_amount += $item->base_discount_amount;
$cart->sub_total = (float)$cart->sub_total + $item->total;
$cart->base_sub_total = (float)$cart->base_sub_total + $item->base_total;
2018-09-26 10:19:18 +00:00
}
$cart->tax_total = Tax::getTaxTotal($cart, false);
$cart->base_tax_total = Tax::getTaxTotal($cart, true);
$cart->grand_total = $cart->sub_total + $cart->tax_total - $cart->discount_amount;
$cart->base_grand_total = $cart->base_sub_total + $cart->base_tax_total - $cart->base_discount_amount;
2018-09-26 10:19:18 +00:00
2021-01-15 05:39:07 +00:00
if ($shipping = $cart->selected_shipping_rate) {
$cart->grand_total = (float) $cart->grand_total + $shipping->price - $shipping->discount_amount;
$cart->base_grand_total = (float) $cart->base_grand_total + $shipping->base_price - $shipping->base_discount_amount;
$cart->discount_amount += $shipping->discount_amount;
$cart->base_discount_amount += $shipping->base_discount_amount;
}
$cart = $this->finalizeCartTotals($cart);
2018-10-05 11:59:43 +00:00
$quantities = 0;
2020-01-09 07:18:59 +00:00
2019-01-15 11:54:41 +00:00
foreach ($cart->items as $item) {
2018-10-05 11:59:43 +00:00
$quantities = $quantities + $item->quantity;
}
$cart->items_count = $cart->items->count();
$cart->items_qty = $quantities;
2020-12-14 08:03:25 +00:00
2020-11-17 10:18:59 +00:00
$cart->cart_currency_code = core()->getCurrentCurrencyCode();
2018-10-05 11:59:43 +00:00
2018-09-26 10:19:18 +00:00
$cart->save();
2019-12-21 05:25:32 +00:00
Event::dispatch('checkout.cart.collect.totals.after', $cart);
2018-09-26 10:19:18 +00:00
}
2018-10-11 06:12:39 +00:00
/**
2021-09-09 14:44:04 +00:00
* Calculates cart items tax.
2018-10-11 06:12:39 +00:00
*
* @return void
2019-11-01 05:33:40 +00:00
*/
public function calculateItemsTax(): void
2018-10-11 06:12:39 +00:00
{
2020-02-19 12:14:07 +00:00
if (! $cart = $this->getCart()) {
2018-10-15 10:39:09 +00:00
return;
2020-02-19 12:14:07 +00:00
}
2020-04-28 16:15:40 +00:00
2020-03-19 11:02:11 +00:00
Event::dispatch('checkout.cart.calculate.items.tax.before', $cart);
2018-10-15 10:39:09 +00:00
foreach ($cart->items as $item) {
2019-07-01 11:33:36 +00:00
$taxCategory = $this->taxCategoryRepository->find($item->product->tax_category_id);
2018-10-15 10:39:09 +00:00
2020-02-19 12:14:07 +00:00
if (! $taxCategory) {
2018-10-15 10:39:09 +00:00
continue;
2020-02-19 12:14:07 +00:00
}
if ($item->product->getTypeInstance()->isStockable()) {
$address = $cart->shipping_address;
} else {
$address = $cart->billing_address;
}
2020-02-07 18:09:41 +00:00
if ($address === null && auth()->guard('customer')->check()) {
$address = auth()->guard('customer')->user()->addresses()
->where('default_address', 1)->first();
2020-02-07 18:09:41 +00:00
}
if ($address === null) {
2021-05-06 10:15:56 +00:00
$address = Tax::getDefaultAddress();
}
2020-02-20 18:23:01 +00:00
$item = $this->setItemTaxToZero($item);
2018-10-15 10:39:09 +00:00
2021-05-06 10:15:56 +00:00
Tax::isTaxApplicableInCurrentAddress($taxCategory, $address, function ($rate) use ($cart, $item) {
/* assigning tax percent */
$item->tax_percent = $rate->tax_rate;
2020-12-14 08:03:25 +00:00
2021-05-06 10:15:56 +00:00
/* getting shipping rate for tax calculation */
$shippingPrice = $shippingBasePrice = 0;
2020-12-14 08:03:25 +00:00
2021-05-06 10:15:56 +00:00
if ($shipping = $cart->selected_shipping_rate) {
if ($shipping->is_calculate_tax) {
$shippingPrice = $shipping->price - $shipping->discount_amount;
$shippingBasePrice = $shipping->base_price - $shipping->base_discount_amount;
}
2018-10-15 10:39:09 +00:00
}
2021-05-06 10:15:56 +00:00
/* now assigning shipping prices for tax calculation */
$item->tax_amount = round((($item->total + $shippingPrice) * $rate->tax_rate) / 100, 4);
$item->base_tax_amount = round((($item->base_total + $shippingBasePrice) * $rate->tax_rate) / 100, 4);
});
$item->save();
2018-10-11 06:12:39 +00:00
}
2020-11-16 14:55:36 +00:00
Event::dispatch('checkout.cart.calculate.items.tax.after', $cart);
2018-10-11 06:12:39 +00:00
}
2020-02-19 10:42:54 +00:00
/**
2021-09-10 04:37:54 +00:00
* To validate if the product information is changed by admin and the items have been added to the cart before it.
2018-10-05 11:59:43 +00:00
*
2020-03-05 05:34:57 +00:00
* @return bool
*/
2021-09-10 04:37:54 +00:00
public function validateItems(): bool
2018-10-05 11:59:43 +00:00
{
2021-09-10 04:37:54 +00:00
if (! $cart = $this->getCart()) {
return false;
2020-02-19 12:14:07 +00:00
}
2018-10-09 12:04:25 +00:00
2021-09-10 04:37:54 +00:00
if (count($cart->items) === 0) {
$this->cartRepository->delete($cart->id);
return false;
}
2021-09-10 04:37:54 +00:00
$isInvalid = false;
foreach ($cart->items as $item) {
2021-09-10 04:37:54 +00:00
$validationResult = $item->product->getTypeInstance()->validateCartItem($item);
2021-09-10 04:37:54 +00:00
if ($validationResult->isItemInactive()) {
$this->removeItem($item->id);
2021-09-10 04:37:54 +00:00
$isInvalid = true;
2020-06-05 06:19:13 +00:00
session()->flash('info', __('shop::app.checkout.cart.item.inactive'));
}
2020-06-11 06:21:45 +00:00
2021-09-10 04:37:54 +00:00
$price = ! is_null($item->custom_price) ? $item->custom_price : $item->base_price;
2021-09-10 04:37:54 +00:00
$this->cartItemRepository->update([
'price' => core()->convertPrice($price),
'base_price' => $price,
'total' => core()->convertPrice($price * $item->quantity),
'base_total' => $price * $item->quantity,
], $item->id);
2021-09-10 04:37:54 +00:00
$isInvalid |= $validationResult->isCartInvalid();
}
return ! $isInvalid;
2018-10-05 11:59:43 +00:00
}
2018-10-09 12:04:25 +00:00
2018-10-05 06:18:58 +00:00
/**
2021-09-10 04:37:54 +00:00
* Prepare data for order.
2018-10-05 06:18:58 +00:00
*
* @return array
*/
2020-04-28 16:15:40 +00:00
public function prepareDataForOrder(): array
2018-10-05 06:18:58 +00:00
{
$data = $this->toArray();
$finalData = [
2020-02-19 12:14:07 +00:00
'cart_id' => $this->getCart()->id,
'customer_id' => $data['customer_id'],
'is_guest' => $data['is_guest'],
'customer_email' => $data['customer_email'],
'customer_first_name' => $data['customer_first_name'],
'customer_last_name' => $data['customer_last_name'],
'customer' => $this->getCurrentCustomer()->check() ? $this->getCurrentCustomer()->user() : null,
'total_item_count' => $data['items_count'],
'total_qty_ordered' => $data['items_qty'],
'base_currency_code' => $data['base_currency_code'],
2018-10-05 06:18:58 +00:00
'channel_currency_code' => $data['channel_currency_code'],
2020-02-19 12:14:07 +00:00
'order_currency_code' => $data['cart_currency_code'],
'grand_total' => $data['grand_total'],
'base_grand_total' => $data['base_grand_total'],
'sub_total' => $data['sub_total'],
'base_sub_total' => $data['base_sub_total'],
'tax_amount' => $data['tax_total'],
'base_tax_amount' => $data['base_tax_total'],
'coupon_code' => $data['coupon_code'],
'applied_cart_rule_ids' => $data['applied_cart_rule_ids'],
2020-02-19 12:14:07 +00:00
'discount_amount' => $data['discount_amount'],
'base_discount_amount' => $data['base_discount_amount'],
'billing_address' => Arr::except($data['billing_address'], ['id', 'cart_id']),
'payment' => Arr::except($data['payment'], ['id', 'cart_id']),
'channel' => core()->getCurrentChannel(),
2018-10-05 06:18:58 +00:00
];
2019-06-28 14:18:52 +00:00
if ($this->getCart()->haveStockableItems()) {
$finalData = array_merge($finalData, [
2020-02-19 12:14:07 +00:00
'shipping_method' => $data['selected_shipping_rate']['method'],
'shipping_title' => $data['selected_shipping_rate']['carrier_title'] . ' - ' . $data['selected_shipping_rate']['method_title'],
'shipping_description' => $data['selected_shipping_rate']['method_description'],
'shipping_amount' => $data['selected_shipping_rate']['price'],
'base_shipping_amount' => $data['selected_shipping_rate']['base_price'],
'shipping_address' => Arr::except($data['shipping_address'], ['id', 'cart_id']),
'shipping_discount_amount' => $data['selected_shipping_rate']['discount_amount'],
2020-01-09 11:33:58 +00:00
'base_shipping_discount_amount' => $data['selected_shipping_rate']['base_discount_amount'],
2019-06-28 14:18:52 +00:00
]);
}
2019-01-15 11:54:41 +00:00
foreach ($data['items'] as $item) {
2018-10-05 06:18:58 +00:00
$finalData['items'][] = $this->prepareDataForOrderItem($item);
}
2021-02-03 07:23:34 +00:00
if ($finalData['payment']['method'] === 'paypal_smart_button') {
$finalData['payment']['additional'] = request()->get('orderData');
2021-02-03 07:23:34 +00:00
}
2018-10-05 06:18:58 +00:00
return $finalData;
}
/**
2021-09-09 14:44:04 +00:00
* Prepares data for order item.
2018-10-05 06:18:58 +00:00
*
2020-03-05 05:34:57 +00:00
* @param array $data
2018-10-05 06:18:58 +00:00
* @return array
*/
2020-04-28 16:15:40 +00:00
public function prepareDataForOrderItem($data): array
2018-10-05 06:18:58 +00:00
{
2020-08-07 12:00:06 +00:00
$locale = ['locale' => core()->getCurrentLocale()->code];
2018-10-05 06:18:58 +00:00
$finalData = [
2020-02-19 12:14:07 +00:00
'product' => $this->productRepository->find($data['product_id']),
'sku' => $data['sku'],
'type' => $data['type'],
'name' => $data['name'],
'weight' => $data['weight'],
'total_weight' => $data['total_weight'],
'qty_ordered' => $data['quantity'],
'price' => $data['price'],
'base_price' => $data['base_price'],
'total' => $data['total'],
'base_total' => $data['base_total'],
'tax_percent' => $data['tax_percent'],
'tax_amount' => $data['tax_amount'],
'base_tax_amount' => $data['base_tax_amount'],
'discount_percent' => $data['discount_percent'],
'discount_amount' => $data['discount_amount'],
2019-06-13 14:04:13 +00:00
'base_discount_amount' => $data['base_discount_amount'],
2020-08-07 12:00:06 +00:00
'additional' => is_array($data['additional']) ? array_merge($data['additional'], $locale) : $locale,
2018-10-05 06:18:58 +00:00
];
2019-08-30 11:39:15 +00:00
if (isset($data['children']) && $data['children']) {
foreach ($data['children'] as $child) {
$child['quantity'] = $child['quantity'] ? $child['quantity'] * $data['quantity'] : $child['quantity'];
2019-08-30 11:39:15 +00:00
$finalData['children'][] = $this->prepareDataForOrderItem($child);
}
2018-10-05 06:18:58 +00:00
}
return $finalData;
}
/**
2021-09-10 04:37:54 +00:00
* Returns cart details in array.
2018-10-30 04:31:01 +00:00
*
2021-09-10 04:37:54 +00:00
* @return array
2018-10-30 04:31:01 +00:00
*/
2021-09-10 04:37:54 +00:00
public function toArray()
{
2018-10-30 11:22:36 +00:00
$cart = $this->getCart();
2019-06-28 14:18:52 +00:00
2021-09-10 04:37:54 +00:00
$data = $cart->toArray();
2018-10-30 04:31:01 +00:00
2021-09-10 04:37:54 +00:00
$data['billing_address'] = $cart->billing_address->toArray();
2018-11-17 06:26:10 +00:00
2021-09-10 04:37:54 +00:00
if ($cart->haveStockableItems()) {
$data['shipping_address'] = $cart->shipping_address->toArray();
2018-11-17 06:26:10 +00:00
2021-09-10 04:37:54 +00:00
$data['selected_shipping_rate'] = $cart->selected_shipping_rate ? $cart->selected_shipping_rate->toArray() : 0.0;
2020-02-19 12:14:07 +00:00
}
2018-11-30 07:40:41 +00:00
2021-09-10 04:37:54 +00:00
$data['payment'] = $cart->payment->toArray();
2021-09-10 04:37:54 +00:00
$data['items'] = $cart->items->toArray();
2021-09-10 04:37:54 +00:00
return $data;
}
/**
2021-09-10 04:37:54 +00:00
* Set Item tax to zero.
*
2021-09-10 04:37:54 +00:00
* @param \Webkul\Checkout\Contracts\CartItem $item
* @return \Webkul\Checkout\Contracts\CartItem
*/
2021-09-10 04:37:54 +00:00
protected function setItemTaxToZero(\Webkul\Checkout\Contracts\CartItem $item): \Webkul\Checkout\Contracts\CartItem
{
2021-09-10 04:37:54 +00:00
$item->tax_percent = 0;
$item->tax_amount = 0;
$item->base_tax_amount = 0;
2021-09-10 04:37:54 +00:00
return $item;
}
/**
* Transfer the user profile information into the cart/into the order.
*
* When logged in as guest or the customer profile is not complete, we use the
* billing address to fill the order customer_ data.
*
2020-04-28 16:15:40 +00:00
* @param \Webkul\Checkout\Contracts\Cart $cart
*/
2020-04-28 16:15:40 +00:00
private function assignCustomerFields(\Webkul\Checkout\Contracts\Cart $cart): void
{
2021-09-09 14:44:04 +00:00
if (
$this->getCurrentCustomer()->check()
&& ($user = $this->getCurrentCustomer()->user())
&& $this->profileIsComplete($user)
) {
$cart->customer_email = $user->email;
$cart->customer_first_name = $user->first_name;
$cart->customer_last_name = $user->last_name;
} else {
$cart->customer_email = $cart->billing_address->email;
$cart->customer_first_name = $cart->billing_address->first_name;
$cart->customer_last_name = $cart->billing_address->last_name;
}
}
/**
2021-09-09 14:44:04 +00:00
* Round cart totals.
*
* @param \Webkul\Checkout\Models\Cart $cart
* @return \Webkul\Checkout\Models\Cart
*/
private function finalizeCartTotals(CartModel $cart): CartModel
{
$cart->discount_amount = round($cart->discount_amount, 2);
$cart->base_discount_amount = round($cart->base_discount_amount, 2);
2021-08-09 08:18:48 +00:00
$cart->sub_total = round($cart->sub_total, 2);
$cart->base_sub_total = round($cart->base_sub_total, 2);
$cart->grand_total = round($cart->grand_total, 2);
$cart->base_grand_total = round($cart->base_grand_total, 2);
return $cart;
}
/**
2021-09-09 14:44:04 +00:00
* Returns true, if cart item is inactive.
*
* @param \Webkul\Checkout\Contracts\CartItem $item
* @return bool
*/
2021-09-09 14:44:04 +00:00
private function isCartItemInactive(\Webkul\Checkout\Contracts\CartItem $item): bool
{
2021-07-20 09:55:31 +00:00
static $loadedCartItem = [];
if (array_key_exists($item->product_id, $loadedCartItem)) {
return $loadedCartItem[$item->product_id];
}
return $loadedCartItem[$item->product_id] = $item->product->getTypeInstance()->isCartItemInactive($item);
}
/**
2021-09-09 14:44:04 +00:00
* Is profile is complete.
*
2021-09-09 14:44:04 +00:00
* @param $user
* @return bool
*/
private function profileIsComplete($user): bool
{
return $user->email && $user->first_name && $user->last_name;
}
2020-03-05 14:52:20 +00:00
/**
2021-09-09 14:44:04 +00:00
* Fill customer attributes.
*
2020-03-05 14:52:20 +00:00
* @return array
*/
private function fillCustomerAttributes(): array
{
$attributes = [];
$user = $this->getCurrentCustomer()->user();
if ($user) {
$attributes['first_name'] = $user->first_name;
$attributes['last_name'] = $user->last_name;
$attributes['email'] = $user->email;
$attributes['customer_id'] = $user->id;
}
return $attributes;
}
/**
2021-09-09 14:44:04 +00:00
* Fill address attributes.
*
2020-03-05 14:52:20 +00:00
* @return array
*/
private function fillAddressAttributes(array $addressAttributes): array
{
$attributes = [];
2020-03-05 15:16:17 +00:00
$cartAddress = new CartAddress();
foreach ($cartAddress->getFillable() as $attribute) {
if (isset($addressAttributes[$attribute])) {
$attributes[$attribute] = $addressAttributes[$attribute];
}
}
2020-03-05 14:52:20 +00:00
return $attributes;
}
/**
2021-09-09 14:44:04 +00:00
* Save addresses when requested.
*
* @param array $data
* @param array $billingAddress
* @param array $shippingAddress
* @return void
2020-03-05 14:52:20 +00:00
*/
private function saveAddressesWhenRequested(
array $data,
array $billingAddress,
array $shippingAddress
2021-09-09 14:44:04 +00:00
): void {
2021-03-22 10:47:51 +00:00
$shippingAddress['cart_id'] = $billingAddress['cart_id'] = NULL;
2020-03-05 14:52:20 +00:00
if (isset($data['billing']['save_as_address']) && $data['billing']['save_as_address']) {
$this->customerAddressRepository->create($billingAddress);
}
if (isset($data['shipping']['save_as_address']) && $data['shipping']['save_as_address']) {
$this->customerAddressRepository->create($shippingAddress);
}
}
/**
2021-09-09 14:44:04 +00:00
* Gather billing address.
2020-03-05 14:52:20 +00:00
*
2021-09-09 14:44:04 +00:00
* @param $data
* @param $cart
2020-03-05 14:52:20 +00:00
* @return array
*/
private function gatherBillingAddress($data, \Webkul\Checkout\Models\Cart $cart): array
{
$customerAddress = [];
if (isset($data['billing']['address_id']) && $data['billing']['address_id']) {
$customerAddress = $this
->customerAddressRepository
->findOneWhere(['id' => $data['billing']['address_id']])
->toArray();
}
$billingAddress = array_merge(
$customerAddress,
$data['billing'],
['cart_id' => $cart->id],
$this->fillCustomerAttributes(),
$this->fillAddressAttributes($data['billing'])
);
return $billingAddress;
}
/**
2021-09-09 14:44:04 +00:00
* Gather shipping address.
2020-03-05 14:52:20 +00:00
*
2021-09-09 14:44:04 +00:00
* @param array $data
* @param \Webkul\Checkout\Cart|null $cart
2020-03-05 14:52:20 +00:00
* @return array
*/
private function gatherShippingAddress($data, \Webkul\Checkout\Models\Cart $cart): array
{
$customerAddress = [];
if (isset($data['shipping']['address_id']) && $data['shipping']['address_id']) {
$customerAddress = $this
->customerAddressRepository
->findOneWhere(['id' => $data['shipping']['address_id']])
->toArray();
}
$shippingAddress = array_merge(
$customerAddress,
$data['shipping'],
['cart_id' => $cart->id],
$this->fillCustomerAttributes(),
$this->fillAddressAttributes($data['shipping'])
);
return $shippingAddress;
}
/**
2021-09-09 14:44:04 +00:00
* Link addresses.
2020-03-05 14:52:20 +00:00
*
2021-09-09 14:44:04 +00:00
* @param \Webkul\Checkout\Cart|null $cart
* @param array $billingAddressData
* @param array $shippingAddressData
2020-03-05 14:52:20 +00:00
* @throws \Prettus\Validator\Exceptions\ValidatorException
*/
private function linkAddresses(
\Webkul\Checkout\Models\Cart $cart,
array $billingAddressData,
array $shippingAddressData
2021-09-09 14:44:04 +00:00
): void {
2020-03-05 14:52:20 +00:00
$billingAddressModel = $cart->billing_address;
if ($billingAddressModel) {
2020-05-06 06:06:07 +00:00
$billingAddressData['address_type'] = CartAddress::ADDRESS_TYPE_BILLING;
2020-03-05 14:52:20 +00:00
$this->cartAddressRepository->update($billingAddressData, $billingAddressModel->id);
if ($cart->haveStockableItems()) {
$shippingAddressModel = $cart->shipping_address;
if ($shippingAddressModel) {
if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) {
2020-05-06 06:06:07 +00:00
$billingAddressData['address_type'] = CartAddress::ADDRESS_TYPE_SHIPPING;
2020-03-05 14:52:20 +00:00
$this->cartAddressRepository->update($billingAddressData, $shippingAddressModel->id);
} else {
2020-05-06 06:09:45 +00:00
$shippingAddressData['address_type'] = CartAddress::ADDRESS_TYPE_SHIPPING;
2020-03-05 14:52:20 +00:00
$this->cartAddressRepository->update($shippingAddressData, $shippingAddressModel->id);
}
} else {
if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) {
2021-09-09 14:44:04 +00:00
$this->cartAddressRepository->create(array_merge(
$billingAddressData,
['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]
));
2020-03-05 14:52:20 +00:00
} else {
2021-09-09 14:44:04 +00:00
$this->cartAddressRepository->create(array_merge(
$shippingAddressData,
['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]
));
2020-03-05 14:52:20 +00:00
}
}
}
} else {
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_BILLING]));
2020-03-05 14:52:20 +00:00
if ($cart->haveStockableItems()) {
if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) {
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
2020-03-05 14:52:20 +00:00
} else {
$this->cartAddressRepository->create(array_merge($shippingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
2020-03-05 14:52:20 +00:00
}
}
}
}
2020-02-20 18:23:01 +00:00
}