From e09eb20d7bf83349e4f3b22125efd2972bdc6c4a Mon Sep 17 00:00:00 2001 From: blair2004 Date: Fri, 6 Aug 2021 13:08:49 +0000 Subject: [PATCH] Changelog - Fixed: owed amount for customer not correctly computed - Fixed: add refund status to order completely refunded --- app/Jobs/ComputeCustomerAccountJob.php | 77 ++++++++++++++----------- app/Listeners/OrderEventsSubscriber.php | 41 ++++++++++++- app/Services/CustomerService.php | 22 +++++++ app/Services/MenuService.php | 4 -- app/Services/OrdersService.php | 32 ++++++---- 5 files changed, 126 insertions(+), 50 deletions(-) diff --git a/app/Jobs/ComputeCustomerAccountJob.php b/app/Jobs/ComputeCustomerAccountJob.php index f6886dd1f..a265eddb8 100755 --- a/app/Jobs/ComputeCustomerAccountJob.php +++ b/app/Jobs/ComputeCustomerAccountJob.php @@ -5,6 +5,7 @@ use App\Events\OrderAfterCreatedEvent; use App\Events\OrderAfterPaymentCreatedEvent; use App\Events\OrderAfterRefundedEvent; +use App\Events\OrderAfterUpdatedEvent; use App\Events\OrderBeforeDeleteEvent; use App\Models\Order; use App\Models\OrderPayment; @@ -19,6 +20,11 @@ class ComputeCustomerAccountJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + /** + * @var CustomerService + */ + protected $customerService; + public $event; /** @@ -26,9 +32,12 @@ class ComputeCustomerAccountJob implements ShouldQueue * * @return void */ - public function __construct( $event ) - { - $this->event = $event; + public function __construct( + $event, + CustomerService $customerService + ) { + $this->event = $event; + $this->customerService = $customerService; } /** @@ -38,61 +47,63 @@ public function __construct( $event ) */ public function handle() { - if ( $this->event instanceof OrderBeforeDeleteEvent ) { - $this->handleDeletion( $this->event ); - } else if ( $this->event instanceof OrderAfterRefundedEvent ) { - $this->reduceCustomerPurchases( $this->event ); - } else if ( $this->event instanceof OrderAfterCreatedEvent ) { - $this->computeCustomerOwed( $this->event ); - $this->computeCustomerRewards( $this->event ); + if ($this->event instanceof OrderBeforeDeleteEvent) { + $this->handleDeletion($this->event); + } else if ($this->event instanceof OrderAfterRefundedEvent) { + $this->reduceCustomerPurchases($this->event); + } else if ( + $this->event instanceof OrderAfterCreatedEvent || + $this->event instanceof OrderAfterUpdatedEvent + ) { + $this->computeCustomerOwed($this->event); + $this->computeCustomerRewards($this->event); } } - private function computeCustomerOwed( OrderAfterCreatedEvent $event ) + /** + * We'll make sure to update the customer owed amount + * when even he's involved on a transaction. + */ + private function computeCustomerOwed( $event ) { - $event->order->customer->owed_amount += ns()->currency - ->define( $event->order->total ) - ->subtractBy( $event->order->tendered ) - ->getRaw(); - - $event->order->customer->save(); + $this->customerService->updateCustomerOwedAmount($event->order->customer); } - private function computeCustomerRewards( OrderAfterCreatedEvent $event ) + private function computeCustomerRewards( $event ) { - if ( $event->order->payment_status === Order::PAYMENT_PAID ) { + if ($event->order->payment_status === Order::PAYMENT_PAID) { /** * @var CustomerService */ - $customerService = app()->make( CustomerService::class ); - - $customerService->computeReward( - $event->order, - $event->order->customer + $customerService = app()->make(CustomerService::class); + + $customerService->computeReward( + $event->order, + $event->order->customer ); } } - private function reduceCustomerPurchases( OrderAfterRefundedEvent $event ) + private function reduceCustomerPurchases(OrderAfterRefundedEvent $event) { $event->order->customer->purchases_amount = $event->order->customer->purchases_amount - $event->orderRefund->total; $event->order->customer->save(); } - private function handleDeletion( OrderBeforeDeleteEvent $event ) + private function handleDeletion(OrderBeforeDeleteEvent $event) { - switch( $event->order->payment_status ) { - case 'paid': + switch ($event->order->payment_status) { + case 'paid': $event->order->customer->purchases_amount -= $event->order->total; - break; - case 'partially_paid': + break; + case 'partially_paid': $event->order->customer->purchases_amount -= $event->order->tendered; - break; + break; default: $event->order->customer->owed_amount -= $event->order->total; - break; + break; } - + $event->order->customer->save(); } } diff --git a/app/Listeners/OrderEventsSubscriber.php b/app/Listeners/OrderEventsSubscriber.php index ef88a23bc..a68014d6f 100755 --- a/app/Listeners/OrderEventsSubscriber.php +++ b/app/Listeners/OrderEventsSubscriber.php @@ -67,6 +67,27 @@ public function subscribe( $events ) [ OrderEventsSubscriber::class, 'handleOrderUpdate' ] ); + /** + * all events likely to affect + * the customer account. + */ + $events->listen( + OrderAfterCreatedEvent::class, + [ OrderEventsSubscriber::class, 'handleCustomerUpdates' ] + ); + $events->listen( + OrderAfterUpdatedEvent::class, + [ OrderEventsSubscriber::class, 'handleCustomerUpdates' ] + ); + $events->listen( + OrderBeforeDeleteEvent::class, + [ OrderEventsSubscriber::class, 'handleCustomerUpdates' ] + ); + $events->listen( + OrderAfterRefundedEvent::class, + [ OrderEventsSubscriber::class, 'handleCustomerUpdates' ] + ); + $events->listen( OrderAfterCreatedEvent::class, [ OrderEventsSubscriber::class, 'handleInstalmentPayment' ] @@ -111,13 +132,27 @@ public function handleOrderUpdate( $event ) ComputeDayReportJob::dispatch() ->delay( now()->addSecond(5) ); - ComputeCustomerAccountJob::dispatch( $event ) - ->delay( now()->addSecond(5) ); - ComputeCashierSalesJob::dispatch( $event ) ->delay( now()->addSecond(10) ); } + public function handleCustomerUpdates( $event ) + { + if ( + $event instanceof OrderAfterCreatedEvent || + $event instanceof OrderAfterUpdatedEvent || + $event instanceof OrderBeforeDeleteEvent || + $event instanceof OrderAfterRefundedEvent + + ) { + ComputeCustomerAccountJob::dispatch( + $event, + app()->make( CustomerService::class ) + ) + ->delay( now()->addSecond(5) ); + } + } + /** * When a sales is made on a specific order * we to increase the customers purchases diff --git a/app/Services/CustomerService.php b/app/Services/CustomerService.php index e64a83854..ec094b734 100755 --- a/app/Services/CustomerService.php +++ b/app/Services/CustomerService.php @@ -510,6 +510,28 @@ public function deleteRelatedCustomerCoupon( Coupon $coupon ) }); } + /** + * Will refresh the owed amount + * for the provided customer + */ + public function updateCustomerOwedAmount( Customer $customer ) + { + $unpaid = Order::whereIn( 'payment_status', [ + Order::PAYMENT_UNPAID + ])->sum( 'total' ); + + /** + * Change here will be negative, so we + * want to be an absolute value. + */ + $change = abs( Order::whereIn( 'payment_status', [ + Order::PAYMENT_PARTIALLY + ])->sum( 'change' ) ); + + $customer->owed_amount = ns()->currency->getRaw( $unpaid + $change ); + $customer->save(); + } + /** * Create customer group using * provided fields diff --git a/app/Services/MenuService.php b/app/Services/MenuService.php index 304871c20..70f77f35a 100755 --- a/app/Services/MenuService.php +++ b/app/Services/MenuService.php @@ -162,10 +162,6 @@ public function buildMenus() 'permissions' => [ 'nexopos.create.expenses-categories' ], 'href' => ns()->url( '/dashboard/expenses/categories/create' ) ], - 'cash-in' => [ - 'label' => __( 'Cash Flow' ), - 'href' => ns()->url( '/dashboard/banking/cash-flow' ) - ] ] ], 'inventory' => [ diff --git a/app/Services/OrdersService.php b/app/Services/OrdersService.php index 4049580ad..83b27b1b0 100755 --- a/app/Services/OrdersService.php +++ b/app/Services/OrdersService.php @@ -1816,6 +1816,10 @@ public function refreshOrder(Order $order) return floatval($product->total_price); })->sum(); + $productTotalQuatity = $products->map( function( $product) { + return floatval( $product->quantity ); + })->sum(); + $productGrossTotal = $products->map(function ($product) { return floatval($product->total_gross_price); })->sum(); @@ -1848,16 +1852,24 @@ public function refreshOrder(Order $order) $refunds = $order->refund; $totalRefunds = $refunds->map( fn( $refund ) => $refund->total )->sum(); - if ( ( float ) $order->total == 0 && $totalRefunds > 0 ) { - $order->payment_status = Order::PAYMENT_REFUNDED; - } else if ( $order->total > 0 && $totalRefunds > 0 ) { - $order->payment_status = Order::PAYMENT_PARTIALLY_REFUNDED; - } else if ( $order->tendered >= $order->total && $order->total > 0 ) { - $order->payment_status = Order::PAYMENT_PAID; - } else if ( ( float ) $order->tendered < ( float ) $order->total ) { - $order->payment_status = Order::PAYMENT_PARTIALLY; - } else if ( $order->total == 0 && $totalRefunds == 0 ) { - $order->payment_status = Order::PAYMENT_UNPAID; + /** + * We believe if the product total is greater + * than "0", then probably the order hasn't been paid yet. + */ + if ( $productTotal ) { + if ( ( float ) $order->total == 0 && $totalRefunds > 0 ) { + $order->payment_status = Order::PAYMENT_REFUNDED; + } else if ( $order->total > 0 && $totalRefunds > 0 ) { + $order->payment_status = Order::PAYMENT_PARTIALLY_REFUNDED; + } else if ( $order->tendered >= $order->total && $order->total > 0 ) { + $order->payment_status = Order::PAYMENT_PAID; + } else if ( ( float ) $order->tendered < ( float ) $order->total ) { + $order->payment_status = Order::PAYMENT_PARTIALLY; + } else if ( $order->total == 0 && $totalRefunds == 0 ) { + $order->payment_status = Order::PAYMENT_UNPAID; + } + } else if ( $productTotal == 0 && $productTotalQuatity == 0 ) { + $order->payment_status = Order::PAYMENT_REFUNDED; } $order->save();