diff --git a/app/Classes/Jobs/CurlContainerListJob.php b/app/Classes/Jobs/CurlContainerListJob.php deleted file mode 100644 index e65a1a18..00000000 --- a/app/Classes/Jobs/CurlContainerListJob.php +++ /dev/null @@ -1,94 +0,0 @@ -page = $page; - } - - /** - * Execute the job. - * - * @return void - * @throws \GuzzleHttp\Exception\GuzzleException - */ - public function handle() - { - $cookies = $this->getCookie(); - - $headers = [ - 'Content-Type' => 'application/json', - 'Cookie' => $cookies, - ]; - - $last_two_month = Carbon::now()->subMonth(2)->format('Y-m-d'); - - $client = new \GuzzleHttp\Client(['headers' => $headers]); - $res = $client->post('http://portal.vtnation.com.my/Services/DataControllerService.asmx/GetPage', [\GuzzleHttp\RequestOptions::JSON => json_decode('{"controller":"VCustomercontainer","view":"grid1","request":{"PageIndex":' . $this->page . ',"PageSize":10,"PageOffset":0,"SortExpression":"CreatedOn DESC","GroupExpression":"","Filter":["LoadedTime:<=%js%\"' . $last_two_month . 'T00:00:00.000\"\u0000"],"ContextKey":"view1","FilterIsExternal":false,"LookupContextFieldName":null,"LookupContextController":null,"LookupContextView":null,"LookupContext":null,"Inserting":false,"LastCommandName":null,"ExternalFilter":[],"DoesNotRequireData":false,"LastView":"grid1","Tag":null,"RequiresFirstLetters":false,"ViewType":"Grid","SupportsCaching":true,"SystemFilter":null,"RequiresRowCount":true,"QuickFindHint":null,"RequiresPivot":false,"PivotDefinitions":null,"RequiresMetaData":true}}')]); - - $data = json_decode($res->getBody()->getContents()); - - if (!empty($data->d->Rows)) { - // insert data here - - // next page - $this->page = $this->page > 0 ? $this->page + 1 : 1; - CurlContainerListJob::dispatch($this->page + 1) - ->delay(Carbon::now()->addSeconds(10)); - } - } - - public function getCookie() - { - // get latest cookies - $client = new \GuzzleHttp\Client(['cookies' => true]); - $r = $client->request('GET', 'http://portal.vtnation.com.my'); - $call_cookie = $client->getConfig('cookies'); - $call_cookie = $call_cookie->toArray(); - $latest_cookie = []; - - foreach ($call_cookie as $key => $row) { - $latest_cookie[] = $row['Name'] . '=' . $row['Value']; - } - $latest_cookie = implode(';', $latest_cookie); - - // get access token - $headers = [ - 'Content-Type' => 'application/json', - 'Cookie' => $latest_cookie, - ]; - $client = new \GuzzleHttp\Client(['headers' => $headers]); - $res = $client->post('http://portal.vtnation.com.my/Services/DataControllerService.asmx/Login', [\GuzzleHttp\RequestOptions::JSON => [ - "username" => "CIEF", - "password" => "0122120880", - "createPersistentCookie" => true, - ]]); - - $token = json_decode($res->getBody()->getContents()); - $token = $token->d->AccessToken; - - $latest_cookie = $latest_cookie . ';AppVTCC=' . $token; - return $latest_cookie; - } -} diff --git a/app/Classes/Jobs/CurlYdOrderListJob.php b/app/Classes/Jobs/FetchOrdersFromYDPortalJob.php similarity index 78% rename from app/Classes/Jobs/CurlYdOrderListJob.php rename to app/Classes/Jobs/FetchOrdersFromYDPortalJob.php index ee5fba54..b67130d3 100644 --- a/app/Classes/Jobs/CurlYdOrderListJob.php +++ b/app/Classes/Jobs/FetchOrdersFromYDPortalJob.php @@ -10,20 +10,12 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -class CurlYdOrderListJob implements ShouldQueue +class FetchOrdersFromYDPortalJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct() - { - - } + public $timeout = 900; /** * Execute the job. @@ -33,6 +25,8 @@ class CurlYdOrderListJob implements ShouldQueue */ public function handle() { + (App()->make(FetchOrderListsFromYdPortalProcessor::class))->execute(); } + } diff --git a/app/Classes/Modules/PackingLists/Processors/CreatePackingListProcessor.php b/app/Classes/Modules/PackingLists/Processors/CreatePackingListProcessor.php index 0a546546..3e2a861d 100644 --- a/app/Classes/Modules/PackingLists/Processors/CreatePackingListProcessor.php +++ b/app/Classes/Modules/PackingLists/Processors/CreatePackingListProcessor.php @@ -48,8 +48,9 @@ class CreatePackingListProcessor /** @var PackingList $packingList */ $packingList = $this->createsPackingList->execute($object, $packable); + $type = $object->getType() === PackingListType::SHIPPING_PACKING_LIST ? PackingListType::SHIPPING_PACKING_LIST_REPLICA : PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA; /** create packing list replica */ - $object = new PackingListObject($object->getReference().'_01', $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id, $object->getType() === PackingListType::SHIPPING_PACKING_LIST ? $object->getType() === PackingListType::SHIPPING_PACKING_LIST_REPLICA : $object->getType() === PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA, ApprovalStatus::PENDING_SUBMISSION); + $object = new PackingListObject($object->getReference().'_01', $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id, $type, ApprovalStatus::PENDING_SUBMISSION); $this->createsPackingList->execute($object, $packingList); return $packingList; diff --git a/app/Classes/Modules/PackingLists/Processors/FetchOrderListsFromYdPortalProcessor.php b/app/Classes/Modules/PackingLists/Processors/FetchOrderListsFromYdPortalProcessor.php index c65b8ee9..4821d4a7 100644 --- a/app/Classes/Modules/PackingLists/Processors/FetchOrderListsFromYdPortalProcessor.php +++ b/app/Classes/Modules/PackingLists/Processors/FetchOrderListsFromYdPortalProcessor.php @@ -2,39 +2,299 @@ namespace App\Classes\Modules\PackingLists\Processors; +use App\Classes\Exceptions\ResourceNotFoundException; +use App\Classes\Modules\Companies\Services\FetchesCompanyModule; use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal; +use App\Classes\Modules\Orders\Services\FetchesOrder; +use App\Classes\Modules\PackingLists\DataTransferObjects\ContainerObject; +use App\Classes\Modules\PackingLists\DataTransferObjects\PackageObject; +use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject; +use App\Classes\Modules\PackingLists\Services\Containers\FetchesContainer; +use App\Classes\Modules\PackingLists\Services\FetchesPackingList; +use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject; +use App\Classes\Modules\Schedules\Services\CreatesSchedule; +use App\Classes\Modules\Steps\DataTransferObjects\StepsObject; +use App\Classes\Modules\Steps\Services\CreatesStep; +use App\Classes\Modules\Transports\DataTransferObjects\TransportObject; +use App\Classes\Modules\Transports\Services\CreatesTransport; +use App\Classes\Modules\Unity\Processors\ActivateContractProcessor; +use App\Classes\Modules\Unity\Processors\AssignContractEntityProcessor; +use App\Classes\Modules\Unity\Processors\CreateContractEntityProcessor; +use App\Classes\Modules\Unity\Services\CreatesContract; +use App\Classes\Modules\Unity\Services\UpdatesContractObligation; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\ContainerTypes; +use App\Classes\ValueObjects\Constants\OrderRoleTypes; +use App\Classes\ValueObjects\Constants\PackageType; +use App\Classes\ValueObjects\Constants\PackingListType; +use App\Classes\ValueObjects\Constants\TransportType; +use App\Models\Container; +use App\Models\Order; +use App\Models\PackingList; +use App\Models\Transport; +use Carbon\Carbon; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Log; class FetchOrderListsFromYdPortalProcessor { - /** - /** @var FetchesDataFromVTPortal */ + /** @var FetchesDataFromYDPortal */ private $fetchesDataFRomYDPortal; - public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal) + /** @var FetchesOrder */ + private $fetchesOrder; + + /** @var UpdatesContractObligation */ + private $updatesContractObligations; + + /** @var CreatePackingListProcessor */ + private $createPackingListProcessor; + + /** @var CreatePackageProcessor */ + private $createPackageProcessor; + + /** @var CreatesTransport */ + private $createsTransport; + + /** @var CreatesSchedule */ + private $createsSchedule; + + /** @var FetchesContainer */ + private $fetchesContainer; + + /** @var FetchesPackingList */ + private $fetchesPackingList; + + /** @var FetchesCompanyModule */ + private $fetchesCompanyModule; + + /** @var CreateContainerProcessor */ + private $createContainerProcessor; + + /** @var CreatesContract */ + private $unityCreateContract; + + /** @var AssignContractEntityProcessor */ + private $unityAssignContractEntity; + + /** @var CreateContractEntityProcessor */ + private $unityCreateContractEntity; + + /** @var CreatesStep */ + private $createsStep; + + /** @var ActivateContractProcessor */ + private $unityActivateContract; + + /** + * FetchOrderListsFromYdPortalProcessor constructor. + * @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal + * @param FetchesOrder $fetchesOrder + * @param UpdatesContractObligation $updatesContractObligations + * @param CreatePackingListProcessor $createPackingListProcessor + * @param CreatePackageProcessor $createPackageProcessor + * @param CreatesTransport $createsTransport + * @param CreatesSchedule $createsSchedule + * @param FetchesContainer $fetchesContainer + * @param FetchesPackingList $fetchesPackingList + * @param FetchesCompanyModule $fetchesCompanyModule + * @param CreateContainerProcessor $createContainerProcessor + * @param CreatesContract $unityCreateContract + * @param AssignContractEntityProcessor $unityAssignContractEntity + * @param CreateContractEntityProcessor $unityCreateContractEntity + * @param CreatesStep $createsStep + * @param ActivateContractProcessor $unityActivateContract + */ + public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, FetchesOrder $fetchesOrder, UpdatesContractObligation $updatesContractObligations, CreatePackingListProcessor $createPackingListProcessor, CreatePackageProcessor $createPackageProcessor, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, FetchesContainer $fetchesContainer, FetchesPackingList $fetchesPackingList, FetchesCompanyModule $fetchesCompanyModule, CreateContainerProcessor $createContainerProcessor, CreatesContract $unityCreateContract, AssignContractEntityProcessor $unityAssignContractEntity, CreateContractEntityProcessor $unityCreateContractEntity, CreatesStep $createsStep, ActivateContractProcessor $unityActivateContract) { $this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal; + $this->fetchesOrder = $fetchesOrder; + $this->updatesContractObligations = $updatesContractObligations; + $this->createPackingListProcessor = $createPackingListProcessor; + $this->createPackageProcessor = $createPackageProcessor; + $this->createsTransport = $createsTransport; + $this->createsSchedule = $createsSchedule; + $this->fetchesContainer = $fetchesContainer; + $this->fetchesPackingList = $fetchesPackingList; + $this->fetchesCompanyModule = $fetchesCompanyModule; + $this->createContainerProcessor = $createContainerProcessor; + $this->unityCreateContract = $unityCreateContract; + $this->unityAssignContractEntity = $unityAssignContractEntity; + $this->unityCreateContractEntity = $unityCreateContractEntity; + $this->createsStep = $createsStep; + $this->unityActivateContract = $unityActivateContract; } + /** * @param Carbon|null $start * @param Carbon|null $end - * @return array - * @throws GuzzleException + * @return void + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + * @throws \GuzzleHttp\Exception\GuzzleException */ - public function execute(?Carbon $start = null, ?Carbon $end = null) { + public function execute(?Carbon $start = null, ?Carbon $end = null) + { + db::beginTransaction(); + $start = $start ? $start : Carbon::now()->subMonths(2); - $orderRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/GetOrderList.ashx', 'GET', [ - 'apicode' => '393b1cb4b8b37d09', - 'begintime' => '1633968000', - 'endtime' => '1639308222', + $startLimit = Carbon::parse('01-12-2021'); + + if($start->isBefore($startLimit)){ + $start = $startLimit; + } + + $end = $end ? $end : Carbon::now(); + + $orderRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/GetOrderList.ashx', 'GET', [ + 'begintime' => $start->timestamp, + 'endtime' => $end->timestamp, + ]); + + $rows = $this->fetchesDataFRomYDPortal->getResponseBody($orderRequest); + + foreach($rows->data as $row){ + $containerReference = null; + $loadingDate = null; + $unstuffingDate = null; + $etd = null; + $eta = null; + + $trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [ + 'trakingno' => $row->expressno ]); + $rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest); + foreach ($rows->data as $trackingRow) { + if($trackingRow->tracking === '货物已送达仓库准备入库中'){ + $receiveDate = Carbon::parse($trackingRow->trackingtime); + } - $order = $this->fetchesDataFRomYDPortal->getResponseBody($orderRequest); + if (strpos($trackingRow->tracking, '货物装柜完成。') !== false) { + $tracking = explode(':', $trackingRow->tracking); + $containerReference = explode('预计到港时间', $tracking[1])[0]; + $loadingDate = Carbon::parse($trackingRow->trackingtime); + $etd = Carbon::parse($tracking[2])->subDays(5); + $eta = Carbon::parse($tracking[2]); + } + + if($trackingRow->tracking === '货物已进目的港仓库'){ + $unstuffingDate = Carbon::parse($trackingRow->trackingtime); + } + } + + $customerno = preg_split('/(-|\/)/', $row->customerno); + + if (!array_key_exists(2, $customerno)){ + if (!array_key_exists(1, $customerno)){ + continue; + } + $customerno[2] = substr($customerno[1], -9); + } + + + $orderNumber = $customerno[2]; + + try { + $order = $this->fetchesOrder->execute(['reference' => $orderNumber]); + } catch (ResourceNotFoundException $exception) { + continue; + } + + $packingListReference = $row->expressno; + + try{ + $packingList = $this->fetchesPackingList->execute(['reference' => $row->expressno]); + } catch (ResourceNotFoundException $exception){ + + $warehouseReceiveObject = new PackingListObject($packingListReference, $order->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id, PackingListType::WAREHOUSE_RECEIVE_LIST, ApprovalStatus::APPROVED); + /** @var PackingList $warehouseReceiveList */ + $warehouseReceiveList = $this->createPackingListProcessor->execute($warehouseReceiveObject, $order); + $transportObject = new TransportObject(TransportType::LAND, null, $row->kuaidilist, Carbon::parse($receiveDate), Carbon::parse($receiveDate), ApprovalStatus::APPROVED); + $this->createsTransport->execute($transportObject, $warehouseReceiveList); + + $contract = $this->unityCreateContract->execute(); + $contractReference = $contract->hash_id; + $contractObligations = $contract->contract_obligation_list; + + $this->unityActivateContract->execute($contractReference); + + $supervisorHashId = $order->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->unity_hash_id; + + $supervisorContractEntity = $this->unityCreateContractEntity->execute($contractReference, $supervisorHashId); + $order->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->update(['entity_hash_id' => $supervisorContractEntity->hash_id, 'entity_signature' => $supervisorContractEntity->entity_signature_hash_id]); + + $importerContractEntity = $this->unityCreateContractEntity->execute($contractReference, $order->orderRoles()->where('role_id', '=', OrderRoleTypes::IMPORTER)->first()->appointee->unity_hash_id); + $order->orderRoles()->where('role_id', '=', OrderRoleTypes::IMPORTER)->first()->update(['entity_hash_id' => $importerContractEntity->hash_id, 'entity_signature' => $importerContractEntity->entity_signature_hash_id]); + + $this->unityAssignContractEntity->execute($supervisorContractEntity->hash_id, $contractObligations); + + $packingListObject = new PackingListObject($packingListReference, $order->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id, PackingListType::SHIPPING_PACKING_LIST, ApprovalStatus::PENDING_VERIFICATION , $contractReference); + + /** @var PackingList $packingList */ + $packingList = $this->createPackingListProcessor->execute($packingListObject, $order); + + foreach($contractObligations as $obligation) { + $stepObject = new StepsObject($order->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->id, $obligation->reference, $obligation->sequence, $obligation->hash_id); + $this->createsStep->execute($packingList, $stepObject); + } + + foreach($row->deliverysize as $package) { + $packageObject = new PackageObject(PackageType::CARTON, $row->goodname, (float) $package->width, (float) $package->height, (float) $package->length, 0, (float) $package->num, ApprovalStatus::APPROVED); + $this->createPackageProcessor->execute($packageObject, $warehouseReceiveList); + $this->createPackageProcessor->execute($packageObject, $packingList); + } + } + + if($containerReference) { + try { + $container = $this->fetchesContainer->execute(['reference' => $containerReference]); + } catch (ResourceNotFoundException $exception){ + $originWarehouse = $this->fetchesCompanyModule->execute(['id' => $order->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee->id]); + $containerObject = new ContainerObject($containerReference, '', '', ContainerTypes::FORTY_FEET_DRY_CONTAINER, $loadingDate, ApprovalStatus::PENDING_VERIFICATION); + /** @var Container $container */ + $container = $this->createContainerProcessor->execute($containerObject, $originWarehouse); + + $container->packingLists()->attach($packingList); + + $transport = $container->transports()->first(); + + if(!$transport){ + $transportObject = new TransportObject(TransportType::SEA, null, null, $etd, null, ApprovalStatus::APPROVED); + /** @var Transport $transport */ + $transport = $this->createsTransport->execute($transportObject, $container); + $this->createsSchedule->execute($transport, new ScheduleObject($etd, $eta, ApprovalStatus::APPROVED)); + } + } + + if($unstuffingDate){ + $container->update(['status' => ApprovalStatus::COMPLETED]); + $container->transports()->first()->update(['drop_date' => $unstuffingDate, 'status' => ApprovalStatus::COMPLETED]); + + /** @var PackingList $packingList */ + foreach($container->packingLists as $packingList){ + + if($packingList->status === ApprovalStatus::PENDING_VERIFICATION){ + $packingList->status = ApprovalStatus::APPROVED; + $packingList->save(); + } + + $signature = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->entity_sigiture; + foreach($packingList->steps()->where('reference', '!=', 'DELIVERY')->get() as $step){ + $this->updatesContractObligations->execute($signature, $step->obligation_hash_id); + $step->update(['status' => ApprovalStatus::COMPLETED]); + } + } + } + + + } + + + } + db::commit(); - dd($order); } } diff --git a/app/Console/Commands/CurlContainerListCommand.php b/app/Console/Commands/CurlContainerListCommand.php deleted file mode 100644 index e5964a40..00000000 --- a/app/Console/Commands/CurlContainerListCommand.php +++ /dev/null @@ -1,48 +0,0 @@ -withoutOverlapping() ->appendOutputTo (storage_path().'/logs/curlvt.log'); + $schedule->command('command:curlYdOrderListCommand') + ->dailyAt('11:00') + ->withoutOverlapping() + ->appendOutputTo (storage_path().'/logs/curlyd.log'); + $schedule->command('command:curlVTCommand') ->dailyAt('14:00') ->withoutOverlapping() ->appendOutputTo (storage_path().'/logs/curlvt.log'); + $schedule->command('command:curlYdOrderListCommand') + ->dailyAt('14:00') + ->withoutOverlapping() + ->appendOutputTo (storage_path().'/logs/curlyd.log'); + $schedule->command('command:curlVTCommand') ->dailyAt('17:00') ->withoutOverlapping() ->appendOutputTo (storage_path().'/logs/curlvt.log'); + + $schedule->command('command:curlYdOrderListCommand') + ->dailyAt('17:00') + ->withoutOverlapping() + ->appendOutputTo (storage_path().'/logs/curlyd.log'); } /** diff --git a/app/Http/Resources/OrderResource.php b/app/Http/Resources/OrderResource.php index b5bdf0ab..78b1b0a1 100644 --- a/app/Http/Resources/OrderResource.php +++ b/app/Http/Resources/OrderResource.php @@ -34,13 +34,13 @@ class OrderResource extends JsonResource 'origin_warehouse_packages' => PackingListResource::collection( $this->originWarehousePackages()->get() ), - 'in_transit_packages' => PackageResource::collection( + 'in_transit_packages' => PackingListResource::collection( $this->inTransitPackages()->get() ), - 'destination_warehouse_packages' => PackageResource::collection( + 'destination_warehouse_packages' => PackingListResource::collection( $this->destinationWarehousePackages()->get() ), - 'delivered_packages' => PackageResource::collection( + 'delivered_packages' => PackingListResource::collection( $this->deliveredPackages()->get() ), 'received_packages' => PackingListResource::collection($this->packingLists()->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->get()), diff --git a/app/Job/CurlYdOrderListJob.php b/app/Job/CurlYdOrderListJob.php index 713df1bc..378ada24 100644 --- a/app/Job/CurlYdOrderListJob.php +++ b/app/Job/CurlYdOrderListJob.php @@ -29,6 +29,7 @@ class CurlYdOrderListJob implements ShouldQueue * Execute the job. * * @return void + * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function handle() { diff --git a/routes/web.php b/routes/web.php index 0eca4f51..099c4368 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,6 +3,7 @@ use App\Classes\Jobs\FetchContainersStatusUpdateFromVTPortalJob; use App\Classes\Jobs\FetchDeliveryListFromVTPortalJob; use App\Classes\Jobs\FetchLoadedContainersFromVTPortalJob; +use App\Classes\Jobs\FetchOrdersFromYDPortalJob; use App\Classes\Jobs\FetchPackingListFromVTPortalJob; use App\Classes\Jobs\FetchWarehouseReceiveListFromVTPortalJob; use App\Classes\Modules\PackingLists\Processors\FetchOrderListsFromYdPortalProcessor; @@ -90,6 +91,8 @@ Route::get('/customer/{marking}', function ($marking) { Route::get('/orders/refresh', function(){ + FetchOrdersFromYDPortalJob::dispatch(); + FetchWarehouseReceiveListFromVTPortalJob::withChain([ new FetchLoadedContainersFromVTPortalJob, new FetchPackingListFromVTPortalJob,