diff --git a/.gitignore b/.gitignore index 95d268cf..9b34cbea 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ db/* docker-compose.yml package-lock.json public/* -/public/* \ No newline at end of file +/public/* +storage/framework/laravel-excel/* diff --git a/app/Classes/Modules/Orders/Processors/CreateOrderRolesProcessor.php b/app/Classes/Modules/Orders/Processors/CreateOrderRolesProcessor.php index 0d4b1860..24495752 100644 --- a/app/Classes/Modules/Orders/Processors/CreateOrderRolesProcessor.php +++ b/app/Classes/Modules/Orders/Processors/CreateOrderRolesProcessor.php @@ -79,6 +79,7 @@ class CreateOrderRolesProcessor $roleObject = new OrderRoleObject($order, $destinationWarehouse, OrderRoleTypes::DESTINATION_WAREHOUSE); $this->createsOrderRole->execute($roleObject); + $roleObject = new OrderRoleObject($order, $freightForwarder, OrderRoleTypes::LAST_MILE_DELIVERY_DRIVER); $this->createsOrderRole->execute($roleObject); diff --git a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/CreateContainerLogic.php b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/CreateContainerLogic.php index 26253f41..df22a66e 100644 --- a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/CreateContainerLogic.php +++ b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/CreateContainerLogic.php @@ -62,6 +62,7 @@ class CreateContainerLogic extends AbstractControllerLogic $request->input('container_number'), $request->input('seal_reference'), $request->input('container_type'), + $request->input('loading_date'), $request->input('status') ); diff --git a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/InboundCustomClearedLogic.php b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/InboundCustomClearedLogic.php new file mode 100644 index 00000000..1df92ffa --- /dev/null +++ b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/InboundCustomClearedLogic.php @@ -0,0 +1,66 @@ + 'Retrieved Containers', + 'message' => 'You have successfully retrieved a list of Containers' + ]; + } + + /** @var CanListContainers */ + private $canListContainers; + + /** @var ListsContainers */ + private $listsContainers; + + private $fetchInboundCustomCleared; + + /** + * ListContainersLogic constructor. + * @param CanListContainers $canListContainers + * @param ListsContainers $listsContainers + */ + public function __construct(CanListContainers $canListContainers, ListsContainers $listsContainers, FetchInboundCustomClearedProcessor $fetchInboundCustomCleared) + { + $this->canListContainers = $canListContainers; + $this->listsContainers = $listsContainers; + $this->fetchInboundCustomCleared = $fetchInboundCustomCleared; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + //$this->canListOrders->passes(); + + //$query = $this->listsOrders->execute(array_merge($this->listsOrders->deserializeFilters($request->input('filters')), ['with_parcels' => true])); + + $d = $this->fetchInboundCustomCleared->execute(); + + return response()->json($d); + + } +} diff --git a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/UpdateContainerLogic.php b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/UpdateContainerLogic.php index 72537db2..75eeddae 100644 --- a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/UpdateContainerLogic.php +++ b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/UpdateContainerLogic.php @@ -52,7 +52,9 @@ class UpdateContainerLogic extends AbstractControllerLogic /** * @param Request $request * @return JsonResponse - * @throws ErrorException + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException */ public function logic(Request $request) : JsonResponse { @@ -64,7 +66,8 @@ class UpdateContainerLogic extends AbstractControllerLogic $container->container_number, $request->input('container_type'), $request->input('seal_reference'), - $container->status, + $request->input('loading_date'), + $container->status, ); $this->canUpdateContainer->passes($object); diff --git a/app/Classes/Modules/PackingLists/DataTransferObjects/ContainerObject.php b/app/Classes/Modules/PackingLists/DataTransferObjects/ContainerObject.php index 3924102c..d4ef5b40 100644 --- a/app/Classes/Modules/PackingLists/DataTransferObjects/ContainerObject.php +++ b/app/Classes/Modules/PackingLists/DataTransferObjects/ContainerObject.php @@ -3,6 +3,7 @@ namespace App\Classes\Modules\PackingLists\DataTransferObjects; use App\Classes\General\Interfaces\DataTransferObject; +use Carbon\Carbon; class ContainerObject implements DataTransferObject { @@ -19,6 +20,9 @@ class ContainerObject implements DataTransferObject /** @var int */ private $containerType; + /** @var Carbon */ + private $loadingDate; + /** @var int */ private $status; @@ -28,14 +32,16 @@ class ContainerObject implements DataTransferObject * @param string $containerNumber * @param string $sealReference * @param int $containerType + * @param Carbon $loadingDate * @param int $status */ - public function __construct(string $reference, string $containerNumber, string $sealReference, int $containerType, int $status) + public function __construct(string $reference, string $containerNumber, string $sealReference, int $containerType, Carbon $loadingDate, int $status) { $this->reference = $reference; $this->containerNumber = $containerNumber; $this->sealReference = $sealReference; $this->containerType = $containerType; + $this->loadingDate = $loadingDate; $this->status = $status; } @@ -71,6 +77,14 @@ class ContainerObject implements DataTransferObject return $this->containerType; } + /** + * @return Carbon + */ + public function getLoadingDate(): Carbon + { + return $this->loadingDate; + } + /** * @return int */ @@ -79,4 +93,5 @@ class ContainerObject implements DataTransferObject return $this->status; } + } diff --git a/app/Classes/Modules/PackingLists/Processors/FetchInboundCustomClearedProcessor.php b/app/Classes/Modules/PackingLists/Processors/FetchInboundCustomClearedProcessor.php new file mode 100644 index 00000000..b4ea6395 --- /dev/null +++ b/app/Classes/Modules/PackingLists/Processors/FetchInboundCustomClearedProcessor.php @@ -0,0 +1,105 @@ +fetchesDataFRomVTPortal = $fetchesDataFRomVTPortal; + $this->createsTransport = $createsTransport; + $this->createsSchedule = $createsSchedule; + $this->updatesContractObligations = $updatesContractObligations; + } + + + /** + * @return array + */ + public function execute(){ + + $packingLists = PackingList::query()->with(['steps' => function ($query) { + $query->where('steps.status', '<>', 3); + }])->first(); + dd($packingLists); + /* + $packingLists = PackingList::where('type', '=', PackingListType::SHIPPING_PACKING_LIST) + ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::SUSPENDED])->get(); + + foreach($packingLists as $packingList){ + try { + $filter = '["PoNumber:=%js%\"'.$packingList->reference.'\"\u0000"]'; + + $shippingPackingListsRequest = $this->fetchesDataFRomVTPortal->clientRequest('https://portalvt.azurewebsites.net/Services/DataControllerService.asmx/GetPage', 'POST', json_decode('{"controller":"VPodetailparcel","view":"grid1","request":{"PageIndex":-1,"PageSize":10000,"SortExpression":"CreatedOn asc","Filter":'.$filter.'}}'), ''); + + $shippingPackingLists = $this->fetchesDataFRomVTPortal->getResponseBody($shippingPackingListsRequest); + + $shippingPackingList = $shippingPackingLists->Rows[0]; + + if(!$shippingPackingList[9] && !$shippingPackingList[10]) { + continue; + } + + $packingList->status = ApprovalStatus::COMPLETED; + $packingList->save(); + + $deliveryDate = Carbon::parse($shippingPackingList[9] ? $shippingPackingList[9]:$shippingPackingList[10]); + $transportObject = new TransportObject(TransportType::LAND, null, null, $deliveryDate, $deliveryDate, ApprovalStatus::APPROVED); + $transport = $this->createsTransport->execute($transportObject, $packingList); + $this->createsSchedule->execute($transport, new ScheduleObject($deliveryDate, $deliveryDate, ApprovalStatus::APPROVED)); + + $deliveryStep = $packingList->steps()->where('reference', '=', 'LAST_MILE_DELIVERY')->first(); + $signature = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->entity_sigiture; + $this->updatesContractObligations->execute($signature, $deliveryStep->obligation_hash_id); + $deliveryStep->update(['status' => ApprovalStatus::COMPLETED]); + + } catch (GuzzleException $exception) { + continue; + } + + }*/ + + + return []; + + } + + +} diff --git a/app/Classes/Modules/PackingLists/Processors/FetchLoadedContainersFromVTPortalProcessor.php b/app/Classes/Modules/PackingLists/Processors/FetchLoadedContainersFromVTPortalProcessor.php index 23dc50ad..5df560d4 100644 --- a/app/Classes/Modules/PackingLists/Processors/FetchLoadedContainersFromVTPortalProcessor.php +++ b/app/Classes/Modules/PackingLists/Processors/FetchLoadedContainersFromVTPortalProcessor.php @@ -6,7 +6,6 @@ use App\Classes\Exceptions\ResourceNotFoundException; use App\Classes\Modules\Companies\Services\FetchesCompanyModule; use App\Classes\Modules\Orders\Services\FetchesDataFromVTPortal; use App\Classes\Modules\Orders\Services\FetchesOrder; -use App\Classes\Modules\PackingList\Processors\GenerateShippingOrderStepsProcessor; use App\Classes\Modules\PackingLists\DataTransferObjects\ContainerObject; use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject; use App\Classes\Modules\PackingLists\Services\Containers\FetchesContainer; @@ -126,7 +125,7 @@ class FetchLoadedContainersFromVTPortalProcessor DB::beginTransaction(); try { - $start = $start ? $start : Carbon::now()->subMonth(); + $start = $start ? $start : Carbon::now()->subDays(5); $startLimit = Carbon::parse('11-08-2021'); @@ -148,7 +147,7 @@ class FetchLoadedContainersFromVTPortalProcessor $containerDetail = $this->fetchesDataFRomVTPortal->getResponseBody($containerDetailRequest); - $containerObject = new ContainerObject($container[0], str_replace(' ', '', $container[24]), str_replace(' ', '', $container[15]), ContainerTypes::FORTY_FEET_DRY_CONTAINER, ApprovalStatus::PENDING_VERIFICATION); + $containerObject = new ContainerObject($container[0], str_replace(' ', '', $container[24]), str_replace(' ', '', $container[15]), ContainerTypes::FORTY_FEET_DRY_CONTAINER, Carbon::parse($container[5]), ApprovalStatus::PENDING_VERIFICATION); try { $container = $this->fetchesContainer->execute(['reference' => $containerObject->getReference()]); diff --git a/app/Classes/Modules/PackingLists/Processors/FetchPackingListProcessor.php b/app/Classes/Modules/PackingLists/Processors/FetchPackingListProcessor.php new file mode 100644 index 00000000..508e2293 --- /dev/null +++ b/app/Classes/Modules/PackingLists/Processors/FetchPackingListProcessor.php @@ -0,0 +1,64 @@ +listsPackingLists = $listsPackingLists; + } + + /** + * @return array + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function execute($params){ + + $packingLists = PackingList::where('type', '=', PackingListType::SHIPPING_PACKING_LIST) + ->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::SUSPENDED]) + ->whereDoesntHave('containers', function($query){ + $query->where('status', '=', ApprovalStatus::COMPLETED); + })->orderBy('created_at','desc')->where('owner_id',$params['orderId'])->get(); + + //dd($packingLists); + $packingListsArray=[]; + foreach($packingLists as $packingList){ + + $address = $packingList->owner->addresses()->first(); + $packingList->fulladdress = $address->street_one.', '.$address->street_two.', '.$address->district->name.', '.$address->post_code.' '.$address->state->name.', '.$address->country->name; + + $container = $packingList->containers()->first(); + $packingList->container_reference = $container->reference; + $packingList->container_number = $container->container_number; + + $packingListsArray[]=$packingList; + + } + + return $packingListsArray; + + } + + +} diff --git a/app/Classes/Modules/PackingLists/Services/Containers/CreatesContainer.php b/app/Classes/Modules/PackingLists/Services/Containers/CreatesContainer.php index eb8ff4e0..41a608dc 100644 --- a/app/Classes/Modules/PackingLists/Services/Containers/CreatesContainer.php +++ b/app/Classes/Modules/PackingLists/Services/Containers/CreatesContainer.php @@ -23,6 +23,7 @@ class CreatesContainer extends AbstractUpdateRelationshipRecord $model->container_number = $object->getContainerNumber(); $model->container_type = $object->getContainerType(); $model->seal_reference = $object->getSealReference(); + $model->loading_date = $object->getLoadingDate(); $model->status = $object->getStatus(); return $this->handler($owner->containers(), $model); diff --git a/app/Classes/Modules/Reports/ControllersLogic/CustomcClearanceLogic.php b/app/Classes/Modules/Reports/ControllersLogic/CustomcClearanceLogic.php new file mode 100644 index 00000000..c7fa2c0d --- /dev/null +++ b/app/Classes/Modules/Reports/ControllersLogic/CustomcClearanceLogic.php @@ -0,0 +1,39 @@ +listsPackingListProcessor = $listsPackingListProcessor; + } + + protected function notification():array { + return []; + } + + public function logic(Request $request) : JsonResponse + { + $params = $request->all(); + $packingLists = $this->listsPackingListProcessor->execute($params); + $excelExportLogic = new ExportExcelLogic(collect($packingLists)); + $this->excelExportLogic = $excelExportLogic; + + return response()->json(['success' => true]); + } + + public function getExcelCollection(){ + return $this->excelExportLogic; + } +} diff --git a/app/Classes/Modules/Reports/ControllersLogic/ExportExcelLogic.php b/app/Classes/Modules/Reports/ControllersLogic/ExportExcelLogic.php new file mode 100644 index 00000000..c1d332a5 --- /dev/null +++ b/app/Classes/Modules/Reports/ControllersLogic/ExportExcelLogic.php @@ -0,0 +1,50 @@ +data=$data; + } + public function collection() + { + return $this->data; + } + public function map($order): array + { + return [ + (string)$order->reference, + (string)$order->container_number, + (string)$order->fulladdress, + (string)$order->created_at, + "ssxxx" + ]; + } + + public function columnFormats(): array + { + return [ + 'A'=>'@', + 'B' => NumberFormat::FORMAT_DATE_DDMMYYYY, + + ]; + } + + public function headings(): array + { + return ["Reference", "Container", "Address", "Created", "Status"]; + } + +} diff --git a/app/Http/Controllers/PackingLists/Containers/InboundCustomClearedController.php b/app/Http/Controllers/PackingLists/Containers/InboundCustomClearedController.php new file mode 100644 index 00000000..303ea5dc --- /dev/null +++ b/app/Http/Controllers/PackingLists/Containers/InboundCustomClearedController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} diff --git a/app/Http/Controllers/Reports/CustomcClearanceReportController.php b/app/Http/Controllers/Reports/CustomcClearanceReportController.php new file mode 100644 index 00000000..061f4a0b --- /dev/null +++ b/app/Http/Controllers/Reports/CustomcClearanceReportController.php @@ -0,0 +1,18 @@ +merge(['orderId' => $orderId]); + $filename = date("Y-m-d H:i:s")." - Custom cleared report "; + $customClearancelogic->logic($request); + return Excel::download( $customClearancelogic->getExcelCollection(), $filename.'.xlsx'); + } +} diff --git a/app/Http/Controllers/Reports/MonthlyReportController.php b/app/Http/Controllers/Reports/MonthlyReportController.php new file mode 100644 index 00000000..96836f97 --- /dev/null +++ b/app/Http/Controllers/Reports/MonthlyReportController.php @@ -0,0 +1,66 @@ +subMonth(); + $containers = Container::whereMonth('loading_date', $month->format('m'))->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), + 'new_customers' => Company::whereMonth('created_at', $month->format('m'))->count(), + 'total_cbm' => $customers->sum(function($customer){ + return $customer['cbm']; + }), + 'packages' => $customers->sum(function($customer){ + return $customer['packages']; + }), + 'total_orders' => Order::whereMonth('created_at', $month->format('m'))->count() + ]]))->handler(); + } +} diff --git a/app/Http/Resources/ContainerResource.php b/app/Http/Resources/ContainerResource.php index bc6337cc..b9daa54f 100644 --- a/app/Http/Resources/ContainerResource.php +++ b/app/Http/Resources/ContainerResource.php @@ -21,6 +21,7 @@ class ContainerResource extends JsonResource 'container_specification' => ContainerTypes::CONTAINER_SPECIFICATION[$this->container_type], 'container_number' => $this->container_number, 'seal_reference' => $this->seal_reference, + 'loading_date' => $this->loading_date ? $this->loading_date->format('d-m-Y') : $this->loading_date, 'transport' => new TransportResource($this->transports()->first()), 'packing_lists' => PackingListResource::collection($this->whenLoaded('packingLists', function(){ return $this->packingLists()->whereHas('packages')->get(); diff --git a/app/Models/Container.php b/app/Models/Container.php index 9ff4fde8..e9acf41e 100644 --- a/app/Models/Container.php +++ b/app/Models/Container.php @@ -15,6 +15,8 @@ class Container extends AbstractModel implements Transportable protected $fillable = ['status']; + protected $dates = ['loading_date']; + public function packingLists(): belongsToMany { return $this->belongsToMany(PackingList::class, ContainerPackingList::class, 'container_id', 'packing_list_id'); diff --git a/composer.json b/composer.json index 824d2d3f..56ab4aac 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "intervention/image": "^2.5", "laravel/framework": "^8.40", "laravel/tinker": "^2.5", + "maatwebsite/excel": "^3.1", "rinvex/countries": "^6.1", "spatie/laravel-activitylog": "^3.14", "spatie/laravel-permission": "^4.2", diff --git a/config/app.php b/config/app.php index bad26462..df3e7a90 100644 --- a/config/app.php +++ b/config/app.php @@ -178,7 +178,8 @@ return [ // Third Parties Spatie\Permission\PermissionServiceProvider::class, Barryvdh\DomPDF\ServiceProvider::class, - Meneses\LaravelMpdf\LaravelMpdfServiceProvider::class + Meneses\LaravelMpdf\LaravelMpdfServiceProvider::class, + Maatwebsite\Excel\ExcelServiceProvider::class, ], /* @@ -233,6 +234,7 @@ return [ 'View' => Illuminate\Support\Facades\View::class, 'PDF' => Barryvdh\DomPDF\Facade::class, 'MPDF' => Meneses\LaravelMpdf\Facades\LaravelMpdf::class, + 'Excel' => Maatwebsite\Excel\Facades\Excel::class, ], ]; diff --git a/config/excel.php b/config/excel.php new file mode 100644 index 00000000..c3199b92 --- /dev/null +++ b/config/excel.php @@ -0,0 +1,328 @@ + [ + + /* + |-------------------------------------------------------------------------- + | Chunk size + |-------------------------------------------------------------------------- + | + | When using FromQuery, the query is automatically chunked. + | Here you can specify how big the chunk should be. + | + */ + 'chunk_size' => 1000, + + /* + |-------------------------------------------------------------------------- + | Pre-calculate formulas during export + |-------------------------------------------------------------------------- + */ + 'pre_calculate_formulas' => false, + + /* + |-------------------------------------------------------------------------- + | Enable strict null comparison + |-------------------------------------------------------------------------- + | + | When enabling strict null comparison empty cells ('') will + | be added to the sheet. + */ + 'strict_null_comparison' => false, + + /* + |-------------------------------------------------------------------------- + | CSV Settings + |-------------------------------------------------------------------------- + | + | Configure e.g. delimiter, enclosure and line ending for CSV exports. + | + */ + 'csv' => [ + 'delimiter' => ',', + 'enclosure' => '"', + 'line_ending' => PHP_EOL, + 'use_bom' => false, + 'include_separator_line' => false, + 'excel_compatibility' => false, + ], + + /* + |-------------------------------------------------------------------------- + | Worksheet properties + |-------------------------------------------------------------------------- + | + | Configure e.g. default title, creator, subject,... + | + */ + 'properties' => [ + 'creator' => '', + 'lastModifiedBy' => '', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'manager' => '', + 'company' => '', + ], + ], + + 'imports' => [ + + /* + |-------------------------------------------------------------------------- + | Read Only + |-------------------------------------------------------------------------- + | + | When dealing with imports, you might only be interested in the + | data that the sheet exists. By default we ignore all styles, + | however if you want to do some logic based on style data + | you can enable it by setting read_only to false. + | + */ + 'read_only' => true, + + /* + |-------------------------------------------------------------------------- + | Ignore Empty + |-------------------------------------------------------------------------- + | + | When dealing with imports, you might be interested in ignoring + | rows that have null values or empty strings. By default rows + | containing empty strings or empty values are not ignored but can be + | ignored by enabling the setting ignore_empty to true. + | + */ + 'ignore_empty' => false, + + /* + |-------------------------------------------------------------------------- + | Heading Row Formatter + |-------------------------------------------------------------------------- + | + | Configure the heading row formatter. + | Available options: none|slug|custom + | + */ + 'heading_row' => [ + 'formatter' => 'slug', + ], + + /* + |-------------------------------------------------------------------------- + | CSV Settings + |-------------------------------------------------------------------------- + | + | Configure e.g. delimiter, enclosure and line ending for CSV imports. + | + */ + 'csv' => [ + 'delimiter' => ',', + 'enclosure' => '"', + 'escape_character' => '\\', + 'contiguous' => false, + 'input_encoding' => 'UTF-8', + ], + + /* + |-------------------------------------------------------------------------- + | Worksheet properties + |-------------------------------------------------------------------------- + | + | Configure e.g. default title, creator, subject,... + | + */ + 'properties' => [ + 'creator' => '', + 'lastModifiedBy' => '', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'manager' => '', + 'company' => '', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Extension detector + |-------------------------------------------------------------------------- + | + | Configure here which writer/reader type should be used when the package + | needs to guess the correct type based on the extension alone. + | + */ + 'extension_detector' => [ + 'xlsx' => Excel::XLSX, + 'xlsm' => Excel::XLSX, + 'xltx' => Excel::XLSX, + 'xltm' => Excel::XLSX, + 'xls' => Excel::XLS, + 'xlt' => Excel::XLS, + 'ods' => Excel::ODS, + 'ots' => Excel::ODS, + 'slk' => Excel::SLK, + 'xml' => Excel::XML, + 'gnumeric' => Excel::GNUMERIC, + 'htm' => Excel::HTML, + 'html' => Excel::HTML, + 'csv' => Excel::CSV, + 'tsv' => Excel::TSV, + + /* + |-------------------------------------------------------------------------- + | PDF Extension + |-------------------------------------------------------------------------- + | + | Configure here which Pdf driver should be used by default. + | Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF + | + */ + 'pdf' => Excel::DOMPDF, + ], + + /* + |-------------------------------------------------------------------------- + | Value Binder + |-------------------------------------------------------------------------- + | + | PhpSpreadsheet offers a way to hook into the process of a value being + | written to a cell. In there some assumptions are made on how the + | value should be formatted. If you want to change those defaults, + | you can implement your own default value binder. + | + | Possible value binders: + | + | [x] Maatwebsite\Excel\DefaultValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class + | + */ + 'value_binder' => [ + 'default' => Maatwebsite\Excel\DefaultValueBinder::class, + ], + + 'cache' => [ + /* + |-------------------------------------------------------------------------- + | Default cell caching driver + |-------------------------------------------------------------------------- + | + | By default PhpSpreadsheet keeps all cell values in memory, however when + | dealing with large files, this might result into memory issues. If you + | want to mitigate that, you can configure a cell caching driver here. + | When using the illuminate driver, it will store each value in a the + | cache store. This can slow down the process, because it needs to + | store each value. You can use the "batch" store if you want to + | only persist to the store when the memory limit is reached. + | + | Drivers: memory|illuminate|batch + | + */ + 'driver' => 'memory', + + /* + |-------------------------------------------------------------------------- + | Batch memory caching + |-------------------------------------------------------------------------- + | + | When dealing with the "batch" caching driver, it will only + | persist to the store when the memory limit is reached. + | Here you can tweak the memory limit to your liking. + | + */ + 'batch' => [ + 'memory_limit' => 60000, + ], + + /* + |-------------------------------------------------------------------------- + | Illuminate cache + |-------------------------------------------------------------------------- + | + | When using the "illuminate" caching driver, it will automatically use + | your default cache store. However if you prefer to have the cell + | cache on a separate store, you can configure the store name here. + | You can use any store defined in your cache config. When leaving + | at "null" it will use the default store. + | + */ + 'illuminate' => [ + 'store' => null, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Transaction Handler + |-------------------------------------------------------------------------- + | + | By default the import is wrapped in a transaction. This is useful + | for when an import may fail and you want to retry it. With the + | transactions, the previous import gets rolled-back. + | + | You can disable the transaction handler by setting this to null. + | Or you can choose a custom made transaction handler here. + | + | Supported handlers: null|db + | + */ + 'transactions' => [ + 'handler' => 'db', + ], + + 'temporary_files' => [ + + /* + |-------------------------------------------------------------------------- + | Local Temporary Path + |-------------------------------------------------------------------------- + | + | When exporting and importing files, we use a temporary file, before + | storing reading or downloading. Here you can customize that path. + | + */ + 'local_path' => storage_path('framework/laravel-excel'), + + /* + |-------------------------------------------------------------------------- + | Remote Temporary Disk + |-------------------------------------------------------------------------- + | + | When dealing with a multi server setup with queues in which you + | cannot rely on having a shared local temporary path, you might + | want to store the temporary file on a shared disk. During the + | queue executing, we'll retrieve the temporary file from that + | location instead. When left to null, it will always use + | the local path. This setting only has effect when using + | in conjunction with queued imports and exports. + | + */ + 'remote_disk' => null, + 'remote_prefix' => null, + + /* + |-------------------------------------------------------------------------- + | Force Resync + |-------------------------------------------------------------------------- + | + | When dealing with a multi server setup as above, it's possible + | for the clean up that occurs after entire queue has been run to only + | cleanup the server that the last AfterImportJob runs on. The rest of the server + | would still have the local temporary file stored on it. In this case your + | local storage limits can be exceeded and future imports won't be processed. + | To mitigate this you can set this config value to be true, so that after every + | queued chunk is processed the local temporary file is deleted on the server that + | processed it. + | + */ + 'force_resync_remote' => null, + ], +]; diff --git a/database/migrations/2021_07_21_110190_create_containers_table.php b/database/migrations/2021_07_21_110190_create_containers_table.php index 59ede968..f668901e 100644 --- a/database/migrations/2021_07_21_110190_create_containers_table.php +++ b/database/migrations/2021_07_21_110190_create_containers_table.php @@ -22,6 +22,7 @@ class CreateContainersTable extends Migration $table->string('container_number')->nullable(); $table->integer('container_type')->default(ContainerTypes::FORTY_FEET_DRY_CONTAINER); $table->string('seal_reference')->nullable(); + $table->timestamp('loading_date')->nullable(); $table->integer('status')->default(ApprovalStatus::PENDING_SUBMISSION); $table->softDeletes(); $table->timestamps(); diff --git a/database/seeders/CompaniesTableSeeder.php b/database/seeders/CompaniesTableSeeder.php index c2ffdeb4..da6c1061 100644 --- a/database/seeders/CompaniesTableSeeder.php +++ b/database/seeders/CompaniesTableSeeder.php @@ -172,49 +172,49 @@ class CompaniesTableSeeder extends Seeder } - // if(true){ - // $companies = OldCompany::all(); - - // foreach($companies as $company){ - - // $marking = explode("CIEF/", $company->marking); - - // if(count($marking) < 2){ - // continue; - // } - - // $marking = str_replace(' ', '', str_replace('/', '', $marking[1])); - - - // /** @var Company $newCompany */ - // $newCompany = $this->createCompanyProcessor->execute($company->name, CompanyType::COMPANY_BUSINESS, ApprovalStatus::PENDING_SUBMISSION); - - // $this->updatesCompanyStatus->execute($newCompany, ApprovalStatus::APPROVED); - - // /** @var CompanyModule $companyModule */ - // $companyModule = $this->createCompanyModuleProcessor->execute($newCompany, BusinessType::IMPORTER); - - // $connectionObject = new CompanyConnectionObject($companyModule, 'CIEF', $marking); - - // $connection = $this->createsCompanyConnection->execute($connectionObject); - // $this->approvesCompanyConnection->execute($connection); - - // $i = 0; - // foreach($company->addresses as $address){ - // $this->createAddressFromOldAddressProcessor->execute($address, $companyModule); - // $contact = preg_replace("/[^0-9.]/", "", $address->contact); - // if($contact){ - // $i++; - // if($i === 1) { - // $contactObject = new ContactObject('', $contact, $company->email, '',); - // $this->createContactProcessor->execute($contactObject, $newCompany); - // } - // } - - - // } - // } - // } +// if(true){ +// $companies = OldCompany::all(); +// +// foreach($companies as $company){ +// +// $marking = explode("CIEF/", $company->marking); +// +// if(count($marking) < 2){ +// continue; +// } +// +// $marking = str_replace(' ', '', str_replace('/', '', $marking[1])); +// +// +// /** @var Company $newCompany */ +// $newCompany = $this->createCompanyProcessor->execute($company->name, CompanyType::COMPANY_BUSINESS, ApprovalStatus::PENDING_SUBMISSION); +// +// $this->updatesCompanyStatus->execute($newCompany, ApprovalStatus::APPROVED); +// +// /** @var CompanyModule $companyModule */ +// $companyModule = $this->createCompanyModuleProcessor->execute($newCompany, BusinessType::IMPORTER); +// +// $connectionObject = new CompanyConnectionObject($companyModule, 'CIEF', $marking); +// +// $connection = $this->createsCompanyConnection->execute($connectionObject); +// $this->approvesCompanyConnection->execute($connection); +// +// $i = 0; +// foreach($company->addresses as $address){ +// $this->createAddressFromOldAddressProcessor->execute($address, $companyModule); +// $contact = preg_replace("/[^0-9.]/", "", $address->contact); +// if($contact){ +// $i++; +// if($i === 1) { +// $contactObject = new ContactObject('', $contact, $company->email, '',); +// $this->createContactProcessor->execute($contactObject, $newCompany); +// } +// } +// +// +// } +// } +// } } diff --git a/resources/assets/vue/components/containers/elements/ContainerComponent.vue b/resources/assets/vue/components/containers/elements/ContainerComponent.vue index bd253565..ded65bb3 100644 --- a/resources/assets/vue/components/containers/elements/ContainerComponent.vue +++ b/resources/assets/vue/components/containers/elements/ContainerComponent.vue @@ -14,11 +14,15 @@
{{item.container_reference}}

{{item.container_number}} / {{item.seal_reference}}

-
+
+

Loading Date

+

{{item.loading_date ? item.loading_date : 'n/a'}}

+
+

ETD

{{item.transport ? item.transport.current_schedule.etd : 'n/a'}}

-
+

ETA

{{item.transport ? item.transport.current_schedule.eta : 'n/a'}}

@@ -26,7 +30,7 @@

Loaded CBM

{{ (Math.ceil((item.packing_lists.reduce((total, obj) => total + obj.packages.reduce((total, obj) => obj.cbm + total, 0), 0)) * 1000) / 1000).toFixed(3) }}

-
+

Status

{{item.status === 3 ? 'Un-stuffed' : 'In Progress'}}

@@ -68,6 +72,14 @@
Release
Hold
+
+ + +
@@ -103,4 +115,4 @@ }, mixins: [componentHandler] } - \ No newline at end of file + diff --git a/resources/assets/vue/components/orders/elements/OrderComponent.vue b/resources/assets/vue/components/orders/elements/OrderComponent.vue index c3104ca9..2262d768 100644 --- a/resources/assets/vue/components/orders/elements/OrderComponent.vue +++ b/resources/assets/vue/components/orders/elements/OrderComponent.vue @@ -2,7 +2,7 @@
-
+ -
+
Order No. @@ -28,8 +28,20 @@
- Delivery Address -
{{item.address.reference}}
+
+
+ Delivery Address +
+
+
+
+
{{item.address.reference}}
+
+
+
+ +
+
diff --git a/resources/assets/vue/components/paymentsBilling/elements/PaymentsBillingComponents.vue b/resources/assets/vue/components/paymentsBilling/elements/PaymentsBillingComponents.vue new file mode 100644 index 00000000..86535a80 --- /dev/null +++ b/resources/assets/vue/components/paymentsBilling/elements/PaymentsBillingComponents.vue @@ -0,0 +1,131 @@ + + diff --git a/resources/assets/vue/components/reports/sections/MonthlyReportSectionComponent.vue b/resources/assets/vue/components/reports/sections/MonthlyReportSectionComponent.vue new file mode 100644 index 00000000..6af42e93 --- /dev/null +++ b/resources/assets/vue/components/reports/sections/MonthlyReportSectionComponent.vue @@ -0,0 +1,170 @@ + + \ No newline at end of file diff --git a/resources/assets/vue/components/shippingQueue/elements/shippingQueueComponents.vue b/resources/assets/vue/components/shippingQueue/elements/shippingQueueComponents.vue new file mode 100644 index 00000000..41c20a1c --- /dev/null +++ b/resources/assets/vue/components/shippingQueue/elements/shippingQueueComponents.vue @@ -0,0 +1,94 @@ + + diff --git a/resources/views/layouts/base_portal.blade.php b/resources/views/layouts/base_portal.blade.php index 87144464..96025829 100644 --- a/resources/views/layouts/base_portal.blade.php +++ b/resources/views/layouts/base_portal.blade.php @@ -21,6 +21,10 @@
+
+ + +
@@ -108,4 +112,4 @@
-@endsection \ No newline at end of file +@endsection diff --git a/resources/views/pages/accounts/claim_business.blade.php b/resources/views/pages/accounts/claim_business.blade.php index 645b8e5f..dd199c15 100644 --- a/resources/views/pages/accounts/claim_business.blade.php +++ b/resources/views/pages/accounts/claim_business.blade.php @@ -8,6 +8,7 @@
+
{{$id}}
diff --git a/resources/views/pages/admin/customers.blade.php b/resources/views/pages/admin/customers.blade.php new file mode 100644 index 00000000..048b81c6 --- /dev/null +++ b/resources/views/pages/admin/customers.blade.php @@ -0,0 +1,25 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
+
+
+
Customers List
+
+
+
+
+ + + +
+
+
+
+
+
+@endsection diff --git a/resources/views/pages/admin/dashboard.blade.php b/resources/views/pages/admin/dashboard.blade.php index 0fe49ba7..f5b7df56 100644 --- a/resources/views/pages/admin/dashboard.blade.php +++ b/resources/views/pages/admin/dashboard.blade.php @@ -1,47 +1,42 @@
-
-
-
-
Customers List
-
-
-
+
+
- - - +
-
-
-
-
-
Identification Verification
+
+
+
+
+
Identification Verification
+
+
+
+
+ + + +
+
-
-
-
- - - -
-
-
-
-
Address Change Verification
-
-
-
-
- - - +
+
+
+
Address Change Verification
+
+
+
+
+ + + +
+
diff --git a/resources/views/pages/templates/paymentsBilling.blade.php b/resources/views/pages/templates/paymentsBilling.blade.php new file mode 100644 index 00000000..f8a7719d --- /dev/null +++ b/resources/views/pages/templates/paymentsBilling.blade.php @@ -0,0 +1,128 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
+
+
+
+
+
+
+ +
+
+
Invoice No
+
+
+
Invoice Date
+
+
+
Status
+
+
+
Amount
+
+ +
+
+
+
+
+ + + +
+
+
+
+
+
+
Payment Summary
+
+
+
+
+
+ +
+
+
+
2 Invoice Selected
+
+
+
+
+
+
+
x1
+
+
+
lorem ipsum
+
+
+
52x62x635 CM
+
+
+
+
+
x1
+
+
+
lorem ipsum
+
+
+
52x62x635 CM
+
+
+
+
+
+
+
+
Shipping Fee
+
+
+
RM 212.15
+
+
+
+
+
Serrvice Fee
+
+
+
RM 41.25
+
+
+
+
+
Discount
+
+
+
RM 0.00
+
+
+
+
+
+
Total Payments
+
+
+
RM 3300.00
+
+
+
+
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/pages/templates/shippingQueue.blade.php b/resources/views/pages/templates/shippingQueue.blade.php new file mode 100644 index 00000000..455d5bb2 --- /dev/null +++ b/resources/views/pages/templates/shippingQueue.blade.php @@ -0,0 +1,120 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
+
+
+

