Compare commits

..

3 Commits

Author SHA1 Message Date
edmondlang dbc57fdaac code update 2023-12-31 12:58:22 +08:00
edmondlang 9c9cf0f96e api and web response time log 2023-12-28 23:04:16 +08:00
edmondlang 8513309126 api response time logging 2023-12-28 22:50:19 +08:00
94 changed files with 166 additions and 3646 deletions
@@ -1,11 +0,0 @@
<?php
namespace App\Classes\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class JobResourceNotFoundException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct($message ?? 'Unable to find the requested resource', HttpStatus::RESOURCE_NOT_FOUND);
}
}
@@ -15,8 +15,6 @@ use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Facades\DB;
use App\Classes\Exceptions\JobResourceNotFoundException;
use Illuminate\Support\Facades\Log;
abstract class AbstractControllerLogic
{
@@ -64,19 +62,6 @@ abstract class AbstractControllerLogic
return $response;
} catch (ErrorException|GeneralExceptions|TypeError $exception){
if ($exception instanceof JobResourceNotFoundException) {
Log::error(sprintf(
"Uncaught exception '%s' with message '%s' in %s:%d",
get_class($exception),
$exception->getMessage(),
$exception->getTrace()[0]['file'],
$exception->getTrace()[0]['line']
));
}
else{
Log::error($exception);
}
return (new ApiResponseObject($this->getNotificationTitle().' failed', $exception->getMessage(),
!in_array($exception->getCode(), [0, 42000]) ? $exception->getCode() : HttpStatus::SERVER_ERROR))->handler();
@@ -6,8 +6,6 @@ namespace App\Classes\General\Eloquent;
use App\Classes\Exceptions\ResourceNotFoundException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use App\Classes\Exceptions\JobResourceNotFoundException;
abstract class AbstractFetchRecord extends AbstractGetRecord
{
@@ -28,18 +26,12 @@ abstract class AbstractFetchRecord extends AbstractGetRecord
* @return Model
* @throws ResourceNotFoundException
*/
public function getResults(Builder $query, array $param = []): Model {
public function getResults(Builder $query): Model {
if(!$query->exists()){
$table = $query->getModel()->getTable();
if($table ==='job_results'){
throw new JobResourceNotFoundException('Unable to find any job based on the criteria provided');
}
else{
throw new ResourceNotFoundException('Unable to find any record based on the criteria provided');
}
throw new ResourceNotFoundException('Unable to find any record based on the criteria provided');
}
return $query->first();
}
}
}
@@ -50,9 +50,9 @@ abstract class AbstractGetRecord
* @param array $filters
* @return mixed
*/
public function handler(array $filters, array $params = []){
public function handler(array $filters){
$this->filters = collect($filters);
return $this->getResults($this->applyFiltersToQuery(), $params);
return $this->getResults($this->applyFiltersToQuery());
}
@@ -65,6 +65,6 @@ abstract class AbstractGetRecord
* @param Builder $query
* @return mixed
*/
abstract function getResults(Builder $query, array $params = []);
abstract function getResults(Builder $query);
}
}
@@ -16,10 +16,11 @@ abstract class AbstractListRecord extends AbstractGetRecord
* @return mixed
* @throws MalformedRequestException
*/
public function execute(array $filters = [], array $param = []){
public function execute(array $filters = []){
try{
return $this->handler($filters, $param);
return $this->handler($filters);
} catch (QueryException $exception){
throw new MalformedRequestException('Unable to fetch the list of records due to unexpected error');
@@ -31,7 +32,7 @@ abstract class AbstractListRecord extends AbstractGetRecord
* @param Builder $query
* @return mixed
*/
public function getResults(Builder $query, array $param = []) {
public function getResults(Builder $query) {
$filters = $this->getDecorationFilters();
if($filters->has('order_by')){
@@ -43,12 +44,8 @@ abstract class AbstractListRecord extends AbstractGetRecord
}
//dd($query->toSql());
if(!empty($param)){
return $filters->has('per_page') ? $query->paginate($filters->get('per_page'), ['*'], 'page', $param['page']) : $query->get(); //page data from query parameters e.g ?page=1
}
else{
return $filters->has('per_page') ? $query->paginate($filters->get('per_page')) : $query->get();
}
return $filters->has('per_page') ? $query->paginate($filters->get('per_page')) : $query->get();
}
}
@@ -1,20 +0,0 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class JobId implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('job_id', $value);
}
}
@@ -1,20 +0,0 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class PostcodeLike implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('postcode', 'LIKE', '%'.$value.'%');
}
}
@@ -1,19 +0,0 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class RequestSignature implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('request_signature', $value);
}
}
@@ -1,18 +0,0 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class ResultNotNull implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereNotNull('result');
}
}
@@ -1,20 +0,0 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class WithContainersPackages implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->with(['containers', 'packages']);
}
}
-9
View File
@@ -2,7 +2,6 @@
namespace App\Classes\General;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
@@ -41,12 +40,4 @@ class Helper
}
}
}
/**
* @param ResourceCollection $collection
* @return array
*/
static function collectionResponse(ResourceCollection $collection){
return json_decode($collection->response()->getContent(), true);
}
}
-45
View File
@@ -1,45 +0,0 @@
<?php
namespace App\Classes\Jobs;
use App\Classes\Modules\PackingLists\Processors\ListPackingListsJobProcessor;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ListPackingListsJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 900;
/** @var ListGenericJobObject */
private $listGenericJobObject;
/**
* ListPackingListsJob constructor.
* @param ListGenericJobObject $listGenericJobObject
*/
public function __construct(ListGenericJobObject $listGenericJobObject)
{
$this->listGenericJobObject = $listGenericJobObject;
}
public function handle()
{
$rawPayload = $this->job->payload();
if(isset($rawPayload['data']['commandName'])){
$this->listGenericJobObject->setJobCommandName($rawPayload['data']['commandName']);
}
if(isset($rawPayload['data']['command'])){
$this->listGenericJobObject->setJobCommand($rawPayload['data']['command']);
}
$result = (App()->make(ListPackingListsJobProcessor::class))->execute($this->listGenericJobObject);
}
}
@@ -1,23 +0,0 @@
<?php
namespace App\Classes\Modules\Imports\Services;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
class GenericImport implements ToCollection, WithHeadingRow
{
function headingRow(): int { return 1; }
public $rows;
/**
* @param Collection $collection
*/
public function collection(Collection $collection)
{
$this->rows = $collection;
}
}
@@ -1,52 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Jobs\Processors\FetchesJobResultProcessor;
use App\Http\Resources\JobResultResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchJobResultLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Data',
'message' => 'You have successfully retrieved data'
];
}
/** @var FetchesJobResultProcessor */
private $fetchesJobResultProcessor;
/**
* FetchJobResultLogic constructor.
* @param FetchesJobResultProcessor $fetchesJobResultProcessor
*/
public function __construct(FetchesJobResultProcessor $fetchesJobResultProcessor)
{
$this->fetchesJobResultProcessor = $fetchesJobResultProcessor;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$query = $this->fetchesJobResultProcessor->execute($request);
return $this->resourceResponse(new JobResultResource($query));
}
}
@@ -1,118 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class ListGenericJobObject implements DataTransferObject
{
/** @var string */
private $name;
/** @var array */
private $payload;
/** @var string */
private $jobId;
/** @var string */
private $requestSignature;
/** @var string */
private $resultSignature;
/** @var object */
private $userInfo;
/** @var string */
private $jobCommandName;
/** @var string */
private $jobCommand;
public function __construct(string $name, array $payload, string $requestSignature, ?string $resultSignature, string $jobId, object $userInfo = null)
{
$this->name = $name;
$this->payload = $payload;
$this->jobId = $jobId;
$this->requestSignature = $requestSignature;
$this->resultSignature = $resultSignature;
$this->userInfo = $userInfo;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return array
*/
public function getPayload(): array
{
return $this->payload;
}
/**
* @return string
*/
public function getJobId(): string
{
return $this->jobId;
}
/**
* @return string
*/
public function getRequestSignature(): string
{
return $this->requestSignature;
}
/**
* @return string
*/
public function getResultSignature(): ?string
{
return $this->resultSignature;
}
/**
* @return object
*/
public function getUserInfo(): object
{
return $this->userInfo;
}
/**
* @return string
*/
public function getJobCommandName(): string
{
return $this->jobCommandName;
}
/**
* @return string
*/
public function getJobCommand(): string
{
return $this->jobCommand;
}
public function setJobCommandName(string $jobCommandName)
{
$this->jobCommandName = $jobCommandName;
}
public function setJobCommand(string $jobCommand)
{
$this->jobCommand = $jobCommand;
}
}
@@ -1,60 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UpdateJobResultObject implements DataTransferObject
{
/** @var string */
private $result;
/** @var string */
private $resultSignature;
/** @var string */
private $jobCommandName;
/** @var string */
private $jobCommand;
public function __construct(string $result, string $resultSignature, string $jobCommandName, string $jobCommand)
{
$this->result = $result;
$this->resultSignature = $resultSignature;
$this->jobCommandName = $jobCommandName;
$this->jobCommand = $jobCommand;
}
/**
* @return string
*/
public function getResult(): string
{
return $this->result;
}
/**
* @return array
*/
public function getResultSignature(): string
{
return $this->resultSignature;
}
/**
* @return string
*/
public function getJobCommandName(): string
{
return $this->jobCommandName;
}
/**
* @return string
*/
public function getJobCommand(): string
{
return $this->jobCommand;
}
}
@@ -1,47 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Processors;
use App\Classes\Exceptions\JobResourceNotFoundException;
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
use Illuminate\Http\Request;
class FetchesJobResultProcessor
{
/** @var FetchesJobResult */
private $fetchesJobResult;
/**
* FetchesJobResultProcessor constructor.
* @param FetchesJobResult $fetchesJobResult
*/
public function __construct(FetchesJobResult $fetchesJobResult)
{
$this->fetchesJobResult = $fetchesJobResult;
}
/**
* @param Request $request
* @return Model
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\JobResourceNotFoundException
* @throws \App\Classes\Exceptions\ResourceNotFoundException
*/
public function execute(Request $request){
$res1 = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]);
if($request->route('is_last')){
$res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
return $res2;
}
if(!$res1->result){
throw new JobResourceNotFoundException('Unable to find any job based on the criteria provided');
}
return $res1;
}
}
@@ -1,64 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Processors;
use App\Classes\Modules\Jobs\Services\UpdatesJobResult;
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
use App\Classes\Exceptions\JobResourceNotFoundException;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use App\Classes\Modules\Jobs\DataTransferObjects\UpdateJobResultObject;
class UpdateJobResultProcessor
{
/** @var FetchesJobResult */
private $fetchesJobResult;
/** @var UpdatesJobResult */
private $updatesJobResult;
/**
* UpdateJobResultProcessor constructor.
* @param FetchesJobResult $fetchesJobResult
* @param UpdatesJobResult $updatesJobResult
*/
public function __construct(FetchesJobResult $fetchesJobResult, UpdatesJobResult $updatesJobResult)
{
$this->fetchesJobResult = $fetchesJobResult;
$this->updatesJobResult = $updatesJobResult;
}
/**
* @param ListGenericJobObject $listGenericJobObject
* @param array $resultCurrent
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\JobResourceNotFoundException
*/
public function execute(ListGenericJobObject $listGenericJobObject, $resultCurrent) {
$jobResultCurrent = $this->fetchesJobResult->execute(['job_id' => $listGenericJobObject->getJobId()]);
$resultCurrentJson = json_encode($resultCurrent);
$resultSignatureCurrent = md5($resultCurrentJson);
try{
$jobResultExisting = $this->fetchesJobResult->execute(['request_signature' => $jobResultCurrent->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
$resultSignatureExisting = $jobResultExisting->result_signature;
//if($resultSignatureExisting != $resultSignatureCurrent){
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
//}
} catch (JobResourceNotFoundException $exception){
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
}
}
private function updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $jobCommandName, $jobCommand){
$updateJobResultObject = new UpdateJobResultObject(
$resultCurrentJson,
$resultSignatureCurrent,
$jobCommandName,
$jobCommand
);
$create = $this->updatesJobResult->execute($jobResultCurrent, $updateJobResultObject);
}
}
@@ -1,26 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Models\JobResult;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
class CreatesJobResult extends AbstractUpdateRecord
{
/**
* @param ListGenericJobObject $listGenericJobObject
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(ListGenericJobObject $listGenericJobObject)
{
$model = new JobResult();
$model->job_id = $listGenericJobObject->getJobId();
$model->request_signature = $listGenericJobObject->getRequestSignature();
$model->result_signature = $listGenericJobObject->getResultSignature();
$model->url = $listGenericJobObject->getName();
return $this->handler($model);
}
}
@@ -1,33 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\JobResult;
class FetchesJobResult extends AbstractFetchRecord
{
/** @var JobResult */
private $repository;
/**
* FetchesJobResult constructor.
* @param JobResult $repository
*/
public function __construct(JobResult $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -1,33 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\JobResult;
class ListsJobResult extends AbstractListRecord
{
/** @var JobResult */
private $repository;
/**
* ListsJobResult constructor.
* @param JobResult $repository
*/
public function __construct(JobResult $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -1,28 +0,0 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\Jobs\DataTransferObjects\UpdateJobResultObject;
use App\Models\JobResult;
class UpdatesJobResult extends AbstractUpdateRecord
{
/**
* @param JobResult $model
* @param UpdateJobResultObject $updateJobResultObject
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(JobResult $model, UpdateJobResultObject $updateJobResultObject) {
$model->result = $updateJobResultObject->getResult();
$model->result_signature = $updateJobResultObject->getResultSignature();
$model->job_command_name = $updateJobResultObject->getJobCommandName();
$model->job_command = $updateJobResultObject->getJobCommand();
return $this->handler($model);
}
}
@@ -1,78 +0,0 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\ListPackingListsJob;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Classes\Modules\Jobs\Services\CreatesJobResult;
class ListPackingListsJobLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Job Retrieving PackingLists',
'message' => 'You have successfully submit a job to retrieve a list of PackingLists'
];
}
/** @var CreatesJobResult */
private $createsJobResult;
/**
* ListPackingListsJobLogic constructor.
* @param CreatesJobResult $createsJobResult
*/
public function __construct(CreatesJobResult $createsJobResult)
{
$this->createsJobResult = $createsJobResult;
}
/**
* @param Request $request
* @return JsonResponse
*/
public function logic(Request $request) : JsonResponse
{
$jobId = uniqid();
$user = Auth::user();
$userInfo = (object) [
// 'email' => $user->email,
'type' => $user->type,
];
$userInfoJson = json_encode($userInfo);
$requestSignature = md5($userInfoJson . $request->fullUrl());
$listGenericJobObject = new ListGenericJobObject(
$request->fullUrl(),
$request->all(),
$requestSignature,
null,
$jobId,
$userInfo
);
ListPackingListsJob::dispatch($listGenericJobObject);
$result = [];
$result['job_id'] = $jobId;
$this->createsJobResult->execute($listGenericJobObject);
return $this->response(['data' => $result]);
}
}
@@ -1,50 +0,0 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\Jobs\Processors\UpdateJobResultProcessor;
use App\Classes\General\Helper;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use App\Http\Resources\ListPackingListJobResource;
class ListPackingListsJobProcessor
{
/** @var ListsPackingLists */
private $listsPackingLists;
/** @var UpdateJobResultProcessor */
private $updateJobResultProcessor;
/**
* ListPackingListsJobProcessor constructor.
* @param ListsPackingLists $listsPackingLists
* @param UpdateJobResultProcessor $updateJobResultProcessor
*/
public function __construct(ListsPackingLists $listsPackingLists, UpdateJobResultProcessor $updateJobResultProcessor)
{
$this->listsPackingLists = $listsPackingLists;
$this->updateJobResultProcessor = $updateJobResultProcessor;
}
/**
* @param ListGenericJobObject $listGenericJobObject
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\JobResourceNotFoundException
*/
public function execute(ListGenericJobObject $listGenericJobObject) {
// $query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page'], 'with_containers_packages' => true]);
$query = $this->listsPackingLists->execute(array_merge($this->listsPackingLists->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page'], 'with_containers_packages' => true]));
foreach ($query->items() as &$item) {
$item['userInfo'] = $listGenericJobObject->getUserInfo();
}
$resultCurrent = Helper::collectionResponse(ListPackingListJobResource::collection($query));
$this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
}
}
@@ -5,7 +5,7 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\ListsTransactions;
use App\Http\Resources\TransactionWithStorageResource;
use App\Http\Resources\TransactionResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
@@ -51,6 +51,6 @@ class ListTransactionsLogic extends AbstractControllerLogic
}
}
return $this->collectionResponse(TransactionWithStorageResource::collection($query));
return $this->collectionResponse(TransactionResource::collection($query));
}
}
@@ -24,7 +24,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransactionDetailType;
use App\Http\Resources\TransactionWithStorageResource;
use App\Http\Resources\TransactionResource;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transaction;
@@ -200,11 +200,6 @@ class CheckStorageInvoiceTransactionProcessor
$this->createStorageInvoiceTransactionDetails($storageInvoice, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded);
}
else if($storageInvoice){
//Additional handling for giving selected storage invoice a waiver
if(isset($storageInvoice->is_waived) && $storageInvoice->is_waived){
$pricePerCBM = 0;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
}
//Additional handling for calculation of numberOfDaysExceeded in the event of the storage already paid
$paymentStorageTransaction = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::APPROVED)->first();
@@ -221,12 +216,10 @@ class CheckStorageInvoiceTransactionProcessor
Log::channel('storage_invoices')->info('Update $transaction->id: '.$transaction->id);
Log::channel('storage_invoices')->info('$storageInvoice->status: '.$storageInvoice->status);
Log::channel('storage_invoices')->info('price_cbm: '.$price_cbm."-".gettype($price_cbm));
Log::channel('storage_invoices')->info('amount: '.$amount);
$proceedToUpdate = false;
if(abs($price_cbm - $amount) > $epsilon && $storageInvoice->status !== ApprovalStatus::COMPLETED){
$paymentTransactions = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::PENDING_SUBMISSION)->get();
if(!$isBackDoorCheck){
if(count($paymentTransactions) > 0){
$this->updatePaymentTransactionViaNonGroupPayment($paymentTransactions);
@@ -236,11 +229,6 @@ class CheckStorageInvoiceTransactionProcessor
}
}
$proceedToUpdate = true;
}
if($proceedToUpdate || ($pricePerCBM == 0 && $amount != 0)){
Log::channel('storage_invoices')->info('proceedToUpdate');
$storageInvoice = $this->updateStorageInvoiceTransaction($storageInvoice, $price_cbm);
$invoiceTransactionDetails = $storageInvoice->transactionDetails()->first();
$this->updateStorageInvoiceTransactionDetails($invoiceTransactionDetails, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded);
@@ -259,7 +247,7 @@ class CheckStorageInvoiceTransactionProcessor
'currentDate' => $resultCurrentDate,
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
'storageInvoice' => new TransactionWithStorageResource($storageInvoice)
'storageInvoice' => new TransactionResource($storageInvoice)
];
return $result;
}
@@ -1,79 +0,0 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Notifications\InvoiceIssuedEmail;
use App\Models\Document;
use App\Models\PackingList;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
class CreateStorageInvoiceDocTransactionFixProcessor
{
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @throws MalformedRequestException
*/
public function execute(PackingList $packingList)
{
/** @var Transaction $invoice_transaction */
$invoice_transaction = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('status', [ApprovalStatus::COMPLETED])->first();
// $this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::STORAGE_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'storage_invoice'
);
// $invouce_transaction_document = $invoice_transaction->documents()->where('document_type', DocumentType::STORAGE_INVOICE)->first();
// if(!$invouce_transaction_document){
/** @var Document $document */
$document = $this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
// $user = $packingList->owner->companyModule->employees()->first();
// if(app()->environment(['production'])) {
// $user->notify(new InvoiceIssuedEmail($user, $packingList));
// }
// }
}
}
@@ -1,36 +0,0 @@
<?php
namespace App\Classes\Notifications;
use App\Models\User;
use Illuminate\Notifications\Messages\MailMessage;
class PermitsReminderEmail extends AbstractEmail
{
/** @var User */
private $user;
private $reminders;
/**
* SendResetPasswordEmail constructor.
* @param User $user
* @param PasswordReset $attempt
*/
public function __construct(User $user, $reminders)
{
$this->user = $user;
$this->reminders = $reminders;
}
public function toMail()
{
return (new MailMessage)
->subject('Permits Renew Remidner Email')
->view('emails.reminder.permits_reminder', ['user' => $this->user, 'reminders' => $this->reminders]);
}
}
+10 -22
View File
@@ -4,9 +4,7 @@ namespace App\Console\Commands;
use App\Classes\Modules\Transactions\Services\FetchesGroup;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor;
use App\Classes\Modules\Transactions\Processors\CreateStorageInvoiceDocTransactionFixProcessor;
use Carbon\Carbon;
use Illuminate\Console\Command;
@@ -32,24 +30,17 @@ class FixGroupPaymentProblem extends Command
/** @var ReleaseGoodsToCustomerProcessor */
private $releaseGoodsToCustomerProcessor;
/** @var FetchesOrder */
private $fetchesOrder;
/** @var CreateStorageInvoiceDocTransactionFixProcessor */
private $createStorageInvoiceDocTransactionProcessor;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(FetchesGroup $fetchesGroup, ReleaseGoodsToCustomerProcessor $releaseGoodsToCustomerProcessor, FetchesOrder $fetchesOrder, CreateStorageInvoiceDocTransactionFixProcessor $createStorageInvoiceDocTransactionProcessor)
public function __construct(FetchesGroup $fetchesGroup, ReleaseGoodsToCustomerProcessor $releaseGoodsToCustomerProcessor)
{
parent::__construct();
$this->fetchesGroup = $fetchesGroup;
$this->releaseGoodsToCustomerProcessor = $releaseGoodsToCustomerProcessor;
$this->fetchesOrder = $fetchesOrder;
$this->createStorageInvoiceDocTransactionProcessor = $createStorageInvoiceDocTransactionProcessor;
}
@@ -65,25 +56,22 @@ class FixGroupPaymentProblem extends Command
$this->info(Carbon::now() . ': Start data patch.');
$start = new Carbon();
/*
$group = $this->fetchesGroup->execute(['id' => 325]);
$this->info('FixGroupPaymentProblem group: '.json_encode($group));
if ($group) {
foreach ($group->groupTransactions as $groupTransaction) {
$invoice = $groupTransaction->transaction;
$this->info('FixGroupPaymentProblem group: '.json_encode($invoice));
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
//$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null);
//if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
//}
}
}
*/
$order = $this->fetchesOrder->execute(['reference' => '729251424']);
$packingLists = $order->destinationWarehousePackages;
foreach ($packingLists as $packingList){
$this->createStorageInvoiceDocTransactionProcessor->execute($packingList, true);
dd(json_encode($packingList));
// $group->status = $status;
// $group->save();
}
@@ -1,74 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Classes\Notifications\PermitsReminderEmail;
use App\Models\PermitsReminder;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
class SendPermitsReminderEmails extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'permitsReminder:send';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send Permits Reminders Email';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$now = now();
$startRange = $now->subDays(3)->startOfDay();
$endRange = $now->copy()->addDays(6)->endOfDay();
$reminders = PermitsReminder::whereDate('reminder_date', '>=', $startRange)
->whereDate('reminder_date', '<=', $endRange)
->pluck('model');
$this->info($this->getTimeStamp() . json_encode($reminders));
$users = User::whereIn(
'email',
[
// 'edmond.wuiming2021@gmail.com',
'anithagurl96@gmail.com'
]
)->get();
foreach ($users as $user) {
$this->info($this->getTimeStamp() . 'Reminder email sent to ' . $user->email);
if (app()->environment('production')) {
$user->notify(new PermitsReminderEmail($user, $reminders));
}
}
}
public function getTimeStamp()
{
return '[' . Carbon::now()->format('Y-m-d H:i:s') . '] - ';
}
}
-5
View File
@@ -67,11 +67,6 @@ class Kernel extends ConsoleKernel
->dailyAt('0:01')
->withoutOverlapping()
->appendOutputTo(storage_path().'/logs/check_storage_invoices.log');
$schedule->command('permitsReminder:send')
->dailyAt('09:30')
->withoutOverlapping()
->appendOutputTo(storage_path().'/logs/permits-reminder-send.log');
}
/**
@@ -1,85 +0,0 @@
<?php
namespace App\Http\Controllers\Imports;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Imports\Services\GenericImport;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\PermitsReminder;
use Carbon\Carbon;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Facades\Excel;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class ImportPermitsReminderController
{
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function import(Request $request)
{
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
$file = json_decode($object->getFiles()[0])->file_info->original->file;
$file = storage_path('app/documents/' . $file);
$import = new GenericImport();
Excel::import($import, $file);
$excelRows = $import->rows->toArray();
$successRows = [];
$returnArray = []; // Initialize the return array
foreach ($excelRows as $row) {
if (is_null($row['expiry_date']) && is_null($row['reminder_date'])) {
continue;
}
$row['expiry_date'] = $this->changeExcelDate($row['expiry_date']);
$row['reminder_date'] = $this->changeExcelDate($row['reminder_date']);
$validator = Validator::make($row, [
'model' => 'required|unique:permits_reminders,model',
'expiry_date' => 'required|date|after_or_equal:today',
'reminder_date' => 'required|date|after_or_equal:today',
]);
if ($validator->fails()) {
$row['status'] = 'failed';
$row['message'] = $validator->errors()->all();
$returnArray[] = $row;
} else {
$row['created_at'] = Carbon::now();
$row['updated_at'] = Carbon::now();
$successRows[] = $row;
}
}
if (!empty($successRows)) {
PermitsReminder::insert($successRows); // Insert only if there are successful rows
}
$successCount = count($successRows);
return response()->json([
'completedRows' => $successCount,
'failedRows' => count($returnArray),
'remark' => "Successful Imported {$successCount} data.",
'data' => $returnArray
]);
}
public function changeExcelDate($date)
{
$formatedDate = DateTime::createFromFormat('d/m/Y', $date);
if ($formatedDate instanceof DateTime) {
return $formatedDate->format('Y-m-d');
}
$unixTime = (($date - 25569) * 86400);
return (new DateTime("@$unixTime"))->format('Y-m-d');
}
}
@@ -1,19 +0,0 @@
<?php
namespace App\Http\Controllers\Jobs;
use App\Classes\Modules\Jobs\ControllersLogic\FetchJobResultLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchJobResultController
{
/**
* @param Request $request
* @param FetchJobResultLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchJobResultLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers\PackingLists;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\PackingLists\ControllersLogic\ListPackingListsJobLogic;
class ListPackingListsJobController
{
/**
* @param Request $request
* @param ListPackingListsJobLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListPackingListsJobLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -1,59 +0,0 @@
<?php
namespace App\Http\Controllers\PermitsReminder;
use App\Classes\Exceptions\RequestValidationException;
use App\Models\PermitsReminder;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class CreatePermitsReminderController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function create(Request $request): JsonResponse
{
// Define validation rules
$rules = [
'model' => 'required|unique:permits_reminders,model',
'expiry_date' => 'required|date|after_or_equal:today',
'reminder_date' => 'required|date|after_or_equal:today',
];
// Perform validation
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
$validationErrors = $validator->errors()->all();
$validationError = implode("<br>", $validationErrors);
// Return validation error response
return response()->json([
'title' => 'Create Permits Reminder Failed',
'message' => $validationError,
"payload" => []
], 422); // 422 Unprocessable Entity status code for validation errors
}
// If validation passes, create the record
$record = PermitsReminder::create([
'expiry_date' => Carbon::parse($request->input('expiry_date'))->format('Y-m-d'),
'reminder_date' => Carbon::parse($request->input('reminder_date'))->format('Y-m-d'),
'model' => $request->input('model'),
]);
$response = [
"title" => "Create Permits Reminder Successful",
"message" => "You have successfully created a Permits Reminder",
"payload" => [
"data" => $record
]
];
return response()->json($response);
}
}
@@ -1,28 +0,0 @@
<?php
namespace App\Http\Controllers\PermitsReminder;
use App\Models\PermitsReminder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeletePermitsReminderController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function delete(Request $request): JsonResponse
{
$record = PermitsReminder::find($request->route('id'));
$record->delete();
$response = [
"title" => "Delete Permits Reminder Successful",
"message" => "You have successfully deleted a Permits Reminder",
"payload" => []
];
return response()->json($response);
}
}
@@ -1,55 +0,0 @@
<?php
namespace App\Http\Controllers\PermitsReminder;
use App\Models\PermitsReminder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListPermitsReminderController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function list(Request $request): JsonResponse
{
$perPage = 10; // Number of items per page
$page = request('page', 1); // Get the current page from the request
// Paginate the PermitsReminder model
$query = PermitsReminder::orderBy('id', 'desc');
$paginator = $query->paginate($perPage, ['*'], 'page', $page);
// Convert paginated data to an array
$data = $paginator->items();
// Create pagination links
$links = [
"first" => $paginator->url(1),
"last" => $paginator->url($paginator->lastPage()),
"prev" => $paginator->previousPageUrl(),
"next" => $paginator->nextPageUrl(),
];
$response = [
"title" => "List Permits Reminder",
"message" => "You have successfully retrieved a list of Permits Reminder",
"payload" => [
'data' => $data,
"links" => $links,
"meta" => [
"current_page" => $paginator->currentPage(),
"from" => $paginator->firstItem(),
"last_page" => $paginator->lastPage(),
"path" => $request->path(),
"per_page" => $paginator->perPage(),
"to" => $paginator->lastItem(),
"total" => $paginator->total(),
]
]
];
return response()->json($response);
}
}
@@ -1,51 +0,0 @@
<?php
namespace App\Http\Controllers\PermitsReminder;
use App\Models\PermitsReminder;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UpdatePermitsReminderController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function update(Request $request): JsonResponse
{
$rules = [
'model' => 'required|unique:permits_reminders,model,' . $request->route('id'),
'expiry_date' => 'required|date|after_or_equal:today',
'reminder_date' => 'required|date|after_or_equal:today',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
$validationErrors = $validator->errors()->all();
$validationError = implode("<br>", $validationErrors);
return response()->json([
'title' => 'Update Permits Reminder Failed',
'message' => $validationError,
"payload" => []
], 422);
}
$record = PermitsReminder::findOrFail($request->route('id'));
$record->model = $request->input('model');
$record->expiry_date = Carbon::parse($request->input('expiry_date'))->format('Y-m-d');
$record->reminder_date = Carbon::parse($request->input('reminder_date'))->format('Y-m-d');
$record->save();
return response()->json([
'title' => 'Permits Reminder Updated',
'message' => 'The permits reminder has been successfully updated.',
"payload" => $record
]);
}
}
+2
View File
@@ -38,11 +38,13 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\WebResponseTimeLog::class,
],
'api' => [
'throttle:300,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\ApiResponseTimeLog::class,
],
'apipub' => [
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ApiResponseTimeLog
{
public function handle(Request $request, Closure $next)
{
// Get route information
$route = $request->route();
$routeName = $route ? $route->getName() : 'undefined';
$uri = $request->getPathInfo();
$startTime = microtime(true); // Start time
$response = $next($request); // Handle the request
$endTime = microtime(true); // End time
$responseTime = $endTime - $startTime; // Calculate the response time
Log::channel('apiResponseTimeLog')->info("\nRequest to route: {$uri} \nRoute name: {$routeName} \nTime Taken: " . number_format($responseTime * 1000, 2) . "ms\n");
return $response;
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class WebResponseTimeLog
{
public function handle(Request $request, Closure $next)
{
// Get route information
$route = $request->route();
$routeName = $route ? $route->getName() : 'undefined';
$uri = $request->getPathInfo();
$startTime = microtime(true); // Start time
$response = $next($request); // Handle the request
$endTime = microtime(true); // End time
$responseTime = $endTime - $startTime; // Calculate the response time
Log::channel('webResponseTimeLog')->info("\nRequest to route: {$uri} \nRoute name: {$routeName} \nTime Taken: " . number_format($responseTime * 1000, 2) . "ms\n");
return $response;
}
}
@@ -4,7 +4,6 @@ namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -18,8 +17,6 @@ class GroupForOrderV2Resource extends JsonResource
*/
public function toArray($request)
{
$payment_transaction = Transaction::where('payment_reference', $this->reference)->first();
return [
'id' => $this->id,
'original_amount' => (float) $this->original_amount,
@@ -36,12 +33,7 @@ class GroupForOrderV2Resource extends JsonResource
'payment_method' => (int)$this->payment_method,
'payment_method_name' => ucwords(PaymentMethodType::PAYMENT_METHODS_ID[$this->payment_method]),
'payment_reference' => $this->reference,
'transactions_ids' => GroupTransactionsForOrderV2Resource::collection($this->groupTransactions),
'payment_transaction' => $payment_transaction ? [
'id' => $payment_transaction->id,
'status' => $payment_transaction->status,
'status_name' => ApprovalStatus::APPROVAL_STATUS_ID[$payment_transaction->status]
] : []
'transactions_ids' => GroupTransactionsForOrderV2Resource::collection($this->groupTransactions)
];
}
}
-22
View File
@@ -1,22 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class JobResultResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'job_id' => $this->job_id,
'result' => $this->result,
];
}
}
@@ -1,47 +0,0 @@
<?php
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Models\Order;
use App\Models\PackingList;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\V2\PackingListV2Resource;
class ListPackingListJobResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$exceptionUsers = in_array($this->userInfo ? $this->userInfo->type : Auth()->user()->type, [RoleTypes::SHADOW_ADMIN, RoleTypes::SUPER_ADMIN]);
$packages = !$this->packingLists()->exists() || $exceptionUsers ? $this->packages : $this->packingLists->first()->packages;
return [
'id' => $this->id,
'claimant_id' => $this->claimant_id,
'reference' => $this->reference,
'status' => $this->status,
'transport' => new TransportResource($this->transports()->first()),
'type' => $this->type,
'receive_packing_list' => $this->when($this->type === PackingListType::SHIPPING_PACKING_LIST, new PackingListV2Resource(PackingList::where('reference', $this->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first(), $this->userInfo)),
// 'packages' => PackageResource::collection($packages),
// $this->mergeWhen($this->owner instanceof Order, [
// 'order' => New OrderResource($this->owner)
// ]),
'container' => new ContainerResource($this->containers->first()),
'packages' => PackageWithoutOrderResource::collection($packages),
$this->mergeWhen($this->owner instanceof Order, [ 'order' => New OrderResource($this->owner) ]),
'shipping_transaction' => new TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereNotIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED])->first()),
'suspended_invoice' => new TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->first()),
// 'suspended_invoices' => TransactionResource::collection($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->get()),
];
}
}
@@ -37,7 +37,6 @@ class MappableTransactionResource extends JsonResource
'owner_type' => Transaction::class,
'owner_id'=> $this->id,
'owner_reference'=> $reference,
'created_at'=> $this->created_at, // invoice date
];
}
}
@@ -27,19 +27,16 @@ class MappableTransactionWithDetailsResource extends JsonResource
'order_reference' => null,
'bill_no' => null,
'marking' => null,
'created_at' => null
];
if ($this->type === TransactionType::PAYMENT) {
$order = $this->owner->owner->owner;
$data['order_reference'] = $order->reference;
$data['debtor_code'] = $order->companyModule->company->debtor;
$data['created_at'] = $this->owner->created_at; // invoice date
} elseif (in_array($this->type, [TransactionType::GROUP_PAYMENT, TransactionType::TOP_UP])) {
$connection = $this->owner->owner->inviters()->withPivot('invitee_reference')->first();
$data['marking'] = $connection ? $connection->pivot->invitee_reference : '';
$data['bill_no'] = $this->bill_no;
$data['created_at'] = $this->created_at;
} else {
$payments = $this->transactions()
->payments()->where('status', ApprovalStatus::APPROVED)
@@ -57,7 +54,6 @@ class MappableTransactionWithDetailsResource extends JsonResource
'type' => $payment->type,
'marking' => null,
'amount' => $payment->amount,
'created_at' => $this->created_at
];
})->toArray();
} else {
@@ -65,7 +61,6 @@ class MappableTransactionWithDetailsResource extends JsonResource
$data['amount'] = 'Transaction Type not allowed';
$data['transaction_type'] = $this->type;
$data['payment_transactions'] = null;
$data['created_at'] = null;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ class OrderV2Resource extends JsonResource
'address' => new AddressResource($this->addresses()->where('status', '=', ApprovalStatus::APPROVED)->first()),
'address_change_request' => new AddressResource($this->addressesPendingVerification()->first()),
'invoices' => $this->whenLoaded('packingLists', function() {
return TransactionWithStorageResource::collection($this->transactions()->whereNotIn('transactions.status', [0, 1])->whereIn('transactions.type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get());
return TransactionResource::collection($this->transactions()->whereNotIn('transactions.status', [0, 1])->whereIn('transactions.type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get());
}),
'storages' => $this->storages ? $this->storages : null, //from middleware
'remarks' => RemarkResource::collection($this->remarks),
@@ -1,38 +0,0 @@
<?php
namespace App\Http\Resources;
use App\Models\Order;
use App\Models\PackingList;
use Illuminate\Http\Resources\Json\JsonResource;
class PackageWithoutOrderResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'type' => $this->type,
'description' => $this->description,
'width' => floatval($this->width),
'height' => floatval($this->height),
'length' => floatval($this->length),
'weight' => $this->weight,
'quantity' => $this->quantity,
'cbm' => (($this->width / 100) * ($this->height / 100) * ($this->length / 100)) * $this->quantity,
'reference' => $this->packingList->reference,
'status' => $this->status,
// $this->mergeWhen($originalPackingList->owner instanceof Order, [
// 'order' => New OrderResource($originalPackingList->owner)
// ]),
// 'container' => new ContainerResource($originalPackingList->containers()->first()),
// 'transport' => new TransportResource($originalPackingList->transports()->first())
];
}
}
+18 -3
View File
@@ -3,15 +3,14 @@
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Group;
use App\Models\Order;
use App\Models\Transaction;
use App\Models\Wallet;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
class TransactionResource extends JsonResource
{
/**
@@ -24,6 +23,8 @@ class TransactionResource extends JsonResource
{
$order = null;
$groupTransactions = null;
$group_payment_attempts = null;
$group_payment_expired = null;
if ($this->owner instanceof Transaction) {
if ($this->owner) {
@@ -35,6 +36,12 @@ class TransactionResource extends JsonResource
if ($this->owner) {
$order = new OrderResource($this->owner->owner);
}
if($this->groups){
$group_payment_attempts = GroupForOrderV2Resource::collection($this->groups->whereNotIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]));
$group_payment_expired = GroupForOrderV2Resource::collection($this->groupsWithTrashed->whereIn('status', [ApprovalStatus::EXPIRED]));
}
} else {
$group = Group::where('reference', $this->payment_reference)->first();
if ($group) {
@@ -48,7 +55,9 @@ class TransactionResource extends JsonResource
'owner_type' => $this->owner_type,
'order' => $order,
'group_transactions' => $groupTransactions,
'group_reference' => $groupTransactions ? ($group ? $group->reference : null ) : null,
'group_reference' => $groupTransactions ? ($group ? $group->reference : null ) : null,
'groups_payment_attempts' => $group_payment_attempts,
'groups_payment_expired' => $group_payment_expired,
'documents' => $groupTransactions ? DocumentResource::collection($this->documents->where('status', ApprovalStatus::PENDING_VERIFICATION)) : DocumentResource::collection($this->documents),
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
@@ -71,6 +80,11 @@ class TransactionResource extends JsonResource
->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)
->get()
),
'payments_expired' => TransactionResource::collection(
$this->transactions()
->payments()->where('status', ApprovalStatus::EXPIRED)
->get()
),
'payment_history' => TransactionResource::collection(
$this->transactions()
->payments()
@@ -78,6 +92,7 @@ class TransactionResource extends JsonResource
->get()
),
'remarks' => RemarkResource::collection($this->remarks),
'storages' => $this->storages ? $this->storages : null, //from middleware
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:s:i'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y'),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y')
@@ -1,128 +0,0 @@
<?php
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Group;
use App\Models\Transaction;
use App\Models\Wallet;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Log;
class TransactionWithStorageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$order = null;
$groupTransactions = null;
$group_payment_attempts = null;
$groupPaymentAttemptsFiltered = [];
$group_payment_expired = null;
$group_payment_history = null;
$groupTotalAmount = 0;
if ($this->owner instanceof Transaction) {
if ($this->owner) {
if ($this->owner->owner) {
$order = new OrderResource($this->owner->owner->owner);
}
}
} else if (!($this->owner instanceof Transaction) && !($this->owner instanceof Wallet)) {
if ($this->owner) {
$order = new OrderResource($this->owner->owner);
}
if($this->groups){
$group_payment_attempts = GroupForOrderV2Resource::collection($this->groups->whereNotIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]));
$group_payment_expired = GroupForOrderV2Resource::collection($this->groupsWithTrashed->whereIn('status', [ApprovalStatus::EXPIRED]));
$group_payment_history = GroupForOrderV2Resource::collection($this->groups->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED]));
}
} else {
$group = Group::where('reference', $this->payment_reference)->first();
if ($group) {
$groupTransactions = GroupTransactionResource::collection($group->groupTransactions);
}
}
$ts = $this->groups->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION])->last();
if ($ts) {
$paymentTransaction = Transaction::where('payment_reference', $ts->reference)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION])->first();
if($paymentTransaction){
$groupTotalAmount = (double) $this->amount;
foreach ($group_payment_history as $key => $value) {
if ($value->id === $ts->id && $value->reference === $ts->reference) {
unset($group_payment_history[$key]);
}
}
foreach ($group_payment_attempts as $key => $value) {
if ($value->id === $ts->id && $value->reference == $ts->reference) {
$groupPaymentAttemptsFiltered[$key] = $value;
}
}
}
}
return [
'id' => $this->id,
'owner_type' => $this->owner_type,
'order' => $order,
'group_transactions' => $groupTransactions,
'group_reference' => $groupTransactions ? ($group ? $group->reference : null ) : null,
'groups_payment_attempts' => $groupPaymentAttemptsFiltered,
'groups_payment_expired' => $group_payment_expired,
'groups_payment_history' => $group_payment_history,
'documents' => $groupTransactions ? DocumentResource::collection($this->documents->where('status', ApprovalStatus::PENDING_VERIFICATION)) : DocumentResource::collection($this->documents),
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
'amount' => (double) $this->amount,
'payment_method' => (int) $this->payment_method,
'payment_reference' => $this->payment_reference,
'outstanding' => (double) $this->amount - ($this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount')),
'floating' => $group_payment_attempts ? $groupTotalAmount : (double) $this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION])->sum('amount'),
'service_charge' => (double) $this->service_charge,
'tax' => (double) $this->tax,
'original_amount' => (double) $this->original_amount,
'currency' => new CurrencyResource($this->currency),
'original_currency' => new CurrencyResource($this->original_currency),
'currency_rate' => (double) $this->currency_rate,
'status' => (int) $this->status,
'details' => TransactionDetailResource::collection($this->transactionDetails),
'transactions' => TransactionResource::collection($this->transactions),
'payment_attempts' => TransactionResource::collection(
$this->transactions()
->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)
->get()
),
'payments_expired' => TransactionResource::collection(
$this->transactions()
->payments()->where('status', ApprovalStatus::EXPIRED)
->get()
),
'payment_history' => TransactionResource::collection(
$this->transactions()
->payments()
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED])
->get()
),
'remarks' => RemarkResource::collection($this->remarks),
'storages' => $this->storages ? $this->storages : null, //from middleware
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:s:i'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y'),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y')
];
}
}
@@ -1,54 +0,0 @@
<?php
namespace App\Http\Resources\V2;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Models\Order;
use App\Models\PackingList;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources as V1;
class PackingListV2Resource extends JsonResource
{
private $userInfo;
public function __construct($resource, $userInfo = null)
{
parent::__construct($resource);
$this->userInfo = $userInfo;
}
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$user = $this->userInfo ? $this->userInfo : Auth()->user();
$exceptionUsers = in_array($user->type, [RoleTypes::SHADOW_ADMIN, RoleTypes::SUPER_ADMIN]);
$packages = !$this->packingLists()->exists() || $exceptionUsers ? $this->packages : $this->packingLists->first()->packages;
return [
'id' => $this->id,
'claimant_id' => $this->claimant_id,
'reference' => $this->reference,
'status' => $this->status,
'transport' => new V1\TransportResource($this->transports()->first()),
'type' => $this->type,
'receive_packing_list' => $this->when($this->type === PackingListType::SHIPPING_PACKING_LIST, new PackingListV2Resource(PackingList::where('reference', $this->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first(), $user)),
'packages' => V1\PackageResource::collection($packages),
$this->mergeWhen($this->owner instanceof Order, [
'order' => New V1\OrderResource($this->owner)
]),
'shipping_transaction' => new V1\TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereNotIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED])->first()),
'suspended_invoice' => new V1\TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->first()),
// 'suspended_invoices' => V1\TransactionResource::collection($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->get()),
];
}
}
-13
View File
@@ -1,13 +0,0 @@
<?php
namespace App\Models;
class JobResult extends AbstractModel
{
protected $table = 'job_results';
public $fillable = [
'job_id',
'result'
];
}
-33
View File
@@ -1,33 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
class PermitsReminder extends Model
{
use SoftDeletes;
protected $table = 'permits_reminders';
protected $dates = ['deleted_at'];
protected $fillable = ['model', 'expiry_date', 'reminder_date'];
public function getExpiryDateAttribute($value)
{
return $this->attributes['expiry_date'] === null ? NULL : Carbon::parse($this->attributes['expiry_date'])->format('d-m-Y');
}
public function getReminderDateAttribute($value)
{
return $this->attributes['reminder_date'] === null ? NULL : Carbon::parse($this->attributes['reminder_date'])->format('d-m-Y');
}
public function getCreatedAtAttribute($value)
{
return $this->attributes['created_at'] === null ? NULL : Carbon::parse($this->attributes['created_at'])->format('d-m-Y');
}
}
+12
View File
@@ -112,6 +112,18 @@ return [
'path' => storage_path('logs/paymentUnknownOrderLog.log'),
'level' => 'info',
],
'apiResponseTimeLog' => [
'driver' => 'single',
'path' => storage_path('logs/apiResponseTime.log'),
'level' => 'info',
],
'webResponseTimeLog' => [
'driver' => 'single',
'path' => storage_path('logs/webResponseTimeLog.log'),
'level' => 'info',
],
],
];
@@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJobResultsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('job_results', function (Blueprint $table) {
$table->id();
$table->string('job_id', 50);
$table->longText('result')->nullable();
$table->timestamps();
// $table->foreign('job_id')->references('id')->on('jobs')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('job_results');
}
}
@@ -1,36 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddNewColumnToJobResultsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('job_results', function (Blueprint $table) {
$table->longText('url')->after('result')->nullable();
$table->string('job_command_name')->after('url')->nullable();
$table->longText('job_command')->after('job_command_name')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('job_results', function (Blueprint $table) {
$table->dropColumn('url');
$table->dropColumn('job_command_name');
$table->dropColumn('job_command');
});
}
}
@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddNewColumn2ToJobResultsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('job_results', function (Blueprint $table) {
$table->string('request_signature')->after('job_id')->nullable();
$table->string('result_signature')->after('request_signature')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('job_results', function (Blueprint $table) {
$table->dropColumn('request_signature');
$table->dropColumn('result_signature');
});
}
}
@@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePermitsRemindersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('permits_reminders', function (Blueprint $table) {
$table->id();
$table->string('model')->nullable();
$table->timestamp('expiry_date')->nullable();
$table->timestamp('reminder_date')->nullable();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('permits_reminders');
}
}
@@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsWaivedToTransactionsLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('transaction_logs', function (Blueprint $table) {
$table->boolean('is_waived')->nullable()->after('status')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('transaction_logs', function (Blueprint $table) {
$table->dropColumn('is_waived');
});
}
}
@@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsWaivedToTransactionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('transactions', function (Blueprint $table) {
$table->boolean('is_waived')->nullable()->after('status')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('transactions', function (Blueprint $table) {
$table->dropColumn('is_waived');
});
}
}
Vendored
+1 -2
View File
@@ -37,7 +37,6 @@ gulp.task('vendorCss', () => {
.pipe(plugins.cleanCss())
.pipe(plugins.replace('../../../font-awesome/', './'))
.pipe(plugins.replace('../../jquery-ui-dist/', ''))
//.pipe(plugins.replace(/background-image:url\(\.\.\/\.\./g, `background-image:url(`)) //cief todo: gulp
.pipe(gulp.dest(pkg.paths.build.css));
});
@@ -116,4 +115,4 @@ gulp.task('watch', (done) => {
gulp.watch(pkg.globs.sourceJs, gulp.series('sourceJs'));
gulp.watch(pkg.globs.sourceJs, gulp.series('sourceFonts'));
done();
});
});
@@ -5,7 +5,7 @@
<div class="col-auto">
<div class="row">
<div class="col">
<h6 v-if="item" class="no-margin fs-12 text-black">{{item.street_one}} {{item.street_two}}, {{item.district.name}}, {{item.post_code}} {{item.state.name}}, {{item.country.name}}</h6>
<h6 class="no-margin fs-12 text-black">{{item.street_one}} {{item.street_two}}, {{item.district.name}}, {{item.post_code}} {{item.state.name}}, {{item.country.name}}</h6>
</div>
</div>
</div>
@@ -3,7 +3,7 @@
<div class="col bg-white padding-40 b-rad-lg">
<div class="row m-b-10">
<div class="col text-center">
<p>Please set the approximate dates of below.</p>
<p>Plese set the approximate dates of below.</p>
</div>
</div>
<div class="row">
@@ -12,13 +12,13 @@
<div class="col p-l-0 p-r-10">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.etd">
<label class="text-primary">Etd</label>
<date-picker-component v-model.lazy="parameters.etd"></date-picker-component>
<date-picker-component :parameters="parameters" :value="'etd'"></date-picker-component>
</validation-wrapper-component>
</div>
<div class="col p-r-0 p-l-10">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.eta">
<label class="text-primary">Eta</label>
<date-picker-component v-model.lazy="parameters.eta"></date-picker-component>
<date-picker-component :parameters="parameters" :value="'eta'"></date-picker-component>
</validation-wrapper-component>
</div>
</div>
@@ -43,8 +43,8 @@
data() {
return {
parameters: {
etd: this.data.transport.current_schedule.etd,
eta: this.data.transport.current_schedule.eta,
etd: this.etd,
eta: this.eta,
}
};
},
@@ -57,4 +57,4 @@
mixins: [modalFormHandler]
}
</script>
</script>
@@ -1,207 +0,0 @@
<template>
<transition-component group enter-class="animate__animated animate__fadeInUp animate__delay-1 animate__faster p-r-30" leave-class="animate__animated animate__fadeOutDown animate__faster p-r-30" style="min-height: 300px;width:100%">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
<div class="row" key="2" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row">
<div class="col">
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-show="!$store.getters.getListData(section).length && !isLoading && emptyListSection">
<div class="col-10">
<div class="row align-items-center justify-content-center hint-text">
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"/></div>
</div>
<div class="row text-center">
<div class="col">
<div class="row m-t-20">
<div class="col">
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
</div>
</div>
<div class="row m-t-5 align-items-center justify-content-center">
<div class="col">
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="!isLoading">
<div class="col">
<div class="list disable-text-selection" data-check-all="checkAll">
<div class="row" ref="list" v-for="item in $store.getters.getListData(section)" v-bind:key="item.id" :data="item">
<div class="col">
<slot name="list" :data="item"></slot>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="!isLoading">
<div class="col">
<pagination-component :section="section" class="mb-5" ref="pagination"></pagination-component>
</div>
</div>
</div>
</div>
</div>
</div>
</transition-component>
</template>
<script>
import requestV2 from '../../../general/mixins/aws/requestV2'
export default {
props: {
section:{
type: String,
required: true
},
endpoint: {
type: String,
required: true
},
options: {
default () {
return {}
}
},
emptyListSection: {
type: Boolean,
default: true,
}
},
data(){
return {
filters: this.options,
pollingInterval: null,
isPolling: false,
isFetchingResult: false,
isLoading: false,
}
},
created(){
this.setDecoratorDefault();
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters}); //cief todo: Uncaught (in promise) null
},
computed: {
pendingList () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingList(inComplete){
if(inComplete){
this.fetchList();
}
}
},
methods: {
fetchList(){
let listDecorators = this.$store.getters.getListDetails(this.section);
let url = this.endpoint + '?page=' + listDecorators.page + '&filters=' + JSON.stringify(listDecorators.filters);
this.isLoading = true;
this.submitJob(url);
},
successHandler(response){
let result = JSON.parse(response.payload.data.result);
result.meta = {
current_page: result.meta.current_page,
first_page_url: result.meta.first_page_url,
from: result.meta.from,
last_page: result.meta.last_page,
last_page_url: result.meta.last_page_url,
next_page_url: result.meta.next_page_url,
path: result.meta.path,
per_page: result.meta.per_page,
prev_page_url: result.meta.prev_page_url,
to: result.meta.to,
total: result.meta.total
};
this.stopPolling();
this.$store.dispatch('completeList', {'name': this.section, 'data': result.data});
this.$refs.pagination.makePagination(result.meta, result.links);
this.isLoading = false;
},
errorHandler(error){
this.isFetchingResult = false;
this.isPolling = false;
},
startPolling(jobId, maxAttempts = 8) {
let attempts = 0;
let interval = 10000; // Initial interval
const resetPollingInterval = (customInterval) => {
this.pollingInterval = setInterval(pollJobResult, customInterval);
};
const pollJobResult = () => {
if (this.isPolling || this.isFetchingResult) {
return;
}
this.isPolling = true;
attempts++;
if(attempts === 1){
this.stopPolling();
resetPollingInterval(5000);
}
if (attempts > maxAttempts) {
this.stopPolling();
this.isLoading = false;
console.log(`Reached maximum attempts (${maxAttempts}). Polling stopped.`);
return;
}
if(attempts === maxAttempts){
this.fetchJobResult(jobId, true);
}
else{
this.fetchJobResult(jobId);
}
};
// pollJobResult(); // Initial call
this.pollingInterval = setInterval(pollJobResult, interval);
},
stopPolling() {
clearInterval(this.pollingInterval);
this.pollingInterval = null;
this.isPolling = false;
this.isFetchingResult = false;
},
submitJob(url){
try {
this.$store.dispatch('crudRequestV2', {endpoint: url, method: 'get'}).then(response => {
let success = response.ok;
response.json().then(response => {
if(!success){return;}
let jobId = response.payload.data.job_id;
if(jobId){
this.startPolling(jobId);
}
});
})
} catch (error) {
console.error('Error submitJob', error);
}
},
fetchJobResult(jobId, isLastAttempt = false) {
// console.log('fetchJobResult: ', jobId);
this.isFetchingResult = true;
try {
let anotherEndpoint = route('api.job.fetch', jobId);
if(isLastAttempt){
anotherEndpoint = route('api.job.fetch.last.attempt', jobId, isLastAttempt);
}
this.poll(anotherEndpoint, 'get', this.section, false, false); //cief todo: Uncaught (in promise) null
} catch (error) {
console.error('Error fetchJobResult', error);
}
}
},
mixins: [requestV2]
}
</script>
@@ -34,17 +34,11 @@
</div>
</div>
</div>
<!-- CIEF TODO: For easy revert to old code -->
<list-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
</template>
</list-component>
<!-- <list-polling-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list.job')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
</template>
</list-polling-component> -->
</div>
</div>
</template>
@@ -1,90 +0,0 @@
<template>
<div class="row m-t-20" @keyup.enter="search">
<div class="col">
<div class="row">
<div class="col-12 col-md">
<div class="row m-b-15">
<div class="col">
<div class="row">
<div class="col p-r-0">
<div class="form-group no-margin form-group-default b-rad-none">
<label class="text-primary">Order Number Like</label>
<input type="text" class="form-control" v-model="marking" />
</div>
</div>
</div>
</div>
<div class="col-auto p-l-0 p-r-0">
<div class="btn btn-primary b-rad-none" @click="search">
<i class="fa fa-search lh-40"></i>
</div>
</div>
<div class="col-auto p-l-0">
<div class="btn btn-secondary b-rad-none" @click="reset">
<i class="fa fa-remove lh-40"></i>
</div>
</div>
</div>
</div>
<div class="col-12 col-md">
<div class="row" v-if="with_export">
<div class="col">
<download-billing-with-dates-component :section="section"></download-billing-with-dates-component>
</div>
</div>
</div>
</div>
<!-- CIEF TODO: For easy revert to old code -->
<!-- <list-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
</template>
</list-component> -->
<list-polling-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list.job')" :options="options">
<template slot="list" slot-scope="{data}">
<single-admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></single-admin-payments-billing-component>
</template>
</list-polling-component>
</div>
</div>
</template>
<script>
export default {
props: {
invoice_status: {
type: String,
required: true
},
options: {
default () {
return {}
}
},
section:{
type: String,
required: true
},
with_export:{
type: Boolean,
default: false
}
},
data(){
return {
marking: '',
currentKey: 1,
}
},
methods: {
search() {
this.options['order_marking_in'] = this.marking;
this.currentKey+=1;
},
reset() {
this.marking = '';
delete(this.options['order_marking_in']);
this.currentKey+=1;
},
},
}
</script>
@@ -102,7 +102,7 @@
<div class="col-12 col-md-7 padding-20">
<div class="row bg-master-lightest">
<div class="col">
<div v-for="(groupItem, index) in items" class="row bg-master-lightest" v-if="groupItem.groups_payment_attempts.length && groupItem.type == 1 && groupTransactionsExist(items, groupItem.groups_payment_attempts)">
<div v-for="(groupPaymentAttemptItem, index) in items" class="row bg-master-lightest" v-if="groupPaymentAttemptItem.groups_payment_attempts.length && groupPaymentAttemptItem.type == 1 && groupTransactionsExist(items, groupPaymentAttemptItem.groups_payment_attempts)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
@@ -111,12 +111,12 @@
</div>
<div class="row">
<div class="col">
<single-group-payment-transaction-details-component v-for="group in groupItem.groups_payment_attempts" v-bind:key="group.id" :data="group" :section="section"></single-group-payment-transaction-details-component>
<shipping-transaction-component v-for="group in groupPaymentAttemptItem.groups_payment_attempts" v-bind:key="group.id" :data="group" :section="section"></shipping-transaction-component>
</div>
</div>
</div>
</div>
<div v-for="(groupItem, index) in items" class="row bg-master-lightest" v-if="groupItem.groups_payment_expired.length && groupItem.type == 1 && groupTransactionsExist(items, groupItem.groups_payment_expired)">
<div v-for="(groupPaymentAttemptItem, index) in items" class="row bg-master-lightest" v-if="groupPaymentAttemptItem.groups_payment_expired.length && groupPaymentAttemptItem.type == 1 && groupTransactionsExist(items, groupPaymentAttemptItem.groups_payment_expired)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
@@ -125,21 +125,7 @@
</div>
<div class="row">
<div class="col">
<payment-expired-component v-for="group in groupItem.groups_payment_expired" v-bind:key="group.id" :data="group" :section="section"></payment-expired-component>
</div>
</div>
</div>
</div>
<div v-for="(groupItem, index) in items" class="row bg-master-lightest" v-if="groupItem.groups_payment_history.length && groupItem.type == 1 && groupTransactionsExist(items, groupItem.groups_payment_history)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment History</div>
</div>
</div>
<div class="row">
<div class="col">
<single-group-payment-history-transaction-details-component v-for="group in groupItem.groups_payment_history" v-bind:key="group.id" :data="group" :section="section"></single-group-payment-history-transaction-details-component>
<payment-expired-component v-for="group in groupPaymentAttemptItem.groups_payment_expired" v-bind:key="group.id" :data="group" :section="section"></payment-expired-component>
</div>
</div>
</div>
@@ -230,7 +216,7 @@
<div class="col">
<div class="btn btn-sm all-caps b-rad-none btn-success btn-block requestModal" data-type="makePayment">Make Payment</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="makePayment">
<group-payment-form-component :section="section" :selectedIds="selectedIds" :sumAmount="totalOutstanding.toFixed(2)" :showManualPayment="true"></group-payment-form-component>
<group-payment-form-component :section="section" :selectedIds="selectedIds" :sumAmount="totalOutstanding.toFixed(2)"></group-payment-form-component>
</modal-component>
</div>
</div>
@@ -1,322 +0,0 @@
<template>
<div class="row m-b-15 m-l-5 m-r-10 parentContainer">
<div class="col bg-white rounded">
<div class="row">
<div class="col padding-20">
<div class="row align-items-center">
<div class="col">
<p class="no-margin fs-10 all-caps">Marking</p>
<div class="no-margin">
<div v-if="item.order">
<a :href="route('customer.profile', item.order.company_module.marking)">{{item.order.company_module.marking}}</a>/<a :href="route('order.show', item.order.reference)">{{item.order.reference}}</a>
<p>{{item.loading_days_ago}}</p>
</div>
<div v-else class="text-danger">Unclaimed Packing List</div>
</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Container</p>
<div v-if="item.container"> {{item.container.container_reference}}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Invoice Date</p>
<div v-if="!item.shipping_transaction">n/a</div>
<div v-if="item.shipping_transaction"> {{ item.shipping_transaction.updated_at }}</div>
</div>
<div class="col">
<div v-if="item.order">
<p class="no-margin fs-10 all-caps">Address</p>
<div>{{ item.order.address.post_code_area}}</div>
<div>{{ item.order.address.district.name +' '+item.order.address.postcode+' '+item.order.address.state.name }}</div>
</div>
<div v-else class="text-danger">Unclaimed</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Status</p>
<div class="all-caps">{{ invoice_status }}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Amount</p>
<div v-if="!item.shipping_transaction">n/a</div>
<div v-if="item.shipping_transaction">MYR {{ item.shipping_transaction.amount.toFixed(2) }}</div>
</div>
<div class="col-auto p-l-0 p-r-0" v-if="['Pending Payment', 'Paid Invoice', 'Suspended Invoice'].includes(invoice_status)">
<div v-if="item.shipping_transaction">
<div v-if="item.shipping_transaction.documents.length">
<div v-for="file in item.shipping_transaction.documents[0].files" v-bind:key="file.id" class="col-auto no-padding">
<document-file-viewer-component :file="file">
<template slot="button">
<div class="btn bg-grey no-border muted">
<i class="fa fa-file-pdf-o"></i>
</div>
</template>
</document-file-viewer-component>
</div>
</div>
<div v-else>
<div class="btn bg-grey no-border muted invisible">
<i class="fa fa-file-pdf-o"></i>
</div>
</div>
</div>
</div>
<div class="col-auto">
<div class="row text-center parentContainer m-b-10" v-if="['Pending Invoice'].includes(invoice_status) && !item.receive_packing_list" >
<div class="col">
<div class="requestModal pointer btn btn-primary btn-xs" data-type="addWarehouseTransport">
Add Warehouse Transport
</div>
<modal-component class="animate_animated animatefast animate_fadeIn" styleType="fill-in" type="addWarehouseTransport">
<create-warehouse-transport-form-component :packinglistId="item.id" :section="section"></create-warehouse-transport-form-component>
</modal-component>
</div>
</div>
<div class="row">
<div class="col">
<div class="btn bg-grey no-border" @click="expanded = !expanded" v-if="['Pending Approval', 'Pending Payment'].includes(invoice_status)">
<i class="fa" :class="{'fa-angle-down': !expanded, 'fa-angle-up': expanded}" ></i>
</div>
<div v-if="!item.shipping_transaction">
<div v-if="item.order">
<div v-if="!item.order.company_module.billingAddress">
<div class="btn btn-primary btn-xs pointer requestModal btn-block" data-type="billingAddressComponent">Add Billing Address</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" size="extra-large" styleType="fill-in" type="billingAddressComponent">
<address-form-component :id="item.order.company_module.id" :section="section" :type=1></address-form-component>
</modal-component>
</div>
<div class="row" v-if="item.order.company_module.billingAddress">
<div class="col">
<div class="col-auto requestModal pointer" data-type="editBillingAddress">
<i class="fa fa-edit pointer fa-fw m-l-5"></i> Edit billing Address
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" size="extra-large" styleType="fill-in" type="editBillingAddress">
<div class="row">
<div class="col bg-white">
<address-form-component :id="item.order.company_module.id" :data="item.order.company_module.billingAddress" section="editBillingAddress"></address-form-component>
</div>
</div>
</modal-component>
</div>
</div>
<div v-if="!item.order.address.post_code_area">
<div class="btn btn-xs btn-primary pointer m-t-10 requestModal btn-block" data-type="defineLocation">Define Location</div>
<modal-component class="animate_animated animatefast animate_fadeIn" styleType="fill-in" type="defineLocation">
<declare-postcode-area-form-component :data="item.order.address" :section="section"></declare-postcode-area-form-component>
</modal-component>
</div>
<div v-if="item.order.company_module.billingAddress && item.order.address.post_code_area" class="btn btn-outline-primary btn-lg pointer" @click="generateInvoice()">Generate Invoice</div>
</div>
<div v-else>
<div class="btn btn-outline-primary btn-lg pointer invisible">Generate Invoice</div>
</div>
</div>
<div class="btn bg-grey no-border muted requestModal" v-if="item.shipping_transaction && invoice_status == 'Pending Approval'" data-type="confirmInvoice">
<i class="fa fa-check fs-12"></i>
</div>
<div class="btn bg-grey no-border muted requestModal" v-if="item.shipping_transaction && invoice_status == 'Pending Approval'" data-type="deleteInoive">
<i class="fa fa-close fs-12"></i>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="confirmInvoice">
<approve-shipping-invoice-form-component :section="section" :data="data"></approve-shipping-invoice-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteInoive">
<delete-shipping-invoice-form-component :section="section" :data="data"></delete-shipping-invoice-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded" v-if="item.shipping_transaction && ['Pending Approval', 'Suspended Invoice'].includes(invoice_status)">
<div class="col p-b-10">
<div class="row">
<div class="col p-l-20 p-r-20 p-t-10 p-b-10">
<div class="row align-items-center">
<div class="col">
<p class="no-margin fs-10 all-caps">Container Reference</p>
<div v-if="item.packages.length">{{ item.container ? item.container.container_reference : 'n/a' }}</div>
<div v-else>n/a</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Due Date</p>
<div v-if="item.packages.length">
<div v-if="item.container">
<div v-if="item.container.transport">{{ item.container.transport.drop_date == null ? item.container.transport.current_schedule.etd : item.container.transport.drop_date }}</div>
<div v-else>n/a</div>
</div>
<div v-else>n/a</div>
</div>
<div v-else>n/a</div>
</div>
<!-- <div class="col">
<p class="no-margin fs-10 all-caps">Paid Date</p>
<div>n/a</div>
</div> -->
<div class="col">
<p class="no-margin fs-10 all-caps">Total CBM</p>
<div>{{ (parseFloat(cbm) + parseFloat(overweight)).toFixed(3) }}</div>
</div>
</div>
</div>
</div>
<h5 class="text-underline text-center">Invoice Details</h5>
<invoice-items-form-component :data="item.shipping_transaction" :section="section"></invoice-items-form-component>
<div class="row">
<div class="col">
<p class="no-margin fs-10 all-caps">Subtotal</p>
<div>{{ item.shipping_transaction.amount - item.shipping_transaction.service_charge - item.shipping_transaction.tax }}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Service Charges</p>
<div>{{ item.shipping_transaction.service_charge }}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Tax</p>
<div>{{ item.shipping_transaction.tax }}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Total</p>
<div>{{ item.shipping_transaction.amount }}</div>
</div>
</div>
</div>
</div>
<div class="row b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded" v-if="item.shipping_transaction && invoice_status == 'Pending Payment'">
<div class="col-12 col-md-7 padding-20">
<div class="row bg-master-lightest h-100">
<div class="col">
<div class="row bg-master-lightest" v-if="item.shipping_transaction.payment_attempts.length">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div class="font-head fs-10 all-caps">Payment Attempt</div>
</div>
</div>
<div class="row">
<div class="col">
<shipping-transaction-component v-for="item in item.shipping_transaction.payment_attempts" v-bind:key="item.id" :data="item" ></shipping-transaction-component>
</div>
</div>
</div>
</div>
<div class="row bg-master-lightest" v-if="item.shipping_transaction.payment_history.length">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div class="font-head fs-10 all-caps">Payment History</div>
</div>
</div>
<div class="row">
<div class="col">
<payment-history-component v-for="item in item.shipping_transaction.payment_history" v-bind:key="item.id" :data="item" ></payment-history-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-5 padding-20 parentContainer">
<div class="row bg-master-lightest h-100">
<div class="col">
<div class="row padding-10">
<div class="col">
<div class="row align-items-end m-b-10 text-complete">
<div class="col">
<div class="font-heading all-caps fs-12">Total Amount:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">MYR {{(Math.round((item.shipping_transaction.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-success hide">
<div class="col">
<div class="font-heading all-caps fs-12">Paid Total:</div>
</div>
<div class="col-auto text-right">
<!-- <div class="font-heading fs-12">MYR {{(Math.round((item.shipping_transaction.paid_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div> -->
<div class="font-heading fs-12">Paid Total</div>
</div>
</div>
<div class="row align-items-end m-b-10 hide">
<div class="col">
<div class="font-heading all-caps fs-12">Floating Amount:</div>
</div>
<div class="col-auto text-right">
<!-- <div class="font-heading fs-12">MYR {{(Math.round((item.shipping_transaction.floating_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div> -->
<div class="font-heading fs-12">Floating Amount</div>
</div>
</div>
<div class="row align-items-end bold text-danger">
<div class="col">
<div class="font-heading all-caps fs-12">OutStanding Total:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">MYR {{(Math.round((item.shipping_transaction.outstanding + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row m-t-20" v-if="item.shipping_transaction.outstanding > 0">
<div class="col">
<div class="btn btn-sm all-caps b-rad-none btn-success btn-block requestModal" data-type="makePayment">Make Payment</div>
</div>
</div>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="makePayment">
<payment-form-component :data="item.shipping_transaction" :section="section"></payment-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
props: {
invoice_status: {
type: String,
required: true
},
section:{
type: String,
required: true
}
},
data(){
return {
parameters: {
packing_list_id: null,
transaction_details: [],
},
expanded: false,
}
},
computed: {
cbm () {
return (Math.ceil((this.item.packages.reduce((total, obj) => (obj.type === 2 ? 0 : obj.cbm) + total, 0)) * 1000) / 1000).toFixed(3)
},
overweight(){
return (Math.ceil((this.item.packages.reduce((total, obj) => (obj.type === 2 ? obj.cbm : 0) + total, 0)) * 1000) / 1000).toFixed(3)
}
},
created(){
this.parameters.packing_list_id = this.data.id;
},
methods: {
generateInvoice() {
this.submit(this.route('api.transaction.invoice.create'), 'post', this.section, true, true);
},
successHandler(response){
this.item = response.payload.data;
this.updateList();
}
},
mixins: [componentHandler]
}
</script>
@@ -1,73 +0,0 @@
<template>
<div class="row m-l-0 m-b-10 m-r-0 parentContainer">
<div class="col-auto bg-master-lighter requestModal pointer" data-type="deleteAttempt">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-times muted"></i>
</div>
</div>
</div>
<div class="col bg-white p-t-10 p-b-10 p-r-0">
<div class="row m-b-5">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
MYR {{(Math.round((item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
</div>
<div class="col-auto p-l-5 p-r-5 bg-success pointer" v-if="item.payment_method === 5">
<a :href="route('billplz.bill', item.payment_reference)">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-repeat fs-20 text-white p-l-10 p-r-10"></i>
</div>
</div>
</a>
</div>
<div class="col-auto p-l-5 p-r-5 bg-success requestModal pointer" v-if="item.payment_method !== 5" data-type="paymentProofModal">
<div @click="selectedID(item.payment_transaction.id)" class="row align-items-center h-100">
<div class="col">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="30" height="30" viewBox="0 0 172 172" style=" fill:#000000;"><defs><linearGradient x1="86" y1="70.76994" x2="86" y2="116.46013" gradientUnits="userSpaceOnUse" id="color-1_52139_gr1"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="61.8125" y1="34.48869" x2="61.8125" y2="144.97181" gradientUnits="userSpaceOnUse" id="color-2_52139_gr2"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="130.34375" y1="34.48869" x2="130.34375" y2="144.97181" gradientUnits="userSpaceOnUse" id="color-3_52139_gr3"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="86" y1="32.25" x2="86" y2="148.71013" gradientUnits="userSpaceOnUse" id="color-4_52139_gr4"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></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><path d="M102.45825,99.43213h-5.70825c-1.4835,0 -2.6875,1.16637 -2.6875,2.65256v8.10013c0,1.48081 -1.19862,2.68481 -2.67944,2.68481h-10.76612c-1.48081,0 -2.67944,-1.204 -2.67944,-2.68481v-8.10013c0,-1.48619 -1.204,-2.65256 -2.6875,-2.65256h-5.70825c-1.93769,0 -3.04225,-2.39188 -1.88125,-4.05275l14.577,-20.855c1.8275,-2.61494 5.69481,-2.61763 7.52231,-0.00538l14.577,20.86306c1.16369,1.66088 0.05644,4.05006 -1.87856,4.05006z" fill="url(#color-1_52139_gr1)"></path><path d="M51.0625,67.1875h5.375c0,-8.0625 7.23206,-16.12231 16.125,-16.12231v-5.375c-11.85456,0 -21.5,10.74731 -21.5,21.49731z" fill="url(#color-2_52139_gr2)"></path><path d="M139.75,80.625c0,-10.75 -8.44144,-18.80981 -18.8125,-18.80981v5.375c7.40944,0 13.4375,5.37231 13.4375,13.43481z" fill="url(#color-3_52139_gr3)"></path><path d="M148.09738,92.27263c1.59369,-3.68188 2.40263,-7.59219 2.40263,-11.64494c0,-16.29969 -13.26281,-29.5625 -29.5625,-29.5625c-6.5145,0 -12.68769,2.08819 -17.78588,5.96088c-4.30269,-13.03438 -16.52006,-22.08587 -30.58912,-22.08587c-17.78319,0 -32.25,14.46681 -32.25,32.25c0,4.14681 0.16662,8.05981 1.42437,10.74731h-1.42437c-13.33806,0 -24.1875,10.84944 -24.1875,24.1875c0,11.56431 8.16194,21.24737 19.0275,23.62044c1.02394,6.39894 6.53869,11.31706 13.2225,11.31706h56.4375h16.125h5.375c6.54944,0 12.00238,-4.71388 13.18488,-10.92469c9.2235,-1.20131 16.37762,-9.08913 16.37762,-18.63513c0,-6.09256 -2.924,-11.72019 -7.77762,-15.23006zM126.3125,131.6875h-5.375h-16.125h-56.4375c-3.49912,0 -6.45538,-2.6875 -7.568,-5.375h93.0735c-1.11263,2.6875 -4.06888,5.375 -7.568,5.375zM137.0625,120.9375h-96.75c-10.37106,0 -18.8125,-8.44144 -18.8125,-18.8125c0,-10.37106 8.44144,-18.8125 18.8125,-18.8125h9.51375l-1.68506,-3.78131c-2.23063,-5.01488 -2.45369,-7.48737 -2.45369,-12.341c0,-14.81888 12.05613,-26.875 26.875,-26.875c13.01825,0 24.13106,9.29875 26.42619,22.11275l0.92719,5.17075l3.64962,-3.77325c4.60638,-4.76225 10.77687,-7.38525 17.372,-7.38525c13.33806,0 24.1875,10.84944 24.1875,24.1875c0,3.6765 -0.81431,7.21056 -2.37575,10.41944l-1.763,3.32713l2.37037,1.26044c4.40481,2.34081 7.14338,6.88806 7.14338,11.868c0,7.40944 -6.02806,13.43481 -13.4375,13.43481z" fill="url(#color-4_52139_gr4)"></path></g></g></svg>
</div>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteAttempt">
<delete-payment-attempt-form-component :data="item" :section="section" class="text-center"></delete-payment-attempt-form-component>
</modal-component>
<modal-component type="paymentProofModal">
<payment-verification-form-component v-if="selected_id === item.payment_transaction.id" :section="section" :data="item"></payment-verification-form-component>
</modal-component>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
data(){
return {
expandPaymentDetails: false,
amount: (Math.round(1000 * 100) / 100).toFixed(2),
selected_id: '',
parameters: {
amount: (Math.round(1000 * 100) / 100).toFixed(2),
bank_id: 1
},
section: 'bookingDetailSection',
}
},
mounted() {
this.item.id = this.item.payment_transaction.id;
},
methods: {
clickExpand(){
this.expandPaymentDetails = !this.expandPaymentDetails;
},
selectedID(id){
this.selected_id = id;
}
},
mixins: [componentHandler]
}
</script>
@@ -55,7 +55,7 @@
</div>
</div>
</div>
<div v-if="$store.getters.isSuperAdmin | showManualPayment">
<div v-if="$store.getters.isSuperAdmin">
<div class="row m-t-10 m-b-10">
<div class="col text-center"><div id="expend-method" class="padding-10 bg-master-lightest pointer" @click="$store.dispatch('toggleSection', {name: 'otherPaymentMethods', status: !$store.getters.isShowing('otherPaymentMethods')})"><i class="fa m-r-10" :class="[{'fa-angle-up': $store.getters.isShowing('otherPaymentMethods')}, {'fa-angle-down': !$store.getters.isShowing('otherPaymentMethods')}]"></i>{{$store.getters.isShowing('otherPaymentMethods') ? 'Hide' : 'Show'}} Alternative Methods <i class="fa m-l-10" :class="[{'fa-angle-up': $store.getters.isShowing('otherPaymentMethods')}, {'fa-angle-down': !$store.getters.isShowing('otherPaymentMethods')}]"></i></div></div>
</div>
@@ -170,10 +170,6 @@
type: Array,
required: true,
},
showManualPayment: {
type: Boolean,
default: false
},
},
data(){
return {
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
<div class="row justify-content-end">
<div class="col">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" :class="{'active': item ? item.status === 2 : true }" tab-name="pendingInvoice" @click="setActiveTab($event)">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" :class="{'active': item ? item.status === 2 : true }" tab-name="pendingInvoice">
<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"
@@ -29,7 +29,7 @@
<div class="row justify-content-end">
<div class="col">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" tab-name="pendingApproval" @click="setActiveTab($event)">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" tab-name="pendingApproval">
<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"
@@ -52,7 +52,7 @@
<div class="row justify-content-end">
<div class="col">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" tab-name="pendingPayment" @click="setActiveTab($event)">
<div class="col p-t-20 p-b-20 m-r-5 bg-master-lighter tabButton" tab-name="pendingPayment">
<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"
@@ -78,7 +78,7 @@
<div class="row justify-content-end">
<div class="col">
<div class="row fs-12 text-center">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="paidInvoice" @click="setActiveTab($event)">
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="paidInvoice">
<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"
@@ -100,23 +100,23 @@
</div>
<div class="row no-margin">
<div class="col bg-master-lightest p-1 p-sm-4">
<div class="row tabsContainer tabContent" tab-name="pendingInvoice" v-if="isActiveTab('pendingInvoice') || showTabContent('pendingInvoice')">
<div class="row tabsContainer tabContent" tab-name="pendingInvoice">
<div class="col">
<admin-payments-billing-with-search-component :options="{does_not_have_transaction_type: 1, type: 2, per_page: 5}" section="pendingInvoiceSection" invoice_status="Pending Invoice"></admin-payments-billing-with-search-component>
</div>
</div>
<div class="row tabsContainer tabContent hide" tab-name="pendingApproval" v-if="isActiveTab('pendingApproval') || showTabContent('pendingApproval')">
<div class="row tabsContainer tabContent hide" tab-name="pendingApproval">
<div class="col">
<admin-payments-billing-with-search-component :options="{has_invoice_status_in: [0, 1], per_page: 5}" section="pendingApprovalSection" invoice_status="Pending Approval"></admin-payments-billing-with-search-component>
</div>
</div>
<div class="row tabsContainer tabContent hide" tab-name="pendingPayment" v-if="isActiveTab('pendingPayment') || showTabContent('pendingPayment')">
<div class="row tabsContainer tabContent hide" tab-name="pendingPayment">
<div class="col">
<payment-filter-component :endpoint="route('api.packing_list.list')" :data="data"></payment-filter-component>
<admin-payments-billing-with-search-component :options="{has_invoice_status_in: [2], packing_list_ordered_by_invoice_date: true, per_page: 5}" section="pendingPaymentSection" invoice_status="Pending Payment" :with_export="true"></admin-payments-billing-with-search-component>
</div>
</div>
<div class="row tabsContainer tabContent hide" tab-name="paidInvoice" v-if="isActiveTab('paidInvoice') || showTabContent('paidInvoice')">
<div class="row tabsContainer tabContent hide" tab-name="paidInvoice">
<div class="col">
<admin-payments-billing-with-search-component :options="{has_invoice_status_in: [3], per_page: 5}" section="paidInvoiceSection" invoice_status="Paid Invoice" :with_export="true"></admin-payments-billing-with-search-component>
</div>
@@ -128,14 +128,7 @@
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import tabHandler from '../../../general/mixins/tabHandler';
export default {
data() {
return {
activeTab: 'pendingInvoice',
displayedTabs: ['pendingInvoice'],
};
},
mixins: [componentHandler, tabHandler]
mixins: [componentHandler]
}
</script>
@@ -1,5 +1,5 @@
<template>
<div class="row m-b-15 parentContainer" :class="{'d-none': searchValue != data.postcode && searchValue != ''}">
<div class="row m-b-15 parentContainer">
<div class="col">
<div class="row align-items-center">
<div class="col-auto p-r-0">
@@ -55,10 +55,6 @@
type: Object,
required: false
},
searchValue: {
type: String,
default: null
},
section: {
default: ''
},
@@ -1,138 +0,0 @@
<template>
<div class="row parentContainer">
<div class="col">
<div class="row" v-if="!returnData">
<div class="col">
<div class="row m-b-20">
<div class="col">
<div class="btn btn-sm btn-primary rounded b-rad-none"
@click="isUploadingCsv = !isUploadingCsv">{{ isUploadingCsv ? "Cancel" : "Upload Excel" }}
</div>
<div class="btn btn-sm btn-primary rounded b-rad-none requestModal"
data-type="addPermitsReminder" v-if="!isUploadingCsv"><i class="fa fa-plus m-r-5"></i>Add
Permits</div>
<modal-component class="animate__animated animate__fast animate__fadeIn"
type="addPermitsReminder">
<add-permits-reminder-form-component
:section="section"></add-permits-reminder-form-component>
</modal-component>
<div class="btn btn-sm btn-default rounded b-rad-none" @click="refreshData"><i class="fa fa-refresh"></i></div>
</div>
</div>
<div class="row m-b-50" v-if="isUploadingCsv">
<div class="col-12 col-md-6">
<div class="row bg-white">
<div class="col">
<file-input-component :validator="$v.files" v-model="files">
<template slot="label">
<div class="font-heading fs-11 all-caps">Permits Reminder Csv</div>
<div class="fs-8 all-caps d-block m-t-10"><a :href="excelFileUrl" download>Click
HERE to download the template</a></div>
</template>
</file-input-component>
</div>
</div>
<div class="row m-t-20">
<div class="col">
<div class="row">
<div class="col">
<button type="button"
class="btn btn-block p-t-10 p-b-10 p-r-35 p-l-35 btn-success b-rad-none"
@click="submitForm">Upload</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else>
<div class="font-heading fs-16 all-caps bold m-b-15">Permits Reminder</div>
<list-component :key="key" :section="section" :endpoint="route('api.permits_reminder.list')">
<template slot="list" slot-scope="{data}">
<permits-reminder-item-component :data="data"
:section="section"></permits-reminder-item-component>
</template>
</list-component>
</div>
</div>
</div>
<div v-if="returnData">
<div class="font-heading fs-16 all-caps bold m-b-15">Upload Summary</div>
<div class="font-heading fs-12 all-caps bold">Total Completed Rows: {{ returnData.completedRows }}</div>
<div class="font-heading fs-12 all-caps bold m-b-15">Total Failed Rows: {{ returnData.failedRows }}</div>
<div v-if="returnData.failedRows">
<div class="font-heading fs-12 all-caps m-b-15">Please copy error below into a excel file and try again
after it has been corrected.</div>
<table class="w-100 table table-bordered">
<tr>
<th class="text-capitalize" v-for="key in returnDataKeys"> {{ key }}</th>
</tr>
<tr v-for="row in returnData.data">
<td v-for="col in row" :class="[{ 'text-danger': row['status'] == 'failed' }]">
{{ col }}
</td>
</tr>
</table>
</div>
<div class="fs-12 font-arial m-b-0 pointer bold m-t-20 text-primary" @click="refreshData()">Click here to
refresh</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
props: {
section: {
type: String,
required: true
}
},
data() {
return {
files: [],
parameters: {},
returnData: null,
data: null,
key: 1,
isUploadingCsv: false,
}
},
computed: {
returnDataKeys() {
return this.returnData ? Object.keys(Object.assign({}, this.returnData.data[0])) : 0;
},
excelFileUrl() {
return `${window.location.origin}/` + 'excel-templates/permits_reminder_template.xlsx';
}
},
validations: {
files: {
required
},
},
methods: {
submitForm() {
this.parameters = {
files: this.files,
};
this.submit(this.route('api.permits_reminder.upload'), 'post', this.section, true, true);
},
errorHandler(error) {
console.log(error);
},
successHandler(response) {
console.log(response);
this.returnData = response;
},
refreshData() {
this.returnData = null;
this.isUploadingCsv = false;
this.key++;
}
},
}
</script>
@@ -1,122 +0,0 @@
<template>
<div class="row parentContainer">
<div class="col">
<div class="row align-items-center">
<div class="col-auto p-r-0">
<div class="padding-5 bg-master-lightest rounded">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="35" height="35" viewBox="0 0 172 172"
style=" fill:#000000;">
<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 fill="#333333">
<path
d="M15.05,25.8v105.35h4.3v2.15c0,3.53669 2.91331,6.45 6.45,6.45h50.5376c1.67444,3.75213 5.30105,6.45 9.6624,6.45c4.36203,0 7.98734,-2.69797 9.6624,-6.45h50.5376c3.53669,0 6.45,-2.91331 6.45,-6.45v-2.15h4.3v-105.35h-64.5c-2.60352,0 -4.86855,1.23893 -6.45,3.08643c-1.58145,-1.8475 -3.84648,-3.08643 -6.45,-3.08643zM19.35,30.1h60.2c2.40083,0 4.3,1.89917 4.3,4.3c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-2.40083 1.89917,-4.3 4.3,-4.3h60.2v96.75h-60.2c-2.60352,0 -4.86855,1.23893 -6.45,3.08643c-1.58145,-1.8475 -3.84648,-3.08643 -6.45,-3.08643h-60.2zM86,40.85c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,49.45c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM119.68193,53.57363v4.12783c-8.0754,0.7482 -12.97979,5.32437 -12.97979,12.23232c0,5.8351 3.64818,9.8429 10.31748,11.54785l2.66231,0.68867v13.63906c-4.45695,-0.50955 -7.33113,-2.99253 -7.62998,-6.55078h-6.33662c0.0301,6.9402 5.41175,11.63533 13.9666,12.20293v3.88428h4.09844v-3.91367c8.7634,-0.7482 13.81963,-5.32289 13.81963,-12.65224c0,-6.192 -3.53195,-9.99125 -11.03975,-11.8166l-2.77988,-0.62568v-12.8958c3.9474,0.47945 6.64034,3.04917 6.76074,6.34082h6.24844c-0.1806,-6.67145 -5.26273,-11.39315 -13.00918,-12.08115v-4.12783zM86,58.05c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM119.68193,63.4124v12.05596c-4.3086,-0.8686 -6.58018,-2.99112 -6.58018,-6.07207c0,-3.26155 2.75103,-5.77534 6.58018,-5.98389zM86,66.65c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,75.25c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM123.78037,82.94717c5.08475,1.01695 7.44521,3.07924 7.44521,6.52139c0,3.79905 -2.71951,6.12871 -7.44521,6.39961zM86,83.85c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,92.45c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,101.05c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,109.65c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,118.25c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM23.65,131.15h55.9c2.40083,0 4.3,1.89917 4.3,4.3h4.3c0,-2.40083 1.89917,-4.3 4.3,-4.3h55.9v2.15c0,1.21481 -0.93519,2.15 -2.15,2.15h-53.56523l-0.41992,1.6083c-0.72235,2.78276 -3.19533,4.8417 -6.21484,4.8417c-3.01952,0 -5.49455,-2.05645 -6.21484,-4.8375l-0.41992,-1.6125h-53.56523c-1.21481,0 -2.15,-0.93519 -2.15,-2.15z">
</path>
</g>
</g>
</svg>
</div>
</div>
<div class="col-2">
<div class="row">
<div class="col-auto p-r-10">
<div class="font-heading all-caps fs-8 muted">Model</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps">{{ data.model }}</div>
</div>
</div>
</div>
<div class="col-2">
<div class="row">
<div class="col-auto p-r-10">
<div class="font-heading all-caps fs-8 muted">Expiry Date</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps">{{ data.expiry_date }}</div>
</div>
</div>
</div>
<div class="col-2">
<div class="row">
<div class="col-auto p-r-10">
<div class="font-heading all-caps fs-8 muted">Reminder Date</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps">{{ data.reminder_date }}</div>
</div>
</div>
</div>
<div class="col-2">
<div class="row">
<div class="col-auto p-r-10">
<div class="font-heading all-caps fs-8 muted">Created At</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps">{{ data.created_at }}</div>
</div>
</div>
</div>
<div class="col-auto">
<div class="row">
<div class="col">
<div class="btn bg-grey no-border muted requestModal" data-type="deleteItem">
<i class="fa fa-trash"></i>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteItem">
<general-confirmation-form-component
contentText="Are you sure you want to delete this Item?"
modalType="delete"
buttonText="Delete"
class="text-center"
:apiRoute="route('api.permits_reminder.delete', data.id)"
apiMethod="delete"
:section="section">
</general-confirmation-form-component>
</modal-component>
<div class="btn bg-grey no-border muted requestModal" data-type="updateItem">
<i class="fa fa-edit"></i>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn"
type="updateItem">
<add-permits-reminder-form-component
:section="section" :existingData="data"></add-permits-reminder-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import modalFormHandler from '../../../general/mixins/modalFormHandler';
import { required } from "vuelidate/lib/validators";
export default {
props: {
data: {
type: Object,
required: false,
parameters: {
}
},
},
mixins: [modalFormHandler]
}
</script>
@@ -1,79 +0,0 @@
<template>
<div class="row m-b-15 parentContainer">
<div class="col">
<div class="row m-b-10" @keyup.enter="submitSearch()">
<div class="col-6 col-md mb-2 mb-md-0">
<validation-wrapper-component :validator="$v.postcode">
<label class="text-primary">Postcode</label>
<input type="text" class="form-control fs-12" v-model="postcode">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-20">
<div class="col-12 col-md-auto m-b-15">
<div class="row">
<div class="col p-r-0">
<div class="btn btn-primary b-rad-none w-100 h-100 d-flex justify-content-center align-items-center p-l-30 p-r-30"
@click="submitSearch()">
Search
</div>
</div>
<div class="col p-l-0">
<div class="btn btn-secondary b-rad-none w-100 h-100 d-flex justify-content-center align-items-center p-l-30 p-r-30"
@click="resetSearch()">
Reset
</div>
</div>
</div>
</div>
</div>
<div class="row m-b-20">
<div class="col">
<list-component :key="key" section="allPostcodesSection" :endpoint="route('api.address.district.list')" :options="options">
<template slot="list" slot-scope="{data}">
<list-postcode-component :data="item" :searchValue="submittedPostcode" v-for="(item, index) in data.postcodeArray" v-bind:key="index"></list-postcode-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</template>
<script>
import modalFormHandler from '../../../general/mixins/modalFormHandler';
import { required } from "vuelidate/lib/validators";
export default {
props: {
section: {
default: 'allStateChargesSection'
},
},
data() {
return {
key: 1,
options: { country_id: 1 },
postcode: '',
submittedPostcode: '',
}
},
validations: {
postcode: {},
},
methods: {
submitSearch() {
this.submittedPostcode = this.postcode;
this.options = { country_id: 1, postcode_like: this.submittedPostcode };
this.key += 1;
},
resetSearch() {
this.options = { country_id: 1 };
this.submittedPostcode = '';
this.postcode = '';
this.key += 1;
},
},
mixins: [modalFormHandler]
}
</script>
@@ -107,8 +107,7 @@
</div>
<div class="row">
<div class="col">
<span v-if="data.contact">{{ data.contact.reference ? data.contact.reference : "-" }}</span>
<span v-else>-</span>
{{ data.contact.reference ? data.contact.reference : "-" }}
</div>
</div>
</div>
@@ -120,8 +119,7 @@
</div>
<div class="row">
<div class="col">
<span v-if="data.contact">{{ data.contact.phone ? data.contact.phone : '-' }}</span>
<span v-else>-</span>
{{ data.contact.phone ? data.contact.phone : '-' }}
</div>
</div>
</div>
@@ -133,8 +131,7 @@
</div>
<div class="row">
<div class="col">
<span v-if="data.contact">{{ data.contact.email ? data.contact.email : '-' }}</span>
<span v-else>-</span>
{{ data.contact.email ? data.contact.email : '-' }}
</div>
</div>
</div>
@@ -146,20 +143,17 @@
</div>
<div class="row">
<div class="col">
<span v-if="data.contact">{{ data.contact.wechat_id ? data.contact.wechat_id : '-' }}</span>
<span v-else>-</span>
{{ data.contact.wechat_id ? data.contact.wechat_id : '-' }}
</div>
</div>
</div>
<div class="col"></div>
<div v-if="data.contact">
<div class="col-auto">
<div class="btn btn-xs btn-default pointer m-t-10 b-primary b-a text-primary requestModal" data-type="warehouseContact">Edit Contact</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" type="warehouseContact" styleType="fill-in">
<contact-form-component :section="section" :data="data.contact" :company_module_id="data.id"></contact-form-component>
</modal-component>
<div class="col-auto">
<div class="btn btn-xs btn-default pointer m-t-10 b-primary b-a text-primary requestModal" data-type="warehouseContact">Edit Contact</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" type="warehouseContact" styleType="fill-in">
<contact-form-component :section="section" :data="data.contact" :company_module_id="data.id"></contact-form-component>
</modal-component>
</div>
</div>
</div>
@@ -1,109 +0,0 @@
<template>
<div class="row" style="width: 450px; margin: auto;" @keyup.enter="submitForm">
<div class="col bg-white b-rad-lg">
<div class="row m-b-15">
<div class="col">
<h6 class="all-caps m-b-5 bold no-margin">{{ existingData ? 'Update' : 'Add' }} PERMITS REMINDER</h6>
</div>
</div>
<div class="row m-b-15 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger" v-html="error"></small>
</div>
</div>
<div class="row">
<div class="col">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.model">
<label class="text-primary">Model</label>
<div class="controls">
<input type="text" class="form-control fs-12" v-model.trim="parameters.model">
</div>
</validation-wrapper-component>
<div class="row m-auto mt-10 mb-10">
<div class="col p-l-0 p-r-10">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.expiry_date">
<label class="text-primary">Expiry Date</label>
<date-picker-component v-model="parameters.expiry_date"></date-picker-component>
</validation-wrapper-component>
</div>
</div>
<div class="row m-auto mt-10 mb-10">
<div class="col p-l-0 p-r-10">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.reminder_date">
<label class="text-primary">Reminder Date</label>
<date-picker-component v-model="parameters.reminder_date"></date-picker-component>
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row m-t-15">
<div class="col p-r-5">
<div class="btn btn-sm btn-default b-rad-none w-100" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-primary w-100" @click="submitForm()">Confirm</div>
</div>
</div>
</div>
</div>
</template>
<script>
import FormHandler from '../../../general/mixins/formHandler';
import { required } from "vuelidate/lib/validators";
export default {
props: {
existingData: {
type: Object,
}
},
data() {
return {
parameters: {
expiry_date: '',
reminder_date: '',
model: ''
},
};
},
mounted() {
if (this.existingData) {
this.parameters.expiry_date = this.existingData.expiry_date;
this.parameters.reminder_date = this.existingData.reminder_date;
this.parameters.model = this.existingData.model;
}
},
validations: {
parameters: {
expiry_date: { required },
reminder_date: { required },
model: { required },
}
},
methods: {
submitForm() {
var apiRoute = this.existingData ? this.route('api.permits_reminder.update', this.existingData.id) : this.route('api.permits_reminder.create');
this.submit(apiRoute, 'post', this.section, true, true);
},
errorHandler(error) {
// this.formHandler(error.message);
console.log(error);
},
successHandler() {
this.closeModal();
// Reset the validation state of the parameters object
this.$v.parameters.$reset();
this.parameters = {
expiry_date: '',
reminder_date: '',
model: ''
};
},
},
mixins: [FormHandler]
}
</script>
@@ -1,7 +1,7 @@
<template>
<div class="row bg-white padding-10 m-b-10 rounded align-datas-center">
<div class="col-3 fs-12">{{data.created_at}}</div>
<div class="col fs-12"><span v-html="data.description"></span> <a target=”_blank” v-if="[9,11].includes(data.type) " :href="route('transaction.credit_note.download', data.id)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a><small v-if="data.bill_no && $store.getters.isAdmin"><br><br>{{ data.bill_no }}</small></div>
<div class="col fs-12"><span v-html="data.description"></span> <a target=”_blank” v-if="[9,11].includes(data.type) " :href="route('transaction.credit_note.download', data.id)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a></div>
<div class="col-2 text-success text-center">{{[5, 9, 15].includes(parseFloat(data.type)) ? formatValue(data.amount) : ''}}</div>
<div class="col-2 text-danger text-center">{{[2, 11].includes(parseFloat(data.type)) ? '- ' + formatValue(data.amount, ) : ''}}</div>
<div class="col-2 text-right">{{formatValue(data.running_balance)}}</div>
-49
View File
@@ -1,49 +0,0 @@
export default {
methods: {
poll(url, method, section, successNotification = true, errorNotification = true){
if(!this.validate()){ return; }
if (section) {
this.$store.dispatch('toggleLoading', {name: section, status: true})
}
this.$store.dispatch('crudRequestV2', {
endpoint: url,
method: method,
parameters: this.parameters
}).then(response => {
let statusCode = response.status,
success = response.ok;
response.json().then(response => {
if(!success){
this.openModal();
errorNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'error'}): null;
this.errorHandler(response, statusCode); return;
}
successNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'success'}): null;
this.successHandler(response)
});
}).catch((error) => {
this.$store.dispatch('createNotification', {title: 'Unexpected Error', message: 'An unexpected error has occurred. Try again!', type: 'error'});
}).then(() => {
if (section) {
this.$store.dispatch('toggleLoading', {name: section, status: false})
}
})
},
validate() {
if(this.$v){
this.$v.$touch();
return !this.$v.$invalid;
}
return true;
},
successHandler(response){},
errorHandler(response){}
}
}
-24
View File
@@ -1,24 +0,0 @@
export default {
data() {
return {
activeTab: null,
displayedTabs: [],
};
},
methods: {
setActiveTab(event) {
const tabName = event.currentTarget.getAttribute('tab-name');
// console.log(`Tab "${tabName}" clicked`);
this.activeTab = tabName;
if (!this.displayedTabs.includes(tabName)) {
this.displayedTabs.push(tabName);
}
},
isActiveTab(tabName) {
return this.activeTab === tabName;
},
showTabContent(tabName) {
return this.displayedTabs.includes(tabName);
},
},
}
+1 -1
View File
@@ -19,4 +19,4 @@ export default {
})
}
}
}
}
-47
View File
@@ -1,47 +0,0 @@
export default {
actions: {
crudRequestV2({getters, dispatch}, {endpoint, method, parameters}){
const queryDomain = endpoint.split('?')[0];
let encodedParams = endpoint.split('?')[1];
let decodedParams = fullyDecodeURI(encodedParams);
const queryParams = encodeURIComponent(decodedParams);
encodedParams = queryParams.toString();
let filteredEncodedParams = encodedParams.replace(/%3D/g,'=');
filteredEncodedParams = filteredEncodedParams.replace(/%26/g,'&');
let combinedAbsoluteUrl = queryDomain;
if(filteredEncodedParams !== undefined && filteredEncodedParams !== 'undefined'){
combinedAbsoluteUrl = queryDomain + '?' + filteredEncodedParams;
}
// return fetch(endpoint, {
return fetch(combinedAbsoluteUrl, {
method: method,
responseType: 'json',
body: parameters ? JSON.stringify(parameters):null,
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer '+getters.getAccessToken
}
}).then(response => {
if(response.status === 401 && window.location.href !== route('login') && window.location.href.indexOf(route('last_mile_delivery.login')) <= -1){
dispatch('userAuthentication', {access_token: '', redirect_url: [7, 8].includes(getters.getCompanyModuleType) ? route('last_mile_delivery.login') : route('login')});
}
return response;
})
}
}
}
function isEncoded(uri) {
uri = uri || '';
return uri !== decodeURIComponent(uri);
}
function fullyDecodeURI(uri){
while (isEncoded(uri)){
uri = decodeURIComponent(uri);
}
return uri;
}
+1 -3
View File
@@ -4,7 +4,6 @@ import toggleSection from './modules/toggleSection'
import toggleLoading from './modules/toggleLoading'
import createNotification from './modules/createNotification'
import crudRequest from './modules/crudRequest'
import crudRequestV2 from './modules/crudRequestV2'
import authentication from './modules/authentication'
import loadRequestQueue from './modules/loadRequestQueue'
@@ -17,7 +16,6 @@ export default new Vuex.Store({
loadRequestQueue,
createNotification,
crudRequest,
crudRequestV2,
authentication
}
})
})
@@ -1,12 +0,0 @@
@extends('emails.layout.base')
@section('content')
<h4 style="font-size: 1em;">Hello, {{ $user->first_name.' '.$user->last_name }}</h4>
<p style="font-size: 0.9em">The permits listed below either expiring within the period of the next 3 days or have already expired 3 days ago.</p>
<ul>
@foreach($reminders as $reminder)
<li>{{ $reminder }}</li>
@endforeach
</ul>
@endsection
@@ -1,8 +0,0 @@
@extends('layouts.base_portal')
@section('inner_content')
<div class="row">
<div class="col">
<admin-payments-billing-polling-section-component></admin-payments-billing-polling-section-component>
</div>
</div>
@endsection
+9 -41
View File
@@ -46,26 +46,6 @@
</div>
</div>
</div>
<div class="row m-b-5" v-if="$store.getters.isSuperAdmin || ([2251]).includes($store.getters.getUserId)">
<div class="col">
<div class="row">
<div class="col">
<div class="row">
<div class="col bg-master-light tabButton" tab-name="permits">
<div class="row align-items-center">
<div class="col-auto p-t-10 p-b-10 b-r b-grey">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="35" height="35" viewBox="0 0 172 172" style=" fill:#000000;"><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 fill="#333333"><path d="M15.05,25.8v105.35h4.3v2.15c0,3.53669 2.91331,6.45 6.45,6.45h50.5376c1.67444,3.75213 5.30105,6.45 9.6624,6.45c4.36203,0 7.98734,-2.69797 9.6624,-6.45h50.5376c3.53669,0 6.45,-2.91331 6.45,-6.45v-2.15h4.3v-105.35h-64.5c-2.60352,0 -4.86855,1.23893 -6.45,3.08643c-1.58145,-1.8475 -3.84648,-3.08643 -6.45,-3.08643zM19.35,30.1h60.2c2.40083,0 4.3,1.89917 4.3,4.3c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-2.40083 1.89917,-4.3 4.3,-4.3h60.2v96.75h-60.2c-2.60352,0 -4.86855,1.23893 -6.45,3.08643c-1.58145,-1.8475 -3.84648,-3.08643 -6.45,-3.08643h-60.2zM86,40.85c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,49.45c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM119.68193,53.57363v4.12783c-8.0754,0.7482 -12.97979,5.32437 -12.97979,12.23232c0,5.8351 3.64818,9.8429 10.31748,11.54785l2.66231,0.68867v13.63906c-4.45695,-0.50955 -7.33113,-2.99253 -7.62998,-6.55078h-6.33662c0.0301,6.9402 5.41175,11.63533 13.9666,12.20293v3.88428h4.09844v-3.91367c8.7634,-0.7482 13.81963,-5.32289 13.81963,-12.65224c0,-6.192 -3.53195,-9.99125 -11.03975,-11.8166l-2.77988,-0.62568v-12.8958c3.9474,0.47945 6.64034,3.04917 6.76074,6.34082h6.24844c-0.1806,-6.67145 -5.26273,-11.39315 -13.00918,-12.08115v-4.12783zM86,58.05c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM119.68193,63.4124v12.05596c-4.3086,-0.8686 -6.58018,-2.99112 -6.58018,-6.07207c0,-3.26155 2.75103,-5.77534 6.58018,-5.98389zM86,66.65c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,75.25c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM123.78037,82.94717c5.08475,1.01695 7.44521,3.07924 7.44521,6.52139c0,3.79905 -2.71951,6.12871 -7.44521,6.39961zM86,83.85c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,92.45c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,101.05c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,109.65c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM86,118.25c-1.18741,0 -2.15,0.96259 -2.15,2.15c0,1.18741 0.96259,2.15 2.15,2.15c1.18741,0 2.15,-0.96259 2.15,-2.15c0,-1.18741 -0.96259,-2.15 -2.15,-2.15zM23.65,131.15h55.9c2.40083,0 4.3,1.89917 4.3,4.3h4.3c0,-2.40083 1.89917,-4.3 4.3,-4.3h55.9v2.15c0,1.21481 -0.93519,2.15 -2.15,2.15h-53.56523l-0.41992,1.6083c-0.72235,2.78276 -3.19533,4.8417 -6.21484,4.8417c-3.01952,0 -5.49455,-2.05645 -6.21484,-4.8375l-0.41992,-1.6125h-53.56523c-1.21481,0 -2.15,-0.93519 -2.15,-2.15z"></path></g></g></svg>
</div>
<div class="col">
<div class="fs-12 m-t-5 all-caps m-b-5">Permits</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<template v-if="$store.getters.isSuperAdmin">
<div class="row m-b-5">
<div class="col">
@@ -245,26 +225,6 @@
</div>
</div>
</div>
<div class="row tabsContainer hide tabContent" tab-name="permits">
<div class="col">
<div class="row">
<div class="col">
<div class="row p-b-5 m-b-20 b-b b-grey align-items-center parentContainer">
<div class="col">
<div class="font-heading all-caps fs-10 hint-text">
Permits
</div>
</div>
</div>
<div class="row m-b-20">
<div class="col">
<permits-reminder-component section="PermitsReminderComponent"></permits-reminder-component>
</div>
</div>
</div>
</div>
</div>
</div>
<template v-if="$store.getters.isSuperAdmin">
<div class="row tabsContainer hide tabContent" tab-name="team">
<div class="col">
@@ -409,7 +369,15 @@
</div>
</div>
</div>
<postcode-section-component></postcode-section-component>
<div class="row m-b-20">
<div class="col">
<list-component section="allPostcodesSection" :endpoint="route('api.address.district.list')" :options="{country_id: 1}">
<template slot="list" slot-scope="{data}">
<list-postcode-component :data="item" v-for="item in data.postcodeArray"></list-postcode-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</div>
-6
View File
@@ -34,8 +34,6 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
Route::post('/import/update-debtor/f614e339d7058904a831aad742e24d55', 'Imports\ImportUpdateDebtorController@import')->name('debtor.import');
Route::post('/import/upload-permits-reminder', 'Imports\ImportPermitsReminderController@import')->name('permits_reminder.upload');
require __DIR__ . '/company.php';
require __DIR__ . '/document.php';
@@ -72,10 +70,6 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
require __DIR__ . '/help_menu.php';
require __DIR__ . '/permits_reminder.php';
require __DIR__ . '/job.php';
});
require __DIR__ . '/announcement.php';
-8
View File
@@ -1,8 +0,0 @@
<?php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'job', 'as' => 'job.', 'namespace' => 'Jobs'], function () {
Route::get('/fetch/{job_id}', 'FetchJobResultController@fetch')->name('fetch');
Route::get('/fetch/{job_id}/{is_last}', 'FetchJobResultController@fetch')->name('fetch.last.attempt');
});
-1
View File
@@ -5,7 +5,6 @@ use Illuminate\Support\Facades\Route;
Route::group(['namespace' => 'PackingLists', 'as' => 'packing_list.', 'prefix' => 'packing_list'], function () {
Route::get('/{id}/show', 'FetchPackingListController@fetch')->name('show');
Route::get('/list', 'ListPackingListsController@list')->name('list');
Route::get('/list/job', 'ListPackingListsJobController@list')->name('list.job');
Route::post('/create', 'CreatePackingListController@create')->name('create');
Route::post('/create/deliver', 'CreateDeliverPackingListController@create')->name('create.deliver');
-11
View File
@@ -1,11 +0,0 @@
<?php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'permits-reminder', 'as' => 'permits_reminder.', 'namespace' => 'PermitsReminder'], function () {
Route::get('/list', 'ListPermitsReminderController@list')->name('list');
Route::post('/create', 'CreatePermitsReminderController@create')->name('create');
Route::delete('/{id}/delete', 'DeletePermitsReminderController@delete')->name('delete');
Route::post('/{id}/update', 'UpdatePermitsReminderController@update')->name('update');
});
+1 -6
View File
@@ -1247,9 +1247,4 @@ Route::get('fix-payment-status-updated-but-failed-update-invoice', function (Upd
echo 'done fix ' . $invoice->owner->owner->reference . '<br>';
}
}
});
//A page to monitor Experimental solution (Vue Polling) to solve an AWS API Gateway problem limitation for Laravel Vapor in the event of a emergency rollback to Google
Route::get('/payment-and-billing-2', function () {
return view('pages.paymentAndBilling2');
})->name('admin.payment-and-billing-2');
});