Laravel Vapor - Code refactor for YD API cron job

This commit is contained in:
Dillon Ngo
2024-07-01 13:59:01 +08:00
parent 49989fd154
commit b2e4e67085
9 changed files with 1015 additions and 0 deletions
@@ -0,0 +1,37 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\V2\FetchContainersFromYdPortalV2Processor;
use App\Classes\Modules\PackingLists\Processors\FetchContainersUpdatesFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\FetchDeliveryUpdatesFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\FetchOrderListsFromYdPortalProcessor;
use App\Models\PackingList;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchContainersFromYdPortalV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $packingList;
public function __construct(PackingList $packingList)
{
$this->packingList = $packingList;
}
public function handle()
{
Log::info('Processing FetchContainersFromYdPortalV2CommandJob');
$processor = app(FetchContainersFromYdPortalV2Processor::class);
$processor->execute($this->packingList);
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\FetchContainersFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\V2\FetchContainersUpdatesFromYdPortalV2Processor;
use App\Classes\Modules\PackingLists\Processors\FetchDeliveryUpdatesFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\FetchOrderListsFromYdPortalProcessor;
use App\Models\Container;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchContainersUpdatesFromYdPortalV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
public function handle()
{
Log::info('Processing FetchContainersUpdatesFromYdPortalV2CommandJob');
$processor = app(FetchContainersUpdatesFromYdPortalV2Processor::class);
$processor->execute($this->container);
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\FetchContainersFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\FetchContainersUpdatesFromYdPortalProcessor;
use App\Classes\Modules\PackingLists\Processors\V2\FetchDeliveryUpdatesFromYdPortalV2Processor;
use App\Classes\Modules\PackingLists\Processors\FetchOrderListsFromYdPortalProcessor;
use App\Models\PackingList;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchDeliveryUpdatesFromYdPortalV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $packingList;
public function __construct(PackingList $packingList)
{
$this->packingList = $packingList;
}
public function handle()
{
Log::info('Processing FetchDeliveryUpdatesFromYdPortalV2CommandJob');
$processor = app(FetchDeliveryUpdatesFromYdPortalV2Processor::class);
$processor->execute($this->packingList);
}
}
@@ -0,0 +1,34 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\V2\FetchPackingListsFromYdPortalV2Processor;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchPackingListsFromYdPortalV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $startDate;
protected $endDate;
public function __construct(?Carbon $startDate, ?Carbon $endDate)
{
$this->startDate = $startDate;
$this->endDate = $endDate;
}
public function handle()
{
Log::info('Processing FetchPackingListsFromYdPortalV2CommandJob for start date: ' . $this->startDate. ', and end date: ' . $this->endDate);
$processor = app(FetchPackingListsFromYdPortalV2Processor::class);
$processor->execute($this->startDate, $this->endDate);
}
}
@@ -0,0 +1,171 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V2;
use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal;
use App\Classes\Modules\PackingLists\Processors\CreateContainerProcessor;
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\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\Notifications\ShipmentDepartureEmail;
use App\Classes\Notifications\ShipmentRescheduleEmail;
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\Classes\ValueObjects\Constants\WarehouseReferences;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Models\Container;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transport;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class FetchContainersFromYdPortalV2Processor
{
/** @var FetchesDataFromYDPortal */
private $fetchesDataFRomYDPortal;
/** @var CreatesTransport */
private $createsTransport;
/** @var CreatesSchedule */
private $createsSchedule;
/** @var FetchesContainer */
private $fetchesContainer;
/** @var CreateContainerProcessor */
private $createContainerProcessor;
/** @var PackingListToPerfexCRMProcessor */
private $packingListToPerfexCRMProcessor;
/**
* @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
* @param CreatesTransport $createsTransport
* @param CreatesSchedule $createsSchedule
* @param FetchesContainer $fetchesContainer
* @param CreateContainerProcessor $createContainerProcessor
* @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
*/
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, FetchesContainer $fetchesContainer, CreateContainerProcessor $createContainerProcessor, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
{
$this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
$this->createsTransport = $createsTransport;
$this->createsSchedule = $createsSchedule;
$this->fetchesContainer = $fetchesContainer;
$this->createContainerProcessor = $createContainerProcessor;
$this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
}
/**
* @param PackingList $packingList
* @return void
* @throws MalformedRequestException
* @throws AccessForbiddenException
* @throws RequestValidationException
*/
public function execute(PackingList $packingList)
{
Log::info('FetchContainersFromYdPortalV2Processor with packingList ' . json_encode($packingList) );
return;
$time_start = microtime(true);
$containerReference = null;
$loadingDate = null;
$etd = null;
$eta = null;
$trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
'trakingno' => $packingList->reference
]);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);
if(!$rows->data){
return;
}
foreach (array_reverse($rows->data) as $trackingRow) {
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($containerReference) {
try {
$container = $this->fetchesContainer->execute(['reference' => $containerReference]);
$container->packingLists()->detach($packingList);
$container->packingLists()->attach($packingList);
} catch (ResourceNotFoundException $exception){
if(!($packingList->owner instanceof Order)) return;
$originWarehouse = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee;
$containerObject = new ContainerObject($containerReference, '', '', ContainerTypes::FORTY_FEET_DRY_CONTAINER, $loadingDate, ApprovalStatus::PENDING_VERIFICATION);
/** @var Container $container */
$container = $this->createContainerProcessor->execute($containerObject, $originWarehouse);
$container->packingLists()->detach($packingList);
$container->packingLists()->attach($packingList);
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::LOAD_CONTAINER);
}
$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));
}
}
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
echo 'successful => <b>Total Execution Time:</b> '.$execution_time.' Mins<br>';
}
}
@@ -0,0 +1,200 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V2;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Unity\Services\UpdatesContractObligation;
use App\Classes\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\Notifications\ShipmentRescheduleEmail;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Models\Container;
use App\Models\Order;
use App\Models\PackingList;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class FetchContainersUpdatesFromYdPortalV2Processor
{
/** @var FetchesDataFromYDPortal */
private $fetchesDataFRomYDPortal;
/** @var UpdatesContractObligation */
private $updatesContractObligations;
/** @var CreatesSchedule */
private $createsSchedule;
/** @var PackingListToPerfexCRMProcessor */
private $packingListToPerfexCRMProcessor;
/**
* @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
* @param UpdatesContractObligation $updatesContractObligations
* @param CreatesSchedule $createsSchedule
* @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
*/
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, UpdatesContractObligation $updatesContractObligations, CreatesSchedule $createsSchedule, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
{
$this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
$this->updatesContractObligations = $updatesContractObligations;
$this->createsSchedule = $createsSchedule;
$this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
}
/**
* @param Container $container
* @return void
* @throws MalformedRequestException
*/
public function execute(Container $container)
{
Log::info('FetchContainersUpdatesFromYdPortalV2Processor with container ' . json_encode($container) );
return;
$time_start = microtime(true);
$packingList = $container->packingLists()->first();
$trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
'trakingno' => $packingList->reference
]);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);
if(!$rows->data){
return;
}
$unstuffingDate = null;
$delayDate = null;
$checkShipSailDate = null;
$checkShipArrivalDate = null;
foreach (array_reverse($rows->data) as $trackingRow) {
$rescheduleETD = strpos($trackingRow->remark, '开') || strpos($trackingRow->remark, '到港');
$rescheduleETA = strpos($trackingRow->remark, '到港');
if (($rescheduleETD !== false || $rescheduleETA !== false) && strpos($trackingRow->tracking, '货物装柜完成。') === false) {
preg_match_all('/([0-9]+.{3})/', $trackingRow->remark, $matches);
$dates = collect();
foreach($matches[0] as $date){
try {
$dates->push(Carbon::parse(str_replace('.', '/', $date).Carbon::now()->format('Y')));
} catch (\Exception $exception) {
continue;
}
}
$rescheduleDate = $dates->sortDesc()->first();
if(!$delayDate || $rescheduleDate > $delayDate){
/** @var Carbon $delayDate */
$delayDate = $rescheduleDate;
if($rescheduleETA === false && $delayDate) {
$delayDate = $delayDate->addDays('5');
}
}
}
if ($trackingRow->tracking === '到港') {
$delayDate = Carbon::parse($trackingRow->trackingtime);
$checkShipArrivalDate = Carbon::parse($trackingRow->trackingtime);
}
if ($trackingRow->tracking === '已开船') {
$delayDate = Carbon::parse($trackingRow->trackingtime)->addDays('5');
$checkShipSailDate = Carbon::parse($trackingRow->trackingtime);
}
if ($trackingRow->tracking === '货物已进目的港仓库') {
$unstuffingDate = Carbon::parse($trackingRow->trackingtime);
}
}
dump($delayDate, $unstuffingDate);
if($checkShipSailDate){
//check if ship has sailed
if($checkShipSailDate->isPast()){
foreach ($container->packingLists as $packingList){
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::SHIP_SAILED);
}
}
}
}
if($checkShipArrivalDate){
//check if ship has arrived at destination
if($checkShipArrivalDate->isPast()){
foreach ($container->packingLists as $packingList){
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::SHIP_ARRIVED);
}
}
}
}
if($delayDate){
$transport = $container->transports()->first();
if(!$transport->schedules()->whereDate('eta', '>=', $delayDate)->first()) {
$etd = $transport->schedules()->where('status', '=', ApprovalStatus::APPROVED)->first()->etd;
$transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
$this->createsSchedule->execute($transport, new ScheduleObject($etd, $delayDate, ApprovalStatus::APPROVED));
foreach ($container->packingLists as $packingList){
if(!($packingList->owner instanceof Order)) continue;
$user = $packingList->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
$user->notify(new ShipmentRescheduleEmail($user, $packingList));
}
}
}
}
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();
}
if(!($packingList->owner instanceof Order)) continue;
$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]);
}
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::UNSTUFFING);
}
}
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
echo 'successful => <b>Total Execution Time:</b> '.$execution_time.' Mins<br>';
}
}
@@ -0,0 +1,119 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V2;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
use App\Classes\Modules\Unity\Services\UpdatesContractObligation;
use App\Classes\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransportType;
use App\Classes\ValueObjects\Constants\WarehouseReferences;
use App\Models\CompanyModule;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transport;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class FetchDeliveryUpdatesFromYdPortalV2Processor
{
/** @var UpdatesContractObligation */
private $updatesContractObligations;
/** @var CreatesTransport */
private $createsTransport;
/** @var CreatesSchedule */
private $createsSchedule;
/** @var PackingListToPerfexCRMProcessor */
private $packingListToPerfexCRMProcessor;
/**
* @param UpdatesContractObligation $updatesContractObligations
* @param CreatesTransport $createsTransport
* @param CreatesSchedule $createsSchedule
* @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
*/
public function __construct(UpdatesContractObligation $updatesContractObligations, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
{
$this->updatesContractObligations = $updatesContractObligations;
$this->createsTransport = $createsTransport;
$this->createsSchedule = $createsSchedule;
$this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
}
/**
* @param PackingList $packingList
* @return void
* @throws MalformedRequestException
* @throws GuzzleException
*/
public function execute(PackingList $packingList)
{
Log::info('FetchDeliveryUpdatesFromYdPortalV2Processor with packingList ' . json_encode($packingList) );
return;
if(!$packingList->reference) return;
$time_start = microtime(true);
$deliveryDate = null;
try {
$client = new \GuzzleHttp\Client(['cookies' => true, 'headers' => ['Cookie' => 'utc_offset=480']]);
$request = $client->request('get', 'https://main.universe.com.my/Tracking/User/Paging?sEcho=1&sTrackingNo='.$packingList->reference.'&sOrgId=sti', ['timeout' => 3]);
$deliveryTracking = json_decode($request->getBody()->getContents());
foreach (array_reverse($deliveryTracking->aaData) as $trackingRow) {
$trackingDate = Carbon::createFromFormat('d/m/y H:i', $trackingRow->LocalDateTime);
if (Str::contains($trackingRow->PublicDescription, ['delivered'])) {
$deliveryDate = $trackingDate;
}
}
} catch (\Exception $exception){
dump($exception);
Log::debug('failed to fetch delivery tracking');
}
if($deliveryDate){
$packingList->status = ApprovalStatus::COMPLETED;
$packingList->save();
$deliveryDate = Carbon::parse($deliveryDate);
$transportObject = new TransportObject(TransportType::LAND, null, null, $deliveryDate, $deliveryDate, ApprovalStatus::APPROVED);
/** @var Transport $transport */
$transport = $this->createsTransport->execute($transportObject, $packingList);
$this->createsSchedule->execute($transport, new ScheduleObject($deliveryDate, $deliveryDate, ApprovalStatus::APPROVED));
if(!($packingList->owner instanceof Order)) return;
$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]);
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::DELIVERY);
}
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
echo 'successful => <b>Total Execution Time:</b> '.$execution_time.' Mins<br>';
}
}
@@ -0,0 +1,257 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V2;
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\PackageObject;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject;
use App\Classes\Modules\PackingLists\Services\FetchesPackingList;
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\PackingLists\Processors\CreatePackingListProcessor;
use App\Classes\Modules\PackingLists\Processors\CreatePackageProcessor;
use App\Classes\Modules\Unity\Services\CreatesContract;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
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\Order;
use App\Models\PackingList;
use Carbon\Carbon;
use DateTime;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class FetchPackingListsFromYdPortalV2Processor
{
/** @var FetchesDataFromYDPortal */
private $fetchesDataFRomYDPortal;
/** @var FetchesOrder */
private $fetchesOrder;
/** @var CreatePackingListProcessor */
private $createPackingListProcessor;
/** @var CreatePackageProcessor */
private $createPackageProcessor;
/** @var CreatesTransport */
private $createsTransport;
/** @var FetchesPackingList */
private $fetchesPackingList;
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var CreatesContract */
private $unityCreateContract;
/** @var AssignContractEntityProcessor */
private $unityAssignContractEntity;
/** @var CreateContractEntityProcessor */
private $unityCreateContractEntity;
/** @var CreatesStep */
private $createsStep;
/** @var ActivateContractProcessor */
private $unityActivateContract;
/**
* @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
* @param FetchesOrder $fetchesOrder
* @param CreatePackingListProcessor $createPackingListProcessor
* @param CreatePackageProcessor $createPackageProcessor
* @param CreatesTransport $createsTransport
* @param FetchesPackingList $fetchesPackingList
* @param FetchesCompanyModule $fetchesCompanyModule
* @param CreatesContract $unityCreateContract
* @param AssignContractEntityProcessor $unityAssignContractEntity
* @param CreateContractEntityProcessor $unityCreateContractEntity
* @param CreatesStep $createsStep
* @param ActivateContractProcessor $unityActivateContract
*/
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, FetchesOrder $fetchesOrder, CreatePackingListProcessor $createPackingListProcessor, CreatePackageProcessor $createPackageProcessor, CreatesTransport $createsTransport, FetchesPackingList $fetchesPackingList, FetchesCompanyModule $fetchesCompanyModule, CreatesContract $unityCreateContract, AssignContractEntityProcessor $unityAssignContractEntity, CreateContractEntityProcessor $unityCreateContractEntity, CreatesStep $createsStep, ActivateContractProcessor $unityActivateContract)
{
$this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
$this->fetchesOrder = $fetchesOrder;
$this->createPackingListProcessor = $createPackingListProcessor;
$this->createPackageProcessor = $createPackageProcessor;
$this->createsTransport = $createsTransport;
$this->fetchesPackingList = $fetchesPackingList;
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->unityCreateContract = $unityCreateContract;
$this->unityAssignContractEntity = $unityAssignContractEntity;
$this->unityCreateContractEntity = $unityCreateContractEntity;
$this->createsStep = $createsStep;
$this->unityActivateContract = $unityActivateContract;
}
/**
* @param Carbon $startDate
* @param Carbon $endDate
* @return void
* @throws GuzzleException
*/
public function execute(Carbon $startDate = null, Carbon $endDate = null)
{
Log::info('FetchPackingListsFromYdPortalV2Processor for start date: ' . $startDate . ', and end date: ' . $endDate);
return;
try {
$orderRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/GetOrderList.ashx', 'GET', [
'begintime' => $startDate->timestamp,
'endtime' => $endDate->timestamp,
]);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($orderRequest);
if(!$rows->data) return;
foreach($rows->data as $row){
if(!is_numeric($row->goodcount)) continue;
$time_start = microtime(true);
$receiveDate = Carbon::parse(substr(preg_replace("/[^0-9]/", "", $row->expressno), 0, 8));
$customerno = preg_split('(-|\(|\)|\/)', $row->customerno);
$orderNumber = $customerno[array_key_last($customerno)];
$allow_contract = true;
try {
$order = $this->fetchesOrder->execute(['reference' => $orderNumber]);
} catch (ResourceNotFoundException $exception) {
try {
$order = $this->fetchesOrder->execute(['reference' => substr($orderNumber, -9)]);
} catch (ResourceNotFoundException $exception) {
$order = $this->fetchesCompanyModule->execute(['id' => 1]);
$allow_contract = false;
}
}
$packingListReference = $row->expressno;
try{
$packingList = $this->fetchesPackingList->execute(['reference' => $row->expressno, 'type' => PackingListType::SHIPPING_PACKING_LIST]);
$packingList->packages()->delete();
$replica = $packingList->packingLists()->where('type', PackingListType::SHIPPING_PACKING_LIST_REPLICA)->first();
if($replica) $replica->packages()->delete();
$warehouseReceiveList = $this->fetchesPackingList->execute(['reference' => $row->expressno, 'type' => PackingListType::WAREHOUSE_RECEIVE_LIST]);
$warehouseReceiveList->packages()->delete();
$replica = $warehouseReceiveList->packingLists()->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA)->first();
if($replica) $replica->packages()->delete();
} catch (ResourceNotFoundException $exception) {
if (!$allow_contract) {
$appointee_id = 2307;
} else {
$appointee_id = $order->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id;
}
$warehouseReceiveObject = new PackingListObject($packingListReference, $appointee_id, PackingListType::WAREHOUSE_RECEIVE_LIST, $allow_contract ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
/** @var PackingList $warehouseReceiveList */
$warehouseReceiveList = $this->createPackingListProcessor->execute($warehouseReceiveObject, $order);
$transportObject = new TransportObject(TransportType::LAND, null, $row->kuaidilist, Carbon::parse($receiveDate), Carbon::parse($receiveDate), $allow_contract ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
$transport = $this->createsTransport->execute($transportObject, $warehouseReceiveList);
if ($allow_contract) {
$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, $appointee_id, PackingListType::SHIPPING_PACKING_LIST, ApprovalStatus::SUSPENDED, !$allow_contract ? null : $contractReference);
/** @var PackingList $packingList */
$packingList = $this->createPackingListProcessor->execute($packingListObject, $order);
if ($allow_contract) {
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(!count($row->deliverysize)){
$measurement = round(((float) $row->volume / (float) $row->goodcount) ** (1/3) * 100, 2);
$packageObject = new PackageObject(PackageType::CARTON, $row->goodname, (float) $measurement, (float) $measurement, (float) $measurement, 0, (float) $row->goodcount, ApprovalStatus::APPROVED);
$this->createPackageProcessor->execute($packageObject, $warehouseReceiveList);
$this->createPackageProcessor->execute($packageObject, $packingList);
}
$weightCbm = (float) $row->weight / 500;
$overWeightCbm = $weightCbm - $packingList->packages()->sum(DB::raw('(width/100) * (height/100) * (length/100) * quantity'));
if($overWeightCbm > 0){
$measurement = round($overWeightCbm ** (1/3) * 100, 2);
$packageObject = new PackageObject(PackageType::OVER_WEIGHT, 'Overweight CBM', (float) $measurement, (float) $measurement, (float) $measurement, 0, 1, ApprovalStatus::APPROVED);
$this->createPackageProcessor->execute($packageObject, $packingList);
}
if($order instanceof Order){
$marking = $order->companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
if(!in_array($marking, ['1290CSW', '8997ITB', '3992WHE', '962LOW', '1152AAT'])){
$this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/confirmsendorder.ashx', 'GET', [
'expressno' => $row->expressno
]);
}
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
echo 'successful => <b>Total Execution Time:</b> '.$execution_time.' Mins<br>';
}
} catch (\Exception $exception) {
Log::debug($exception);
}
}
}
@@ -0,0 +1,125 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\YD\FetchPackingListsFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchContainersFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchContainersUpdatesFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchDeliveryUpdatesFromYdPortalV2CommandJob;
use App\Models\PackingList;
use App\Models\Container;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Log;
class ProcessYDPortalDataV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'process-yd-portal-data-command {start_date?} {end_date?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Process data from YD Portal for the given date range';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$jobs = [];
$jobs = array_merge($jobs, $this->fetchPackingListsFromYdPortalV2CommandJobs());
$jobs = array_merge($jobs, $this->fetchContainersFromYdPortalV2CommandJobs());
$jobs = array_merge($jobs, $this->fetchContainersUpdatesFromYdPortalV2CommandJob());
$jobs = array_merge($jobs, $this->fetchDeliveryUpdatesFromYdPortalV2CommandJobs());
Bus::chain($jobs)->dispatch();
}
private function fetchPackingListsFromYdPortalV2CommandJobs(){
$jobs = [];
$start = $this->argument('start_date') ? Carbon::parse($this->argument('start_date')) : null;
$end = $this->argument('end_date') ? Carbon::parse($this->argument('end_date')) : null;
// $start = $this->startDate ? Carbon::parse($this->startDate) : null;
// $end = $this->endDate ? Carbon::parse($this->endDate) : null;
$from = $end ? Carbon::today()->diffInDays($end) : 0;
$to = $start ? Carbon::today()->diffInDays($start) : 10;
for ($x = $from; $x <= $to; $x++) {
$startDate = Carbon::today()->subDays($x);
$startLimit = Carbon::parse('01-12-2021');
if($startDate->isBefore($startLimit)){
$startDate = $startLimit;
}
$endDate = Carbon::today()->subDays($x - 1);
$jobs[] = new FetchPackingListsFromYdPortalV2CommandJob($startDate, $endDate);
//FetchPackingListsFromYdPortalV2CommandJob::dispatch($startDate, $endDate);
Log::info('Dispatched FetchPackingListsFromYdPortalV2CommandJob for start date: ' . $startDate . ', end date: ' . $endDate);
}
return $jobs;
}
private function fetchContainersFromYdPortalV2CommandJobs(){
$jobs = [];
$maxFetchTime = Carbon::now()->subMonths(4);
$packingLists = PackingList::where('type', PackingListType::SHIPPING_PACKING_LIST)->whereDate('created_at', '>=', $maxFetchTime)->doesntHave('containers')->get();
foreach ($packingLists as $packingList) {
$jobs[] = new FetchContainersFromYdPortalV2CommandJob($packingList);
Log::info('Dispatched FetchContainersFromYdPortalV2CommandJob for packingList with id ' . $packingList->id);
}
return $jobs;
}
private function fetchContainersUpdatesFromYdPortalV2CommandJob(){
$jobs = [];
$containers = Container::where('status', ApprovalStatus::PENDING_VERIFICATION)->get();
foreach ($containers as $container) {
$jobs[] = new FetchContainersUpdatesFromYdPortalV2CommandJob($container);
Log::info('Dispatched FetchContainersUpdatesFromYdPortalV2CommandJob for container with id ' . $container->id);
}
return $jobs;
}
private function fetchDeliveryUpdatesFromYdPortalV2CommandJobs(){
$jobs = [];
$packingLists = PackingList::where('type', PackingListType::SHIPPING_PACKING_LIST)->whereRaw('LENGTH(reference) > 12')->whereHas('containers', function ($container){
return $container->where('status', 3);
})->doesntHave('transports')->get()->reverse();
foreach ($packingLists->chunk(50) as $chunk) {
foreach ($chunk as $packingList){
// $processor = app(FetchDeliveryUpdatesFromYdPortalV2Processor::class);
// $processor->execute($packingList);
$jobs[] = new FetchDeliveryUpdatesFromYdPortalV2CommandJob($packingList);
Log::info('Dispatched FetchDeliveryUpdatesFromYdPortalV2CommandJob for packingList with id' . $packingList->id);
}
}
return $jobs;
}
}