mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 20:43:56 +00:00
690 lines
49 KiB
PHP
690 lines
49 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\Banks\DataTransferObjects\BankObject;
|
|
use App\Classes\Modules\Banks\Services\CreatesBank;
|
|
use App\Classes\Modules\Banks\Services\SetsBankToDefault;
|
|
use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject;
|
|
use App\Classes\Modules\Bookings\Services\CreatesBooking;
|
|
use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation;
|
|
use App\Classes\Modules\Bookings\Services\GeneratesBookingMarking;
|
|
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\Processors\AssignSegmentProcessor;
|
|
use App\Classes\Modules\Companies\Services\CreatesCompany;
|
|
use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject;
|
|
use App\Classes\Modules\Contacts\Services\CreatesContact;
|
|
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject;
|
|
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
|
use App\Classes\Modules\Documents\Services\ApprovesDocument;
|
|
use App\Classes\Modules\Documents\Services\CreatesDocument;
|
|
use App\Classes\Modules\Documents\Services\CreatesFiles;
|
|
use App\Classes\Modules\Documents\Services\RejectsDocument;
|
|
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
|
|
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
|
|
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
|
|
use App\Classes\Modules\Transactions\Processors\CreateSupplierTransactionProcessor;
|
|
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
|
|
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
|
|
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
|
|
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
|
|
use App\Classes\Modules\Wallets\Services\CreatesWallet;
|
|
use App\Classes\Modules\Wallets\Services\GeneratesWalletCode;
|
|
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
|
|
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
|
use App\Classes\ValueObjects\Constants\BusinessType;
|
|
use App\Classes\ValueObjects\Constants\CompanyType;
|
|
use App\Classes\ValueObjects\Constants\DocumentType;
|
|
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
|
use App\Classes\ValueObjects\Constants\RoleTypes;
|
|
use App\Classes\ValueObjects\Constants\TransactionType;
|
|
use App\Models\Address;
|
|
use App\Models\Company;
|
|
use App\Models\Document;
|
|
use App\Models\Group;
|
|
use App\Models\ServiceType;
|
|
use App\Models\Transaction;
|
|
use App\Models\User;
|
|
use App\Models\Wallet;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Database\Seeder;
|
|
|
|
use Faker\Generator as Faker;
|
|
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
|
|
use Mpdf\MpdfException;
|
|
|
|
class DummyDataSeeder extends Seeder
|
|
{
|
|
|
|
/** @var Faker */
|
|
public $faker;
|
|
|
|
/** @var CreatesUser */
|
|
public $createsUser;
|
|
|
|
/** @var CreatesCompany */
|
|
public $createsCompany;
|
|
|
|
/** @var CreatesContact */
|
|
public $createsContact;
|
|
|
|
/** @var CreatesAddress */
|
|
public $createsAddress;
|
|
|
|
/** @var AssignEmployeeProcessor */
|
|
public $assignEmployeeProcessor;
|
|
|
|
/** @var CreatesDocument */
|
|
public $createsDocument;
|
|
|
|
/** @var CreatesFiles */
|
|
public $createsFiles;
|
|
|
|
/** @var GeneratesWalletCode */
|
|
public $generatesWalletCode;
|
|
|
|
/** @var CreatesWallet */
|
|
public $createsWallet;
|
|
|
|
/** @var GeneratesTransactionBillNumber */
|
|
public $generatesTransactionBillNumber;
|
|
|
|
/** @var CreatesTransaction */
|
|
public $createsTransaction;
|
|
|
|
/** @var UpdatesTransactionStatus */
|
|
public $updatesTransactionStatus;
|
|
|
|
/** @var UpdatesWalletBalance */
|
|
public $updatesWalletBalance;
|
|
|
|
/** @var createsBank */
|
|
public $createsBank;
|
|
|
|
/** @var GeneratesBookingMarking */
|
|
public $generatesBookingMarking;
|
|
|
|
/** @var CreatesBooking */
|
|
public $createsBooking;
|
|
|
|
/** @var FetchesBookingQuotation */
|
|
public $fetchBookingQuotation;
|
|
|
|
/** @var ApprovesDocument */
|
|
public $approvesDocument;
|
|
|
|
/** @var RejectsDocument */
|
|
public $rejectsDocument;
|
|
|
|
/** @var CreatePurchaseOrderTransactionProcessor */
|
|
public $createPurchaseOrderTransactionProcessor;
|
|
|
|
/** @var CreateInvoiceTransactionProcessor */
|
|
public $createInvoiceTransactionProcessor;
|
|
|
|
/** @var CreateSupplierTransactionProcessor */
|
|
public $createSupplierTransactionProcessor;
|
|
|
|
/** @var AssignSegmentProcessor */
|
|
private $assignSegmentProcessor;
|
|
|
|
/** @var SetsBankToDefault*/
|
|
private $setsBankToDefault ;
|
|
|
|
/**
|
|
* @param Faker $faker
|
|
* @param CreatesUser $createsUser
|
|
* @param CreatesCompany $createsCompany
|
|
* @param CreatesContact $createsContact
|
|
* @param CreatesAddress $createsAddress
|
|
* @param AssignEmployeeProcessor $assignEmployeeProcessor
|
|
* @param CreatesDocument $createsDocument
|
|
* @param CreatesFiles $createsFiles
|
|
* @param GeneratesWalletCode $generatesWalletCode
|
|
* @param CreatesWallet $createsWallet
|
|
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
|
|
* @param CreatesTransaction $createsTransaction
|
|
* @param UpdatesTransactionStatus $updatesTransactionStatus
|
|
* @param UpdatesWalletBalance $updatesWalletBalance
|
|
* @param CreatesBank $createsBank
|
|
* @param GeneratesBookingMarking $generatesBookingMarking
|
|
* @param CreatesBooking $createsBooking
|
|
* @param FetchesBookingQuotation $fetchBookingQuotation
|
|
* @param ApprovesDocument $approvesDocument
|
|
* @param RejectsDocument $rejectsDocument
|
|
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
|
|
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
|
|
* @param CreateSupplierTransactionProcessor $createSupplierTransactionProcessor
|
|
* @param AssignSegmentProcessor $assignSegmentProcessor
|
|
* @param SetsBankToDefault $setsBankToDefault
|
|
*/
|
|
public function __construct(Faker $faker, CreatesUser $createsUser, CreatesCompany $createsCompany, CreatesContact $createsContact, CreatesAddress $createsAddress, AssignEmployeeProcessor $assignEmployeeProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFiles, GeneratesWalletCode $generatesWalletCode, CreatesWallet $createsWallet, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, UpdatesTransactionStatus $updatesTransactionStatus, UpdatesWalletBalance $updatesWalletBalance, CreatesBank $createsBank, GeneratesBookingMarking $generatesBookingMarking, CreatesBooking $createsBooking, FetchesBookingQuotation $fetchBookingQuotation, ApprovesDocument $approvesDocument, RejectsDocument $rejectsDocument, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor, CreateSupplierTransactionProcessor $createSupplierTransactionProcessor, AssignSegmentProcessor $assignSegmentProcessor, SetsBankToDefault $setsBankToDefault)
|
|
{
|
|
$this->faker = $faker;
|
|
$this->createsUser = $createsUser;
|
|
$this->createsCompany = $createsCompany;
|
|
$this->createsContact = $createsContact;
|
|
$this->createsAddress = $createsAddress;
|
|
$this->assignEmployeeProcessor = $assignEmployeeProcessor;
|
|
$this->createsDocument = $createsDocument;
|
|
$this->createsFiles = $createsFiles;
|
|
$this->generatesWalletCode = $generatesWalletCode;
|
|
$this->createsWallet = $createsWallet;
|
|
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
|
|
$this->createsTransaction = $createsTransaction;
|
|
$this->updatesTransactionStatus = $updatesTransactionStatus;
|
|
$this->updatesWalletBalance = $updatesWalletBalance;
|
|
$this->createsBank = $createsBank;
|
|
$this->generatesBookingMarking = $generatesBookingMarking;
|
|
$this->createsBooking = $createsBooking;
|
|
$this->fetchBookingQuotation = $fetchBookingQuotation;
|
|
$this->approvesDocument = $approvesDocument;
|
|
$this->rejectsDocument = $rejectsDocument;
|
|
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
|
|
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
|
|
$this->createSupplierTransactionProcessor = $createSupplierTransactionProcessor;
|
|
$this->assignSegmentProcessor = $assignSegmentProcessor;
|
|
$this->setsBankToDefault = $setsBankToDefault;
|
|
}
|
|
|
|
|
|
/**
|
|
* Run the database seeds.
|
|
*
|
|
* @return void
|
|
* @throws AccessForbiddenException
|
|
* @throws MalformedRequestException
|
|
* @throws RequestValidationException
|
|
* @throws MpdfException
|
|
*/
|
|
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@exchange.com', $password, $password,RoleTypes::SUPER_ADMIN, ApprovalStatus::APPROVED);
|
|
$this->createsUser->execute($userObject);
|
|
|
|
Auth()->login(User::find(1), true);
|
|
|
|
// create admin
|
|
$userObject = new RegistrationObject($this->faker->name, 'admin@exchange.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);
|
|
|
|
// =============================================== //
|
|
// 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,BusinessType::CURRENCY_VENDOR, CompanyType::COMPANY_BUSINESS, ApprovalStatus::APPROVED);
|
|
/** @var Company $company */
|
|
$company = $this->createsCompany->execute($company_object);
|
|
$bank_object = new BankObject($company->id, $this->faker->numberBetween(2, 3),
|
|
$this->faker->company, $this->faker->name, $this->faker->bankAccountNumber,
|
|
$this->faker->city, null, null,
|
|
2, $this->faker->company);
|
|
|
|
$bank = $this->createsBank->execute($bank_object);
|
|
$this->setsBankToDefault->execute($bank);
|
|
|
|
}
|
|
|
|
|
|
// =============================================== //
|
|
// Create Customer //
|
|
// =============================================== //
|
|
// 1. create user
|
|
// 2. create company
|
|
|
|
// 3. Attach Employee
|
|
// 4. create contact
|
|
//
|
|
// 5. create Address
|
|
|
|
// 6. identification verification
|
|
|
|
// =============================================== //
|
|
// Wallet //
|
|
// =============================================== //
|
|
|
|
// 7. top up wallet
|
|
|
|
// =============================================== //
|
|
// Order Workflow //
|
|
// =============================================== //
|
|
|
|
// 8. create recipient bank
|
|
// 9. create booking
|
|
// 10. make payment (Manual, FPX, Wallet)
|
|
// 11. approve payment (For manual payments only) * N
|
|
// 12. create supplier order
|
|
// 13. upload china payment proof (outsource * N)
|
|
// 14. create purchase order (maybe outsource)
|
|
// 15. approve purchase order ()
|
|
// 16. generate invoice
|
|
|
|
// generate random number of users
|
|
for($userLoop=1; $userLoop <= 20; $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 //
|
|
// ================= //
|
|
|
|
// company reference is called marking, it is the human readable id.
|
|
|
|
// 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;
|
|
|
|
$company_object = new CompanyObject($companyName,
|
|
mt_rand(1000, 9999).(new GeneratesInitials())->name($companyName)->length(3)->generate(),
|
|
$isCompany ? CompanyType::COMPANY_BUSINESS : CompanyType::PERSONAL_BUSINESS,
|
|
ApprovalStatus::APPROVED);
|
|
|
|
/** @var Company $company */
|
|
$company = $this->createsCompany->execute($company_object);
|
|
$this->assignSegmentProcessor->execute($company);
|
|
|
|
|
|
// === //
|
|
// 3 // ===========//
|
|
// Attach Employee //
|
|
// ==================//
|
|
// employees are attached to company modules not companies, because an employee maybe working for one or many "Departments".
|
|
$Object = new EmploymentObject($company, $user);
|
|
$this->assignEmployeeProcessor->execute($Object);
|
|
|
|
// === //
|
|
// 4 // ========== //
|
|
// 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($company->id, $customerName, (int) $this->faker->randomNumber(7), $customerEmail, null, 1);
|
|
$this->createsContact->execute($contactObject);
|
|
|
|
// === //
|
|
// 5 // ========== //
|
|
// 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 is 1 type of address we use:
|
|
// AddressType::BILLING : for the invoice billing address
|
|
|
|
// create delivery address
|
|
$addressObject = new AddressObject($this->faker->streetAddress, '', 1, $this->faker->numberBetween(1, 15), $this->faker->numberBetween(1, 100), $this->faker->postcode);
|
|
/** @var Address $address */
|
|
$address = $this->createsAddress->execute($company, $addressObject);
|
|
|
|
// === //
|
|
// 6 // ====================== //
|
|
// 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);
|
|
|
|
// === //
|
|
// 7 // ========= //
|
|
// top up wallet //
|
|
// ================ //
|
|
// when a customer tries to top up their wallet, if the wallet doesn't already exist it will be automatically created.
|
|
// wallet credit can be used to pay for transfer orders to enjoy better conversion rates.
|
|
// wallet top-ups can only be performed using FPX at the moment. but super admin can manually credit or debit credit to a customer's wallet
|
|
|
|
// The transaction table is considered the most confusing part of our database because it is being used by multiple model using a polymorphic relationship
|
|
// and is used for many use cases in our application which is an unintended flaw, and we are looking for ways to improve it.
|
|
|
|
|
|
// A wallet top up is TransactionType::TOP_UP, there are many types of transactions used by a wallet:
|
|
// TransactionType::TOP_UP : represent a top-up amount to a wallet;
|
|
// TransactionType::PAYMENT : represent payment out of the wallet;
|
|
// TransactionType::CREDIT_NOTE : represent a manual top-up to a wallet, and can only be performed by super admin;
|
|
// TransactionType::DEBDIT_NOTE : represent a deduction from a wallet, and can only be performed by super admin;
|
|
// TransactionType::WITHDRAW : represent a customer withdrawing credit out of a wallet to a bank account (refund);
|
|
|
|
|
|
// top up only some customers
|
|
$shouldTopUp = $this->faker->numberBetween(0, 1);
|
|
if($shouldTopUp) {
|
|
$object = new WalletObject($company->id, 1, $this->generatesWalletCode->execute());
|
|
/** @var Wallet $wallet */
|
|
$wallet = $this->createsWallet->execute($object, $company);
|
|
|
|
$amount = $this->faker->numberBetween(10, 300000);
|
|
$billNumber = $this->generatesTransactionBillNumber->execute('TOPUP-');
|
|
|
|
// create billplz bill using api, we will skip this part in the seed.
|
|
$billPlzBill = $this->faker->bothify('???#####');
|
|
|
|
$transaction_object = new TransactionObject($billNumber, TransactionType::TOP_UP, 1, $company->id, 1, PaymentMethodType::PAYMENT_GATEWAY, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, [], $billPlzBill);
|
|
|
|
/** @var Transaction $transaction */
|
|
$transaction = $this->createsTransaction->execute($wallet, $transaction_object);
|
|
|
|
|
|
// on billplz callback url
|
|
$status = $this->faker->randomElement([ApprovalStatus::APPROVED, ApprovalStatus::REJECTED]);
|
|
$this->updatesTransactionStatus->execute($transaction, $status);
|
|
if($status === ApprovalStatus::APPROVED) {
|
|
$this->updatesWalletBalance->execute($wallet, $amount);
|
|
}
|
|
}
|
|
|
|
// === //
|
|
// 8 // ========================== //
|
|
// Create Recipient Bank Accounts //
|
|
// ================================= //
|
|
// bank accounts are used to store bank account details, and can be used in a variety of ways
|
|
// Bank types:
|
|
// 1. PERSONAL : belong to the same entity
|
|
// 2. EXTERNAL : Doesn't belong to the entity, belongs to an external entity;
|
|
// 3. ALIPAY : : Is an external entity, but flag the type of bank as alipay e-wallet;
|
|
//
|
|
// here are some of the current use cases for banks in our application:
|
|
// 1. Recipient bank (EXTERNAL) (the account the customer is requesting to transfer funds to)
|
|
// 2. AliPay Transfer (EXTERNAL) (the account the customer is requesting to transfer funds to when bank type is ALIPAY)
|
|
// 3. Refund bank (PERSONAL) (the account the customer is requesting his order refunds to be transferred to)
|
|
$bank_object = new BankObject($company->id, $this->faker->numberBetween(2, 3),
|
|
$this->faker->company, $this->faker->name, $this->faker->bankAccountNumber,
|
|
$this->faker->city, null, null,
|
|
2, $this->faker->company);
|
|
|
|
// todo create multiple bank accounts with multiple types
|
|
$bank = $this->createsBank->execute($bank_object);
|
|
|
|
// generate random number of bookings
|
|
for($orderLoop=1; $orderLoop <= rand(1, 5); $orderLoop++) {
|
|
echo 'booking created';
|
|
// === //
|
|
// 9 // ========= //
|
|
// Create Booking //
|
|
// ================ //
|
|
// A booking is simply a transfer order to a supplier/manufacturer bank account overseas
|
|
// to pay for goods they are buying from overseas. the booking is not proceed until the
|
|
// customer requests to make a payment, when the customer start the payment process he
|
|
// will receive a quote for the cost to transfer the booked amount (e.g. 100 USD) in RM
|
|
|
|
// bookings require 2 actions from the customer to be completed
|
|
// 1. Make Full payment **
|
|
// 2. Provide Purchase Order (itemized list of the products they are buying)
|
|
|
|
// ** A booking will be the sum of payments transferred to one bank account
|
|
// but can be partially paid (e.g. 1000 USD can be paid: $300 deposit + $700 balance)
|
|
// 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.
|
|
|
|
// service types are configured by the super admin from the settings
|
|
// it will include things like conversion rates, service charge, etc..
|
|
// and can be used to place different type of transfer orders (e.g. 1 day transfer, 3 days transfer, 1688 Payment)
|
|
|
|
// randomly selects a service type
|
|
$service = ServiceType::inRandomOrder()->first();
|
|
|
|
// Booking human readable id
|
|
$reference = $this->generatesBookingMarking->execute();
|
|
|
|
// random currency booking (CNY, USD)
|
|
$bookedCurrency = 2;
|
|
$bank = $company->banks()->inRandomOrder()->first();
|
|
$object = new BookingObject($service->id, $bank->id, $reference, $this->faker->numberBetween(10, 300000), $bookedCurrency, $bookedCurrency, 1);
|
|
$booking = $this->createsBooking->execute($company, $object);
|
|
|
|
|
|
// === //
|
|
// 10 // ====== //
|
|
// make payment //
|
|
// ============== //
|
|
// There are few type of transactions related to a booking:
|
|
// TransactionType::PAYMENT : is used for 2 type of use cases (1. payments to transfer orders, 2. payment out of wallet) and is attached to a booking;
|
|
// TransactionType::BILL : is to represent the payment out to CIEF currency supplier (expenses) and is attached to a transaction of type TransactionType::PAYMENT;
|
|
// TransactionType::TRANSFER_FEE : is to represent the transfer fee charged by CIEF currency supplier is attached to a transaction type TransactionType::BILL;
|
|
// TransactionType::REFUND : is to represent a request for refund on a payment, and is attached to a transaction type TransactionType::PAYMENT;
|
|
|
|
$numberOfPayments = $this->faker->numberBetween(0, 3);
|
|
|
|
for ($paymentLoop=0; $paymentLoop <= $numberOfPayments; $paymentLoop++) {
|
|
echo 'payment created';
|
|
$shouldSubmit = $this->faker->numberBetween(0, 1);
|
|
$shouldApprove = $this->faker->numberBetween(0, 1);
|
|
if ($numberOfPayments > 1){
|
|
|
|
$amount = $booking->fix_amount / $numberOfPayments;
|
|
|
|
$conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $amount)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS['cash']);
|
|
|
|
$configurations = $this->fetchBookingQuotation->execute($booking->company, $conversionObject);
|
|
|
|
$billNumber = $this->generatesTransactionBillNumber->execute('PYMT-');
|
|
|
|
$object = new TransactionObject($billNumber, TransactionType::PAYMENT, 1, $booking->company->id,
|
|
$configurations->getConfigurations()->getBankId(), $configurations->getConversionObject()->getPaymentMethod(),
|
|
$configurations->getTotal(), $configurations->getForeignTotal(), 1,
|
|
$configurations->getConversionObject()->getCurrencyId(), $configurations->getConfigurations()->getRate(),
|
|
$configurations->getTax(), $configurations->getServiceCharge(), Carbon::now()->addMinutes(10), ApprovalStatus::PENDING_SUBMISSION, [], null);
|
|
|
|
/** @var Transaction $transaction */
|
|
$transaction = $this->createsTransaction->execute($booking, $object);
|
|
|
|
if($shouldSubmit || $shouldApprove) {
|
|
$object = new DocumentObject( DocumentType::CUSTOMER_PAYMENT_PROOF, ['data:image/png;base64,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'],
|
|
'', ApprovalStatus::PENDING_VERIFICATION, 'payments');
|
|
/** @var Document $document */
|
|
$document = $this->createsDocument->execute($transaction, $object);
|
|
$this->createsFiles->execute($document, $object);
|
|
$this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_SUBMISSION);
|
|
}
|
|
|
|
if($shouldApprove) {
|
|
$this->approvesDocument->execute($document);
|
|
$this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED);
|
|
|
|
$shouldReject = $this->faker->numberBetween(0, 1);
|
|
if($shouldReject){
|
|
$this->rejectsDocument->execute($document);
|
|
$this->updatesTransactionStatus->execute($transaction, ApprovalStatus::REJECTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// creating the purchase order can happen before or after the payment is made, the customer needs to fill up the list of product
|
|
// they are buying and attaching it to the booking, a purchase order is a transaction of type TransactionType::PURCHASE_ORDER
|
|
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
|
|
|
|
|
|
$shouldSubmit = $this->faker->numberBetween(0, 1);
|
|
$shouldApprove = $this->faker->numberBetween(0, 1);
|
|
|
|
if($shouldSubmit){
|
|
$completeSubmission = $this->faker->numberBetween(0, 1);
|
|
|
|
$quantity = $this->faker->numberBetween(5, 200);
|
|
$unitPrice = $booking->fix_amount / $quantity;
|
|
|
|
$products = collect([[
|
|
'stockCode' => $this->faker->numerify('#####'),
|
|
'description' => $this->faker->text,
|
|
'quantity' => $completeSubmission ? $quantity : $quantity - $this->faker->numberBetween(1, 4),
|
|
'unit_price' => (string) round($unitPrice, 5)
|
|
]]);
|
|
|
|
$total = $products->first()['quantity'] * (float) $products->first()['unit_price'];
|
|
|
|
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
|
|
1, PaymentMethodType::CASH,
|
|
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
|
|
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products->toArray());
|
|
|
|
$transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
|
|
}
|
|
|
|
if($transaction->status === ApprovalStatus::PENDING_VERIFICATION) {
|
|
$this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// when processing a customer order, we will place an order with one of our currency supplier which will generate a transaction type TransactionType::BILL
|
|
// and attach it to the customer payment TransactionType::PAYMENT, and it will update the TransactionType::PAYMENT status to ApprovalStatus::COMPLETED
|
|
$totalApprovedPayments = Transaction::where('type', TransactionType::PAYMENT)->where('status', 2)->count();
|
|
$totalWhiteForms = round($totalApprovedPayments / $this->faker->numberBetween(2, 5));
|
|
$perWhiteForm = $totalApprovedPayments / (round($totalWhiteForms / 2) ?: 1);
|
|
|
|
for($orderLoop=1; $orderLoop <= ($totalWhiteForms / 2); $orderLoop++) {
|
|
$supplier = Company::where('business_type', BusinessType::CURRENCY_VENDOR)->inRandomOrder()->first();
|
|
$rate = $this->faker->randomFloat(5, 1.3, 1.6);
|
|
$payments = Transaction::where('type', TransactionType::PAYMENT)->where('status', ApprovalStatus::APPROVED)->inRandomOrder()->limit($perWhiteForm)->get();
|
|
|
|
$this->createSupplierTransactionProcessor->execute($supplier, $rate, $payments->toArray());
|
|
|
|
$group = new Group();
|
|
$group->save();
|
|
|
|
$issuer = '';
|
|
$receiver = '';
|
|
$amount = 0;
|
|
$original_amount = 0;
|
|
$currency_id = 0;
|
|
$original_currency_id = '';
|
|
$currency_rate = '';
|
|
$tax = 0;
|
|
$service_charge = 0;
|
|
|
|
foreach ($this->createSupplierTransactionProcessor->getBills() as $key => $row) {
|
|
$group->transactions()->sync($row->id, false);
|
|
$issuer = $row->issuer;
|
|
$receiver = $row->receiver;
|
|
$amount += $row->amount;
|
|
$original_amount += $row->original_amount;
|
|
$currency_id = $row->currency_id;
|
|
$original_currency_id = $row->original_currency_id;
|
|
$currency_rate = $row->currency_rate;
|
|
$tax += $row->tax;
|
|
$service_charge += $row->service_charge;
|
|
}
|
|
|
|
$group->issuer = $issuer;
|
|
$group->receiver = $receiver;
|
|
$group->reference = $this->generatesTransactionBillNumber->execute('SPO-');
|
|
$group->amount = $amount;
|
|
$group->original_amount = $original_amount;
|
|
$group->currency_id = $currency_id;
|
|
$group->original_currency_id = $original_currency_id;
|
|
$group->currency_rate = $currency_rate;
|
|
$group->tax = $tax;
|
|
$group->service_charge = $service_charge;
|
|
|
|
$group->update();
|
|
|
|
$pdf = LaravelMpdf::loadView('pages.pdfs.currency_vendor_order', ['transactions' => $this->createSupplierTransactionProcessor->getBills(), 'transferFeeTransactions' => $this->createSupplierTransactionProcessor->getTransferTransactions(), 'supplier' => $supplier]);
|
|
|
|
$object = new DocumentObject(
|
|
DocumentType::CURRENCY_VENDOR_ORDER,
|
|
[chunk_split('data:application/pdf;base64,'.base64_encode($pdf->output()))],
|
|
'',
|
|
ApprovalStatus::COMPLETED,
|
|
'currency_vendor_order'
|
|
);
|
|
|
|
/** @var Document $document */
|
|
$document = $this->createsDocument->execute($group, $object);
|
|
$this->createsFiles->execute($document, $object);
|
|
|
|
|
|
foreach ($payments as $payment) {
|
|
$chinaBankSlipUploaded = $this->faker->numberBetween(0, 1);
|
|
|
|
if($chinaBankSlipUploaded){
|
|
$bill = $payment->transactions()->where('type', TransactionType::BILL)->first();
|
|
|
|
// when our currency supplier completes the transfer they will send us the bank slip as proof of payment, then the admin user
|
|
// will upload the bank slip document and attaching it to transaction type TransactionType::BILL
|
|
$object = new DocumentObject( DocumentType::CUSTOMER_PAYMENT_PROOF, ['data:image/png;base64,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'],
|
|
'', ApprovalStatus::APPROVED, 'china_bank_slip');
|
|
/** @var Document $document */
|
|
$document = $this->createsDocument->execute($bill, $object);
|
|
$this->createsFiles->execute($document, $object);
|
|
|
|
$this->updatesTransactionStatus->execute($bill, ApprovalStatus::APPROVED);
|
|
|
|
// the invoicing documents will be generated once they 2 conditions are met:
|
|
// 1. Full payment completed (completed is flagged when the china payment proof is uploaded)
|
|
// 2. The purchase order is filled and approved (when the purchase order is not filled for more than 2 months the system will automatically generate a random products for Purchase order to close the order)
|
|
|
|
// once the invoice is generated the transaction table will include 2 new transaction type TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVERY
|
|
// and for documents will be generated and attached to the booking.
|
|
// once this process is complete the booking status will update to ApprovalStatus::COMPLETED
|
|
$this->createInvoiceTransactionProcessor->execute($booking);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|