sarga/packages/Webkul/Sales/src/Repositories/OrderRepository.php

405 lines
13 KiB
PHP
Raw Normal View History

<?php
namespace Webkul\Sales\Repositories;
2021-03-02 07:22:02 +00:00
use Webkul\Sales\Contracts\Order;
2018-10-04 06:42:06 +00:00
use Illuminate\Support\Facades\DB;
2021-01-15 05:58:05 +00:00
use Illuminate\Support\Facades\Log;
2018-10-05 06:18:58 +00:00
use Webkul\Core\Eloquent\Repository;
2021-03-02 07:22:02 +00:00
use Illuminate\Support\Facades\Event;
use Webkul\Shop\Generators\Sequencer;
2021-03-02 07:22:02 +00:00
use Illuminate\Container\Container as App;
use Webkul\Shop\Generators\OrderNumberIdSequencer;
class OrderRepository extends Repository
{
/**
2021-03-02 07:22:02 +00:00
* OrderItemRepository $orderItemRepository
*
2020-03-05 13:37:08 +00:00
* @var \Webkul\Sales\Repositories\OrderItemRepository
*/
2019-06-28 14:18:52 +00:00
protected $orderItemRepository;
/**
2021-03-02 07:22:02 +00:00
* DownloadableLinkPurchasedRepository $downloadableLinkPurchasedRepository
2019-06-28 14:18:52 +00:00
*
2020-03-05 13:37:08 +00:00
* @var \Webkul\Sales\Repositories\DownloadableLinkPurchasedRepository
2019-06-28 14:18:52 +00:00
*/
protected $downloadableLinkPurchasedRepository;
/**
* Create a new repository instance.
*
2020-03-05 13:37:08 +00:00
* @param \Webkul\Sales\Repositories\OrderItemRepository $orderItemRepository
* @param \Webkul\Sales\Repositories\DownloadableLinkPurchasedRepository $downloadableLinkPurchasedRepository
2021-03-02 07:22:02 +00:00
* @param \Illuminate\Container\Container $app
* @return void
*/
public function __construct(
2019-06-28 14:18:52 +00:00
OrderItemRepository $orderItemRepository,
DownloadableLinkPurchasedRepository $downloadableLinkPurchasedRepository,
App $app
2019-11-22 07:49:22 +00:00
) {
2019-06-28 14:18:52 +00:00
$this->orderItemRepository = $orderItemRepository;
$this->downloadableLinkPurchasedRepository = $downloadableLinkPurchasedRepository;
parent::__construct($app);
}
/**
2021-03-12 08:01:35 +00:00
* Specify model class name.
*
2020-03-05 13:37:08 +00:00
* @return string
*/
public function model()
{
2019-04-03 13:21:05 +00:00
return Order::class;
}
/**
2021-01-15 05:58:05 +00:00
* This method will try attempt to a create order.
2021-03-02 07:22:02 +00:00
*
2020-03-05 13:37:08 +00:00
* @return \Webkul\Sales\Contracts\Order
*/
2021-01-15 05:58:05 +00:00
public function createOrderIfNotThenRetry(array $data)
{
2018-10-04 06:42:06 +00:00
DB::beginTransaction();
2018-10-15 10:45:29 +00:00
2018-10-04 06:42:06 +00:00
try {
Event::dispatch('checkout.order.save.before', [$data]);
2018-10-04 06:42:06 +00:00
2019-01-15 11:54:41 +00:00
if (isset($data['customer']) && $data['customer']) {
2018-10-05 06:18:58 +00:00
$data['customer_id'] = $data['customer']->id;
$data['customer_type'] = get_class($data['customer']);
2018-10-05 11:59:43 +00:00
} else {
unset($data['customer']);
2018-10-05 06:18:58 +00:00
}
2018-10-05 11:59:43 +00:00
2019-01-15 11:54:41 +00:00
if (isset($data['channel']) && $data['channel']) {
$data['channel_id'] = $data['channel']->id;
$data['channel_type'] = get_class($data['channel']);
$data['channel_name'] = $data['channel']->name;
} else {
unset($data['channel']);
}
2019-01-25 14:14:07 +00:00
$data['status'] = 'pending';
2018-10-05 11:59:43 +00:00
2018-10-05 06:18:58 +00:00
$order = $this->model->create(array_merge($data, ['increment_id' => $this->generateIncrementId()]));
2018-10-04 06:42:06 +00:00
2018-10-05 06:18:58 +00:00
$order->payment()->create($data['payment']);
2019-11-22 07:49:22 +00:00
if (isset($data['shipping_address'])) {
2019-06-28 14:18:52 +00:00
$order->addresses()->create($data['shipping_address']);
2019-11-22 07:49:22 +00:00
}
2018-10-15 10:45:29 +00:00
2018-10-05 06:18:58 +00:00
$order->addresses()->create($data['billing_address']);
2019-01-15 11:54:41 +00:00
foreach ($data['items'] as $item) {
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.order.orderitem.save.before', $data);
2019-06-28 14:18:52 +00:00
$orderItem = $this->orderItemRepository->create(array_merge($item, ['order_id' => $order->id]));
2018-10-05 06:18:58 +00:00
2019-08-30 11:39:15 +00:00
if (isset($item['children']) && $item['children']) {
foreach ($item['children'] as $child) {
$this->orderItemRepository->create(array_merge($child, ['order_id' => $order->id, 'parent_id' => $orderItem->id]));
}
2018-10-05 06:18:58 +00:00
}
2018-10-05 11:59:43 +00:00
2019-06-28 14:18:52 +00:00
$this->orderItemRepository->manageInventory($orderItem);
2019-10-11 05:02:40 +00:00
$this->downloadableLinkPurchasedRepository->saveLinks($orderItem, 'available');
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.order.orderitem.save.after', $data);
2018-10-05 06:18:58 +00:00
}
2018-10-26 13:43:01 +00:00
2019-12-24 14:01:13 +00:00
Event::dispatch('checkout.order.save.after', $order);
2018-10-04 06:42:06 +00:00
} catch (\Exception $e) {
2021-01-15 05:58:05 +00:00
/* rolling back first */
2018-10-04 06:42:06 +00:00
DB::rollBack();
2021-01-15 05:58:05 +00:00
/* storing log for errors */
Log::error('OrderRepository:createOrderIfNotThenRetry: ' . $e->getMessage(),
['data' => $data]);
2018-10-15 10:45:29 +00:00
2021-01-15 05:58:05 +00:00
/* recalling */
$this->createOrderIfNotThenRetry($data);
} finally {
/* commit in each case */
DB::commit();
}
2018-10-04 06:42:06 +00:00
return $order;
}
2018-10-05 06:18:58 +00:00
2021-01-15 05:58:05 +00:00
/**
2021-03-12 08:01:35 +00:00
* Create order.
*
2021-01-15 05:58:05 +00:00
* @param array $data
* @return \Webkul\Sales\Contracts\Order
*/
public function create(array $data)
{
return $this->createOrderIfNotThenRetry($data);
}
2018-10-15 10:39:09 +00:00
/**
2021-03-02 07:22:02 +00:00
* Cancel order. This method should be independent as admin also can cancel the order.
*
* @param \Webkul\Sales\Models\Order|int $orderOrId
2020-03-05 13:37:08 +00:00
* @return \Webkul\Sales\Contracts\Order
2018-10-15 10:39:09 +00:00
*/
2021-03-02 07:22:02 +00:00
public function cancel($orderOrId)
2018-10-15 10:39:09 +00:00
{
2021-03-02 07:22:02 +00:00
/* order */
$order = $this->resolveOrderInstance($orderOrId);
2018-10-15 10:39:09 +00:00
2021-03-02 07:22:02 +00:00
/* check wether order can be cancelled or not */
2019-11-22 07:49:22 +00:00
if (! $order->canCancel()) {
2018-10-15 10:39:09 +00:00
return false;
2019-11-22 07:49:22 +00:00
}
2018-10-15 10:39:09 +00:00
2019-12-24 14:01:13 +00:00
Event::dispatch('sales.order.cancel.before', $order);
2019-01-15 11:54:41 +00:00
foreach ($order->items as $item) {
2019-11-22 07:49:22 +00:00
if (! $item->qty_to_cancel) {
continue;
2019-11-22 07:49:22 +00:00
}
$orderItems = [];
2018-10-15 10:39:09 +00:00
2019-10-22 13:27:06 +00:00
if ($item->getTypeInstance()->isComposite()) {
foreach ($item->children as $child) {
$orderItems[] = $child;
}
} else {
$orderItems[] = $item;
}
foreach ($orderItems as $orderItem) {
2019-11-22 07:49:22 +00:00
if ($orderItem->product) {
2019-10-23 05:19:44 +00:00
$this->orderItemRepository->returnQtyToProductInventory($orderItem);
2019-11-22 07:49:22 +00:00
}
if ($orderItem->qty_ordered) {
$orderItem->qty_canceled += $orderItem->qty_to_cancel;
$orderItem->save();
if ($orderItem->parent && $orderItem->parent->qty_ordered) {
$orderItem->parent->qty_canceled += $orderItem->parent->qty_to_cancel;
$orderItem->parent->save();
}
} else {
$orderItem->parent->qty_canceled += $orderItem->parent->qty_to_cancel;
$orderItem->parent->save();
}
2018-10-15 10:39:09 +00:00
}
2019-10-11 05:02:40 +00:00
$this->downloadableLinkPurchasedRepository->updateStatus($item, 'expired');
2018-10-15 10:39:09 +00:00
}
$this->updateOrderStatus($order);
2019-12-24 14:01:13 +00:00
Event::dispatch('sales.order.cancel.after', $order);
2019-01-17 11:47:53 +00:00
2018-10-15 10:39:09 +00:00
return true;
}
2018-10-05 06:18:58 +00:00
/**
2021-03-02 07:22:02 +00:00
* Generate increment id.
*
2020-03-05 13:37:08 +00:00
* @return int
2018-10-05 06:18:58 +00:00
*/
2019-11-22 07:49:22 +00:00
public function generateIncrementId()
2018-10-05 06:18:58 +00:00
{
2021-03-02 07:22:02 +00:00
/**
* @var $generatorClass Sequencer
*/
$generatorClass = core()->getConfigData('sales.orderSettings.order_number.order_number_generator-class') ?: false;
if ($generatorClass !== false
&& class_exists($generatorClass)
&& in_array(Sequencer::class, class_implements($generatorClass), true)
) {
return $generatorClass::generate();
2020-02-27 08:03:03 +00:00
}
2018-10-05 06:18:58 +00:00
return OrderNumberIdSequencer::generate();
2018-10-05 06:18:58 +00:00
}
/**
2021-03-02 07:22:02 +00:00
* Is order in completed state.
*
2020-03-05 13:37:08 +00:00
* @param \Webkul\Sales\Contracts\Order $order
2018-10-15 10:39:09 +00:00
* @return void
*/
public function isInCompletedState($order)
{
2019-09-23 12:05:00 +00:00
$totalQtyOrdered = $totalQtyInvoiced = $totalQtyShipped = $totalQtyRefunded = $totalQtyCanceled = 0;
2018-10-15 10:39:09 +00:00
foreach ($order->items()->get() as $item) {
2018-10-15 10:39:09 +00:00
$totalQtyOrdered += $item->qty_ordered;
$totalQtyInvoiced += $item->qty_invoiced;
2019-06-28 14:18:52 +00:00
2019-11-21 12:48:34 +00:00
if (! $item->isStockable()) {
2020-09-05 13:01:56 +00:00
$totalQtyShipped += $item->qty_invoiced;
2019-06-28 14:18:52 +00:00
} else {
$totalQtyShipped += $item->qty_shipped;
}
2018-10-15 10:39:09 +00:00
$totalQtyRefunded += $item->qty_refunded;
$totalQtyCanceled += $item->qty_canceled;
}
2019-06-28 14:18:52 +00:00
if ($totalQtyOrdered != ($totalQtyRefunded + $totalQtyCanceled)
2019-10-14 09:15:09 +00:00
&& $totalQtyOrdered == $totalQtyInvoiced + $totalQtyCanceled
2019-11-22 07:49:22 +00:00
&& $totalQtyOrdered == $totalQtyShipped + $totalQtyRefunded + $totalQtyCanceled) {
2018-10-15 10:39:09 +00:00
return true;
2019-11-22 07:49:22 +00:00
}
2018-10-15 10:39:09 +00:00
return false;
}
/**
2021-03-02 07:22:02 +00:00
* Is order in cancelled state.
*
2020-03-05 13:37:08 +00:00
* @param \Webkul\Sales\Contracts\Order $order
* @return void
*/
2018-10-15 10:39:09 +00:00
public function isInCanceledState($order)
{
2019-10-11 05:30:16 +00:00
$totalQtyOrdered = $totalQtyCanceled = 0;
2018-10-15 10:39:09 +00:00
2019-10-11 05:30:16 +00:00
foreach ($order->items()->get() as $item) {
2018-10-15 10:39:09 +00:00
$totalQtyOrdered += $item->qty_ordered;
$totalQtyCanceled += $item->qty_canceled;
}
2019-10-14 09:15:09 +00:00
return $totalQtyOrdered === $totalQtyCanceled;
2018-10-15 10:39:09 +00:00
}
/**
2021-03-02 07:22:02 +00:00
* Is order in closed state.
*
2021-03-02 07:22:02 +00:00
* @param mixed $order
2018-10-15 10:39:09 +00:00
* @return void
*/
public function isInClosedState($order)
{
2019-10-11 05:30:16 +00:00
$totalQtyOrdered = $totalQtyRefunded = $totalQtyCanceled = 0;
2018-10-15 10:39:09 +00:00
foreach ($order->items()->get() as $item) {
2018-10-15 10:39:09 +00:00
$totalQtyOrdered += $item->qty_ordered;
$totalQtyRefunded += $item->qty_refunded;
$totalQtyCanceled += $item->qty_canceled;
}
2019-10-14 09:15:09 +00:00
return $totalQtyOrdered === $totalQtyRefunded + $totalQtyCanceled;
2018-10-15 10:39:09 +00:00
}
/**
2021-03-02 07:22:02 +00:00
* Update order status.
*
2020-03-05 13:37:08 +00:00
* @param \Webkul\Sales\Contracts\Order $order
2018-10-15 10:39:09 +00:00
* @return void
*/
2021-05-02 17:18:30 +00:00
public function updateOrderStatus($order, $orderState = null)
2018-10-15 10:39:09 +00:00
{
2021-05-02 17:39:03 +00:00
if (!empty($orderState)) {
2021-05-02 17:18:30 +00:00
$status = $orderState;
} else {
$status = "processing";
2018-10-15 10:39:09 +00:00
2021-05-02 17:18:30 +00:00
if ($this->isInCompletedState($order)) {
$status = 'completed';
}
2018-10-15 10:39:09 +00:00
2021-05-02 17:18:30 +00:00
if ($this->isInCanceledState($order)) {
$status = 'canceled';
} elseif ($this->isInClosedState($order)) {
$status = 'closed';
}
2019-11-22 07:49:22 +00:00
}
2018-10-15 10:39:09 +00:00
$order->status = $status;
$order->save();
}
/**
2021-03-02 07:22:02 +00:00
* Collect totals.
*
2020-03-05 13:37:08 +00:00
* @param \Webkul\Sales\Contracts\Order $order
* @return mixed
*/
public function collectTotals($order)
{
2021-03-02 07:22:02 +00:00
// order invoice total
$order->sub_total_invoiced = $order->base_sub_total_invoiced = 0;
$order->shipping_invoiced = $order->base_shipping_invoiced = 0;
$order->tax_amount_invoiced = $order->base_tax_amount_invoiced = 0;
2019-09-19 09:56:07 +00:00
$order->discount_invoiced = $order->base_discount_invoiced = 0;
2019-01-15 11:54:41 +00:00
foreach ($order->invoices as $invoice) {
$order->sub_total_invoiced += $invoice->sub_total;
$order->base_sub_total_invoiced += $invoice->base_sub_total;
$order->shipping_invoiced += $invoice->shipping_amount;
$order->base_shipping_invoiced += $invoice->base_shipping_amount;
$order->tax_amount_invoiced += $invoice->tax_amount;
$order->base_tax_amount_invoiced += $invoice->base_tax_amount;
2019-05-23 11:30:11 +00:00
$order->discount_invoiced += $invoice->discount_amount;
$order->base_discount_invoiced += $invoice->base_discount_amount;
}
2019-05-23 11:30:11 +00:00
$order->grand_total_invoiced = $order->sub_total_invoiced + $order->shipping_invoiced + $order->tax_amount_invoiced - $order->discount_invoiced;
$order->base_grand_total_invoiced = $order->base_sub_total_invoiced + $order->base_shipping_invoiced + $order->base_tax_amount_invoiced - $order->base_discount_invoiced;
2021-03-02 07:22:02 +00:00
// order refund total
2019-09-18 13:27:40 +00:00
$order->sub_total_refunded = $order->base_sub_total_refunded = 0;
$order->shipping_refunded = $order->base_shipping_refunded = 0;
$order->tax_amount_refunded = $order->base_tax_amount_refunded = 0;
2019-09-23 11:19:34 +00:00
$order->discount_refunded = $order->base_discount_refunded = 0;
2019-09-18 13:27:40 +00:00
$order->grand_total_refunded = $order->base_grand_total_refunded = 0;
foreach ($order->refunds as $refund) {
$order->sub_total_refunded += $refund->sub_total;
$order->base_sub_total_refunded += $refund->base_sub_total;
$order->shipping_refunded += $refund->shipping_amount;
$order->base_shipping_refunded += $refund->base_shipping_amount;
$order->tax_amount_refunded += $refund->tax_amount;
$order->base_tax_amount_refunded += $refund->base_tax_amount;
$order->discount_refunded += $refund->discount_amount;
$order->base_discount_refunded += $refund->base_discount_amount;
$order->grand_total_refunded += $refund->adjustment_refund - $refund->adjustment_fee;
$order->base_grand_total_refunded += $refund->base_adjustment_refund - $refund->base_adjustment_fee;
}
$order->grand_total_refunded += $order->sub_total_refunded + $order->shipping_refunded + $order->tax_amount_refunded - $order->discount_refunded;
$order->base_grand_total_refunded += $order->base_sub_total_refunded + $order->base_shipping_refunded + $order->base_tax_amount_refunded - $order->base_discount_refunded;
$order->save();
return $order;
}
2021-03-02 07:22:02 +00:00
/**
* This method will find order if id is given else pass the order as it is.
*
* @param \Webkul\Sales\Models\Order|int $orderOrId
* @return \Webkul\Sales\Contracts\Order
*/
private function resolveOrderInstance($orderOrId)
{
return $orderOrId instanceof \Webkul\Sales\Models\Order
? $orderOrId
: $this->findOrFail($orderOrId);
}
2019-11-22 07:49:22 +00:00
}