mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal.git
synced 2026-08-19 04:24:12 +00:00
619 lines
38 KiB
PHP
619 lines
38 KiB
PHP
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Classes\Exceptions\AccessForbiddenException;
|
|
use App\Classes\Exceptions\MalformedRequestException;
|
|
use App\Classes\Exceptions\RequestValidationException;
|
|
use App\Classes\General\Services\GeneratesInitials;
|
|
use App\Classes\Modules\Accounts\DataTransferObjects\RegistrationObject;
|
|
use App\Classes\Modules\Accounts\Services\CreatesUser;
|
|
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
|
|
use App\Classes\Modules\Addresses\Services\CreatesAddress;
|
|
use App\Classes\Modules\Companies\DataTransferObjects\CompanyConnectionObject;
|
|
use App\Classes\Modules\Companies\DataTransferObjects\CompanyModuleObject;
|
|
use App\Classes\Modules\Companies\DataTransferObjects\CompanyObject;
|
|
use App\Classes\Modules\Companies\DataTransferObjects\EmploymentObject;
|
|
use App\Classes\Modules\Companies\Processors\AssignEmployeeProcessor;
|
|
use App\Classes\Modules\Companies\Services\ApprovesCompanyConnection;
|
|
use App\Classes\Modules\Companies\Services\CreatesCompany;
|
|
use App\Classes\Modules\Companies\Services\CreatesCompanyConnection;
|
|
use App\Classes\Modules\Companies\Services\CreatesCompanyModule;
|
|
use App\Classes\Modules\Companies\Services\GeneratesUniqueAccountNumber;
|
|
use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject;
|
|
use App\Classes\Modules\Contacts\Services\CreatesContact;
|
|
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
|
use App\Classes\Modules\Documents\Services\CreatesDocument;
|
|
use App\Classes\Modules\Documents\Services\CreatesFiles;
|
|
use App\Classes\Modules\Orders\Processors\CreateOrderProcessor;
|
|
use App\Classes\Modules\Orders\Services\GeneratesOrderNumber;
|
|
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\Processors\CreateContainerProcessor;
|
|
use App\Classes\Modules\PackingLists\Processors\CreatePackageProcessor;
|
|
use App\Classes\Modules\PackingLists\Processors\CreatePackingListProcessor;
|
|
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\ValueObjects\Constants\AddressType;
|
|
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
|
use App\Classes\ValueObjects\Constants\BusinessType;
|
|
use App\Classes\ValueObjects\Constants\CompanyType;
|
|
use App\Classes\ValueObjects\Constants\ContainerTypes;
|
|
use App\Classes\ValueObjects\Constants\DocumentType;
|
|
use App\Classes\ValueObjects\Constants\PackageType;
|
|
use App\Classes\ValueObjects\Constants\PackingListType;
|
|
use App\Classes\ValueObjects\Constants\RoleTypes;
|
|
use App\Classes\ValueObjects\Constants\SegmentConstants;
|
|
use App\Classes\ValueObjects\Constants\TransportType;
|
|
use App\Classes\Modules\Segments\Processors\UpdatePostcodeSegmentProcessor;
|
|
use App\Models\Address;
|
|
use App\Models\Company;
|
|
use App\Models\CompanyModule;
|
|
use App\Models\Container;
|
|
use App\Models\Document;
|
|
use App\Models\PackingList;
|
|
use App\Models\SegmentConstant;
|
|
use App\Models\Transport;
|
|
use App\Models\User;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Database\Seeder;
|
|
|
|
use Faker\Generator as Faker;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
|
|
class DummyDataSeeder extends Seeder
|
|
{
|
|
|
|
/** @var Faker */
|
|
public $faker;
|
|
|
|
/** @var CreatesUser */
|
|
public $createsUser;
|
|
|
|
/** @var GeneratesUniqueAccountNumber */
|
|
public $generatesUniqueAccountNumber;
|
|
|
|
/** @var CreatesCompany */
|
|
public $createsCompany;
|
|
|
|
/** @var CreatesCompanyModule */
|
|
public $createsCompanyModule;
|
|
|
|
/** @var CreatesContact */
|
|
public $createsContact;
|
|
|
|
/** @var CreatesAddress */
|
|
public $createsAddress;
|
|
|
|
/** @var CreateContainerProcessor */
|
|
public $createContainerProcessor;
|
|
|
|
/** @var CreatesTransport */
|
|
public $createsTransport;
|
|
|
|
/** @var CreatesSchedule */
|
|
public $createsSchedule;
|
|
|
|
/** @var CreatesCompanyConnection */
|
|
public $createsCompanyConnection;
|
|
|
|
/** @var ApprovesCompanyConnection */
|
|
public $approvesCompanyConnection;
|
|
|
|
/** @var AssignEmployeeProcessor */
|
|
public $assignEmployeeProcessor;
|
|
|
|
/** @var CreatesDocument */
|
|
public $createsDocument;
|
|
|
|
/** @var CreatesFiles */
|
|
public $createsFiles;
|
|
|
|
/** @var GeneratesOrderNumber */
|
|
public $generatesOrderNumber;
|
|
|
|
/** @var CreateOrderProcessor */
|
|
public $createOrderProcessor;
|
|
|
|
/** @var CreatePackingListProcessor */
|
|
public $createPackingListProcessor;
|
|
|
|
/** @var CreatePackageProcessor */
|
|
public $createPackageProcessor;
|
|
|
|
/**
|
|
* @param Faker $faker
|
|
* @param CreatesUser $createsUser
|
|
* @param GeneratesUniqueAccountNumber $generatesUniqueAccountNumber
|
|
* @param CreatesCompany $createsCompany
|
|
* @param CreatesCompanyModule $createsCompanyModule
|
|
* @param CreatesContact $createsContact
|
|
* @param CreatesAddress $createsAddress
|
|
* @param CreateContainerProcessor $createContainerProcessor
|
|
* @param CreatesTransport $createsTransport
|
|
* @param CreatesSchedule $createsSchedule
|
|
* @param CreatesCompanyConnection $createsCompanyConnection
|
|
* @param ApprovesCompanyConnection $approvesCompanyConnection
|
|
* @param AssignEmployeeProcessor $assignEmployeeProcessor
|
|
* @param CreatesDocument $createsDocument
|
|
* @param CreatesFiles $createsFiles
|
|
* @param GeneratesOrderNumber $generatesOrderNumber
|
|
* @param CreateOrderProcessor $createOrderProcessor
|
|
* @param CreatePackingListProcessor $createPackingListProcessor
|
|
* @param CreatePackageProcessor $createPackageProcessor
|
|
*/
|
|
public function __construct(Faker $faker, CreatesUser $createsUser, GeneratesUniqueAccountNumber $generatesUniqueAccountNumber, CreatesCompany $createsCompany, CreatesCompanyModule $createsCompanyModule, CreatesContact $createsContact, CreatesAddress $createsAddress, CreateContainerProcessor $createContainerProcessor, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, CreatesCompanyConnection $createsCompanyConnection, ApprovesCompanyConnection $approvesCompanyConnection, AssignEmployeeProcessor $assignEmployeeProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFiles, GeneratesOrderNumber $generatesOrderNumber, CreateOrderProcessor $createOrderProcessor, CreatePackingListProcessor $createPackingListProcessor, CreatePackageProcessor $createPackageProcessor)
|
|
{
|
|
$this->faker = $faker;
|
|
$this->createsUser = $createsUser;
|
|
$this->generatesUniqueAccountNumber = $generatesUniqueAccountNumber;
|
|
$this->createsCompany = $createsCompany;
|
|
$this->createsCompanyModule = $createsCompanyModule;
|
|
$this->createsContact = $createsContact;
|
|
$this->createsAddress = $createsAddress;
|
|
$this->createContainerProcessor = $createContainerProcessor;
|
|
$this->createsTransport = $createsTransport;
|
|
$this->createsSchedule = $createsSchedule;
|
|
$this->createsCompanyConnection = $createsCompanyConnection;
|
|
$this->approvesCompanyConnection = $approvesCompanyConnection;
|
|
$this->assignEmployeeProcessor = $assignEmployeeProcessor;
|
|
$this->createsDocument = $createsDocument;
|
|
$this->createsFiles = $createsFiles;
|
|
$this->generatesOrderNumber = $generatesOrderNumber;
|
|
$this->createOrderProcessor = $createOrderProcessor;
|
|
$this->createPackingListProcessor = $createPackingListProcessor;
|
|
$this->createPackageProcessor = $createPackageProcessor;
|
|
}
|
|
|
|
|
|
/**
|
|
* Run the database seeds.
|
|
*
|
|
* @return void
|
|
* @throws MalformedRequestException
|
|
* @throws AccessForbiddenException
|
|
* @throws RequestValidationException
|
|
*/
|
|
public function run()
|
|
{
|
|
// Local Development Default Password Hash
|
|
$password = '123456abcabc';
|
|
|
|
// At the moment we only have 3 different user roles:
|
|
// RoleTypes::SUPER_ADMIN : Full access, at the moment is not attached to a company but should be in the future.
|
|
// RoleTypes::ADMIN : Full access except for some sensitive features that require higher level of approval, at the moment is not attached to a company but should be in the future.
|
|
// RoleTypes::USER : This is the customer, can only access their own orders only, must be attached to a company.
|
|
|
|
// User Status
|
|
// ApprovalStatus::PENDING_VERIFICATION : This should be the default status before the user verifies their email status, but currently this is not being implemented.
|
|
// ApprovalStatus::APPROVED : This is the status of users with verified emails.
|
|
// ApprovalStatus::SUSPENDED : This is the status if the users is blocked from the system, but currently this is not being implemented.
|
|
|
|
|
|
// =============================================== //
|
|
// Create CIEF Entities //
|
|
// =============================================== //
|
|
|
|
// create super admin
|
|
$userObject = new RegistrationObject($this->faker->name, 'super_admin@izyim.com', $password, $password,RoleTypes::SUPER_ADMIN, ApprovalStatus::APPROVED);
|
|
$this->createsUser->execute($userObject);
|
|
|
|
// create admin
|
|
$userObject = new RegistrationObject($this->faker->name, 'admin@izyim.com', $password, $password,RoleTypes::ADMIN, ApprovalStatus::APPROVED);
|
|
$this->createsUser->execute($userObject);
|
|
|
|
// create CIEF
|
|
$company_object = new CompanyObject('CIEF Worldwide Sdn Bhd', 'CIEF',CompanyType::COMPANY_BUSINESS,ApprovalStatus::APPROVED);
|
|
/** @var Company $company */
|
|
$company = $this->createsCompany->execute($company_object);
|
|
|
|
$companyModuleObject = new CompanyModuleObject('CIEF Worldwide Sdn Bhd', 'CIEF', '', '', BusinessType::FREIGHT_FORWARDER, ApprovalStatus::APPROVED);
|
|
/** @var CompanyModule $CIEF */
|
|
$CIEF = $this->createsCompanyModule->execute($company, $companyModuleObject);
|
|
|
|
// =============================================== //
|
|
// Create Supplier Entities //
|
|
// =============================================== //
|
|
// supplier entities consist of 2 type of company module [BusinessType::FREIGHT_FORWARDER, BusinessType::FREIGHT_FORWARDER, BusinessType::WAREHOUSE]
|
|
// in this use case we are creating 3 supplier, with each supplier having 6 company modules, 1 BusinessType::FREIGHT_FORWARDER and 5 BusinessType::WAREHOUSE. 1 warehouse for each location.
|
|
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
$supplierName = $this->faker->company;
|
|
$supplierReference = $this->faker->bothify('??-????');
|
|
|
|
$company_object = new CompanyObject($supplierName, $supplierReference,CompanyType::COMPANY_BUSINESS,ApprovalStatus::APPROVED);
|
|
/** @var Company $company */
|
|
$company = $this->createsCompany->execute($company_object);
|
|
|
|
$companyModuleObject = new CompanyModuleObject($supplierName, $supplierReference, '', '', BusinessType::FREIGHT_FORWARDER, ApprovalStatus::APPROVED);
|
|
$this->createsCompanyModule->execute($company, $companyModuleObject);
|
|
|
|
// create supplier warehouses
|
|
foreach(['Guangzhou', 'Yiwu', 'Klang', 'Sabah', 'Sarawak'] as $name){
|
|
|
|
$warehouseReference = '';
|
|
$isChina = false;
|
|
|
|
switch($name) {
|
|
case 'Guangzhou': $warehouseReference = 'GZ-V0'.$i; $isChina = true; break;
|
|
case 'Yiwu': $warehouseReference = 'YY-V0'.$i; $isChina = true; break;
|
|
case 'Klang': $warehouseReference = 'KL-V0'.$i; break;
|
|
case 'Sabah': $warehouseReference = 'SB-V0'.$i; break;
|
|
case 'Sarawak':$warehouseReference = 'SRW-V0'.$i; break;
|
|
}
|
|
|
|
$companyModuleObject = new CompanyModuleObject($name, $warehouseReference, '', '', BusinessType::WAREHOUSE, ApprovalStatus::APPROVED);
|
|
/** @var CompanyModule $companyModule */
|
|
$companyModule = $this->createsCompanyModule->execute($company, $companyModuleObject);
|
|
|
|
$address = new AddressObject( $this->faker->streetAddress, $this->faker->streetAddress, $isChina ? 2 : 1, $isChina ? 35 : 15, $isChina ? 633 : 412, $isChina ? 510450 : 41400, AddressType::DELIVERY, ApprovalStatus::APPROVED);
|
|
$this->createsAddress->execute($companyModule, $address);
|
|
|
|
$contact = new ContactObject($this->faker->name, $this->faker->phoneNumber, '', '');
|
|
$this->createsContact->execute($companyModule, $contact);
|
|
}
|
|
}
|
|
|
|
// =============================================== //
|
|
// Create Containers //
|
|
// =============================================== //
|
|
// Containers belongs to a warehouse, a container will include many packing lists that will be shipped together
|
|
// when a container is loaded it will be attached to transport arrangement and a schedule to indicate when the container will depart (ETD) and when it will arrive (ETA)
|
|
// the shipping schedule can be interrupted which will result in a delay for the (ETA)
|
|
|
|
for($containerLoop=1; $containerLoop <= rand(15, 60); $containerLoop++) {
|
|
$loadingDate = Carbon::today()->addDays(10)->subDays(rand(1, 30));
|
|
$containerObject = new ContainerObject($this->faker->bothify('??-######'), '', '', ContainerTypes::FORTY_FEET_DRY_CONTAINER, $loadingDate, ApprovalStatus::PENDING_VERIFICATION);
|
|
|
|
// randomly selects an origin warehouse
|
|
$warehouse = CompanyModule::where('reference', $this->faker->randomElement(['GZ-V01', 'GZ-V02', 'GZ-V03', 'YY-V01', 'YY-V03', 'YY-V03']))->first();
|
|
|
|
/** @var Container $container */
|
|
$container = $this->createContainerProcessor->execute($containerObject, $warehouse);
|
|
|
|
$departureDate = $loadingDate->copy()->addDays(rand(0, 3));
|
|
$arrivalDate = $departureDate->copy()->addDays(7);
|
|
|
|
// Container Shipping Schedule
|
|
$transportObject = new TransportObject(TransportType::SEA, null, null, $departureDate, null, ApprovalStatus::APPROVED);
|
|
|
|
/** @var Transport $transport */
|
|
$transport = $this->createsTransport->execute($transportObject, $container);
|
|
$this->createsSchedule->execute($transport, new ScheduleObject($departureDate, $arrivalDate, ApprovalStatus::APPROVED));
|
|
|
|
// randomly reschedule some containers
|
|
if($this->faker->numberBetween(0, 1)){
|
|
$delayedArrivalDate = $departureDate->copy()->addDay();
|
|
|
|
// reschedule shipment
|
|
for($scheduleLoop=1; $scheduleLoop <= rand(1, 5); $scheduleLoop++) {
|
|
$delayedArrivalDate = $delayedArrivalDate->copy()->addDays(rand(0, 5));
|
|
$transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
|
|
$this->createsSchedule->execute($transport, new ScheduleObject($departureDate, $delayedArrivalDate, ApprovalStatus::APPROVED));
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// =============================================== //
|
|
// Create Customer //
|
|
// =============================================== //
|
|
// 1. create user
|
|
// 2. create company
|
|
|
|
// 3. create Company Module
|
|
// 4. Declare Company Relationship with CIEF
|
|
|
|
// 5. Attach Employee
|
|
// 6. create contact
|
|
// 7. create Address
|
|
|
|
// 8. identification verification
|
|
|
|
// =============================================== //
|
|
// Order Workflow //
|
|
// =============================================== //
|
|
|
|
// 9. Create Shipping Label
|
|
// 10. Receive Goods at warehouse (our record match supplier record + detect any problems)
|
|
// 11. Load into container for shipping (our record match supplier record + detect any problems)
|
|
// 12. generate invoice (add billing address + double check price)
|
|
// 13. additional charges
|
|
// 12. Un-stuffing Container (our record match supplier record + detect any problems)
|
|
// 13. last mile delivery (our record match supplier record + on hold)
|
|
|
|
// generate random number of users
|
|
for($userLoop=1; $userLoop <= rand(20, 50); $userLoop++) {
|
|
|
|
// === //
|
|
// 1 // ========== //
|
|
// Create user //
|
|
// ================= //
|
|
$customerName = $this->faker->name;
|
|
$customerEmail = $this->faker->email;
|
|
$userObject = new RegistrationObject($customerName, $customerEmail, $password, $password, RoleTypes::USER, ApprovalStatus::APPROVED);
|
|
/** @var User $user */
|
|
$user = $this->createsUser->execute($userObject);
|
|
|
|
// === //
|
|
// 2 // ========== //
|
|
// Create Company //
|
|
// ================= //
|
|
|
|
// CompanyTypes
|
|
// CompanyType::COMPANY_BUSINESS : For SME Business Entities and requires SSM for identity verification.
|
|
// CompanyType::PERSONAL_BUSINESS : For Personal Entities and requires IC for identity verification, and the company name will follow the customer name in this case.
|
|
|
|
// Company Status
|
|
// ApprovalStatus::APPROVED : This is the default status of registered company.
|
|
// ApprovalStatus::SUSPENDED : This is the status if the company is blocked from releasing packages from warehouse due to pending verification.
|
|
|
|
$isCompany = $this->faker->numberBetween(0, 1);
|
|
$companyName = $isCompany ? $this->faker->company : $customerName;
|
|
$companyAccountNumber = $this->generatesUniqueAccountNumber->execute();
|
|
$company_object = new CompanyObject($companyName,
|
|
$companyAccountNumber,
|
|
$isCompany ? CompanyType::COMPANY_BUSINESS : CompanyType::PERSONAL_BUSINESS,
|
|
ApprovalStatus::APPROVED);
|
|
|
|
/** @var Company $company */
|
|
$company = $this->createsCompany->execute($company_object);
|
|
|
|
// === //
|
|
// 3 // =================//
|
|
// Create Company Module //
|
|
// ========================//
|
|
// Company Module are sub entities of the company, and is used to declare what kind of business role this sub entity is in "Like Departments"
|
|
// one company can have multiple company module if they play multiple roles in the process:
|
|
// BusinessType::IMPORTER :
|
|
// BusinessType::FREIGHT_FORWARDER :
|
|
// BusinessType::WAREHOUSE :
|
|
$companyModuleObject = new CompanyModuleObject($companyName, $companyAccountNumber, '', '', BusinessType::IMPORTER, ApprovalStatus::APPROVED);
|
|
/** @var CompanyModule $companyModule */
|
|
$companyModule = $this->createsCompanyModule->execute($company, $companyModuleObject);
|
|
|
|
// === //
|
|
// 4 // ================================== //
|
|
// Declare Company Relationship with CIEF //
|
|
// ========================================= //
|
|
// In order for 2 entities to work together they must both agree to the relationship "Like facebook friend requests".
|
|
// But at the moment since CIEF is the only Entity that has a direct relationship with importers we just declare this relationship by default.
|
|
$connectionObject = new CompanyConnectionObject($companyModule, $CIEF, mt_rand(1000, 9999) . (new GeneratesInitials())->name($companyName)->length(3)->generate(), 'CIEF');
|
|
$connection = $this->createsCompanyConnection->execute($connectionObject);
|
|
$this->approvesCompanyConnection->execute($connection);
|
|
|
|
// === //
|
|
// 5 // ===========//
|
|
// Attach Employee //
|
|
// ==================//
|
|
// employees are attached to company modules not companies, because an employee maybe working for one or many "Departments".
|
|
$Object = new EmploymentObject($companyModule, $user);
|
|
$this->assignEmployeeProcessor->execute($Object);
|
|
|
|
// === //
|
|
// 6 // =========== //
|
|
// Create Contact //
|
|
// ================= //
|
|
// Contacts uses eloquent polymorphic relationship to declare its owner. and for this use case it will be attached to the company not the company module.
|
|
$contactObject = new ContactObject($customerName, $this->faker->phoneNumber, $customerEmail, null);
|
|
$this->createsContact->execute($company, $contactObject);
|
|
|
|
// === //
|
|
// 7 // ========== //
|
|
// Create Address //
|
|
// ================= //
|
|
// Addresses uses eloquent polymorphic relationship to declare its owner. and for this use case it will be attached to the company module.
|
|
// an address has at least 1 contact for the PIC.
|
|
// there are 2 type of address we use:
|
|
// AddressType::DELIVERY : for the orders delivery address
|
|
// AddressType::BILLING : for the invoice billing address
|
|
|
|
foreach ([AddressType::DELIVERY, AddressType::BILLING] as $type) {
|
|
// create delivery address
|
|
$addressObject = new AddressObject($this->faker->streetAddress, '', 1, $this->faker->numberBetween(1, 15), $this->faker->numberBetween(1, 442), $this->faker->postcode, $type, ApprovalStatus::APPROVED);
|
|
/** @var Address $address */
|
|
$address = $this->createsAddress->execute($companyModule, $addressObject);
|
|
|
|
// create delivery address contact for person in charge
|
|
$contact = new ContactObject($this->faker->name, $this->faker->phoneNumber, '', '');
|
|
$this->createsContact->execute($address, $contact);
|
|
|
|
}
|
|
|
|
|
|
// === //
|
|
// 8 // ======================= //
|
|
// identification verification //
|
|
// ============================== //
|
|
// please refer to company types section for more insight
|
|
$object = new DocumentObject($isCompany ? DocumentType::SSM_REGISTRATION : DocumentType::IDENTITY_CARD, ['data:image/png;base64,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'],
|
|
$isCompany ? $this->faker->bothify('SSM-#######') : $this->faker->bothify('############'), ApprovalStatus::APPROVED, 'identifications');
|
|
/** @var Document $document */
|
|
$document = $this->createsDocument->execute($company, $object);
|
|
$this->createsFiles->execute($document, $object);
|
|
|
|
// generate random number of shipping labels
|
|
for($orderLoop=1; $orderLoop <= rand(1, 30); $orderLoop++) {
|
|
|
|
// === //
|
|
// 9 // ================= //
|
|
// Create Shipping Label //
|
|
// ======================== //
|
|
// The shipping label is stored in the warehouse as an order entity.
|
|
// the shipping label comes with the warehouse address which will receive the shipment, and
|
|
// the shipping label comes with a qr code that helps the supplier warehouse to identify
|
|
// the customer that owns the order and the delivery address.
|
|
// A shipping label can be re-used, and each batch that arrives at the supplier warehouse
|
|
// is referred to as a packing list. more on this later.
|
|
|
|
$orderNumber = $this->generatesOrderNumber->execute();
|
|
$deliveryAddress = $company->addresses()->where('type', AddressType::DELIVERY);
|
|
|
|
// randomly selects an origin warehouse
|
|
$originWarehouse = CompanyModule::where('reference', $this->faker->randomElement(['GZ-V01', 'GZ-V02', 'GZ-V03', 'YY-V01', 'YY-V03', 'YY-V03']))->first();
|
|
|
|
// creates shipping label
|
|
$order = $this->createOrderProcessor->execute($company, $originWarehouse, $address, $orderNumber);
|
|
|
|
// Packing List Types
|
|
// A packing list is a group of packages, there are many type of packing lists, but currently we are only using 4 types of packing list:
|
|
// PackingListType::WAREHOUSE_RECEIVE_LIST : group of packages that has arrived to the warehouse with the original measurements provided by the warehouse.
|
|
// PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA : group of packages that has arrived to the warehouse with the modified measurements. e.g. add 1 cm to width, length, and height.
|
|
// PackingListType::SHIPPING_PACKING_LIST : group of packages that has packed into the container with the original measurements provided by the warehouse.
|
|
// PackingListType::SHIPPING_PACKING_LIST_REPLICA : group of packages that has packed into the container with the modified measurements. e.g. add 1 cm to width, length, and height.
|
|
|
|
if($orderLoop !== 1) {
|
|
// generate random number of packing lists
|
|
for($packingListLoop=1; $packingListLoop <= rand(2, 4); $packingListLoop++) {
|
|
|
|
// ==== //
|
|
// 10 // ===================== //
|
|
// Receive Goods at warehouse //
|
|
// WAREHOUSE_RECEIVE_LIST //
|
|
// ============================= //
|
|
// When a batch of goods arrives to the warehouse a WAREHOUSE_RECEIVE_LIST packing list is created.
|
|
// A transport arrangement is attached to WAREHOUSE_RECEIVE_LIST packing list to represent the trip
|
|
// from supplier to the warehouse and is used to record the arrival date.
|
|
|
|
|
|
// create random packages
|
|
$packages = [];
|
|
for ($packagesLoop = 1; $packagesLoop <= rand(2, 5); $packagesLoop++) {
|
|
$packages[] = new PackageObject(PackageType::CARTON, $this->faker->word, (float)$this->faker->numberBetween(1, 100), (float)$this->faker->numberBetween(1, 100), (float)$this->faker->numberBetween(1, 100), 0, (float)$this->faker->numberBetween(1, 10), ApprovalStatus::APPROVED);
|
|
}
|
|
|
|
$packingListReference = $this->faker->bothify('???#########');
|
|
|
|
$warehouseReceiveObject = new PackingListObject($packingListReference, $originWarehouse->id, PackingListType::WAREHOUSE_RECEIVE_LIST, ApprovalStatus::APPROVED);
|
|
|
|
// Creates WAREHOUSE_RECEIVE_LIST & WAREHOUSE_RECEIVE_LIST_REPLICA
|
|
/** @var PackingList $warehouseReceiveList */
|
|
$warehouseReceiveList = $this->createPackingListProcessor->execute($warehouseReceiveObject, $order);
|
|
|
|
// attach packages to packing list
|
|
foreach ($packages as $package) {
|
|
// Attach packages to both WAREHOUSE_RECEIVE_LIST & WAREHOUSE_RECEIVE_LIST_REPLICA
|
|
$this->createPackageProcessor->execute($package, $warehouseReceiveList);
|
|
}
|
|
|
|
// random arrival date in the last 30 days
|
|
$receiveDate = Carbon::today()->subDays(rand(10, 45));
|
|
|
|
// create transport arrangement for the trip from manufacturer to warehouse (to record drop off/ receive date)
|
|
$transportObject = new TransportObject(TransportType::LAND, null, $this->faker->bothify('??#########'), $receiveDate, $receiveDate, ApprovalStatus::APPROVED);
|
|
$this->createsTransport->execute($transportObject, $warehouseReceiveList);
|
|
|
|
// ==== //
|
|
// 11 // =========================== //
|
|
// Load into container for shipping //
|
|
// SHIPPING_PACKING_LIST //
|
|
// =================================== //
|
|
// When a batch of goods is loaded in a container to prepare for shipping a SHIPPING_PACKING_LIST packing list is created.
|
|
// A SHIPPING_PACKING_LIST is a copy of the WAREHOUSE_RECEIVE_LIST in most cases.
|
|
|
|
$shippingPackingListObject = new PackingListObject($packingListReference, $originWarehouse->id, PackingListType::SHIPPING_PACKING_LIST, ApprovalStatus::APPROVED);
|
|
// Creates SHIPPING_PACKING_LIST & SHIPPING_PACKING_LIST_REPLICA
|
|
/** @var PackingList $warehouseReceiveList */
|
|
$shippingPackingList = $this->createPackingListProcessor->execute($shippingPackingListObject, $order);
|
|
|
|
// attach packages to packing list
|
|
foreach ($packages as $package) {
|
|
// Attach packages to both SHIPPING_PACKING_LIST & SHIPPING_PACKING_LIST_REPLICA
|
|
$this->createPackageProcessor->execute($package, $shippingPackingList);
|
|
}
|
|
|
|
// select random container
|
|
$container = $this->faker->randomElement(Container::whereDate('loading_date', '>=', $receiveDate)->get());
|
|
|
|
// attach packing list to container
|
|
$container->packingLists()->attach($shippingPackingList, ['created_at' => now(), 'updated_at' => now()]);
|
|
|
|
if ($container->status !== ApprovalStatus::COMPLETED) {
|
|
// ==== //
|
|
// 12 // ================================= //
|
|
// Un-stuffing Container //
|
|
// container arrived to malaysia warehouse //
|
|
// ========================================= //
|
|
// when a container arrives to malaysia's warehouse it is un-stuffed, the un-stuffing date will update
|
|
// the container's transport drop off date and to container status is update to ApprovalStatus::COMPLETE
|
|
|
|
$containerTransport = $container->transports()->first();
|
|
$schedule = $containerTransport->schedules()->where('status', ApprovalStatus::APPROVED)->first();
|
|
|
|
// container Has arrived
|
|
if ($schedule->eta->isPast()) {
|
|
// update transport drop date
|
|
$containerTransport->drop_date = $schedule->eta;
|
|
$containerTransport->save();
|
|
|
|
// update container status to complete
|
|
$container->status = ApprovalStatus::COMPLETED;
|
|
$container->save();
|
|
|
|
// ==== //
|
|
// 13 // ================ //
|
|
// Last Mile Delivery //
|
|
// ======================== //
|
|
// after the container is un-stuffed, the malaysian warehouse will arrange for delivery.
|
|
// to schedule the delivery we will need to attach a transport arrangement with a schedule to the SHIPPING_PACKING_LIST
|
|
|
|
$isDelivered = rand(0, 1);
|
|
if ($isDelivered) {
|
|
$deliveryDate = $schedule->eta->copy()->addDays(rand(1, 5));
|
|
$transportObject = new TransportObject(TransportType::LAND, null, null, $deliveryDate, $deliveryDate, ApprovalStatus::APPROVED);
|
|
/** @var Transport $transport */
|
|
$transport = $this->createsTransport->execute($transportObject, $shippingPackingList);
|
|
$this->createsSchedule->execute($transport, new ScheduleObject($deliveryDate, $deliveryDate, ApprovalStatus::APPROVED));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
// Missing Functions //
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
// 1. on hold shipments
|
|
// 2. invoices & payments
|
|
// 3. overweight cbm
|
|
}
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
// Generate and Approve Dummmy Invoice //
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
ini_set('memory_limit', '-1');
|
|
$randomCompanyModule = CompanyModule::latest('id')->take(5)->get();
|
|
|
|
$centerPostcodeConstantObject = SegmentConstant::where('reference', SegmentConstants::CENTER_POSTCODE)->get();
|
|
$centerPostcodeConstant = $centerPostcodeConstantObject->isEmpty() ? [] : (array)$centerPostcodeConstantObject->first()->value;
|
|
|
|
foreach($randomCompanyModule as $companyModule) {
|
|
foreach($companyModule->addresses as $address) {
|
|
$postcode = $address->postcode;
|
|
$postcodeArea = in_array($postcode, $centerPostcodeConstant) ? 'CENTER_POSTCODE' : null;
|
|
|
|
if (!$postcodeArea) {
|
|
$random = rand(0, 1);
|
|
$postcodeArray = ['OUTSTATION_POSTCODE', 'CENTER_POSTCODE'];
|
|
(App()->make(UpdatePostcodeSegmentProcessor::class))->execute('1', $postcodeArray[$random],$postcode);
|
|
$this->command->info($postcodeArray[$random]);
|
|
}
|
|
}
|
|
}
|
|
|
|
Artisan::call('invoice:generate');
|
|
Artisan::call('approve:invoice');
|
|
|
|
}
|
|
|
|
}
|