Shipping ID: 05052021-25-0100

+
+
+
+
+
+
+
+
+
Discount Code
+
+
+
+
+
Free 10
+
+
+
Removed
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+

Shipping cost estimation

+
+
+
+
+
+
+
Shipping Cost: RM8400
+
+
+
+
+
SST(6%): RM600
+
+
+
+
+
Discount: RM100
+
+
+
+
+
+
+
+
+
Total Cost:
+
+
+
+
+

RM7300

+
+
+
+
+
+
+
+
+
+
+
+
+

Group my products with same destination

+
+
+
+
+

You will get grouped package at once if possible

+
+
+
+
+
+
+
+
+
+
+
+
+ Checkout +
+
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/partials/menu.blade.php b/resources/views/partials/menu.blade.php index e0881b5f..c32eb3df 100644 --- a/resources/views/partials/menu.blade.php +++ b/resources/views/partials/menu.blade.php @@ -30,6 +30,17 @@
Dashboard
+
+
+ +
+
+
Customers
+
+
-
Payments & Billing
+
Payments & Billing
@@ -107,6 +118,17 @@
Tracking
+
+
+ +
+ +
diff --git a/resources/views/swagger/json.blade.php b/resources/views/swagger/json.blade.php index 4fa056ef..cd4df686 100644 --- a/resources/views/swagger/json.blade.php +++ b/resources/views/swagger/json.blade.php @@ -107,6 +107,54 @@ } } }, + "/packing_list/container/inbound-custom-cleared": { + "get": { + "tags": [ + "Packing" + ], + "produces": [ + "application/json" + ], + "operationId": "listPackingIn", + "summary": "List packing", + "description": "", + "parameters": [ + { + "name": "filter", + "in": "query", + "description": "Filters", + "required": false, + "type": "array", + "items": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "headers": { + "X-Expires-After": { + "type": "string", + "format": "date-time", + "description": "date in UTC when token expires" + }, + "X-Rate-Limit": { + "type": "integer", + "format": "int32", + "description": "calls per hour allowed by the user" + } + }, + "schema": { + "type": "string" + } + }, + "422": { + "description": "Invalid input supplied" + } + } + } + }, "/packing_list/list": { "get": { "tags": [ @@ -2982,7 +3030,7 @@ } } }, - "/account/registration/registration": { + "/account/registration": { "post": { "tags": [ "Account", diff --git a/routes/api.php b/routes/api.php index a7552465..3399972b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -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'); + }); }); diff --git a/routes/packing_list.php b/routes/packing_list.php index 3abe6253..9d2fc80d 100644 --- a/routes/packing_list.php +++ b/routes/packing_list.php @@ -30,6 +30,7 @@ Route::group(['namespace' => 'PackingLists', 'as' => 'packing_list.', 'prefix' = Route::post('/create', 'CreatePackageController@create')->name('create'); Route::put('/update/{id}', 'UpdatePackageController@update')->name('update'); Route::delete('/delete/{id}', 'DeletePackageController@delete')->name('delete'); + Route::get('/inbound-custom-cleared', 'InboundCustomClearedController@list')->name('list.inbound.custom.cleared'); Route::put('/switch-packing-list/{id}', 'SwitchPackagePackingListController@switch')->name('switch.packing_list'); Route::group(['namespace' => 'PackageItems', 'prefix' => 'item', 'as' => 'item.'], function () { diff --git a/routes/web.php b/routes/web.php index a036ac20..5e4cba15 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,9 +5,11 @@ use App\Classes\Jobs\FetchDeliveryListFromVTPortalJob; use App\Classes\Jobs\FetchLoadedContainersFromVTPortalJob; use App\Classes\Jobs\FetchPackingListFromVTPortalJob; use App\Classes\Jobs\FetchWarehouseReceiveListFromVTPortalJob; +use App\Classes\Modules\Orders\Services\FetchesDataFromVTPortal; use App\Models\CompanyConnection; -use App\Models\Container; +use App\Models\Order; use Illuminate\Support\Facades\Crypt; +use App\Models\Container; use Illuminate\Support\Facades\Route; /* @@ -52,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'); @@ -114,12 +120,67 @@ Route::get('/deliveries/refresh', function(){ Route::get('/order/{id}/download', 'Orders\DownloadOrderQrPdfController@download')->name('order.qr.download'); -//Route::get('/test', function(){ -// $addresses = \App\Models\Address::all(); -// foreach ($addresses as $address){ -// $address->street_one = (new \App\Classes\Modules\Addresses\Services\CleansOldAddress())->cleanAddress($address->street_one, $address->district, $address->postcode); -// $address->street_two = (new \App\Classes\Modules\Addresses\Services\CleansOldAddress())->cleanAddress($address->street_two, $address->district, $address->postcode); -// $address->save(); -// } -//})->name('test'); +Route::get('/report/customclearance', 'Reports\CustomcClearanceReportController@download')->name('report.customclearance'); + +Route::get('/report/customclearance/{orderid}', 'Reports\CustomcClearanceReportController@download')->name('report.customclearance'); + +Route::group(['prefix' => 'template', 'as' => 'template.'], function () { + Route::get('/payments-and-billing', function () { + return view('pages.templates.paymentsBilling'); + })->name('payments-and-billing'); + + Route::get('/shipping-queue', function () { + return view('pages.templates.shippingQueue'); + })->name('shipping-queue'); +}); + +Route::get('/report', function(){ + $containers = Container::whereMonth('loading_date', '=', '09')->whereYear('loading_date', '=', '2021')->orderBy('loading_date')->get(); + + $total = 0; + $customers = collect(); + + foreach ($containers as $container){ + echo ''.$container->reference.': '.$container->packingLists->sum(function($packingList){ + return $packingList->packages->sum(function ($package){ + return (( (float) $package->width / 100) * ( (float) $package->length / 100) * ( (float) $package->height / 100)) * $package->quantity; + }); + }).'CBM ('. $container->loading_date->format('d-m-Y') .')

'; + 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'); + } + } + + echo '

total cbm: '. $total . '

'; + echo '

active customers: '. count($customers) . '



'; + + $i = 1; + foreach ($customers->sortByDesc(function($customer){ + return $customer['cbm']; + }) as $marking => $customer) { + echo ''.$i.'. '.$marking.': '.$customer['cbm'].' CBM ('. $customer['orders'] .' - '.$customer['packages'].' ) CTNS

'; + $i++; + } + + +}); +