diff --git a/app/Classes/Exceptions/JobResourceNotFoundException.php b/app/Classes/Exceptions/JobResourceNotFoundException.php
new file mode 100644
index 00000000..a8ef358e
--- /dev/null
+++ b/app/Classes/Exceptions/JobResourceNotFoundException.php
@@ -0,0 +1,11 @@
+getMessage(),
+ $exception->getTrace()[0]['file'],
+ $exception->getTrace()[0]['line']
+ ));
+ }
+ else{
+ log::error($exception);
+ }
+
return (new ApiResponseObject($this->getNotificationTitle().' failed', $exception->getMessage(),
$exception->getCode() ? $exception->getCode() : HttpStatus::SERVER_ERROR))->handler();
diff --git a/app/Classes/General/Eloquent/AbstractFetchRecord.php b/app/Classes/General/Eloquent/AbstractFetchRecord.php
index 248deee7..503fb369 100644
--- a/app/Classes/General/Eloquent/AbstractFetchRecord.php
+++ b/app/Classes/General/Eloquent/AbstractFetchRecord.php
@@ -4,9 +4,11 @@ namespace App\Classes\General\Eloquent;
use App\Classes\Exceptions\ResourceNotFoundException;
+use App\Classes\Exceptions\JobResourceNotFoundException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Psy\Exception\ErrorException;
+use Illuminate\Support\Facades\Log;
abstract class AbstractFetchRecord extends AbstractGetRecord
{
@@ -27,12 +29,18 @@ abstract class AbstractFetchRecord extends AbstractGetRecord
* @return Model
* @throws ResourceNotFoundException
*/
- public function getResults(Builder $query): Model {
+ public function getResults(Builder $query, array $param = []): Model {
if(!$query->exists()){
- throw new ResourceNotFoundException('Unable to find any record based on the criteria provided');
+ $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');
+ }
}
return $query->first();
}
-}
\ No newline at end of file
+}
diff --git a/app/Classes/General/Eloquent/AbstractGetRecord.php b/app/Classes/General/Eloquent/AbstractGetRecord.php
index f927d818..1a7eac3e 100644
--- a/app/Classes/General/Eloquent/AbstractGetRecord.php
+++ b/app/Classes/General/Eloquent/AbstractGetRecord.php
@@ -30,11 +30,25 @@ abstract class AbstractGetRecord
return $this->filters->only(self::DECORATION_FILTERS);
}
+ // /**
+ // * @param null|string $json
+ // * @return array
+ // */
+ // public function deserializeFilters(?string $json): array {
+ // return $json !== null ? collect(json_decode($json))->toArray() : [];
+ // }
+
/**
- * @param null|string $json
+ * @param null|string $param
* @return array
*/
- public function deserializeFilters(?string $json): array {
+ public function deserializeFilters($param): array {
+ if(gettype($param) == "array"){
+ $json = implode(',', $param);
+ }
+ else{
+ $json = $param;
+ }
return $json !== null ? collect(json_decode($json))->toArray() : [];
}
@@ -50,9 +64,9 @@ abstract class AbstractGetRecord
* @param array $filters
* @return mixed
*/
- public function handler(array $filters){
+ public function handler(array $filters, array $params = []){
$this->filters = collect($filters);
- return $this->getResults($this->applyFiltersToQuery());
+ return $this->getResults($this->applyFiltersToQuery(), $params);
}
@@ -65,6 +79,6 @@ abstract class AbstractGetRecord
* @param Builder $query
* @return mixed
*/
- abstract function getResults(Builder $query);
+ abstract function getResults(Builder $query, array $params = []);
-}
\ No newline at end of file
+}
diff --git a/app/Classes/General/Eloquent/AbstractListRecord.php b/app/Classes/General/Eloquent/AbstractListRecord.php
index 7b7d0df9..f898f108 100644
--- a/app/Classes/General/Eloquent/AbstractListRecord.php
+++ b/app/Classes/General/Eloquent/AbstractListRecord.php
@@ -17,11 +17,11 @@ abstract class AbstractListRecord extends AbstractGetRecord
* @return mixed
* @throws MalformedRequestException
*/
- public function execute(array $filters = []){
+ public function execute(array $filters = [], array $param = []){
try{
- return $this->handler($filters);
+ return $this->handler($filters, $param);
} catch (QueryException $exception){
log::error($exception);
@@ -30,18 +30,24 @@ abstract class AbstractListRecord extends AbstractGetRecord
}
+
/**
* @param Builder $query
* @return mixed
*/
- public function getResults(Builder $query) {
+ public function getResults(Builder $query, array $param = []) {
$filters = $this->getDecorationFilters();
if($filters->has('order_by')){
$query = $query->orderBy($filters->get('order_by')->column, $filters->get('order_by')->DESC ? 'DESC': 'ASC');
}
- return $filters->has('per_page') ? $query->paginate($filters->get('per_page')) : $query->get();
+ 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();
+ }
}
diff --git a/app/Classes/General/Eloquent/Filters/JobId.php b/app/Classes/General/Eloquent/Filters/JobId.php
new file mode 100644
index 00000000..42ac51a4
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/JobId.php
@@ -0,0 +1,20 @@
+where('job_id', $value);
+ }
+
+}
diff --git a/app/Classes/General/Eloquent/Filters/OrderByIdDesc.php b/app/Classes/General/Eloquent/Filters/OrderByIdDesc.php
new file mode 100644
index 00000000..547ec9bd
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/OrderByIdDesc.php
@@ -0,0 +1,20 @@
+orderBy('id', 'desc');
+ }
+
+}
diff --git a/app/Classes/General/Eloquent/Filters/RequestSignature.php b/app/Classes/General/Eloquent/Filters/RequestSignature.php
new file mode 100644
index 00000000..67dde0a3
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/RequestSignature.php
@@ -0,0 +1,19 @@
+where('request_signature', $value);
+ }
+
+}
diff --git a/app/Classes/General/Eloquent/Filters/ResultNotNull.php b/app/Classes/General/Eloquent/Filters/ResultNotNull.php
new file mode 100644
index 00000000..3f6a0341
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/ResultNotNull.php
@@ -0,0 +1,18 @@
+whereNotNull('result');
+ }
+}
diff --git a/app/Classes/General/Helper.php b/app/Classes/General/Helper.php
index ac89540b..45c72f53 100644
--- a/app/Classes/General/Helper.php
+++ b/app/Classes/General/Helper.php
@@ -2,6 +2,7 @@
namespace App\Classes\General;
+use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
@@ -42,4 +43,27 @@ class Helper
}
}
}
+
+ /**
+ * @param null|string $param
+ * @return array
+ */
+ static function deserializeFilters($param): array {
+ if(gettype($param) == "array"){
+ $json = implode(',', $param);
+ }
+ else{
+ $json = $param;
+ }
+ return $json !== null ? collect(json_decode($json))->toArray() : [];
+ }
+
+ /**
+ * @param ResourceCollection $collection
+ * @return array
+ */
+ static function collectionResponse(ResourceCollection $collection){
+ return json_decode($collection->response()->getContent(), true);
+ }
+
}
diff --git a/app/Classes/Jobs/ListBookingsJob.php b/app/Classes/Jobs/ListBookingsJob.php
new file mode 100644
index 00000000..b021b71d
--- /dev/null
+++ b/app/Classes/Jobs/ListBookingsJob.php
@@ -0,0 +1,52 @@
+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(ListBookingsJobProcessor::class))->execute($this->listGenericJobObject);
+ }
+
+ public function getJobId(){
+ return $this->job->getJobId();
+ }
+}
diff --git a/app/Classes/Jobs/ListDocumentsJob.php b/app/Classes/Jobs/ListDocumentsJob.php
new file mode 100644
index 00000000..6e93062b
--- /dev/null
+++ b/app/Classes/Jobs/ListDocumentsJob.php
@@ -0,0 +1,63 @@
+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(ListDocumentsJobProcessor::class))->execute($this->listGenericJobObject);
+
+ //cief todo: Insert into DB: job id, query result, timestamp
+ // Store the result in the job_results table
+
+ //cief todo: why cannot save data in table like this
+ // $model = new JobResult();
+ // $model->job_id = $this->job->getJobId();
+ // $model->result = json_encode($result);
+ // $model->save();
+
+ // Log::error(json_encode($model->id));
+ }
+
+ public function getJobId(){
+ return $this->job->getJobId();
+ }
+}
diff --git a/app/Classes/Jobs/ListTransactionsJob.php b/app/Classes/Jobs/ListTransactionsJob.php
new file mode 100644
index 00000000..a2b28656
--- /dev/null
+++ b/app/Classes/Jobs/ListTransactionsJob.php
@@ -0,0 +1,52 @@
+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(ListTransactionsJobProcessor::class))->execute($this->listGenericJobObject);
+ }
+
+ public function getJobId(){
+ return $this->job->getJobId();
+ }
+}
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php
new file mode 100644
index 00000000..ef3570f7
--- /dev/null
+++ b/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php
@@ -0,0 +1,75 @@
+ 'List Booking Job',
+ 'message' => 'You have successfully submit a job to list bookings'
+ ];
+ }
+
+ /** @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) [
+ 'type' => $user->type,
+ ];
+
+ $userInfoJson = json_encode($userInfo);
+ $requestSignature = md5($userInfoJson . $request->fullUrl());
+
+ $listGenericJobObject = new ListGenericJobObject(
+ $request->fullUrl(),
+ $request->all(),
+ $requestSignature,
+ null,
+ $jobId,
+ $userInfo
+ );
+
+ ListBookingsJob::dispatch($listGenericJobObject);
+
+ $result = [];
+ $result['job_id'] = $jobId;
+
+ $this->createsJobResult->execute($listGenericJobObject);
+
+ return $this->response(['data' => $result]);
+ }
+
+}
diff --git a/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php b/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php
new file mode 100644
index 00000000..2a09eb12
--- /dev/null
+++ b/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php
@@ -0,0 +1,46 @@
+listsBookings = $listsBookings;
+ $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->listsBookings->execute($this->listsBookings->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page']]);
+ foreach ($query->items() as &$item) {
+ $item['userInfo'] = $listGenericJobObject->getUserInfo();
+ }
+ $resultCurrent = Helper::collectionResponse(ListBookingJobResource::collection($query));
+ $this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
+ }
+}
diff --git a/app/Classes/Modules/Documents/ControllersLogic/ListDocumentJobLogic.php b/app/Classes/Modules/Documents/ControllersLogic/ListDocumentJobLogic.php
new file mode 100644
index 00000000..5e895ad8
--- /dev/null
+++ b/app/Classes/Modules/Documents/ControllersLogic/ListDocumentJobLogic.php
@@ -0,0 +1,75 @@
+ 'List Document Job',
+ 'message' => 'You have successfully submit a job to list documents'
+ ];
+ }
+
+ /** @var CreatesJobResult */
+ private $createsJobResult;
+
+ /**
+ * ListDocumentJobLogic 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
+ );
+
+ ListDocumentsJob::dispatch($listGenericJobObject);
+
+ $result = [];
+ $result['job_id'] = $jobId;
+
+ $this->createsJobResult->execute($listGenericJobObject);
+
+ return $this->response(['data' => $result]);
+ }
+}
diff --git a/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php b/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php
new file mode 100644
index 00000000..70777f0c
--- /dev/null
+++ b/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php
@@ -0,0 +1,47 @@
+listsDocuments = $listsDocuments;
+ $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->listsDocuments->execute($this->listsDocuments->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page']]);
+ foreach ($query->items() as &$item) {
+ $item['userInfo'] = $listGenericJobObject->getUserInfo();
+ }
+ $resultCurrent = Helper::collectionResponse(ListDocumentJobResource::collection($query));
+ $this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
+ }
+}
+
diff --git a/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php b/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php
new file mode 100644
index 00000000..c4b72cf0
--- /dev/null
+++ b/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php
@@ -0,0 +1,51 @@
+ '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));
+ }
+
+}
diff --git a/app/Classes/Modules/Jobs/DataTransferObjects/ListGenericJobObject.php b/app/Classes/Modules/Jobs/DataTransferObjects/ListGenericJobObject.php
new file mode 100644
index 00000000..953d77d7
--- /dev/null
+++ b/app/Classes/Modules/Jobs/DataTransferObjects/ListGenericJobObject.php
@@ -0,0 +1,118 @@
+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;
+ }
+
+}
diff --git a/app/Classes/Modules/Jobs/DataTransferObjects/UpdateJobResultObject.php b/app/Classes/Modules/Jobs/DataTransferObjects/UpdateJobResultObject.php
new file mode 100644
index 00000000..636c56b0
--- /dev/null
+++ b/app/Classes/Modules/Jobs/DataTransferObjects/UpdateJobResultObject.php
@@ -0,0 +1,60 @@
+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;
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php b/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php
new file mode 100644
index 00000000..89783fe8
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php
@@ -0,0 +1,47 @@
+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;
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php b/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php
new file mode 100644
index 00000000..0106417d
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php
@@ -0,0 +1,64 @@
+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);
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Services/CreatesJobResult.php b/app/Classes/Modules/Jobs/Services/CreatesJobResult.php
new file mode 100644
index 00000000..e70e0e6a
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Services/CreatesJobResult.php
@@ -0,0 +1,26 @@
+job_id = $listGenericJobObject->getJobId();
+ $model->request_signature = $listGenericJobObject->getRequestSignature();
+ $model->result_signature = $listGenericJobObject->getResultSignature();
+ $model->url = $listGenericJobObject->getName();
+
+ return $this->handler($model);
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Services/FetchesJobResult.php b/app/Classes/Modules/Jobs/Services/FetchesJobResult.php
new file mode 100644
index 00000000..1cc99cb6
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Services/FetchesJobResult.php
@@ -0,0 +1,33 @@
+repository = $repository;
+ }
+
+
+ /**
+ * @return Builder
+ */
+ public function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Services/ListsJobResult.php b/app/Classes/Modules/Jobs/Services/ListsJobResult.php
new file mode 100644
index 00000000..55f3b267
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Services/ListsJobResult.php
@@ -0,0 +1,33 @@
+repository = $repository;
+ }
+
+
+ /**
+ * @return Builder
+ */
+ function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/Modules/Jobs/Services/UpdatesJobResult.php b/app/Classes/Modules/Jobs/Services/UpdatesJobResult.php
new file mode 100644
index 00000000..ab3d9385
--- /dev/null
+++ b/app/Classes/Modules/Jobs/Services/UpdatesJobResult.php
@@ -0,0 +1,28 @@
+result = $updateJobResultObject->getResult();
+ $model->result_signature = $updateJobResultObject->getResultSignature();
+ $model->job_command_name = $updateJobResultObject->getJobCommandName();
+ $model->job_command = $updateJobResultObject->getJobCommand();
+
+ return $this->handler($model);
+
+ }
+}
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ListTransactionsJobLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ListTransactionsJobLogic.php
new file mode 100644
index 00000000..654a360f
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/ListTransactionsJobLogic.php
@@ -0,0 +1,74 @@
+ 'List Transaction Job',
+ 'message' => 'You have successfully submit a job to list transactions'
+ ];
+ }
+
+ /** @var CreatesJobResult */
+ private $createsJobResult;
+
+ /**
+ * ListTransactionsJobLogic 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) [
+ 'type' => $user->type,
+ ];
+
+ $userInfoJson = json_encode($userInfo);
+ $requestSignature = md5($userInfoJson . $request->fullUrl());
+
+ $listGenericJobObject = new ListGenericJobObject(
+ $request->fullUrl(),
+ $request->all(),
+ $requestSignature,
+ null,
+ $jobId,
+ $userInfo
+ );
+
+ ListTransactionsJob::dispatch($listGenericJobObject);
+
+ $result = [];
+ $result['job_id'] = $jobId;
+
+ $this->createsJobResult->execute($listGenericJobObject);
+
+ return $this->response(['data' => $result]);
+ }
+
+}
diff --git a/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php b/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php
new file mode 100644
index 00000000..475d4715
--- /dev/null
+++ b/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php
@@ -0,0 +1,45 @@
+listsTransactions = $listsTransactions;
+ $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->listsTransactions->execute($this->listsTransactions->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page']]);
+
+ $resultCurrent = Helper::collectionResponse(ListTransactionJobResource::collection($query));
+ $this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
+ }
+}
+
diff --git a/app/Http/Controllers/Bookings/ListBookingsJobController.php b/app/Http/Controllers/Bookings/ListBookingsJobController.php
new file mode 100644
index 00000000..9b32fc77
--- /dev/null
+++ b/app/Http/Controllers/Bookings/ListBookingsJobController.php
@@ -0,0 +1,22 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Documents/ListDocumentsJobController.php b/app/Http/Controllers/Documents/ListDocumentsJobController.php
new file mode 100644
index 00000000..8b763085
--- /dev/null
+++ b/app/Http/Controllers/Documents/ListDocumentsJobController.php
@@ -0,0 +1,19 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Jobs/FetchJobResultController.php b/app/Http/Controllers/Jobs/FetchJobResultController.php
new file mode 100644
index 00000000..cfef2f5c
--- /dev/null
+++ b/app/Http/Controllers/Jobs/FetchJobResultController.php
@@ -0,0 +1,19 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Transactions/ListTransactionsJobController.php b/app/Http/Controllers/Transactions/ListTransactionsJobController.php
new file mode 100644
index 00000000..fb341d5d
--- /dev/null
+++ b/app/Http/Controllers/Transactions/ListTransactionsJobController.php
@@ -0,0 +1,21 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php
index f3a7881d..70fbc95c 100644
--- a/app/Http/Resources/BookingResource.php
+++ b/app/Http/Resources/BookingResource.php
@@ -11,11 +11,9 @@ use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\DocumentType;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
-use Illuminate\Support\Facades\Log;
class BookingResource extends JsonResource
{
-
/**
* Transform the resource into an array.
*
diff --git a/app/Http/Resources/CompanyResource.php b/app/Http/Resources/CompanyResource.php
index 85ecee16..eff2bd1b 100644
--- a/app/Http/Resources/CompanyResource.php
+++ b/app/Http/Resources/CompanyResource.php
@@ -15,7 +15,6 @@ use App\Models\SegmentConstant;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\Log;
class CompanyResource extends JsonResource
{
diff --git a/app/Http/Resources/DocumentResource.php b/app/Http/Resources/DocumentResource.php
index 59933a67..c0f801bb 100644
--- a/app/Http/Resources/DocumentResource.php
+++ b/app/Http/Resources/DocumentResource.php
@@ -3,10 +3,7 @@
namespace App\Http\Resources;
use App\Models\Booking;
-use App\Models\Company;
-use App\Models\Document;
use Carbon\Carbon;
-use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Resources\Json\JsonResource;
class DocumentResource extends JsonResource
diff --git a/app/Http/Resources/JobResultResource.php b/app/Http/Resources/JobResultResource.php
new file mode 100644
index 00000000..51bc1898
--- /dev/null
+++ b/app/Http/Resources/JobResultResource.php
@@ -0,0 +1,22 @@
+ $this->job_id,
+ 'result' => $this->result,
+ ];
+ }
+}
diff --git a/app/Http/Resources/ListBookingJobResource.php b/app/Http/Resources/ListBookingJobResource.php
new file mode 100644
index 00000000..06f8c38d
--- /dev/null
+++ b/app/Http/Resources/ListBookingJobResource.php
@@ -0,0 +1,81 @@
+userInfo = $userInfo ?? ($resource->userInfo ?? null);
+ }
+
+ /**
+ * Transform the resource into an array.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return array
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ public function toArray($request)
+ {
+ return [
+ 'id' => $this->id,
+ 'company' => new CompanyResource($this->company, $this->userInfo),
+ 'bank' => new BankResource($this->bank),
+ 'service' => new ServiceTypeResource($this->service),
+ 'marking' => $this->marking,
+ 'amount' => $this->fix_amount,
+ 'floating_amount' => floatval((App()->make(CalculatesBookingFloatingAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'paid_amount' => floatval((App()->make(CalculatesBookingPayableAmount::class))->execute($this->resource, $this->fix_currency_id)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'fixed_currency' => new CurrencyResource($this->fixedCurrency),
+ 'convertible_currency' => new CurrencyResource($this->convertibleCurrency),
+ 'conversion_currency' => new CurrencyResource($this->conversionCurrency),
+ 'documents' => [
+ 'purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->first()),
+ 'delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->first()),
+ 'invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->first()),
+ 'supplier_delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()),
+ 'proforma_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()),
+ 'ecommerce_purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->first()),
+ ],
+ 'status' => $this->status,
+ 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'),
+ 'created_at_with_time' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
+ $this->mergeWhen($this->relationLoaded('transactions'), [
+ 'purchase_order' => new TransactionResource($this->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first()),
+ 'payment_attempts' => TransactionResource::collection(
+ $this->transactions()
+ ->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)
+ ->whereDate('expires_on', '>=', Carbon::now())
+ ->get()
+ ),
+ 'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()),
+ 'payment_history' => TransactionResource::collection($this->transactions()->where(function($query){
+ $query->where(function($query){
+ $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]);
+ })->orWhere(function($query){
+ $query->where(function($query){
+ $query->where('type', TransactionType::REFUND)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED, ApprovalStatus::COMPLETED]);
+ })->orWhere(function($query){
+ $query->where('type', TransactionType::CREDIT_NOTE)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ });
+ });
+ })->latest()->get())
+ ])
+ ];
+ }
+}
diff --git a/app/Http/Resources/ListDocumentJobResource.php b/app/Http/Resources/ListDocumentJobResource.php
new file mode 100644
index 00000000..edf549ef
--- /dev/null
+++ b/app/Http/Resources/ListDocumentJobResource.php
@@ -0,0 +1,31 @@
+ $this->id,
+ 'reference' => $this->reference,
+ 'status' => (int) $this->status,
+ 'document_type' => $this->document_type,
+ 'owner' => $this->relationLoaded('owner') ? ($this->owner instanceof Booking ? new BookingV2Resource($this->owner, $this->userInfo) : new CompanyV2Resource($this->owner, $this->userInfo)) : null,
+ 'files' => FileResource::collection($this->files),
+ 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A')
+ ];
+ }
+}
diff --git a/app/Http/Resources/ListTransactionJobResource.php b/app/Http/Resources/ListTransactionJobResource.php
new file mode 100644
index 00000000..6c4c0ece
--- /dev/null
+++ b/app/Http/Resources/ListTransactionJobResource.php
@@ -0,0 +1,54 @@
+type, [TransactionType::BILL, TransactionType::REFUND])? $this->owner->owner : $this->owner;
+ $days = $this->created_at->endOfDay()->addWeekdays($booking->service_id === 3 ? 3 : 1);
+
+ return [
+ 'id' => $this->id,
+ 'booking' => new BookingResource($booking),
+ 'type' => (int) $this->type,
+ 'bill_no' => $this->bill_no,
+ 'payment_reference' => $this->payment_reference,
+ 'payment_method' => (float) $this->payment_method,
+ 'recipient_bank_account' => new BankResource($booking->bank),
+ 'issuer_name' => $this->issuerCompany->name,
+ 'issuer_id' => $this->issuerCompany->id,
+ 'amount' => (double) $this->amount,
+ 'original_amount' => (double) $this->original_amount,
+ 'currency' => new CurrencyResource($this->currency),
+ 'original_currency' => new CurrencyResource($this->original_currency),
+ 'service_charge' => (double) $this->service_charge,
+ 'tax' => (double) $this->tax,
+ 'currency_rate' => (double) $this->currency_rate,
+ 'status' => (int) $this->status,
+ 'details' => TransactionDetailResource::collection($this->transactionDetails),
+ 'documents' => new DocumentResource($this->documents()->first()),
+ 'transaction_bill' => new TransactionResource($this->when((int) $this->type === TransactionType::PAYMENT, $this->transactions()->bills()->first())),
+ 'transaction_refunds' => TransactionResource::collection($this->when((int) $this->type === TransactionType::PAYMENT, $this->transactions()->refunds()->get())),
+ 'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:i:s A'),
+ 'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y h:i:s A'),
+ 'interval' => [
+ 'value' => $days->gt(Carbon::now()) ? '+' : '-',
+ 'duration' => $days->diff(Carbon::now())->format('%d'),
+ ],
+ 'redemption' => new VoucherRedemptionResource($this->voucherRedemption)
+ ];
+ }
+}
diff --git a/app/Http/Resources/V2/BookingV2Resource.php b/app/Http/Resources/V2/BookingV2Resource.php
new file mode 100644
index 00000000..ee17181e
--- /dev/null
+++ b/app/Http/Resources/V2/BookingV2Resource.php
@@ -0,0 +1,82 @@
+userInfo = $userInfo ?? ($resource->userInfo ?? null);
+ }
+
+ /**
+ * Transform the resource into an array.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return array
+ * @throws \Illuminate\Contracts\Container\BindingResolutionException
+ */
+ public function toArray($request)
+ {
+ return [
+ 'id' => $this->id,
+ 'company' => new CompanyV2Resource($this->company, $this->userInfo),
+ 'bank' => new V1\BankResource($this->bank),
+ 'service' => new V1\ServiceTypeResource($this->service),
+ 'marking' => $this->marking,
+ 'amount' => $this->fix_amount,
+ 'floating_amount' => floatval((App()->make(CalculatesBookingFloatingAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'paid_amount' => floatval((App()->make(CalculatesBookingPayableAmount::class))->execute($this->resource, $this->fix_currency_id)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)),
+ 'fixed_currency' => new V1\CurrencyResource($this->fixedCurrency),
+ 'convertible_currency' => new V1\CurrencyResource($this->convertibleCurrency),
+ 'conversion_currency' => new V1\CurrencyResource($this->conversionCurrency),
+ 'documents' => [
+ 'purchase_order' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->first()),
+ 'delivery_order' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->first()),
+ 'invoice' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->first()),
+ 'supplier_delivery_order' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()),
+ 'proforma_invoice' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()),
+ 'ecommerce_purchase_order' => new V1\DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->first()),
+ ],
+ 'status' => $this->status,
+ 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'),
+ 'created_at_with_time' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
+ $this->mergeWhen($this->relationLoaded('transactions'), [
+ 'purchase_order' => new V1\TransactionResource($this->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first()),
+ 'payment_attempts' => V1\TransactionResource::collection(
+ $this->transactions()
+ ->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)
+ ->whereDate('expires_on', '>=', Carbon::now())
+ ->get()
+ ),
+ 'expired_payment_attempts' => V1\TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()),
+ 'payment_history' => V1\TransactionResource::collection($this->transactions()->where(function($query){
+ $query->where(function($query){
+ $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]);
+ })->orWhere(function($query){
+ $query->where(function($query){
+ $query->where('type', TransactionType::REFUND)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED, ApprovalStatus::COMPLETED]);
+ })->orWhere(function($query){
+ $query->where('type', TransactionType::CREDIT_NOTE)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ });
+ });
+ })->latest()->get())
+ ])
+ ];
+ }
+}
diff --git a/app/Http/Resources/V2/CompanyV2Resource.php b/app/Http/Resources/V2/CompanyV2Resource.php
new file mode 100644
index 00000000..64fca7c7
--- /dev/null
+++ b/app/Http/Resources/V2/CompanyV2Resource.php
@@ -0,0 +1,100 @@
+userInfo = $userInfo;
+ }
+
+ /**
+ * Transform the resource into an array.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return array
+ */
+ public function toArray($request)
+ {
+ $lastPayment = $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->orderBy('id', 'DESC')->first();
+ $totalPayments = $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount');
+
+ $segment = SegmentConstant::where('reference', SegmentConstants::SUPPLIER_CURRENCIES)->where('detail->id', $this->id)->first();
+ $serviceCharge = SegmentConstant::where('reference', SegmentConstants::SERVICE_CHARGE)->where('detail->id', $this->id)->first();
+
+ $userResource = null;
+
+ $userInfoEmail = $this->userInfo && isset($this->userInfo->email) ? $this->userInfo->email : null;
+ $userInfoType = $this->userInfo && isset($this->userInfo->type) ? $this->userInfo->type : null;
+
+ if(!$userInfoEmail && Auth::user()){
+ $userInfoEmail = Auth::user()->email;
+ }
+ if(!$userInfoType && Auth::user()){
+ $userInfoType = Auth::user()->type;
+ }
+
+ if(!is_null($userInfoEmail) && !is_null($userInfoType)){
+ $userResource = new V1\UserResource($userInfoType === RoleTypes::USER ? $this->employees()->where('email', '=', $userInfoEmail)->first() : $this->employees()->orderBy('id', 'DESC')->first());
+ }
+
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'reference' => $this->reference,
+ 'debtor' => $this->debtor,
+ 'type' => (int) $this->type,
+ 'business_type' => (int) $this->business_type,
+ 'status' => (int) $this->status,
+ 'contact' => new V1\ContactResource ($this->when($this->has('contacts'), $this->contacts->first())),
+ 'address' => new V1\AddressResource($this->when($this->has('addresses'), $this->addresses->where('billing', true)->first())),
+ 'employee' => $userResource,
+ 'identification' => new V1\DocumentResource($this->documents->whereIn('document_type', DocumentType::IDENTIFICATION_DOCUMENTS)->first()),
+ 'bookings' => $this->whenLoaded('bookings', $this->bookings()->orderBy('id', 'DESC')->get(), []),
+ 'confirmed_bookings' => $this->bookings()->whereHas('transactions', function ($query){
+ $query->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ })->count(),
+ 'total_payments' => (float) $totalPayments,
+ 'average_spending_per_day' => (float) $totalPayments / ($this->created_at->diff(Carbon::now())->days === 0 ? 1 : $this->created_at->diff(Carbon::now())->days),
+ 'average_spending_per_booking' => (float) $totalPayments > 0 ? $totalPayments / $this->bookings()->whereHas('transactions', function ($query){
+ $query->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ })->count() : $totalPayments,
+ 'last_payment' => $lastPayment ? $lastPayment->created_at->diffForHumans() : 'No Payments',
+ 'personal_banks' => V1\BankResource::collection($this->banks->where('type', BankAccountType::PERSONAL)),
+ 'recipient_banks' => [
+ 'accounts' => V1\BankResource::collection($this->banks->where('type', BankAccountType::EXTERNAL)),
+ 'default' => new V1\BankResource($this->banks->where('type', BankAccountType::EXTERNAL)->where('default', true)->first())
+ ],
+ 'segments' => V1\SegmentResource::collection($this->segments),
+ 'seasonalSegment' => $this->whenLoaded('seasonalSegments', V1\SeasonalSegmentResource::collection($this->seasonalSegments)),
+ 'services' => (new FetchesCompanyServices())->getServices($this->servicesConfigurations()),
+ 'wallet' => $this->whenLoaded('wallets', new V1\WalletResource($this->wallets()->with('transactions')->first()), new V1\WalletResource($this->wallets()->first())),
+ 'created_at' => $this->created_at->format('d-m-Y'),
+ $this->mergeWhen($this->business_type === BusinessType::CURRENCY_VENDOR, [
+ 'currencies' => $segment ? V1\CurrencyResource::collection(Currency::whereIn('id', $segment->detail->currencies)->get()) : [],
+ 'service_charge' => $serviceCharge
+ ])
+
+ ];
+ }
+}
diff --git a/app/Models/JobResult.php b/app/Models/JobResult.php
new file mode 100644
index 00000000..f30b5076
--- /dev/null
+++ b/app/Models/JobResult.php
@@ -0,0 +1,13 @@
+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');
+ }
+}
diff --git a/database/migrations/2023_08_29_063531_add_new_column_to_job_results_table.php b/database/migrations/2023_08_29_063531_add_new_column_to_job_results_table.php
new file mode 100644
index 00000000..8e6b8342
--- /dev/null
+++ b/database/migrations/2023_08_29_063531_add_new_column_to_job_results_table.php
@@ -0,0 +1,36 @@
+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');
+ });
+ }
+}
diff --git a/database/migrations/2023_12_11_193200_add_new_column_2_to_job_results_table.php b/database/migrations/2023_12_11_193200_add_new_column_2_to_job_results_table.php
new file mode 100644
index 00000000..12c6d57f
--- /dev/null
+++ b/database/migrations/2023_12_11_193200_add_new_column_2_to_job_results_table.php
@@ -0,0 +1,34 @@
+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');
+ });
+ }
+}
diff --git a/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue
new file mode 100644
index 00000000..966ccbbc
--- /dev/null
+++ b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue
@@ -0,0 +1,136 @@
+
+

Nothing To Show Here
+