diff --git a/resources/lang/en/default.php b/resources/lang/en/default.php index 3ed60ed..52b50e8 100644 --- a/resources/lang/en/default.php +++ b/resources/lang/en/default.php @@ -13,6 +13,7 @@ 'text_tab_title_order' => 'Order', 'text_menu_price_include_tax' => 'Menu prices already include tax', 'text_apply_tax_on_menu_price' => 'Apply tax on top of my menu price', + 'text_charts_orders' => 'Orders', 'text_basket' => 'Basket', 'text_update_heading' => 'Updating menu choices', diff --git a/src/Cart.php b/src/Cart.php index 9e9c72d..642be3b 100644 --- a/src/Cart.php +++ b/src/Cart.php @@ -8,7 +8,7 @@ use Igniter\Cart\Contracts\Buyable; use Igniter\Cart\Exceptions\InvalidRowIDException; use Igniter\Cart\Exceptions\UnknownModelException; -use Illuminate\Events\Dispatcher; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Session\SessionManager; class Cart diff --git a/src/Database/Factories/MenuFactory.php b/src/Database/Factories/MenuFactory.php index bda7105..bf08316 100644 --- a/src/Database/Factories/MenuFactory.php +++ b/src/Database/Factories/MenuFactory.php @@ -12,7 +12,7 @@ public function definition(): array { return [ 'menu_name' => $this->faker->sentence(2), - 'menu_price' => $this->faker->randomFloat(), + 'menu_price' => $this->faker->randomFloat(null, 0, 100), 'minimum_qty' => 1, 'menu_status' => 1, ]; diff --git a/src/Extension.php b/src/Extension.php index 09714f7..55ab492 100644 --- a/src/Extension.php +++ b/src/Extension.php @@ -2,7 +2,10 @@ namespace Igniter\Cart; +use Igniter\Admin\DashboardWidgets\Charts; +use Igniter\Admin\DashboardWidgets\Statistics; use Igniter\Admin\Widgets\Form; +use Igniter\Cart\Listeners\RegistersDashboardCards; use Igniter\Cart\Models\Category; use Igniter\Cart\Models\Concerns\LocationAction; use Igniter\Cart\Models\Menu; @@ -83,6 +86,7 @@ public function boot() $this->bindCartEvents(); $this->bindCheckoutEvents(); $this->bindOrderStatusEvent(); + $this->extendDashboardChartsDatasets(); LocationModel::implement(LocationAction::class); @@ -124,6 +128,10 @@ public function boot() ], ], 'primary'); }); + + Statistics::registerCards(function() { + return (new RegistersDashboardCards())(); + }); } public function registerCartConditions() @@ -442,4 +450,23 @@ protected function registerSystemSettings() ]); }); } + + protected function extendDashboardChartsDatasets() + { + Charts::extend(function($charts) { + $charts->bindEvent('charts.extendDatasets', function() use ($charts) { + $charts->addDataset('reports', [ + 'sets' => [ + 'orders' => [ + 'label' => 'lang:igniter.cart::default.text_charts_orders', + 'color' => '#64B5F6', + 'model' => Order::class, + 'column' => 'order_date', + 'priority' => 20, + ], + ], + ]); + }); + }); + } } diff --git a/src/Listeners/RegistersDashboardCards.php b/src/Listeners/RegistersDashboardCards.php new file mode 100644 index 0000000..b0cc5cc --- /dev/null +++ b/src/Listeners/RegistersDashboardCards.php @@ -0,0 +1,167 @@ + [ + 'label' => 'lang:igniter::admin.dashboard.text_total_sale', + 'icon' => ' text-success fa fa-4x fa-line-chart', + 'valueFrom' => [$this, 'getValue'] + ], + 'lost_sale' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_lost_sale', + 'icon' => ' text-danger fa fa-4x fa-line-chart', + 'valueFrom' => [$this, 'getValue'] + ], + 'cash_payment' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_cash_payment', + 'icon' => ' text-warning fa fa-4x fa-money-bill', + 'valueFrom' => [$this, 'getValue'] + ], + 'order' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_order', + 'icon' => ' text-success fa fa-4x fa-shopping-cart', + 'valueFrom' => [$this, 'getValue'] + ], + 'delivery_order' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_delivery_order', + 'icon' => ' text-primary fa fa-4x fa-truck', + 'valueFrom' => [$this, 'getValue'] + ], + 'collection_order' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_collection_order', + 'icon' => ' text-info fa fa-4x fa-shopping-bag', + 'valueFrom' => [$this, 'getValue'] + ], + 'completed_order' => [ + 'label' => 'lang:igniter::admin.dashboard.text_total_completed_order', + 'icon' => ' text-success fa fa-4x fa-receipt', + 'valueFrom' => [$this, 'getValue'] + ], + ]; + } + + public function getValue($code, $start, $end, callable $callback) + { + return match ($code) { + 'sale' => $this->getTotalSaleSum($callback), + 'lost_sale' => $this->getTotalLostSaleSum($callback), + 'cash_payment' => $this->getTotalCashPaymentSum($callback), + 'order' => $this->getTotalOrderSum($callback), + 'delivery_order' => $this->getTotalDeliveryOrderSum($callback), + 'collection_order' => $this->getTotalCollectionOrderSum($callback), + 'completed_order' => $this->getTotalCompletedOrderSum($callback), + default => 0, + }; + } + + /** + * Return the total amount of order sales + */ + protected function getTotalSaleSum(callable $callback): string + { + $query = Order::query(); + $query->where('status_id', '>', '0') + ->where('status_id', '!=', Settings::get('canceled_order_status')); + + $callback($query); + + return currency_format($query->sum('order_total') ?? 0); + } + + /** + * Return the total amount of lost order sales + */ + protected function getTotalLostSaleSum(callable $callback): string + { + $query = Order::query(); + $query->where(function($query) { + $query->where('status_id', '<=', '0'); + $query->orWhere('status_id', Settings::get('canceled_order_status')); + }); + + $callback($query); + + return currency_format($query->sum('order_total') ?? 0); + } + + /** + * Return the total amount of cash payment order sales + */ + protected function getTotalCashPaymentSum(callable $callback): string + { + $query = Order::query(); + $query->where(function($query) { + $query->where('status_id', '>', '0'); + $query->where('status_id', '!=', Settings::get('canceled_order_status')); + })->where('payment', 'cod'); + + $callback($query); + + return currency_format($query->sum('order_total') ?? 0); + } + + /** + * Return the total number of orders placed + */ + protected function getTotalOrderSum(callable $callback): int + { + $query = Order::query(); + + $callback($query); + + return $query->count(); + } + + /** + * Return the total number of completed orders + */ + protected function getTotalCompletedOrderSum(callable $callback): int + { + $query = Order::query(); + $query->whereIn('status_id', Settings::get('completed_order_status') ?? []); + + $callback($query); + + return $query->count(); + } + + /** + * Return the total number of delivery orders + */ + protected function getTotalDeliveryOrderSum(callable $callback): string + { + $query = Order::query(); + $query->where(function($query) { + $query->where('order_type', '1'); + $query->orWhere('order_type', 'delivery'); + }); + + $callback($query); + + return currency_format($query->sum('order_total') ?? 0); + } + + /** + * Return the total number of collection orders + */ + protected function getTotalCollectionOrderSum(callable $callback): string + { + $query = Order::query(); + $query->where(function($query) { + $query->where('order_type', '2'); + $query->orWhere('order_type', 'collection'); + }); + + $callback($query); + + return currency_format($query->sum('order_total') ?? 0); + } +}