customer report

This commit is contained in:
omair saleh
2021-10-02 14:59:15 +08:00
parent 019073afc5
commit bbc247d67e
7 changed files with 308 additions and 39 deletions
@@ -0,0 +1,62 @@
<?php
namespace App\Http\Controllers\Reports;
use App\Classes\ValueObjects\Constants\HttpStatus;
use App\Classes\ValueObjects\Response\ApiResponseObject;
use App\Models\Container;
use App\Models\Order;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class MonthlyReportController
{
public function report(Request $request): JsonResponse {
$containers = Container::whereMonth('loading_date', '=', '09')->whereYear('loading_date', '=', '2021')->orderBy('loading_date')->get();
$total = 0;
$customers = collect();
foreach ($containers as $container){
foreach($container->packingLists as $packingList){
$cbm = $packingList->packages->sum(function ($package){
return (( (float) $package->width / 100) * ( (float) $package->length / 100) * ( (float) $package->height / 100)) * $package->quantity;
});
$total += $cbm;
$marking = $packingList->owner->companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
if(!$customers->has($marking)){
$customers->put($marking, collect([
'cbm' => $cbm,
'orders' => 1,
'packages' => $packingList->packages->sum('quantity')
]));
continue;
}
$customers[$marking]['cbm'] += $cbm;
$customers[$marking]['orders'] += 1;
$customers[$marking]['packages'] += $packingList->packages->sum('quantity');
}
}
$activeOrders = $customers->sum(function($customer){
return $customer['orders'];
});
return (new ApiResponseObject('fetch monthly report Successful',
'',
HttpStatus::OK_WITH_MESSAGE, ['data' => [
'containers' => count($containers),
'activated_orders' => $activeOrders,
'active_customers' => count($customers),
'total_cbm' => $customers->sum(function($customer){
return $customer['cbm'];
}),
'packages' => $customers->sum(function($customer){
return $customer['packages'];
}),
'total_orders' => Order::whereMonth('created_at', 9)->whereHas('packingLists')->count()
]]))->handler();
}
}
@@ -0,0 +1,168 @@
<template>
<div class="row" >
<div class="col">
<loading-component v-if="isLoading"></loading-component>
<div class="row" v-if="report">
<div class="col">
<div class="card no-border bg-master-lightest widget-loader-bar m-b-10">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title">
<span class="font-montserrat fs-11 all-caps">Total CBM</span>
</div>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="p-l-20 p-t-50 p-b-40 p-r-20">
<h3 class="no-margin p-b-5">{{(Math.ceil(report.total_cbm * 1000) / 1000).toFixed(3)}} CBM</h3>
<span class="small hint-text pull-left">{{ Math.ceil((((report.total_cbm / 700) * 100) * 100) / 100).toFixed(2)}}%</span>
<span class="pull-right small text-primary">Goal: 700 CBM</span>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-bottom">
<div class="progress progress-small m-b-0">
<div class="progress-bar progress-bar-primary" :style="{'width': Math.ceil((((report.total_cbm / 700) * 100) * 100) / 100).toFixed(2)+'%'}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card no-border bg-master-lightest widget-loader-bar m-b-10">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title">
<span class="font-montserrat fs-11 all-caps">Activated Orders</span>
</div>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="p-l-20 p-t-50 p-b-40 p-r-20">
<h3 class="no-margin p-b-5">{{report.activated_orders}}</h3>
<span class="small hint-text pull-left">{{ Math.ceil((((report.activated_orders / report.total_orders) * 100) * 100) / 100).toFixed(2)}}%</span>
<span class="pull-right small text-primary">Total: {{report.total_orders}} Orders</span>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-bottom">
<div class="progress progress-small m-b-0">
<div class="progress-bar progress-bar-primary" :style="{'width': Math.ceil((((report.activated_orders / report.total_orders) * 100) * 100) / 100).toFixed(2)+'%'}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card no-border bg-master-lightest widget-loader-bar m-b-10">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title">
<span class="font-montserrat fs-11 all-caps">Active Customers</span>
</div>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="p-l-20 p-t-50 p-b-40 p-r-20">
<h3 class="no-margin p-b-5">{{report.active_customers}}</h3>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-bottom">
<div class="progress progress-small m-b-0">
<div class="progress-bar progress-bar-primary" style="width: 0"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card no-border bg-master-lightest widget-loader-bar m-b-10">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title">
<span class="font-montserrat fs-11 all-caps">Containers</span>
</div>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="p-l-20 p-t-50 p-b-40 p-r-20">
<h3 class="no-margin p-b-5">{{report.containers}}</h3>
</div>
</div>
</div>
<div class="row-xs-height">
<div class="col-xs-height col-bottom">
<div class="progress progress-small m-b-0">
<div class="progress-bar progress-bar-primary" style="width: 0"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import LoadingComponent from "../../general/elements/LoadingComponent";
export default {
components: {LoadingComponent},
data(){
return {
section: 'monthlyReportSection',
isLoading: true,
report: null
}
},
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingQueue(inComplete){
if(inComplete){
this.fetchReport();
}
}
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
fetchReport(){
this.isLoading = true;
this.submit(route('api.report'), 'get', this.section, false, false)
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.isLoading = false;
this.report = response.payload.data;
}
}
}
</script>
@@ -0,0 +1,25 @@
@extends('layouts.base_portal')
@section('inner_content')
<div class="row">
<div class="col">
<div class="row d-none" :class="[{'d-flex': $store.getters.isAdmin}]" v-if="$store.getters.isAdmin">
<div class="col-8">
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Customers List</h6>
</div>
</div>
<div class="row m-l-0 m-r-0">
<div class="col">
<list-component key="2" section="customerListSection" :endpoint="route('api.company.list')" :options="{'has_business_module_type': 1}">
<template slot="list" slot-scope="{data}">
<company-component :data="data"></company-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
+34 -39
View File
@@ -1,47 +1,42 @@
<div class="row d-none" :class="[{'d-flex': $store.getters.isAdmin}]" v-if="$store.getters.isAdmin">
<div class="col-8">
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Customers List</h6>
</div>
</div>
<div class="row m-l-0 m-r-0">
<div class="col">
<div class="row m-b-50">
<div class="col">
<list-component key="2" section="customerListSection" :endpoint="route('api.company.list')" :options="{'has_business_module_type': 1}">
<template slot="list" slot-scope="{data}">
<company-component :data="data"></company-component>
</template>
</list-component>
<monthly-report-section-component></monthly-report-section-component>
</div>
</div>
</div>
<div class="col-4">
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Identification Verification</h6>
<div class="row">
<div class="col-4">
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Identification Verification</h6>
</div>
</div>
<div class="row no-margin">
<div class="col">
<list-component key="2" section="identificationVerificationSection" :options="{'per_page': 10, 'document_type_in': ['SSM_REGISTRATION', 'IDENTITY_CARD'], 'status': 1, 'with_company': true}" :endpoint="route('api.document.list')">
<template slot="list" slot-scope="{data}">
<identification-verification-component section="identificationVerificationSection" :data="data"></identification-verification-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
<div class="row no-margin">
<div class="col">
<list-component key="2" section="identificationVerificationSection" :options="{'per_page': 5, 'document_type_in': ['SSM_REGISTRATION', 'IDENTITY_CARD'], 'status': 1, 'with_company': true}" :endpoint="route('api.document.list')">
<template slot="list" slot-scope="{data}">
<identification-verification-component section="identificationVerificationSection" :data="data"></identification-verification-component>
</template>
</list-component>
</div>
</div>
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Address Change Verification</h6>
</div>
</div>
<div class="row no-margin">
<div class="col">
<list-component key="2" section="addressVerificationSection" :options="{'per_page': 5, 'status': 1, 'with_owner': true}" :endpoint="route('api.address.list')">
<template slot="list" slot-scope="{data}">
<address-verification-component section="addressVerificationSection" :data="data"></address-verification-component>
</template>
</list-component>
<div class="col-4">
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
<div class="col no-padding">
<h6>Address Change Verification</h6>
</div>
</div>
<div class="row no-margin">
<div class="col">
<list-component key="2" section="addressVerificationSection" :options="{'per_page': 10, 'status': 1, 'with_owner': true}" :endpoint="route('api.address.list')">
<template slot="list" slot-scope="{data}">
<address-verification-component section="addressVerificationSection" :data="data"></address-verification-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</div>
File diff suppressed because one or more lines are too long
+2
View File
@@ -50,5 +50,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
require __DIR__ . '/schedule.php';
Route::get('/report', 'Reports\MonthlyReportController@report')->name('report');
});
});
+6
View File
@@ -7,6 +7,7 @@ use App\Classes\Jobs\FetchPackingListFromVTPortalJob;
use App\Classes\Jobs\FetchWarehouseReceiveListFromVTPortalJob;
use App\Classes\Modules\Orders\Services\FetchesDataFromVTPortal;
use App\Models\CompanyConnection;
use App\Models\Order;
use Illuminate\Support\Facades\Crypt;
use App\Models\Container;
use Illuminate\Support\Facades\Route;
@@ -53,6 +54,10 @@ Route::get('/dashboard', function () {
return view('pages.dashboard');
})->name('dashboard');
Route::get('/customers', function () {
return view('pages.admin.customers');
})->name('customers');
Route::get('/orders', function () {
return view('pages.orders.index');
})->name('orders');
@@ -178,3 +183,4 @@ Route::get('/report', function(){
});