Merge branch 'activity-route-log' of https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0 into development

This commit is contained in:
edmondlang
2023-01-04 22:17:39 +08:00
57 changed files with 1703 additions and 155 deletions
@@ -16,6 +16,7 @@ use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
abstract class AbstractControllerLogic
{
@@ -66,6 +67,7 @@ abstract class AbstractControllerLogic
return $response;
} catch (ErrorException|GeneralExceptions $exception){
log::error($exception);
return (new ApiResponseObject($this->getNotificationTitle().' failed', $exception->getMessage(),
$exception->getCode() ? $exception->getCode() : HttpStatus::SERVER_ERROR))->handler();
@@ -99,4 +101,4 @@ abstract class AbstractControllerLogic
return $this->response(json_decode($collection->response()->getContent(), true));
}
}
}
@@ -6,6 +6,7 @@ namespace App\Classes\General\Eloquent;
use App\Classes\Exceptions\MalformedRequestException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
abstract class AbstractListRecord extends AbstractGetRecord
{
@@ -23,6 +24,7 @@ abstract class AbstractListRecord extends AbstractGetRecord
return $this->handler($filters);
} catch (QueryException $exception){
log::error($exception);
throw new MalformedRequestException('Unable to fetch the list of records due to unexpected error');
}
@@ -43,4 +45,4 @@ abstract class AbstractListRecord extends AbstractGetRecord
}
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class CompanyIdNotIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereNotIn('company_id', $value);
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class DoesNotHavePurchaseOrderStatusIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereDoesntHave('transactions', function($transaction) use($value) {
return $transaction->where('transactions.type', TransactionType::PURCHASE_ORDER)->whereIn('transactions.status', $value);
});
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class DoesNotHaveTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereDoesntHave('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class HasPaymentStatusIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', $value);
});
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class HasPurchaseOrderStatusIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', TransactionType::PURCHASE_ORDER)->whereIn('transactions.status', $value);
});
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class HasTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->has('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class WithWallets implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->with('wallets');
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace App\Classes\General\Traits;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
trait LogData
{
public static function boot()
{
parent::boot();
static::updating(function($model)
{
$tableName = Str::singular($model->table).'_logs';
$relationshipColumn = Str::singular($model->table).'_id';
$originalData = $model->getRawOriginal();
$originalData[$relationshipColumn] = $originalData['id'];
unset($originalData['id']);
if (!Schema::hasTable($tableName)) {
DB::statement('CREATE TABLE '.$tableName.' LIKE '.$model->table);
$indexs = DB::select('SHOW INDEX FROM '.$tableName.';');
$removedIndexes = [];
foreach ($indexs as $index){
if($index->Column_name === 'id' || in_array($index->Key_name, $removedIndexes)) continue;
DB::statement('ALTER TABLE '.$tableName.' drop index '.$index->Key_name);
$removedIndexes[] = $index->Key_name;
}
DB::statement('ALTER TABLE '.$tableName.' ADD COLUMN `'.$relationshipColumn.'` BIGINT NOT NULL AFTER `id`');
}
DB::table($tableName)->insert($originalData);
});
}
}
@@ -64,8 +64,8 @@ class AutoPurchaseOrderFillLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$bookings = Booking::where(function($query){
return $query->whereMonth('created_at', 05)->whereYear('created_at', 2022);
$bookings = Booking::where('service_id', '!=', 4)->where(function($query){
return $query->whereMonth('created_at', 07)->whereYear('created_at', 2022);
})->whereDoesntHave('transactions', function($q){
$q->where('type', TransactionType::PURCHASE_ORDER);
$q->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED]);
@@ -111,4 +111,4 @@ class AutoPurchaseOrderFillLogic extends AbstractControllerLogic
return $this->response([]);
}
}
}
@@ -129,7 +129,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
/** @var Wallet $wallet */
$wallet = $booking->company->wallets()->first();
if(round($wallet->amount) < round($amount, 2)){
if((float) number_format(($wallet->amount - $amount),2) < 0){
throw new MalformedRequestException('Insufficient wallet balance. Please Top up your wallet.');
}
@@ -161,4 +161,4 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
}
}
}
@@ -10,6 +10,7 @@ use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Documents\Services\DeletesDocument;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Http\Resources\BookingResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -57,7 +58,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
*/
public function __construct(
CanFetchBooking $canFetchBooking,
CanFetchBooking $canFetchBooking,
FetchesBooking $fetchesBooking,
DeletesTransaction $deletesTransaction,
UpdatesBookingStatus $updatesBookingStatus,
@@ -86,7 +87,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
$this->canFetchBooking->passes();
$booking = $this->fetchesBooking->execute([
'id' => $request->route('id'),
'id' => $request->route('id'),
'status' => ApprovalStatus::COMPLETED,
'with_transactions' => true]
);
@@ -98,7 +99,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
$this->deletesTransaction->execute($row);
}
$document = $booking->documents()->get();
$document = $booking->documents()->whereIn('document_type', [DocumentType::PURCHASE_ORDER, DocumentType::INVOICE, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->get();
foreach ($document as $key => $row) {
$this->deletesDocument->execute($row);
}
@@ -108,4 +109,4 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
return $this->resourceResponse(new BookingResource($booking));
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Processors\CreatePurchaseOrderFor1688OrderProcessor;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Documents\Services\ApprovesDocument;
@@ -11,11 +12,15 @@ use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\FetchesDocument;
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\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Document;
use Illuminate\Http\JsonResponse;
@@ -43,18 +48,23 @@ class UploadPurchaseOrderLogic extends AbstractControllerLogic
/** @var CreatesFiles */
private $createsFile;
/** @var CreatePurchaseOrderFor1688OrderProcessor */
private $createPurchaseOrderFor1688OrderProcessor;
/**
* UploadPurchaseOrderLogic constructor.
* @param FetchesBooking $fetchesBooking
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param CreatePurchaseOrderFor1688OrderProcessor $createPurchaseOrderFor1688OrderProcessor
*/
public function __construct(FetchesBooking $fetchesBooking, CreatesDocument $createsDocument, CreatesFiles $createsFile)
public function __construct(FetchesBooking $fetchesBooking, CreatesDocument $createsDocument, CreatesFiles $createsFile, CreatePurchaseOrderFor1688OrderProcessor $createPurchaseOrderFor1688OrderProcessor)
{
$this->fetchesBooking = $fetchesBooking;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
$this->createPurchaseOrderFor1688OrderProcessor = $createPurchaseOrderFor1688OrderProcessor;
}
/**
@@ -74,7 +84,11 @@ class UploadPurchaseOrderLogic extends AbstractControllerLogic
$this->createsFile->execute($document, $object);
if(in_array($booking->company->id, [199, 510])){
$this->createPurchaseOrderFor1688OrderProcessor->execute($booking);
}
return $this->response([]);
}
}
}
@@ -0,0 +1,96 @@
<?php
namespace App\Classes\Modules\Bookings\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Bookings\Services\Convert1688PurchaseOrderToProductList;
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\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
class CreatePurchaseOrderFor1688OrderProcessor
{
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatePurchaseOrderTransactionProcessor */
private $createPurchaseOrderTransactionProcessor;
/** @var Convert1688PurchaseOrderToProductList */
private $convert1688PurchaseOrderToProductList;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreateInvoiceTransactionProcessor */
private $createInvoiceTransactionProcessor;
/**
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
* @param Convert1688PurchaseOrderToProductList $convert1688PurchaseOrderToProductList
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
*/
public function __construct(GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, Convert1688PurchaseOrderToProductList $convert1688PurchaseOrderToProductList, UpdatesTransactionStatus $updatesTransactionStatus, CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor)
{
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
$this->convert1688PurchaseOrderToProductList = $convert1688PurchaseOrderToProductList;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
}
public function execute(Booking $booking)
{
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
$documents = $booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get();
$products = [];
foreach ($documents as $document) {
foreach ($document->files as $file) {
try {
$products = $this->convert1688PurchaseOrderToProductList->execute($file);
} catch (MalformedRequestException $exception) {
continue;
}
}
}
if (empty($products)){
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
1, PaymentMethodType::CASH,
0, 0, $booking->fix_currency_id, $booking->fix_currency_id,
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, []);
$this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
return false;
}
$total = collect($products)->sum(function($product){
return $product['quantity'] * floatval(str_replace(',', '', $product['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);
$purchaseOrder = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
if($purchaseOrder->amount === $booking->fix_amount){
$this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED);
$this->createInvoiceTransactionProcessor->execute($booking);
}
}
}
@@ -0,0 +1,91 @@
<?php
namespace App\Classes\Modules\Bookings\Services;
use App\Classes\Exceptions\MalformedRequestException;
use App\Models\File;
use Exception;
use Illuminate\Support\Facades\Storage;
class Convert1688PurchaseOrderToProductList
{
/**
* @param File $file
* @return array
* @throws MalformedRequestException
*/
public function execute(File $file): array
{
$parser = new \Smalot\PdfParser\Parser();
$productList = [];
$shipping = 0;
$discount = 0;
try {
$pdf = $parser->parseFile(Storage::disk('documents')->path($file->file->file_info->original->file));
} catch (Exception $exception) {
throw new MalformedRequestException('Invalid file format.');
}
$text = $pdf->getText();
if(str_contains($text, '订单详情单')) throw new MalformedRequestException('Can\'t process non english documents');
$tables = explode('Amount (yuan)', $text);
$footer = end($tables);
$footer = preg_split('(Shipping|运费)', $footer);
if(array_key_exists(1, $footer)){
$footer = preg_split('/[\t\n]/', $footer[1]);
$shipping = (float) filter_var( $footer[0], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
$discount = array_filter($footer, function($var) { return preg_match("/(Discount|优惠)/", $var); });
$discount = (float) filter_var(reset($discount), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
}
array_shift($tables);
foreach ($tables as $table){
$products = preg_split('/(yuan\/|yuan \/|元\/|元 \/)/', str_replace("\r\n","",$table));
array_pop($products);
foreach ($products as $product){
$product = preg_split('/[\t]/',$product);
$adjuster = (count($product) - 7);
$descriptionIndex = 3 + $adjuster;
$quantity = (int) str_replace("\n","",$product[$descriptionIndex + 2]);
$unitPrice = (float) str_replace("\n","",$product[$descriptionIndex + 3]);
$productList[] = [
'stockCode' => '',
'description' => str_replace("\n","",$product[$descriptionIndex]),
'quantity' => $quantity,
'unit_price' => $unitPrice,
'total' => (float) str_replace("\n","",$product[$descriptionIndex + 3])
];
}
}
if($shipping > 0) {
$productList[] = [
'stockCode' => '',
'description' => 'Shipping Fee',
'quantity' => 1,
'unit_price' => $shipping,
'total' => $shipping
];
}
if($discount > 0) {
$productList[] = [
'stockCode' => '',
'description' => 'Discount',
'quantity' => 1,
'unit_price' => $discount * -1,
'total' => $discount * -1
];
}
return $productList;
}
}
@@ -52,10 +52,10 @@ class FetchCompanyLogic extends AbstractControllerLogic
{
$this->canFetchCompany->passes();
$query = $this->fetchesCompany->execute(['id' => $request->route('id'), 'with_bookings' => true]);
$query = $this->fetchesCompany->execute(['id' => $request->route('id'), 'with_bookings' => true, 'with_wallets' => true]);
return $this->resourceResponse(new CompanyResource($query));
}
}
}
@@ -0,0 +1,71 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Illuminate\Http\Request;
use App\Classes\Modules\Companies\Services\ListsCompanies;
class ExportsLeadsTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
private $request;
public function __construct(Request $request, ListsCompanies $listsCompanies)
{
$this->request = $request;
$this->listsCompanies = $listsCompanies;
}
public function headings(): array
{
return [
'Agent Name',
'User Name',
'Contact Number',
'Email',
'Customer Code',
'Register Date'
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
$query = $this->listsCompanies->execute(
[
'business_type' => 2,
'with_bookings' => true,
'without_confirmed_payments' => true,
'does_not_have_segments' => [5],
]
);
return $query->toQuery();
}
/**
* @param $row
* @return array
*/
public function map($row): array
{
return [
'',
$row->name,
strval($row->contacts->first()->phone),
// $row->contacts->first()->email,
$row->employees()->first() == null ? '' : $row->employees()->first()->email,
$row->reference,
$row->created_at->format('d-m-Y')
];
}
}
@@ -80,9 +80,9 @@ class ExportsTransactions implements FromQuery, WithHeadingRow, WithMapping, Sho
$transactionTypes[$transaction->type],
$transaction->issuerCompany->name,
$transaction->reciver,
$transaction->currency_id === 1 ? 'MYR' : 'RMB',
$transaction->currency->short_code,
$transaction->amount,
$transaction->original_currency_id === 1 ? 'MYR' : 'RMB',
$transaction->original_currency->short_code,
$transaction->original_amount,
$transaction->currency_rate,
$transaction->tax,
@@ -90,7 +90,7 @@ class ExportsTransactions implements FromQuery, WithHeadingRow, WithMapping, Sho
$transactionStatus[$transaction->status],
\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel($transaction->created_at),
\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel($transaction->updated_at),
$marking
// $marking
];
}
}
}
@@ -6,7 +6,10 @@ use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Document;
use Meneses\LaravelMpdf\Facades\LaravelMpdf;
use Webklex\PDFMerger\Facades\PDFMergerFacade as PDFMerger;
class CreateInvoiceDocumentProcessor
{
@@ -40,6 +43,24 @@ class CreateInvoiceDocumentProcessor
$lowercaseDocumentType = strtolower($document_type);
$order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier]);
if($purchaseOrder->booking->service_id === 4) {
$purchaseOrderDocuments = $purchaseOrder->booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get();
$oMerger = PDFMerger::init();
$order_pdf->save(storage_path('app/documents/temp.pdf'));
$oMerger->addPDF(storage_path('app/documents/temp.pdf'), 'all');
foreach ($purchaseOrderDocuments as $document){
$oMerger->addPDF(storage_path('app/documents/'.$document->files()->first()->file->file_info->original->file), 'all');
}
$oMerger->merge();
$order_pdf = $oMerger;
}
$document_object = new DocumentObject(
$document_type,
[chunk_split('data:application/pdf;base64,' . base64_encode($order_pdf->output()))],
@@ -48,7 +69,9 @@ class CreateInvoiceDocumentProcessor
$lowercaseDocumentType . 's'
);
/** @var Document $document */
$document = $this->createsDocument->execute($purchaseOrder->booking, $document_object);
$this->createsFile->execute($document, $document_object);
}
}
@@ -100,7 +100,7 @@ class CreateProformaInvoiceTransactionProcessor
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Booking $booking)
public function execute(Booking $booking)
{
$po_order_transaction = $booking->transactions()
@@ -129,14 +129,26 @@ class CreateProformaInvoiceTransactionProcessor
$billNumber = $this->generatesTransactionBillNumber->execute('PROFORMA-');
$payable_amount = $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->sum('amount');
$payable_amount = $booking->transactions()->payments()->where(function($query){
return $query->where(function($query){
return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString());
})->orWhere(function($query){
return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
});
})->sum('amount');
$booking_amount = $booking->fix_amount;
$transaction = $booking->transactions()
->where('type', TransactionType::PAYMENT)
->first();
$booking_currency_average_rate = $booking_amount / $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
$booking_currency_average_rate = $booking_amount / $booking->transactions()->payments()->where(function($query){
return $query->where(function($query){
return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString());
})->orWhere(function($query){
return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
});
})->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
$total_service_charge = $booking->transactions()
->where('type', TransactionType::PAYMENT)
@@ -86,4 +86,4 @@ class GeneratesGroupTransactionsPurchaseOrder
}
}
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class RouteType {
public const WEB = 1;
public const API = 2;
}
@@ -6,6 +6,7 @@ namespace App\Http\Controllers\Exports;
use App\Classes\Modules\Exports\Services\ExportsCustomers;
use App\Classes\Modules\Exports\Services\ExportsTransactions;
use App\Classes\Modules\Exports\Services\ExportsBookingTransactions;
use App\Classes\Modules\Exports\Services\ExportsLeadsTransactions;
use App\Classes\Modules\Exports\Services\ExportsNullDebtors;
use App\Classes\Modules\Exports\Services\ExportsPaymentTransactions;
@@ -61,4 +62,10 @@ class ExportCustomersToExcelController
ob_end_clean();
return $response;
}
public function leadsData(ExportsLeadsTransactions $exportsLeadsTransactions, Request $request){
$response = $exportsLeadsTransactions->download('leadsData.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
}
}
@@ -27,4 +27,4 @@ class ImportUpdateDebtorController
Excel::import(new ImportsDebtor(), json_decode($object->getFiles()[0])->file_info->original->file);
return [];
}
}
}
+2
View File
@@ -45,11 +45,13 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\WebRouteLogs::class,
],
'api' => [
'throttle:300,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\ApiRouteLogs::class,
],
];
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Models\RouteLog;
use App\Classes\ValueObjects\Constants\RouteType;
use Illuminate\Support\Facades\Auth;
class ApiRouteLogs
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$ip_address = getenv('REMOTE_ADDR') == '::1' ? '127.0.0.1' : getenv('REMOTE_ADDR');
$url = urldecode($request->fullUrl());
$request_method = $request->method();
$platform = $request->header('sec-ch-ua-platform');
$browser = Str::after($request->header('sec-ch-ua'), 'Not?A_Brand";v="8", "Chromium";v="108", "');
$geo = unserialize(file_get_contents("http://www.geoplugin.net/php.gp?ip=$ip_address"));
$longitude = $geo["geoplugin_longitude"];
$latitude = $geo["geoplugin_latitude"];
$last_page = url()->previous();
$countryName = $geo["geoplugin_countryName"];
$user_id = Auth::user() ? Auth::user()->id : 0;
// if ($user_id != 0) {
// // $ip_address
// $webRouteLogWithSameIp = RouteLog::where('ip_address', $ip_address)->where('user_id', 0)->get();
// dd($webRouteLogWithSameIp);
// foreach($webRouteLogWithSameIp as $result){
// $result
// }
// }
$route_log = [
'user_id' => $user_id,
// 'ip_address' => $request->ip(),
'ip_address' => $ip_address,
'url' => $url,
'request_method' => $request_method,
'browser' => $browser,
'platform' => $platform,
'longitude' => $longitude,
'latitude' => $latitude,
'last_page' => $last_page,
'countryname' => $countryName,
'route_type' => RouteType::API,
];
RouteLog::create($route_log);
return $next($request);
}
}
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Models\RouteLog;
use App\Classes\ValueObjects\Constants\RouteType;
use Illuminate\Support\Facades\Auth;
class WebRouteLogs
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$ip_address = getenv('REMOTE_ADDR') == '::1' ? '127.0.0.1' : getenv('REMOTE_ADDR');
$url = $request->fullUrl();
$request_method = $request->method();
$platform = $request->header('sec-ch-ua-platform');
$browser = Str::after($request->header('sec-ch-ua'), 'Not?A_Brand";v="8", "Chromium";v="108", "');
$geo = unserialize(file_get_contents("http://www.geoplugin.net/php.gp?ip=$ip_address"));
$longitude = $geo["geoplugin_longitude"];
$latitude = $geo["geoplugin_latitude"];
$last_page = url()->previous();
$countryName = $geo["geoplugin_countryName"];
$route_log = [
'user_id' => Auth::user() ? Auth::user()->id : 0,
// 'ip_address' => $request->ip(),
'ip_address' => $ip_address,
'url' => $url,
'request_method' => $request_method,
'browser' => $browser,
'platform' => $platform,
'longitude' => $longitude,
'latitude' => $latitude,
'last_page' => $last_page,
'countryname' => $countryName,
'route_type' => RouteType::WEB,
];
// dd($route_log);
RouteLog::create($route_log);
return $next($request);
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ class BookingResource extends JsonResource
->whereDate('expires_on', '>=', Carbon::now())
->get()
),
'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '<', Carbon::now())->get()),
'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()),
'payment_history' => TransactionResource::collection($this->transactions()->where(function($query){
$query->where(function($query){
$query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]);
+1 -1
View File
@@ -61,7 +61,7 @@ class CompanyResource extends JsonResource
],
'segments' => SegmentResource::collection($this->segments),
'services' => (new FetchesCompanyServices())->getServices($this->servicesConfigurations()),
'wallet' => new WalletResource($this->wallets()->first()),
'wallet' => $this->whenLoaded('wallets', new WalletResource($this->wallets()->with('transactions')->first()), new WalletResource($this->wallets()->first())),
'created_at' => $this->created_at->format('d-m-Y'),
$this->mergeWhen($this->business_type === BusinessType::CURRENCY_VENDOR, [
'currencies' => $segment ? CurrencyResource::collection(Currency::whereIn('id', $segment->detail->currencies)->get()) : [],
+3
View File
@@ -22,6 +22,9 @@ class GroupResource extends JsonResource
public function toArray($request)
{
if(!$this->issuerCompany){
dd($this->id);
}
return [
'id' => $this->id,
'original_amount' => (float) $this->original_amount,
+2 -2
View File
@@ -21,8 +21,8 @@ class WalletResource extends JsonResource
'currency_id' => $this->currency_id,
'amount' => (double) $this->amount,
'company_id' => (int) $this->owner->id,
'transactions' => WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()),
'top_up_records' => WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get())
'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []),
'top_up_records' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get()), []),
];
}
}
+2
View File
@@ -4,6 +4,7 @@ namespace App\Models;
use App\Classes\General\Interfaces\Documentable;
use App\Classes\General\Interfaces\Transactionable;
use App\Classes\General\Traits\LogData;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Scopes\CustomerBookingsScope;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -28,6 +29,7 @@ class Booking extends AbstractModel implements Documentable, Transactionable
{
use HasRelationships;
use SoftDeletes;
use LogData;
protected $table = 'bookings';
+1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Classes\General\Traits\LogData;
use Illuminate\Database\Eloquent\Model;
use App\Classes\General\Interfaces\Documentable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class RouteLog extends Model
{
protected $fillable = [
'user_id',
'ip_address',
'url',
'request_method',
'browser',
'platform',
'longitude',
'latitude',
'last_page',
'countryname',
'route_type'
];
}
+2
View File
@@ -4,6 +4,7 @@ namespace App\Models;
use App\Classes\General\Interfaces\Documentable;
use App\Classes\General\Interfaces\Transactionable;
use App\Classes\General\Traits\LogData;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
@@ -22,6 +23,7 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
{
use HasTableAlias;
use SoftDeletes;
use LogData;
protected $table = 'transactions';
+2
View File
@@ -3,6 +3,7 @@
namespace App\Models;
use App\Classes\General\Interfaces\Transactionable;
use App\Classes\General\Traits\LogData;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -12,6 +13,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
class Wallet extends AbstractModel implements Transactionable
{
use SoftDeletes;
use LogData;
protected $table = 'wallets';
/**
+8 -6
View File
@@ -17,25 +17,27 @@
"doctrine/dbal": "^2.12.1",
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^1.0",
"guzzlehttp/guzzle": "^6.3",
"guzzlehttp/guzzle": "^7.0.1",
"intervention/image": "^2.5",
"laravel/framework": "^7.0",
"laravel/framework": "^8.0",
"laravel/tinker": "^2.0",
"maatwebsite/excel": "^3.1",
"rinvex/countries": "^6.1",
"smalot/pdfparser": "^2.2",
"spatie/laravel-activitylog": "^3.14",
"spatie/laravel-permission": "^3.17",
"staudenmeir/eloquent-has-many-deep": "^1.7",
"timehunter/laravel-google-recaptcha-v3": "~2.5",
"tymon/jwt-auth": "^1.0"
"tymon/jwt-auth": "^1.0",
"webklex/laravel-pdfmerger": "^1.3"
},
"require-dev": {
"facade/ignition": "^2.0",
"facade/ignition": "^2.3.6",
"fzaninotto/faker": "^1.9.1",
"laravel/dusk": "^6.23",
"mockery/mockery": "^1.3.1",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
"nunomaduro/collision": "^5.0",
"phpunit/phpunit": "^9.0"
},
"config": {
"optimize-autoloader": true,
+4 -2
View File
@@ -179,7 +179,8 @@ return [
Spatie\Permission\PermissionServiceProvider::class,
Barryvdh\DomPDF\ServiceProvider::class,
Meneses\LaravelMpdf\LaravelMpdfServiceProvider::class,
TimeHunter\LaravelGoogleReCaptchaV3\Providers\GoogleReCaptchaV3ServiceProvider::class
TimeHunter\LaravelGoogleReCaptchaV3\Providers\GoogleReCaptchaV3ServiceProvider::class,
Webklex\PDFMerger\Providers\PDFMergerServiceProvider::class
],
@@ -234,7 +235,8 @@ return [
'View' => Illuminate\Support\Facades\View::class,
'PDF' => Barryvdh\DomPDF\Facade::class,
'MPDF' => Meneses\LaravelMpdf\Facades\LaravelMpdf::class,
'GoogleReCaptchaV3'=> TimeHunter\LaravelGoogleReCaptchaV3\Facades\GoogleReCaptchaV3::class
'GoogleReCaptchaV3'=> TimeHunter\LaravelGoogleReCaptchaV3\Facades\GoogleReCaptchaV3::class,
'PDFMerger' => Webklex\PDFMerger\Facades\PDFMergerFacade::class
],
@@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRouteLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('route_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->unsigned();
$table->string('ip_address');
$table->string('url', 255);
$table->string('request_method');
$table->string('browser')->nullable();
$table->string('platform')->nullable();
$table->string('longitude')->nullable();
$table->string('latitude')->nullable();
$table->string('last_page')->nullable();
$table->string('countryname')->nullable();
$table->integer('route_type');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('route_logs');
}
}
+508
View File
@@ -0,0 +1,508 @@
<?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\Bookings\DataTransferObjects\BookingObject;
use App\Classes\Modules\Bookings\Services\CreatesBooking;
use App\Classes\Modules\Bookings\Services\GeneratesBookingMarking;
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\Transactions\DataTransferObjects\TransactionObject;
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\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
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\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\BankAccountType;
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\PaymentMethodType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\TransportType;
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\ServiceType;
use App\Models\Transaction;
use App\Models\Transport;
use App\Models\User;
use App\Models\Wallet;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Faker\Generator as Faker;
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;
/**
* @param Faker $faker
* @param CreatesUser $createsUser
* @param CreatesCompany $createsCompany
* @param CreatesContact $createsContact
* @param CreatesAddress $createsAddress
* @param AssignEmployeeProcessor $assignEmployeeProcessor
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(Faker $faker, CreatesUser $createsUser, CreatesCompany $createsCompany, CreatesContact $createsContact, CreatesAddress $createsAddress, AssignEmployeeProcessor $assignEmployeeProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->faker = $faker;
$this->createsUser = $createsUser;
$this->createsCompany = $createsCompany;
$this->createsContact = $createsContact;
$this->createsAddress = $createsAddress;
$this->assignEmployeeProcessor = $assignEmployeeProcessor;
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* 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);
// =============================================== //
// 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 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 <= 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 //
// ================= //
// 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);
// === //
// 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, $this->faker->phoneNumber, $customerEmail, null, $this->faker->bothify('??#####'));
$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, 442), $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,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAIAAAB7GkOtAAANGklEQVR4nOzXDa/fdX3G8R44Ww54BIFV2wFyoxUoKmsFhA0zEGQj1jOMo5o5IQPmYE5wrSvjdhbHAGWt0BWEwmChuHEjSF2LrY6tlmFjJbblprQstD21UFzbrBhX1tKyR3ElJtfr9QCu78k/v5N3PoOzbv/SmKR/mv94dP+FN9dH95+7+J7o/sjse6P7y3d/Orq/6qKTovtLN94f3Z9w39nR/XeFv/+nrlse3V/xhbXR/Xuv/kx0f3TDjuj+oltviO7PHJf9/veJrgPwK0sAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQafOeyu6MPPP9by6L7f7n/yuj+rWN/Et3/xiu/Gd3/xQduju7ve+KE6P7wc6dG9yde/lx0f86J2e/nO38yLrq/ftXT0f0/m7wzuj9jw4vR/V2n74jub7v8zOi+CwCglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKDWw40dD0Qc2PP+O6P6cJauj+zP+dVl0//izT47uv+eazdH9bf+3I7r/xhFXR/dnzjwmun/lJ56N7n/vA/Oi+5NmnxDdf3jqtuj+8j0PRPfnzPtUdP/Jt++K7rsAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSgwsfXhl94KuHrIjuHzvmxuj+g6+9EN1//Pz/jO5P/2x2f/dTL0X3f+e9S6L7f3zJHdH9jafOjO6/7/LDo/s3bL4+un/rnNOi+yMXDUX3Bw6YFt2/+IyTovsuAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACg1OCEe34UfWDn+SPR/bcWrY3u//DMbdH94w4diu4/sPTo6P7tNx0Z3V92wrzo/k8/uzu6f8DwndH9v5i1ILq/+UO3Rfd3Lz4nuv+VRx6K7s9Y+nJ0f+HKsdF9FwBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUGrw9+84JfrAof89P7r/wf8aG90/d8//RvdvXf/30f3JI8ui+8ceeUd0/+DPr4nuf3jX56L7p168Krr/rcfOiu6PHvhqdH/xLauj+8+Mbozur/vpj6P7E8edH913AQCUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQYXb9kafeDSf/lWdP/fdx4c3X9k60vR/b13Xxjdnzb1Z9H90ctWRfffmvRGdP+8e96M7m+avT26/45vnh3d/9rNY6P7Tz/5w+j+e6bMj+4f8rHro/vHH579/l0AAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAECpwb037R994NK5a6P7/7zgvuj+JTNPiO7/7fKjo/t7H7wmuj/8+pnR/f2nbojuH33tndH9333536L7E25+Kro//NuTo/vLT1oe3f+jNZdG9y+ffHB0f972e6L7LgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoNTgYcd8LvrA9IGd0f3jh6+K7l8/d010f5/hrdH98euGovuf+OvbovsHnPpSdP/p6X8e3d8ztD26v+bJydH9GQfcG91/+MWPRve/vPSX0f2P/OmC6P7AdYdF910AAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAECpgXMG3x59YPXKWdH9xc9+P7q/3/SjovvLjjs3uv83E4+N7p904Lej+9MXfCq6//ULvxvdf2D2KdH9afOuiu5PnPm26P7QM1Oy+yPZ7/PItdui+1v+Y1103wUAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQaeOKXH48+sGnNtOj+mGkrovNvm3tddH/MoWOj8y/cckx0/6D5743u/+ydI9H9O/d+JLr/yuwLovtbHhqI7r//wuz3+Z2PfTC6/5VXVkX3/+G+c6L7Xz9vRnTfBQBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBp4/ZC7og/84cLx0f1fX7gyuj/xy6PR/eueuDG6P/6rS6L7t//g8ej+Xa9Niu6/9sSM6P4bmx6L7t+14+Do/se/NBzd3/7Rq6L7a976dHR/xruy/1+jO/aN7rsAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSg48/PyX6wBenDkX3Z607Lbo/d9f7o/tblmd//5u+Oyu6f/rP50X3B1/dEN2/5O6V0f0rLr0tur/omp9E918deT26/+Dpe6P7N179d9H9TdeORvd33XdOdN8FAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUGpgzcW/0gQ9PPyK6P/jtB6P7nzxrU3T/i/dvjO6vPuWQ6P6Z7/616P76T94Q3X/37qHo/rzfmx/dv2V8dv/+/S6L7j/6B0uj+wftuyS6v+KK7O+/++Xs3+8CACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKDTx24TeiDzz68MnR/UU7D4/uH/ah7P6PH5oT3T/viCuj+18b2RTd//7J+0f3L7nipuj+lAueie6PmXpUdH7mpDOi+y/ueiS6f9kP/iq6/+yEn0f3p1x0UXTfBQBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBo86urN0Qemjk6N7n9v+Nzo/uHXfj66P3fF1uj+Pvv9T3T/wBOj82MeOuvR6P64cVdE9/9x4KDo/m+cdmV0f8HSPdH9910wKbo//gv3Rve/+YszovufufO46L4LAKCUAACUEgCAUgIAUEoAAEoJAEApAQAoJQAApQQAoJQAAJQSAIBSAgBQSgAASgkAQCkBACglAAClBACglAAAlBIAgFICAFBKAABKCQBAKQEAKCUAAKUEAKCUAACUEgCAUgIAUEoAAEoJAEApAQAo9f8BAAD//3aYjHM9JD/iAAAAAElFTkSuQmCC'],
$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::CREDIT_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->bank, $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, 30); $orderLoop++) {
// === //
// 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::where('reference', $this->faker->numberBetween(1, 3))->first();
// Booking human readable id
$reference = $this->generatesBookingMarking->execute();
// random currency booking (CNY, USD)
$bookedCurrency = $this->faker->numberBetween(2, 3);
$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;
// todo make payment
// todo approve payment
// todo create supplier order
// 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
// todo upload china payment proof
// 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
// todo create purchase order
// 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
// todo approve purchase order
// todo generate invoice
// 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
}
}
}
}
@@ -14,56 +14,108 @@
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-10" v-if="type === 2">
<div class="row" v-if="currency !== 'USD'">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.reference">
<label>Reference</label>
<input type="text" class="form-control" v-model="parameters.reference" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.holder_name">
<label>Account Holder Name</label>
<input type="text" class="form-control" v-model="parameters.holder_name" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.account_no">
<label>{{ serviceType ? serviceType.id === 4 ? 'Alipay recipient Email / Phone' : 'Account No.' : 'Account No.'}}</label>
<input type="text" class="form-control" v-model="parameters.account_no" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row" v-if="type === 2">
<div class="col">
<div class="row m-b-10">
<div class="row m-b-10" v-if="type === 2">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_name">
<label>Bank Name</label>
<input type="text" class="form-control" v-model="parameters.bank_name" :disabled="disabled">
<validation-wrapper-component :validator="$v.parameters.reference">
<label>Reference</label>
<input type="text" class="form-control" v-model="parameters.reference" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_branch">
<label>Bank Branch / 所在地</label>
<input type="text" class="form-control" v-model="parameters.bank_branch" :disabled="disabled">
<validation-wrapper-component :validator="$v.parameters.holder_name">
<label>Account Holder Name</label>
<input type="text" class="form-control" v-model="parameters.holder_name" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10 hide">
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.account_no">
<label>{{ serviceType ? serviceType.id === 4 ? 'Alipay recipient Email / Phone' : 'Account No.' : 'Account No.'}}</label>
<input type="text" class="form-control" v-model="parameters.account_no" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row" v-if="type === 2">
<div class="col">
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_name">
<label>Bank Name</label>
<input type="text" class="form-control" v-model="parameters.bank_name" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_branch">
<label>Bank Branch / 所在地</label>
<input type="text" class="form-control" v-model="parameters.bank_branch" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-if="currency === 'USD'">
<div class="col">
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.holder_name">
<label>Account Holder Name</label>
<input type="text" class="form-control" v-model="parameters.holder_name" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.reference">
<label>Account Holder Address</label>
<input type="text" class="form-control" v-model="parameters.reference" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.account_no">
<label>Account No</label>
<input type="text" class="form-control" v-model="parameters.account_no" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row" v-if="type === 2">
<div class="col">
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_name">
<label>Bank Name</label>
<input type="text" class="form-control" v-model="parameters.bank_name" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.bank_branch">
<label>Bank Address</label>
<input type="text" class="form-control" v-model="parameters.bank_branch" :disabled="disabled">
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row m-b-10" >
<div class="col p-r-5">
<validation-wrapper-component :validator="$v.parameters.swift">
<label>Swift</label>
<input type="text" class="form-control" v-model="parameters.swift" :disabled="disabled">
</validation-wrapper-component>
</div>
<div class="col p-l-5">
<div class="col p-l-5 hide">
<validation-wrapper-component :validator="$v.parameters.snap">
<label>Snap</label>
<input type="text" class="form-control" v-model="parameters.snap" :disabled="disabled">
@@ -122,6 +174,11 @@
type: Object,
required: false,
default: null
},
currency: {
type: String,
required: false,
default: 'RMB'
}
},
data(){
@@ -181,4 +238,4 @@
mixins: [FormHandler]
}
</script>
</script>
@@ -148,7 +148,7 @@
</div>
<div class="row" v-show="createBank">
<div class="col">
<bank-account-form-component v-if="data.serviceType.id !== 4" section="customerProfileSection" :disabled="formDisabled" :data="Object.keys(parameters.bankAccount).length ? parameters.bankAccount : {account_no: account_no, company_id: data.company.id, country_id: 2, account_type: 2}" :company_id="data.company.id" :country_id="2" :type="2" v-on:createdBank="updateBank($event)" :serviceType="data.serviceType" :closable=false v-on:close="clearAccount()"></bank-account-form-component>
<bank-account-form-component v-if="data.serviceType.id !== 4" section="customerProfileSection" :disabled="formDisabled" :data="Object.keys(parameters.bankAccount).length ? parameters.bankAccount : {account_no: account_no, company_id: data.company.id, country_id: 2, account_type: 2}" :company_id="data.company.id" :country_id="2" :type="2" :currency="data.serviceType.selectedCurrency.short_code" v-on:createdBank="updateBank($event)" :serviceType="data.serviceType" :closable=false v-on:close="clearAccount()"></bank-account-form-component>
<phone-account-form-component v-if="data.serviceType.id === 4" section="customerProfileSection" :disabled="formDisabled" :data="Object.keys(parameters.bankAccount).length ? parameters.bankAccount : {account_no: account_no, company_id: data.company.id, country_id: 2, account_type: 2}" :company_id="data.company.id" :country_id="2" :type="2" v-on:createdBank="updateBank($event)" :serviceType="data.serviceType" :closable=false v-on:close="clearAccount()"></phone-account-form-component>
</div>
</div>
@@ -228,14 +228,14 @@
</div>
</div>
<div class="col">
<p class="m-b-0 fs-12">Due to the system upgrades, you are no longer required to fill out the Purchase Order. We apologize that the invoices won't be available until the system has been fully upgraded. Thanks for your patience.</p>
<p class="m-b-0 fs-12">You are no longer required to key in your purchase order details manually, the system will automatically get your purchase order detail from 1688 directly.</p>
</div>
</div>
<div class="row">
<div class="col">
<div class="row" v-if="booking.documents.ecommerce_purchase_order">
<div class="col-md col-6 h-100">
<document-file-viewer-component :file="booking.documents.ecommerce_purchase_order.files[0]" v-if="booking.documents.ecommerce_purchase_order">
<div class="col-md col-6 h-100" v-for="file in booking.documents.ecommerce_purchase_order.files">
<document-file-viewer-component :file="file">
<template slot="button">
<div class="bg-white text-center padding-20 pointer b-grey">
<div class="m-b-10">
@@ -254,6 +254,13 @@
</div>
</div>
</div>
<div class="row" v-if="booking.documents.ecommerce_purchase_order && $store.getters.isAdmin && !booking.purchase_order">
<div class="col">
<a :href="route('ecommerce.fix', booking.marking)" target="_blank">
<div class="btn btn-danger">Fix 1688 PO</div>
</a>
</div>
</div>
<div class="row m-b-25" v-if="$store.getters.isAdmin && booking.service.id === 4 && booking.status !== 3">
<div class="col">
<div class="row" v-if="!booking.documents.ecommerce_purchase_order">
@@ -263,7 +270,7 @@
</div>
</div>
</div>
<purchase-order-form-component v-if="booking.service.id !== 4" :data="booking" :section="section"></purchase-order-form-component>
<purchase-order-form-component v-if="booking.service.id !== 4 || $store.getters.isAdmin || [199, 510].includes($store.getters.getCompanyId)" :data="booking" :section="section"></purchase-order-form-component>
</div>
</div>
<div class="row m-t-15" v-if="booking.status === 3 && $store.getters.isSuperAdmin">
@@ -494,4 +501,4 @@
}
}
}
</script>
</script>
@@ -1,7 +1,7 @@
<template>
<div class="row">
<div class="col">
<div class="row m-b-20 text-center" v-if="$store.getters.isSuperAdmin && creditable">
<div class="row m-b-20 text-center" v-if="($store.getters.isSuperAdmin || $store.getters.getUserId === 2231)&& creditable">
<div class="col">
<div class="row">
<div class="col p-r-5">
@@ -263,6 +263,9 @@
<div class="row no-margin">
<div class="col bg-white padding-25">
<div class="row tabsContainer tabContent hide m-l-0 m-r-0 hide" tab-name="customer-leads" v-if="$store.getters.isAdmin">
<a :href="route('leads.export')" class="m-b-15" target="_blank">
<button class="btn btn-success btn-xs">Export Leads Data</button>
</a>
<list-component key="2" section="leadCustomerListSection" :endpoint="route('api.company.list')" :options="{'business_type': 2, with_bookings:true, without_confirmed_payments: true, does_not_have_segments: [5]}">
<template slot="list" slot-scope="{data}">
<company-component :data="data"></company-component>
@@ -202,7 +202,7 @@
</div>
<div class="row">
<div class="col">
<list-component key="2" section="poPendingApprovalSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, purchase_order_approval: true}">
<list-component key="2" section="poPendingApprovalSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, purchase_order_approval: true, status_in: [2]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
@@ -220,7 +220,7 @@
</div>
<div class="row">
<div class="col">
<list-component key="2" section="poPendingSubmissionSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, pending_purchase_order: true}">
<list-component key="2" section="poPendingSubmissionSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, pending_purchase_order: true, has_payment_status_in: [2, 3]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
@@ -310,4 +310,4 @@
</div>
</div>
</div>
</div>
</div>
@@ -40,10 +40,12 @@
CIEF Worldwide Sdn Bhd (1134596-M)
</span>
<div class="address">
Malaysia Global Innovation & CreativityCentre, Level 1 CWS, Block 3730, PersiaranAPEC 63000 Cyberjaya
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur
</div>
<div class="contact-no">
Phone: 0182909252
Tel: 03-8082 1252
</div>
</td>
</tr>
@@ -66,7 +68,7 @@
@php
$subtotal = 0;
@endphp
@foreach($group->transactions as $po_order_transaction)
@foreach ($po_order_transaction->owner->owner->transactions()->where('type', \App\Classes\ValueObjects\Constants\TransactionType::PURCHASE_ORDER)->where('status', \App\Classes\ValueObjects\Constants\ApprovalStatus::APPROVED)->first()->transactionDetails as $key => $transaction_detail)
<tr>
@@ -91,7 +93,7 @@
<tfoot>
<tr class="subtotal">
<td colspan="4"></td>
<td class="right middle">Subtotal</td>
<td class="right middle">Subtotal</td>
<td class="right middle">
{{ number_format($subtotal, 2) }}
</td>
@@ -54,21 +54,21 @@
@php
$sub_total_booking_amount = number_format((float)$transactions->sum('original_amount'), 2, '.', '');
@endphp
<td>RMB {{$sub_total_booking_amount}}</td>
<td>{{$transaction->original_currency->short_code}} {{$sub_total_booking_amount}}</td>
</tr>
<tr>
<td width="70%" style="text-align: right;">Transfer fee: </td>
@php
$transfer_fee = number_format((float)$transferFeeTransactions->sum('service_charge'), 2, '.', '');
@endphp
<td>RMB {{$transfer_fee}}</td>
<td>{{$transaction->original_currency->short_code}} {{$transfer_fee}}</td>
</tr>
<tr>
<td width="70%" style="text-align: right;">Total booking amount: </td>
@php
$total_booking_amount = number_format((float) ($transactions->sum('original_amount') + $transfer_fee), 2, '.', '');
@endphp
<td>RMB {{$total_booking_amount}}</td>
<td>{{$transaction->original_currency->short_code}} {{$total_booking_amount}}</td>
</tr>
<tr>
<td width="70%" style="text-align: right;">Sub total amount: </td>
@@ -100,4 +100,4 @@
</tr>
</table>
</htmlpagefooter>
@endsection
@endsection
@@ -18,10 +18,10 @@
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
Malaysian Global Innovation &amp; Creativity Center <br>
Level 1 CWS, Block 3730, Persiaran APEC, <br>
63000 Cyberjaya, Malaysia. <br>
Tel: 018-2909252
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252
</td>
<td class="header-details">
<div class="title">
@@ -85,7 +85,7 @@
@php
$subtotal = 0;
@endphp
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
<tr>
<td width="5%" class="center top">{{ $key + 1 }}</td>
@@ -101,13 +101,13 @@
</td>
<td width="20%" class="right top">
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
$subtotal += number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2,'.','');
@endphp
@else
@else
{{ number_format((float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
@@ -137,9 +137,9 @@
<td colspan="4"></td>
<td class="right">Adjustment</td>
<td class="right">
@if($transaction->booking()->first()->fix_currency_id !== 1)
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@else
@else
{{ number_format((float)number_format($transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@endif
</td>
+9 -9
View File
@@ -17,10 +17,10 @@
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
Malaysian Global Innovation &amp; Creativity Center <br>
Level 1 CWS, Block 3730, Persiaran APEC, <br>
63000 Cyberjaya, Malaysia. <br>
Tel: 018-2909252
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252
</td>
<td class="header-details">
<div class="title">
@@ -100,13 +100,13 @@
</td>
<td width="20%" class="right top">
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
$subtotal += number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2,'.','');
@endphp
@else
@else
{{ number_format((float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
@@ -136,9 +136,9 @@
<td colspan="4"></td>
<td class="right">Adjustment</td>
<td class="right">
@if($transaction->booking()->first()->fix_currency_id !== 1)
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@else
@else
{{ number_format((float)number_format($transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@endif
</td>
@@ -17,10 +17,10 @@
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
Malaysian Global Innovation &amp; Creativity Center <br>
Level 1 CWS, Block 3730, Persiaran APEC, <br>
63000 Cyberjaya, Malaysian. <br>
Tel: 018-2909252
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252
</td>
<td class="header-details">
<div class="title">
@@ -100,13 +100,13 @@
</td>
<td width="20%" class="right top">
@if($invoice_transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$invoice_transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
$subtotal += number_format((float)number_format( (1/$invoice_transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2,'.','');
@endphp
@else
@else
{{ number_format((float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
@@ -44,8 +44,8 @@
@php
$addresses = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }}
{{ $addresses->street_one }}
{{ $addresses->street_two }}
{{ $addresses->state()->first()->name }}
{{ $addresses->district()->first()->name }}
</span>
@@ -63,10 +63,12 @@
CIEF Worldwide Sdn Bhd (1134596-M)
</span>
<div class="address">
Malaysia Global Innovation & CreativityCentre, Level 1 CWS, Block 3730, PersiaranAPEC 63000 Cyberjaya
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur
</div>
<div class="contact-no">
Phone: 0182909252
Tel: 03-8082 1252
</div>
</td>
</tr>
@@ -89,7 +91,7 @@
@php
$subtotal = 0;
@endphp
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
<tr>
<td width="5%" class="center top">{{ $key + 1 }}</td>
@@ -105,13 +107,13 @@
</td>
<td width="20%" class="right top">
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
$subtotal += number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2,'.','');
@endphp
@else
@else
{{ number_format((float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
@@ -125,7 +127,7 @@
<tfoot>
<tr class="subtotal">
<td colspan="4"></td>
<td class="right middle">Subtotal</td>
<td class="right middle">Subtotal</td>
<td class="right middle">
{{ number_format($subtotal, 2) }}
</td>
@@ -141,9 +143,9 @@
<td colspan="4"></td>
<td class="right">Adjustment</td>
<td class="right">
@if($transaction->booking()->first()->fix_currency_id !== 1)
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@else
@else
{{ number_format((float)number_format($transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@endif
</td>
@@ -34,25 +34,17 @@
Buyer
</span>
<br>
<div class="buyer-company">
CIEF Worldwide Sdn Bhd (1134596-M)
</div>
<span class="buyer-company">
Malaysia Global Innovation & CreativityCentre, Level 1 CWS, Block 3730, PersiaranAPEC 63000 Cyberjaya
</span>
<span class="reg">
{{-- {{ $supplier }} --}}
</span>
<br>
<span class="address">
{{-- {{ $buyer['address'] }} --}}
</span>
<br>
<span class="contact-no">
Phone: 0182909252
CIEF Worldwide Sdn Bhd (1134596-M)
</span>
<div class="address">
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur
</div>
<div class="contact-no">
Tel: 03-8082 1252
</div>
</td>
</tr>
</table>
@@ -74,7 +66,7 @@
@php
$subtotal = 0;
@endphp
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
<tr>
<td width="5%" class="center top">{{ $key + 1 }}</td>
@@ -92,11 +84,11 @@
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
$subtotal += number_format((float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2,'.','');
@endphp
@else
@else
{{ number_format((float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity,2) }}
@php
@@ -119,9 +111,9 @@
<td colspan="4"></td>
<td class="right">Adjustment</td>
<td class="right">
@if($transaction->booking()->first()->fix_currency_id !== 1)
@if($transaction->booking()->first()->fix_currency_id !== 1)
{{ number_format((float)number_format( (1/$transaction->currency_rate) * $transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@else
@else
{{ number_format((float)number_format($transaction->amount, 2,'.','') - (float)number_format($subtotal, 2,'.',''),2) }}
@endif
</td>
@@ -0,0 +1,129 @@
@extends('layouts.base_portal')
@section('inner_content')
<div class="row" v-if="$store.getters.isAdmin">
<div class="col p-t-15 p-b-15">
<div class="row tabsContainer">
<div class="col">
<div class="row m-l-0 m-r-0 d-flex">
<div class="col">
<div class="row justify-content-end">
<div class="col">
<div class="row">
<div class="col b-r b-white">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton active" tab-name="no-submission">
<div class="row justify-content-center m-b-5">
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="35" height="35"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="104.8125" y1="95.74219" x2="104.8125" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-1_TUOBhQt-Vj1j_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="67.1875" y1="95.74219" x2="67.1875" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-2_TUOBhQt-Vj1j_gr2"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="125.40413" x2="86" y2="133.41288" gradientUnits="userSpaceOnUse" id="color-3_TUOBhQt-Vj1j_gr3"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="10.234" x2="86" y2="158.13788" gradientUnits="userSpaceOnUse" id="color-4_TUOBhQt-Vj1j_gr4"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><circle cx="39" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-1_TUOBhQt-Vj1j_gr1)"></circle><circle cx="25" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-2_TUOBhQt-Vj1j_gr2)"></circle><rect x="28" y="47" transform="scale(2.6875,2.6875)" width="8" height="3" fill="url(#color-3_TUOBhQt-Vj1j_gr3)"></rect><path d="M142.4375,80.11975v-7.55725c0,-31.11856 -25.31625,-56.4375 -56.4375,-56.4375c-31.12125,0 -56.4375,25.31894 -56.4375,56.4375v7.55725c-4.81062,2.79231 -8.0625,7.98994 -8.0625,13.94275c0,8.89294 7.23206,16.125 16.125,16.125h0.13706c1.40556,25.42106 22.47019,45.6875 48.23794,45.6875c25.76775,0 46.83238,-20.26644 48.23794,-45.6875h0.13706c8.89294,0 16.125,-7.23206 16.125,-16.125c0,-5.95281 -3.25188,-11.15044 -8.0625,-13.94275zM34.9375,77.9375v-5.375h16.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-5.375h-5.375v5.375c0,4.44512 -3.61738,8.0625 -8.0625,8.0625h-15.83744c2.69556,-25.63875 24.43475,-45.6875 50.77494,-45.6875c26.34019,0 48.07938,20.04875 50.77494,45.6875h-42.71244c-4.44512,0 -8.0625,-3.61738 -8.0625,-8.0625v-5.375h-5.375v5.375c0,7.40944 6.02806,13.4375 13.4375,13.4375h43v5.375h-46.91837c-8.213,0 -14.89413,-6.68113 -14.89413,-14.89413v-9.29337h-5.375v8.94937c0,8.40113 -6.837,15.23813 -15.23813,15.23813zM26.875,94.0625c0,-5.92863 4.82138,-10.75 10.75,-10.75v8.0625h-2.6875c-1.4835,0 -2.6875,1.20131 -2.6875,2.6875c0,1.48619 1.204,2.6875 2.6875,2.6875h2.6875v8.0625c-5.92862,0 -10.75,-4.82137 -10.75,-10.75zM86,150.5c-23.70912,0 -43,-19.29087 -43,-43v-24.1875h11.63687c7.61906,0 14.28675,-4.15488 17.85575,-10.31731c3.48031,6.15438 10.08888,10.31731 17.6515,10.31731h38.85587v24.1875c0,23.70913 -19.29087,43 -43,43zM134.375,104.8125v-8.0625h2.6875c1.4835,0 2.6875,-1.20131 2.6875,-2.6875c0,-1.48619 -1.204,-2.6875 -2.6875,-2.6875h-2.6875v-8.0625c5.92863,0 10.75,4.82137 10.75,10.75c0,5.92863 -4.82137,10.75 -10.75,10.75z" fill="url(#color-4_TUOBhQt-Vj1j_gr4)"></path></g></g></svg>
</div>
</div>
<div class="row">
<div class="col">
<div class="fs-12 m-t-5 all-caps">No Submission</div>
</div>
</div>
</div>
</div>
</div>
<div class="col b-r b-white">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="incomplete-submission">
<div class="row justify-content-center m-b-5">
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="35" height="35"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="104.8125" y1="95.74219" x2="104.8125" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-1_TUOBhQt-Vj1j_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="67.1875" y1="95.74219" x2="67.1875" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-2_TUOBhQt-Vj1j_gr2"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="125.40413" x2="86" y2="133.41288" gradientUnits="userSpaceOnUse" id="color-3_TUOBhQt-Vj1j_gr3"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="10.234" x2="86" y2="158.13788" gradientUnits="userSpaceOnUse" id="color-4_TUOBhQt-Vj1j_gr4"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><circle cx="39" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-1_TUOBhQt-Vj1j_gr1)"></circle><circle cx="25" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-2_TUOBhQt-Vj1j_gr2)"></circle><rect x="28" y="47" transform="scale(2.6875,2.6875)" width="8" height="3" fill="url(#color-3_TUOBhQt-Vj1j_gr3)"></rect><path d="M142.4375,80.11975v-7.55725c0,-31.11856 -25.31625,-56.4375 -56.4375,-56.4375c-31.12125,0 -56.4375,25.31894 -56.4375,56.4375v7.55725c-4.81062,2.79231 -8.0625,7.98994 -8.0625,13.94275c0,8.89294 7.23206,16.125 16.125,16.125h0.13706c1.40556,25.42106 22.47019,45.6875 48.23794,45.6875c25.76775,0 46.83238,-20.26644 48.23794,-45.6875h0.13706c8.89294,0 16.125,-7.23206 16.125,-16.125c0,-5.95281 -3.25188,-11.15044 -8.0625,-13.94275zM34.9375,77.9375v-5.375h16.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-5.375h-5.375v5.375c0,4.44512 -3.61738,8.0625 -8.0625,8.0625h-15.83744c2.69556,-25.63875 24.43475,-45.6875 50.77494,-45.6875c26.34019,0 48.07938,20.04875 50.77494,45.6875h-42.71244c-4.44512,0 -8.0625,-3.61738 -8.0625,-8.0625v-5.375h-5.375v5.375c0,7.40944 6.02806,13.4375 13.4375,13.4375h43v5.375h-46.91837c-8.213,0 -14.89413,-6.68113 -14.89413,-14.89413v-9.29337h-5.375v8.94937c0,8.40113 -6.837,15.23813 -15.23813,15.23813zM26.875,94.0625c0,-5.92863 4.82138,-10.75 10.75,-10.75v8.0625h-2.6875c-1.4835,0 -2.6875,1.20131 -2.6875,2.6875c0,1.48619 1.204,2.6875 2.6875,2.6875h2.6875v8.0625c-5.92862,0 -10.75,-4.82137 -10.75,-10.75zM86,150.5c-23.70912,0 -43,-19.29087 -43,-43v-24.1875h11.63687c7.61906,0 14.28675,-4.15488 17.85575,-10.31731c3.48031,6.15438 10.08888,10.31731 17.6515,10.31731h38.85587v24.1875c0,23.70913 -19.29087,43 -43,43zM134.375,104.8125v-8.0625h2.6875c1.4835,0 2.6875,-1.20131 2.6875,-2.6875c0,-1.48619 -1.204,-2.6875 -2.6875,-2.6875h-2.6875v-8.0625c5.92863,0 10.75,4.82137 10.75,10.75c0,5.92863 -4.82137,10.75 -10.75,10.75z" fill="url(#color-4_TUOBhQt-Vj1j_gr4)"></path></g></g></svg>
</div>
</div>
<div class="row">
<div class="col">
<div class="fs-12 m-t-5 all-caps">In-complete Submission</div>
</div>
</div>
</div>
</div>
</div>
<div class="col b-r b-white">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="pending-review">
<div class="row justify-content-center m-b-5">
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="35" height="35"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="104.8125" y1="95.74219" x2="104.8125" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-1_TUOBhQt-Vj1j_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="67.1875" y1="95.74219" x2="67.1875" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-2_TUOBhQt-Vj1j_gr2"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="125.40413" x2="86" y2="133.41288" gradientUnits="userSpaceOnUse" id="color-3_TUOBhQt-Vj1j_gr3"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="10.234" x2="86" y2="158.13788" gradientUnits="userSpaceOnUse" id="color-4_TUOBhQt-Vj1j_gr4"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><circle cx="39" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-1_TUOBhQt-Vj1j_gr1)"></circle><circle cx="25" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-2_TUOBhQt-Vj1j_gr2)"></circle><rect x="28" y="47" transform="scale(2.6875,2.6875)" width="8" height="3" fill="url(#color-3_TUOBhQt-Vj1j_gr3)"></rect><path d="M142.4375,80.11975v-7.55725c0,-31.11856 -25.31625,-56.4375 -56.4375,-56.4375c-31.12125,0 -56.4375,25.31894 -56.4375,56.4375v7.55725c-4.81062,2.79231 -8.0625,7.98994 -8.0625,13.94275c0,8.89294 7.23206,16.125 16.125,16.125h0.13706c1.40556,25.42106 22.47019,45.6875 48.23794,45.6875c25.76775,0 46.83238,-20.26644 48.23794,-45.6875h0.13706c8.89294,0 16.125,-7.23206 16.125,-16.125c0,-5.95281 -3.25188,-11.15044 -8.0625,-13.94275zM34.9375,77.9375v-5.375h16.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-5.375h-5.375v5.375c0,4.44512 -3.61738,8.0625 -8.0625,8.0625h-15.83744c2.69556,-25.63875 24.43475,-45.6875 50.77494,-45.6875c26.34019,0 48.07938,20.04875 50.77494,45.6875h-42.71244c-4.44512,0 -8.0625,-3.61738 -8.0625,-8.0625v-5.375h-5.375v5.375c0,7.40944 6.02806,13.4375 13.4375,13.4375h43v5.375h-46.91837c-8.213,0 -14.89413,-6.68113 -14.89413,-14.89413v-9.29337h-5.375v8.94937c0,8.40113 -6.837,15.23813 -15.23813,15.23813zM26.875,94.0625c0,-5.92863 4.82138,-10.75 10.75,-10.75v8.0625h-2.6875c-1.4835,0 -2.6875,1.20131 -2.6875,2.6875c0,1.48619 1.204,2.6875 2.6875,2.6875h2.6875v8.0625c-5.92862,0 -10.75,-4.82137 -10.75,-10.75zM86,150.5c-23.70912,0 -43,-19.29087 -43,-43v-24.1875h11.63687c7.61906,0 14.28675,-4.15488 17.85575,-10.31731c3.48031,6.15438 10.08888,10.31731 17.6515,10.31731h38.85587v24.1875c0,23.70913 -19.29087,43 -43,43zM134.375,104.8125v-8.0625h2.6875c1.4835,0 2.6875,-1.20131 2.6875,-2.6875c0,-1.48619 -1.204,-2.6875 -2.6875,-2.6875h-2.6875v-8.0625c5.92863,0 10.75,4.82137 10.75,10.75c0,5.92863 -4.82137,10.75 -10.75,10.75z" fill="url(#color-4_TUOBhQt-Vj1j_gr4)"></path></g></g></svg>
</div>
</div>
<div class="row">
<div class="col">
<div class="fs-12 m-t-5 all-caps">Pending Review</div>
</div>
</div>
</div>
</div>
</div>
<div class="col b-r b-white">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="approved">
<div class="row justify-content-center m-b-5">
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="35" height="35"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="104.8125" y1="95.74219" x2="104.8125" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-1_TUOBhQt-Vj1j_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="67.1875" y1="95.74219" x2="67.1875" y2="114.9175" gradientUnits="userSpaceOnUse" id="color-2_TUOBhQt-Vj1j_gr2"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="125.40413" x2="86" y2="133.41288" gradientUnits="userSpaceOnUse" id="color-3_TUOBhQt-Vj1j_gr3"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="10.234" x2="86" y2="158.13788" gradientUnits="userSpaceOnUse" id="color-4_TUOBhQt-Vj1j_gr4"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><circle cx="39" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-1_TUOBhQt-Vj1j_gr1)"></circle><circle cx="25" cy="39" transform="scale(2.6875,2.6875)" r="3" fill="url(#color-2_TUOBhQt-Vj1j_gr2)"></circle><rect x="28" y="47" transform="scale(2.6875,2.6875)" width="8" height="3" fill="url(#color-3_TUOBhQt-Vj1j_gr3)"></rect><path d="M142.4375,80.11975v-7.55725c0,-31.11856 -25.31625,-56.4375 -56.4375,-56.4375c-31.12125,0 -56.4375,25.31894 -56.4375,56.4375v7.55725c-4.81062,2.79231 -8.0625,7.98994 -8.0625,13.94275c0,8.89294 7.23206,16.125 16.125,16.125h0.13706c1.40556,25.42106 22.47019,45.6875 48.23794,45.6875c25.76775,0 46.83238,-20.26644 48.23794,-45.6875h0.13706c8.89294,0 16.125,-7.23206 16.125,-16.125c0,-5.95281 -3.25188,-11.15044 -8.0625,-13.94275zM34.9375,77.9375v-5.375h16.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-5.375h-5.375v5.375c0,4.44512 -3.61738,8.0625 -8.0625,8.0625h-15.83744c2.69556,-25.63875 24.43475,-45.6875 50.77494,-45.6875c26.34019,0 48.07938,20.04875 50.77494,45.6875h-42.71244c-4.44512,0 -8.0625,-3.61738 -8.0625,-8.0625v-5.375h-5.375v5.375c0,7.40944 6.02806,13.4375 13.4375,13.4375h43v5.375h-46.91837c-8.213,0 -14.89413,-6.68113 -14.89413,-14.89413v-9.29337h-5.375v8.94937c0,8.40113 -6.837,15.23813 -15.23813,15.23813zM26.875,94.0625c0,-5.92863 4.82138,-10.75 10.75,-10.75v8.0625h-2.6875c-1.4835,0 -2.6875,1.20131 -2.6875,2.6875c0,1.48619 1.204,2.6875 2.6875,2.6875h2.6875v8.0625c-5.92862,0 -10.75,-4.82137 -10.75,-10.75zM86,150.5c-23.70912,0 -43,-19.29087 -43,-43v-24.1875h11.63687c7.61906,0 14.28675,-4.15488 17.85575,-10.31731c3.48031,6.15438 10.08888,10.31731 17.6515,10.31731h38.85587v24.1875c0,23.70913 -19.29087,43 -43,43zM134.375,104.8125v-8.0625h2.6875c1.4835,0 2.6875,-1.20131 2.6875,-2.6875c0,-1.48619 -1.204,-2.6875 -2.6875,-2.6875h-2.6875v-8.0625c5.92863,0 10.75,4.82137 10.75,10.75c0,5.92863 -4.82137,10.75 -10.75,10.75z" fill="url(#color-4_TUOBhQt-Vj1j_gr4)"></path></g></g></svg>
</div>
</div>
<div class="row">
<div class="col">
<div class="fs-12 m-t-5 all-caps">Approved</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row no-margin">
<div class="col bg-white padding-25">
<div class="row tabsContainer tabContent m-l-0 m-r-0" tab-name="no-submission">
<list-component key="2" section="all" :endpoint="route('api.booking.list')" :options="{per_page: 10, ServiceId: 4, status_in:[2], company_id_not_in: [199, 510], has_payment_status_in: [1, 2, 3], does_not_have_purchase_order_status_in: [0, 1, 2, 3]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
</list-component>
</div>
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="incomplete-submission">
<list-component key="2" section="poPendingSubmissionSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, ServiceId: 4, status_in:[2], company_id_not_in: [199, 510], has_payment_status_in: [2, 3], has_purchase_order_status_in: [0]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
</list-component>
</div>
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="pending-review">
<list-component key="2" section="poPendingReviewSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, ServiceId: 4, status_in:[2], company_id_not_in: [199, 510], has_payment_status_in: [1, 2, 3], has_purchase_order_status_in: [1]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
</list-component>
</div>
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="approved">
<list-component key="2" section="poApprovedSection" :endpoint="route('api.booking.list')" :options="{per_page: 10, ServiceId: 4, status_in:[3], company_id_not_in: [199, 510], has_purchase_order_status_in: [2]}">
<template slot="list" slot-scope="{data}">
<booking-component :data="data"></booking-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
+2 -2
View File
@@ -8,6 +8,6 @@
</script>
<script type="text/javascript">window.$crisp=[];window.CRISP_WEBSITE_ID="665dcd41-1edf-4451-8cb9-f1cf9ed35e15";(function(){d=document;s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();</script>
<script src="{{ asset('js/vendor.js') }}" type="text/javascript"></script>
<script src="{{mix('vue/app.js')}}"></script>
<script src="@if (env('APP_ENV') === 'local') {{asset('vue/app.js')}} @else {{mix('vue/app.js')}} @endif"></script>
<script src="{{ asset('js/site.js') }}" type="text/javascript"></script>
{{--END VENDOR JS--}}
{{--END VENDOR JS--}}
+123 -5
View File
@@ -1,5 +1,6 @@
<?php
use App\Classes\Modules\Bookings\Processors\CreatePurchaseOrderFor1688OrderProcessor;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
@@ -15,9 +16,11 @@ use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Excel;
use Meneses\LaravelMpdf\Facades\LaravelMpdf;
use Webklex\PDFMerger\Facades\PDFMergerFacade as PDFMerger;
/*
|--------------------------------------------------------------------------
@@ -100,12 +103,17 @@ Route::get('/transfer/merge/{marking}', function ($marking) {
return view('pages.bookings.merge', ['marking' => $marking]);
})->name('booking.merge');
Route::get('/purchase_orders', function () {
return view('pages.purchase_orders');
})->name('purchase_orders');
Route::get('/online_payment/redirect', 'Billplz\CallbackBillplzController@callback')->name('online_payment.redirect');
Route::get('/export/customers/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@export');
Route::get('/export/transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@transactions');
Route::get('/export/analytic/booking', 'Exports\ExportAnalyticToExcelController@bookingData');
Route::get('/export/analytic/bills', 'Exports\ExportAnalyticToExcelController@billingData');
Route::get('/export/customers/leads', 'Exports\ExportCustomersToExcelController@leadsData')->name('leads.export');
Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) {
return $exportsProducts->download('products.csv', Excel::CSV, ['Content-Type' => 'text/csv']);
@@ -204,7 +212,7 @@ Route::get('/transactions/supplier/{id}/mock_up', 'Transactions\DownloadMockUpWh
Route::get('/notifications/list', 'Notifications\ListNotificationsController@list')->name('notifications.list');
Route::get('/supplier/pi/export', function(){
$groups = \App\Models\Group::where('issuer', 2210)->whereMonth('created_at', 5)->whereYear('created_at', 2022)->get();
$groups = \App\Models\Group::where('issuer', 2729)->whereMonth('created_at', 9)->whereYear('created_at', 2022)->get();
echo '<table>';
$i = 0;
@@ -215,6 +223,7 @@ Route::get('/supplier/pi/export', function(){
if(!$purchaseOrder) {
echo '<tr>';
echo '<td>-</td>';
echo '<td>'.$group->created_at.'</td>';
echo '<td style="color: red">warning, booking ref.'.$booking->marking.' doesn\'t have purchase order</td>';
echo '<td>0</td>';
echo '<td>0</td>';
@@ -227,6 +236,7 @@ Route::get('/supplier/pi/export', function(){
$i++;
echo '<tr>';
echo '<td>'.$i.'</td>';
echo '<td>'.$group->created_at.'</td>';
echo '<td>'.$item->product_name.'</td>';
echo '<td>'.$item->quantity.'</td>';
echo '<td>'.$item->price * (1/$group->currency_rate).'</td>';
@@ -260,8 +270,8 @@ Route::get('/pending_orders', function(){
$i = 0;
foreach ($payments as $payment){
$booking = $payment->owner;
if($booking->service_id === 4){
continue;
if(!$booking instanceof Booking){
dd($payment);
}
$bankType = str::length($booking->bank->holder_name) > 4 ? 'Company' : 'Personal';
@@ -343,11 +353,11 @@ Route::get('/wallet/audit', function (Request $request) {
if((int) $transaction->type === TransactionType::PAYMENT) $payments += (float) $transaction->amount;
if((int) $transaction->type === TransactionType::DEBIT_NOTE) $debit += (float) $transaction->amount;
}
if(round((float) $wallet->amount - (($topups + $credit) - ($payments + $debit)), 2) == 0) continue;
if((round((float) $wallet->amount - (($topups + $credit) - ($payments + $debit)), 2) == 0) AND $wallet->amount > -0.01) continue;
$i++;
echo $i.". Marking: ". $wallet->owner->reference ."<br>Current Balance: ". $wallet->amount ."<br>Audit Balance: ". (($topups + $credit) - ($payments + $debit)) ."<br>Difference: ". round((float) $wallet->amount - (($topups + $credit) - ($payments + $debit)), 2) ."<br><br><br>";
echo $i.". Marking: ". $wallet->owner->reference ."(".$wallet->id.")<br>Current Balance: ". $wallet->amount ."<br>Audit Balance: ". (($topups + $credit) - ($payments + $debit)) ."<br>Difference: ". round((float) $wallet->amount - (($topups + $credit) - ($payments + $debit)), 2) ."<br><br><br>";
}
});
@@ -366,6 +376,7 @@ Route::get('/wallets/active', function(){
});
Route::get('/payments/manual', function(){
$payments = Transaction::where('type', TransactionType::PAYMENT)->whereIn('payment_method', [\App\Classes\ValueObjects\Constants\PaymentMethodType::CASH, \App\Classes\ValueObjects\Constants\PaymentMethodType::BA, \App\Classes\ValueObjects\Constants\PaymentMethodType::CHEQUE])->where('owner_type', Booking::class)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
$i = 0;
@@ -382,3 +393,110 @@ Route::get('/payments/manual', function(){
echo '</table>';
});
Route::get('/1688/fix/{reference}', function($reference){
$booking = Booking::where('marking', $reference)->first();
(App()->make(createPurchaseOrderFor1688OrderProcessor::class))->execute($booking);
// set_time_limit(1800);
// $purchaseOrderDocuments = \App\Models\Document::where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get();
//
// foreach($purchaseOrderDocuments as $document){
// $booking = $document->owner;
// $booking->status = ApprovalStatus::APPROVED;
// $booking->save();
//
// $booking->documents()->whereIn('document_type', [DocumentType::INVOICE, DocumentType::PURCHASE_ORDER, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->delete();
//
// (App()->make(createPurchaseOrderFor1688OrderProcessor::class))->execute($document->owner);
// }
})->name('ecommerce.fix');
Route::get('/po/manual/fix', function(){
$bookings = Booking::whereIn('company_id', [199, 510])->whereHas('documents', function($query){
return $query->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER);
})->get();
foreach ($bookings as $booking){
$booking->status = ApprovalStatus::APPROVED;
$booking->save();
$booking->documents()->whereIn('document_type', [DocumentType::PURCHASE_ORDER, DocumentType::DELIVER_ORDER, DocumentType::INVOICE, DocumentType::SUPPLIER_DELIVER_ORDER])->delete();
$booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->update(['status' => ApprovalStatus::PENDING_SUBMISSION]);
}
})->name('ecommerce.fix');
Route::get('/payment/check', function(){
$transactions = Transaction::where('type', TransactionType::BILL)->whereDate('created_at', '>=', Carbon::today())->get();
foreach ($transactions as $transaction){
$booking = $transaction->owner->owner;
$documents = $transaction->documents;
if(!count($documents)){
echo $booking->marking.'<br><br>';
continue;
}
// echo $transaction->owner->owner->marking.'. payment: '.$transaction->updated_at.' -> document: '.$documents[0]->created_at.'<br>';
}
})->name('payment.check');
Route::get('/refund/fix', function(){
$bookings = Booking::whereIn('marking', [82935, 92135, 96183, 94448, 29819, 30403, 63969, 42116, 79278, 89987, 51432, 76289, 67767, 98433, 47431, 93472, 50933, 87298, 35329, 93845, 55902, 82629, 51019, 42820, 90666, 40167, 29253, 48891, 67364, 64628, 91859, 22123, 34154, 84366, 27370, 58222, 67695, 71233, 26466, 83894, 35664, 65669, 68986, 40382, 63743, 39611, 60658, 32893, 98243, 23822, 64323, 79271, 79053, 48497, 48708, 86463, 30054, 50590, 85808, 88988, 79663, 57558, 85902, 95451, 95897, 33164, 82342, 38091, 27451, 64809, 39444, 32101, 27242, 71851, 50850, 70659, 89403, 55540, 65743, 77315, 22921, 35623, 77315, 32344, 81717, 57176, 48775, 34133, 39396, 67473, 42749, 89395, 32132, 23670, 36783, 21783, 66348, 47205, 72784, 22437, 96271, 45396, 45352, 47896, 61654, 73174, 47002, 25448, 95810, 80827, 81180, 52142, 37640, 30295, 59816, 99197, 76541, 94786, 30776, 89769, 77720, 30610, 28546, 50931, 94525, 43425, 37461, 20629, 60586, 87228, 24814, 68011, 90547, 30572, 26274, 26274, 38599, 44487, 96767, 63872, 29576, 20173, 23555, 64657, 71021, 65316, 86540, 73981, 32747, 71086, 83221, 66168, 90541, 52366, 29227, 30915, 45242, 81384, 37533, 89752, 70133, 45894, 21918, 85579, 48650, 88747, 23200, 37018, 21753, 21188, 60449, 63918, 68888, 49910, 30402, 96338, 36578, 82133, 37872, 90437, 54404, 73439, 94283, 97752, 83333, 38548, 74366, 21060, 43240, 94612, 33164, 98630, 33164, 22898, 44320, 31153, 36480, 55085, 64039, 99796, 42238, 71458, 34415, 49935, 37902, 25598, 51833, 89733, 38081, 71564, 51366, 20173, 91400, 86540, 92131, 76724, 22657, 62117, 86443, 85827, 46570, 99809, 89258, 68834, 20785, 24478, 79588, 49111, 24838, 41989, 79081, 48440, 57375, 86104, 78719, 61502, 96167, 23398, 27873, 80065, 33048, 83138, 99211, 98183, 28639, 54547, 70098, 27216, 67404, 47761, 85049, 41906, 62328, 63645, 46750, 86975, 69955, 21714, 33889, 87344, 58345, 34183, 82504, 68636, 70962, 92553, 20125, 88625, 20661, 98146, 92075, 67543, 99045, 27395, 67163, 32245, 43347, 87947, 97897, 59860, 26003, 47852, 96008, 54166, 50037, 31435, 35821, 81929, 76751, 80379, 32473, 81598, 58716, 70554, 67473, 82491, 93859, 99159, 84772, 84772, 32473, 42050, 26532, 81526, 81526, 45780, 46570, 78657, 35293, 98311, 62095, 86914, 45215, 37650, 57708, 60449, 46750, 91834, 60989, 54877, 98298, 52382, 86346, 65219])
->get();
$notPlaced = [];
$placed = [];
$completed = [];
foreach ($bookings as $booking){
$payments = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
foreach ($payments as $payment){
if($payment->status === ApprovalStatus::APPROVED){
$notPlaced[] = $booking;
continue;
}
$bill = $payment->transactions()->where('type', TransactionType::BILL)->first();
if(!$bill){
$notPlaced[] = $booking;
continue;
}
if(in_array($bill->status, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])){
$completed[] = $booking;
continue;
}
$placed[] = $booking;
}
}
echo '<h3>Customer Paid ('.count($notPlaced).')</h3>';
foreach ($notPlaced as $booking){
echo '<a href="'.route('booking.details', $booking->marking).'" target="_blank">'.$booking->marking.'</a><br>';
}
echo '<h3>White Form Generated ('.count($placed).')</h3>';
foreach ($placed as $booking){
echo '<a href="'.route('booking.details', $booking->marking).'" target="_blank">'.$booking->marking.'</a><br>';
}
echo '<h3>China Bankslip Uploaded ('.count($completed).')</h3>';
foreach ($completed as $booking){
echo '<a href="'.route('booking.details', $booking->marking).'" target="_blank">'.$booking->marking.'</a><br>';
}
});