diff --git a/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php new file mode 100644 index 00000000..c0eb9e74 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php @@ -0,0 +1,23 @@ +where(function($q) use ($value) { + $q->whereDoesntHave('owners'); + $q->orwhereDoesntHave('owner_status'); + }); + } + +} 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/Eloquent/Filters/StatementTransactionPostingEnd.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php new file mode 100644 index 00000000..e837245e --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '<=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php new file mode 100644 index 00000000..c3560357 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '>=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php new file mode 100644 index 00000000..b10fd92d --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereNotNull($value); + }); + } + +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php new file mode 100644 index 00000000..a9317771 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereNull($value); + }); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php index f9eb9c7b..7ae8a2ae 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php @@ -62,7 +62,7 @@ class GroupApproveStatementTransactionLogic extends AbstractControllerLogic $statementTransactions = $this->listsBankStatementTransactions->execute($filters); foreach ($statementTransactions as $statementTransaction) { - $owners = $statementTransaction->owners; + $owners = $statementTransaction->owners()->where('status', ApprovalStatus::PENDING_VERIFICATION)->get(); if (count($owners)) { $this->updatesBankStatementTransactionOwnerStatus->execute($owners->first(), ApprovalStatus::APPROVED); diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php index 9f6c28e6..70186ce1 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php @@ -157,7 +157,7 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic 'owner_reference' => $owner_reference, ]; - return $bankStatementTransaction->owners()->firstOrCreate($ownerData); + return $bankStatementTransaction->owners()->where('status','<>',ApprovalStatus::REJECTED)->firstOrCreate($ownerData); } private function editAccountMapped(StatementTransactionOwner $owner){ diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index 36fc684a..6f7efe5e 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -28,6 +28,7 @@ class CreateBankStatementTransactionOwnersProcessor // $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get(); foreach ($transactions as $transaction) { + $mapped = false; $keywords = array_filter(explode(" ", $transaction->transaction_description . " " . $transaction->transaction_description_2)); if($transaction->amount > 0){ @@ -36,7 +37,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -45,12 +46,11 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - // Shipping Portal Sales - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 2, PaymentMethodType::WALLET); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [2], PaymentMethodType::WALLET); foreach ($creditTransactions as $creditTransaction) { if($creditTransaction['owner_type'] === Wallet::class) continue; - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -63,7 +63,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -72,9 +72,9 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 5, null); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [5,15], null); foreach ($creditTransactions as $creditTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -85,7 +85,7 @@ class CreateBankStatementTransactionOwnersProcessor // fpx charge refund if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND ]); } @@ -94,7 +94,7 @@ class CreateBankStatementTransactionOwnersProcessor // INTERNAL_BANK_TRANSFER_IN if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN ]); } @@ -119,7 +119,7 @@ class CreateBankStatementTransactionOwnersProcessor ->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get(); foreach ($debitTransactions as $debitTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT, 'system' => 'EXCHANGE', 'owner_type' => Group::class, @@ -135,7 +135,7 @@ class CreateBankStatementTransactionOwnersProcessor $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($debitTransactions as $debitTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -148,50 +148,52 @@ class CreateBankStatementTransactionOwnersProcessor // STATUTORY if(str_contains($transaction->transaction_description_2, 'PEMBANGUNAN SUMBER') || str_contains($transaction->transaction_description_2, 'HASIL') || str_contains($transaction->transaction_description_2, 'PERTUBUHAN KESELAMAT') || str_contains($transaction->transaction_description_2, 'KUMPULAN WANG SIMPAN')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::STATUTORY ]); } // FPX_CHARGE if($transaction->transaction_description === 'DR DUITNOW S/CHRG' || str_contains($transaction->transaction_description, 'Manual FPX') || str_contains($transaction->transaction_description, 'CMS - DR FPX CHG')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE ]); } // BANK_CHARGE if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::BANK_CHARGE ]); } // CREDIT_CARD_PAYMENT if(str_contains($transaction->transaction_description_2, 'VISA CARD')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::CREDIT_CARD_PAYMENT ]); } // INTERNAL_BANK_TRANSFER_OUT if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE') || str_contains($transaction->transaction_description_2, 'CIEF WORLWIDE') || str_contains($transaction->transaction_description_2, 'IZYIM GLOBAL')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_OUT ]); } // non-operational charges if(str_contains($transaction->transaction_description_2, 'HIRE PURCHASE') || str_contains($transaction->transaction_description_2, 'TENAGA NASIONAL') || str_contains($transaction->transaction_description, 'CABLE CHARGE') || str_contains($transaction->transaction_description_2, 'CTOS DATA SYSTEMS') || str_contains($transaction->transaction_description_2, 'MAXIS')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::NON_OPERATIONAL ]); } } + if (isset($data) && $data->wasRecentlyCreated) $mapped = true; + $this->updateMappedRate($transaction, $mapped); } - } + } - private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { $dateRange = $this->getDateRange($date, 4); if (App::environment(['production'])) { $query = $model::whereIn('status', $statuses) @@ -318,7 +320,7 @@ class CreateBankStatementTransactionOwnersProcessor try{ $client = new \GuzzleHttp\Client(['verify' => false]); - $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":['.$type.']}'); + $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":'.json_encode($type).'}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload']; @@ -345,4 +347,11 @@ class CreateBankStatementTransactionOwnersProcessor 'end_date' => $nextDay, ]; } + + private function updateMappedRate($transaction, $mapped) { + $statement = $transaction->statement; + $statement->total_rows = StatementTransaction::where('account_statement_id',$transaction->account_statement_id)->count(); + $statement->mapped_rows = $mapped ? $statement->mapped_rows+1 : $statement->mapped_rows; + $statement->save(); + } } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php new file mode 100644 index 00000000..8ee2bbfa --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php @@ -0,0 +1,57 @@ + 'Expire Payment', + 'message' => 'You have successfully expire the Payment' + ]; + } + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** + * DeletePurchaseOrderPdfLogic constructor. + * @param FetchesBooking $fetchesBooking + */ + public function __construct(fetchesBooking $fetchesBooking) + { + $this->fetchesBooking = $fetchesBooking; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $payment = $booking->transactions() + ->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) + ->first(); + + $payment->status = ApprovalStatus::EXPIRED; + $payment->save(); + + return $this->response([]); + } + +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php index c87751a3..ef3570f7 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/ListBookingJobLogic.php @@ -5,12 +5,12 @@ namespace App\Classes\Modules\Bookings\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Jobs\ListBookingsJob; -use App\Classes\Modules\Bookings\Standards\Rules\CanListBookings; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; -use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use App\Classes\Modules\Jobs\Services\CreatesJobResult; + class ListBookingJobLogic extends AbstractControllerLogic { @@ -24,6 +24,19 @@ class ListBookingJobLogic extends AbstractControllerLogic ]; } + /** @var CreatesJobResult */ + private $createsJobResult; + + /** + * ListPackingListsJobLogic constructor. + * @param CreatesJobResult $createsJobResult + */ + public function __construct(CreatesJobResult $createsJobResult) + { + $this->createsJobResult = $createsJobResult; + } + + /** * @param Request $request * @return JsonResponse @@ -34,13 +47,17 @@ class ListBookingJobLogic extends AbstractControllerLogic $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 ); @@ -50,6 +67,8 @@ class ListBookingJobLogic extends AbstractControllerLogic $result = []; $result['job_id'] = $jobId; + $this->createsJobResult->execute($listGenericJobObject); + return $this->response(['data' => $result]); } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php index 252412a2..5d067fd5 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -9,13 +9,16 @@ use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus; use App\Classes\Modules\Transactions\Services\DeletesTransaction; use App\Classes\Modules\Documents\Services\DeletesDocument; use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor; - +use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionWithInvoiceNoProcessor; +use Illuminate\Support\Str; use App\Classes\ValueObjects\Constants\DocumentType; use App\Http\Resources\BookingResource; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; +use App\Models\Transaction; +use Illuminate\Support\Carbon; class RegenerateInvoiceBookingLogic extends AbstractControllerLogic { @@ -23,7 +26,8 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic /** * @return array */ - protected function notification():array { + protected function notification(): array + { return [ 'title' => 'Regenerate Booking Invoice', 'message' => 'You have successfully regenerate booking invoice' @@ -48,6 +52,9 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic /** @var CreateInvoiceTransactionProcessor */ private $createInvoiceTransactionProcessor; + /** @var CreateInvoiceTransactionWithInvoiceNoProcessor */ + private $createInvoiceTransactionWithInvoiceNoProcessor; + /** * FetchBookingLogic constructor. * @param CanFetchBooking $canFetchBooking @@ -56,6 +63,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic * @param UpdatesBookingStatus $updatesBookingStatus * @param DeletesDocument $deletesDocument * @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor + * @param CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor */ public function __construct( CanFetchBooking $canFetchBooking, @@ -63,15 +71,16 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic DeletesTransaction $deletesTransaction, UpdatesBookingStatus $updatesBookingStatus, DeletesDocument $deletesDocument, - CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor - ) - { + CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor, + CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor + ) { $this->canFetchBooking = $canFetchBooking; $this->fetchesBooking = $fetchesBooking; $this->deletesTransaction = $deletesTransaction; $this->updatesBookingStatus = $updatesBookingStatus; $this->deletesDocument = $deletesDocument; $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; + $this->createInvoiceTransactionWithInvoiceNoProcessor = $createInvoiceTransactionWithInvoiceNoProcessor; } @@ -82,18 +91,45 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic * @throws \App\Classes\Exceptions\MalformedRequestException * @throws \App\Classes\Exceptions\RequestValidationException */ - public function logic(Request $request) : JsonResponse + public function logic(Request $request): JsonResponse { $this->canFetchBooking->passes(); - $booking = $this->fetchesBooking->execute([ - 'id' => $request->route('id'), - 'status' => ApprovalStatus::COMPLETED, - 'with_transactions' => true] + $booking = $this->fetchesBooking->execute( + [ + 'id' => $request->route('id'), + 'status' => ApprovalStatus::COMPLETED, + 'with_transactions' => true + ] ); $this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED); + $firstInvoice = $booking->transactions() + ->whereIn('type', [TransactionType::INVOICE]) + ->withTrashed() + ->orderBy('created_at', 'asc') + ->first(); + + // get the first bill_no + $firstBillNo = $firstInvoice->bill_no; + if (strpos($firstBillNo, '-deleted') !== false) { + $firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted')); + } + + // update currentInvoice bill_no to '-deleted-' + $currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first(); + $currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp); + $currentInvoice->save(); + + $transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get(); + if ($transactionWithSameBillNo) { + foreach ($transactionWithSameBillNo as $transaction) { + $transaction->bill_no = $transaction->bill_no . "-deleted-" . Str::random(10); + $transaction->save(); + } + } + $transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get(); foreach ($transaction as $key => $row) { $this->deletesTransaction->execute($row); @@ -104,9 +140,8 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic $this->deletesDocument->execute($row); } - $this->createInvoiceTransactionProcessor->execute($booking); + $this->createInvoiceTransactionWithInvoiceNoProcessor->execute($booking, $firstBillNo); return $this->resourceResponse(new BookingResource($booking)); } - } diff --git a/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php b/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php index 6ded2977..2a09eb12 100644 --- a/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php +++ b/app/Classes/Modules/Bookings/Processors/ListBookingsJobProcessor.php @@ -3,14 +3,10 @@ namespace App\Classes\Modules\Bookings\Processors; use App\Classes\Modules\Bookings\Services\ListsBookings; -use App\Classes\Modules\Jobs\Services\CreatesJobResult; -use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\Modules\Jobs\Processors\UpdateJobResultProcessor; use App\Classes\General\Helper; -use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Log; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; -use Illuminate\Http\Resources\Json\ResourceCollection; -use App\Http\Resources\BookingResource; +use App\Http\Resources\ListBookingJobResource; class ListBookingsJobProcessor { @@ -18,24 +14,25 @@ class ListBookingsJobProcessor /** @var ListsBookings */ private $listsBookings; - /** @var CreatesJobResult */ - private $createsJobResult; + /** @var UpdateJobResultProcessor */ + private $updateJobResultProcessor; /** * ListBookingsJobProcessor constructor. * @param ListsBookings $listsBookings - * @param CreatesJobResult $createsJobResult + * @param UpdateJobResultProcessor $updateJobResultProcessor */ - public function __construct(ListsBookings $listsBookings, CreatesJobResult $createsJobResult) + public function __construct(ListsBookings $listsBookings, UpdateJobResultProcessor $updateJobResultProcessor) { $this->listsBookings = $listsBookings; - $this->createsJobResult = $createsJobResult; + $this->updateJobResultProcessor = $updateJobResultProcessor; } /** * @param ListGenericJobObject $listGenericJobObject - * @return null|object + * @return void * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\JobResourceNotFoundException */ public function execute(ListGenericJobObject $listGenericJobObject) { @@ -43,15 +40,7 @@ class ListBookingsJobProcessor foreach ($query->items() as &$item) { $item['userInfo'] = $listGenericJobObject->getUserInfo(); } - - //cief todo: remove comments - $result = Helper::collectionResponse(BookingResource::collection($query)); - - // $result = new JobBookingCollectionResponse($query, $listGenericJobObject->getuserInfo()); - // $result = $this->collectionResponse(new BookingResourceCollection(BookingResource::collection($query), $listGenericJobObject->getuserInfo())); - - $create = $this->createsJobResult->execute($listGenericJobObject, json_encode($result)); - - return $create; + $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 index 041bb9c8..5e895ad8 100644 --- a/app/Classes/Modules/Documents/ControllersLogic/ListDocumentJobLogic.php +++ b/app/Classes/Modules/Documents/ControllersLogic/ListDocumentJobLogic.php @@ -4,15 +4,11 @@ namespace App\Classes\Modules\Documents\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Documents\Services\ListsDocuments; +use App\Classes\Modules\Jobs\Services\CreatesJobResult; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; use App\Classes\Jobs\ListDocumentsJob; -use App\Http\Resources\DocumentResource; -use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use App\Classes\General\Helper; -use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Auth; class ListDocumentJobLogic extends AbstractControllerLogic @@ -28,6 +24,19 @@ class ListDocumentJobLogic extends AbstractControllerLogic ]; } + /** @var CreatesJobResult */ + private $createsJobResult; + + /** + * ListDocumentJobLogic constructor. + * @param CreatesJobResult $createsJobResult + */ + public function __construct(CreatesJobResult $createsJobResult) + { + $this->createsJobResult = $createsJobResult; + } + + /** * @param Request $request * @return JsonResponse @@ -42,33 +51,25 @@ class ListDocumentJobLogic extends AbstractControllerLogic '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); - //cief todo: remove comments - // // Create your job instance with delay, so we can back here within delay and take control in our hands. - // $job = new ListDocuments($listGenericJobObject); - // $job->delay(now()->addSeconds(5)); - - // // Dispath your job with our custom_dispatch helper. This will return job id from jobs table - // // $jobId = $this->custom_dispatch($job); - - $result = []; $result['job_id'] = $jobId; + $this->createsJobResult->execute($listGenericJobObject); + return $this->response(['data' => $result]); } - - //cief todo: no longer need jobId - // function custom_dispatch($job): int { - // return app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($job); - // } } diff --git a/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php b/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php index eb7cf1c4..70777f0c 100644 --- a/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php +++ b/app/Classes/Modules/Documents/Processors/ListDocumentsJobProcessor.php @@ -3,15 +3,10 @@ namespace App\Classes\Modules\Documents\Processors; use App\Classes\Modules\Documents\Services\ListsDocuments; -use App\Classes\Modules\Jobs\Services\CreatesJobResult; -use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\Modules\Jobs\Processors\UpdateJobResultProcessor; use App\Classes\General\Helper; -use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Log; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; -use App\Http\Controllers\Documents\ListDocumentsController; -use Illuminate\Http\Resources\Json\ResourceCollection; -use App\Http\Resources\DocumentResource; +use App\Http\Resources\ListDocumentJobResource; class ListDocumentsJobProcessor { @@ -19,24 +14,25 @@ class ListDocumentsJobProcessor /** @var ListsDocuments */ private $listsDocuments; - /** @var CreatesJobResult */ - private $createsJobResult; + /** @var UpdateJobResultProcessor */ + private $updateJobResultProcessor; /** * ListDocumentsJobProcessor constructor. * @param ListsDocuments $listsDocuments - * @param CreatesJobResult $createsJobResult + * @param UpdateJobResultProcessor $updateJobResultProcessor */ - public function __construct(ListsDocuments $listsDocuments, CreatesJobResult $createsJobResult) + public function __construct(ListsDocuments $listsDocuments, UpdateJobResultProcessor $updateJobResultProcessor) { $this->listsDocuments = $listsDocuments; - $this->createsJobResult = $createsJobResult; + $this->updateJobResultProcessor = $updateJobResultProcessor; } /** * @param ListGenericJobObject $listGenericJobObject - * @return null|object + * @return void * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\JobResourceNotFoundException */ public function execute(ListGenericJobObject $listGenericJobObject) { @@ -44,11 +40,8 @@ class ListDocumentsJobProcessor foreach ($query->items() as &$item) { $item['userInfo'] = $listGenericJobObject->getUserInfo(); } - - $result = Helper::collectionResponse(DocumentResource::collection($query)); - - $create = $this->createsJobResult->execute($listGenericJobObject, json_encode($result)); - - return $create; + $resultCurrent = Helper::collectionResponse(ListDocumentJobResource::collection($query)); + $this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent); } } + diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php index 71363b52..e629675f 100644 --- a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php +++ b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php @@ -39,7 +39,8 @@ class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHead 'Net Total', 'Cancelled', 'Mapped Status', - 'Mapped Reference No' + 'Mapped Reference No', + 'MapPayment Received Date' ]; } @@ -72,6 +73,7 @@ class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHead Arr::get($data,'cancelled'), Arr::get($data,'mapped_status'), Arr::get($data,'mapped_result_reference'), + Arr::get($data,'payment_received_date'), ]; } diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index 79ca4380..a7041b1c 100644 --- a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php @@ -4,7 +4,6 @@ namespace App\Classes\Modules\Exports\Services; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; -use App\Models\StatementTransactionOwner; use App\Models\Transaction; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromQuery; @@ -18,6 +17,8 @@ use App\Classes\Modules\Accounting\Processors\ListShippingPortalTransactions; use App\Classes\ValueObjects\Constants\ShippingTransactionType; use App\Classes\ValueObjects\Constants\TransactionType; use Illuminate\Support\Facades\Log; +use App\Classes\General\Eloquent\ApplyFiltersToQuery; +use App\Models\StatementTransaction; class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize { @@ -33,19 +34,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading public function headings(): array { - $header = []; - if ($this->request->input('type') == 'invoices') { - $header[] = 'DocNo'; - $header[] = 'DocDate'; - $header[] = 'DebtorCode'; - } else { - $header[] = 'OrNo'; - $header[] = 'OrDate'; - $header[] = 'CreditorCode'; - } - $header[] = 'Ref'; - $header[] = ($this->request->input('type') == 'invoices' ? 'DebtorName' : 'CreditorName'); - $header = array_merge($header, [ + $header = [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Ref', + 'DebtorName', 'CurrencyCode', 'ShipInfo', 'ItemCode', @@ -55,7 +49,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading 'UnitPrice', 'AccNo', 'DeptNo' - ]); + ]; return $header; } @@ -64,10 +58,9 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function query() { - $data = StatementTransactionOwner::whereNull('invoice_reference') - ->whereIn('type', [StatementTransactionOwnerType::SALES, StatementTransactionOwnerType::WALLET_TOP_UP]) - ->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED]); - if ($this->request->has('bankStatementOwnerId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementOwnerId'))); + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + return $data; } @@ -78,11 +71,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function map($transaction): array { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); $logArray = [ 'counter' => $this->counter, - 'system' => $transaction->system, - 'StatementTransactionOwner_id' => $transaction->id, - 'transaction_table_id' => $transaction->owner_id, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, ]; $this->counter += 1; $logArray = json_encode($logArray); @@ -92,8 +86,8 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; file_put_contents($filePath, $textToAppend, FILE_APPEND); - if ($transaction->system == 'EXCHANGE') { - $row = (App()->make($transaction->owner_type))->where('id', $transaction->owner_id)->first(); + if ($statementTransactionOwner->system == 'EXCHANGE') { + $row = (App()->make($statementTransactionOwner->owner_type))->where('id', $statementTransactionOwner->owner_id)->first(); $company = $row->type === TransactionType::PAYMENT ? $row->owner->company : $row->owner->owner; $booking = $row->owner; @@ -116,15 +110,15 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading ]; } else { $row = (App()->make(ListShippingPortalTransactions::class))->execute([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, ]); if (empty($row) || $row[0]['status'] != 'success') { $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Fetch Shipping Transaction Fail ' . json_encode([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, - 'StatementTransactionOwner_id' => $transaction->id, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, ]) . PHP_EOL; file_put_contents($errorFilePath, $textToAppend, FILE_APPEND); @@ -133,7 +127,24 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading Log::info('Error in Exports Invoice Transactions ' . $this->counter); - return []; + return [ + 'Transaction Not Found', + $transaction->posting_date->format('m/d/Y H:m'), + $transaction->transaction_description.' - '.$transaction->transaction_description_2, + $statementTransactionOwner->system, + '', + '', + '', + '', + '', + '', + 0, + $transaction->amount, + '', + '', + '', + '' + ]; } $row = $row[0]; diff --git a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php new file mode 100644 index 00000000..bde46225 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php @@ -0,0 +1,199 @@ +request = $request; + } + + public function startCell(): string + { + return 'A2'; + } + + public function registerEvents(): array { + + return [ + AfterSheet::class => function(AfterSheet $event) { + $sheet = $event->sheet; + + $sheet->mergeCells('A1:A1'); + $sheet->setCellValue('A1', '"'); + + $sheet->mergeCells('M1:Y1'); + $sheet->setCellValue('M1', "Payment Detail Column"); + + $sheet->mergeCells('Z1:AB1'); + $sheet->setCellValue('Z1', "Knock Off Detail"); + + $styleArray = [ + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + ], + ]; + + $cellRange = 'A1:AB1'; + $event->sheet->getDelegate()->getStyle($cellRange)->applyFromArray($styleArray); + }, + ]; + } + + public function headings(): array + { + $header = [ + [ + ' ', + '(20 chars)', + '(Date: dd/MM/yyyy)', + '(12 chars)', + '(40 chars)', + '(25 chars)', + '(10 chars)', + '(10 chars)', + '(5 chars)', + '(Number, use System Currency Rate Decimal)', + '(Number, use System Currency Rate Decimal)', + '(Rich Text)', + '(20 chars)', + '(20 chars)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Rate Decimal)', + '(14 chars)', + '(30 chars)', + '(10 chars)', + '(10 chars)', + '(20 chars)', + '(Integer)', + '(Boolean. Indicate T for stock control or F for non stock control)', + '(Returned Cheque Date: dd/MM/yyyy)', + '(2 chars, RI for Invoice, RD for D/N)', + '', + '(Number, use System Currency Decimal)', + ], + [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Description', + 'DocNo2', + 'ProjNo', + 'DeptNo', + 'CurrencyCode', + 'ToHomeRate', + 'ToDebtorRate', + 'Note', + 'PaymentMethod', + 'ChequeNo', + 'PaymentAmt', + 'BankCharge', + 'ToBankRate', + 'BankChargeTaxType', + 'BankChargeTaxRefNo', + 'BankChargeProjNo', + 'BankChargeDeptNo', + 'PaymentBy', + 'FloatDay', + 'IsRCHQ', + 'RCHQDate', + 'KnockOffDocType', + 'KnockOffDocNo', + 'KnockOffAmt', + '', + ] + ]; + return $header; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + + return $data; + } + + /** + * @param StatementTransaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); + $logArray = [ + 'counter' => $this->counter, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, + ]; + $this->counter += 1; + $logArray = json_encode($logArray); + + $filePath = storage_path('logs/exports_receipt_transactions.log'); + $errorFilePath = storage_path('logs/exports_receipt_transactions_error.log'); + $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; + file_put_contents($filePath, $textToAppend, FILE_APPEND); + + $company = Company::where('name',$transaction->transaction_description_2)->first(); + + return [ + '<>', + Carbon::parse($transaction->posting_date)->format('d/m/Y'), + ($company ? $company->debtor : null), + 'Payment for '.$transaction->transaction_description, + '', + '', + '', + 'MYR', + 1, + 1, + '', + 'MBB', + '', + $transaction->amount, + '', + 1, + '', + '', + '', + '', + '', + '0', + '', + '', + 'RI', + $transaction->transaction_ref, + $transaction->amount, + '', + ]; + } +} diff --git a/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php b/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php index 366fda8c..c4b72cf0 100644 --- a/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php +++ b/app/Classes/Modules/Jobs/ControllersLogic/FetchJobResultLogic.php @@ -4,9 +4,8 @@ namespace App\Classes\Modules\Jobs\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Jobs\Services\FetchesJobResult; +use App\Classes\Modules\Jobs\Processors\FetchesJobResultProcessor; use App\Http\Resources\JobResultResource; -use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -23,16 +22,16 @@ class FetchJobResultLogic extends AbstractControllerLogic ]; } - /** @var FetchesJobResult */ - private $fetchesJobResult; + /** @var FetchesJobResultProcessor */ + private $fetchesJobResultProcessor; /** * FetchJobResultLogic constructor. - * @param FetchesJobResult $fetchesJobResult + * @param FetchesJobResultProcessor $fetchesJobResultProcessor */ - public function __construct(FetchesJobResult $fetchesJobResult) + public function __construct(FetchesJobResultProcessor $fetchesJobResultProcessor) { - $this->fetchesJobResult = $fetchesJobResult; + $this->fetchesJobResultProcessor = $fetchesJobResultProcessor; } @@ -45,10 +44,8 @@ class FetchJobResultLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - $query = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]); - + $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 index 365cd316..953d77d7 100644 --- a/app/Classes/Modules/Jobs/DataTransferObjects/ListGenericJobObject.php +++ b/app/Classes/Modules/Jobs/DataTransferObjects/ListGenericJobObject.php @@ -2,7 +2,6 @@ namespace App\Classes\Modules\Jobs\DataTransferObjects; -use Illuminate\Http\Request; use App\Classes\General\Interfaces\DataTransferObject; class ListGenericJobObject implements DataTransferObject @@ -16,6 +15,12 @@ class ListGenericJobObject implements DataTransferObject /** @var string */ private $jobId; + /** @var string */ + private $requestSignature; + + /** @var string */ + private $resultSignature; + /** @var object */ private $userInfo; @@ -25,11 +30,13 @@ class ListGenericJobObject implements DataTransferObject /** @var string */ private $jobCommand; - public function __construct(string $name, array $payload, string $jobId, object $userInfo = null) + 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; } @@ -57,6 +64,22 @@ class ListGenericJobObject implements DataTransferObject return $this->jobId; } + /** + * @return string + */ + public function getRequestSignature(): string + { + return $this->requestSignature; + } + + /** + * @return string + */ + public function getResultSignature(): ?string + { + return $this->resultSignature; + } + /** * @return object */ @@ -81,10 +104,6 @@ class ListGenericJobObject implements DataTransferObject return $this->jobCommand; } - // public function setJobId(int $jobId) - // { - // $this->jobId = $jobId; - // } public function setJobCommandName(string $jobCommandName) { 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..e19456e7 --- /dev/null +++ b/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php @@ -0,0 +1,45 @@ +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(!$res1->result){ + Log::info('Job id: '.$request->route('job_id')); + $res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]); + Log::info('Job id: '.$res2->id." , request_signature: ".$res2->request_signature); + return $res2; + } + + 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..fff83bb0 --- /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 index 00acc1eb..e70e0e6a 100644 --- a/app/Classes/Modules/Jobs/Services/CreatesJobResult.php +++ b/app/Classes/Modules/Jobs/Services/CreatesJobResult.php @@ -10,18 +10,16 @@ class CreatesJobResult extends AbstractUpdateRecord { /** * @param ListGenericJobObject $listGenericJobObject - * @param string $result * @return \Illuminate\Database\Eloquent\Model * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute(ListGenericJobObject $listGenericJobObject, string $result) + public function execute(ListGenericJobObject $listGenericJobObject) { $model = new JobResult(); $model->job_id = $listGenericJobObject->getJobId(); - $model->result = $result; + $model->request_signature = $listGenericJobObject->getRequestSignature(); + $model->result_signature = $listGenericJobObject->getResultSignature(); $model->url = $listGenericJobObject->getName(); - $model->job_command_name = $listGenericJobObject->getJobCommandName(); - $model->job_command = $listGenericJobObject->getJobCommand(); return $this->handler($model); } 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 index d317d7eb..654a360f 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/ListTransactionsJobLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/ListTransactionsJobLogic.php @@ -5,10 +5,11 @@ namespace App\Classes\Modules\Transactions\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Jobs\ListTransactionsJob; +use App\Classes\Modules\Jobs\Services\CreatesJobResult; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; -use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class ListTransactionsJobLogic extends AbstractControllerLogic { @@ -22,6 +23,19 @@ class ListTransactionsJobLogic extends AbstractControllerLogic ]; } + /** @var CreatesJobResult */ + private $createsJobResult; + + /** + * ListTransactionsJobLogic constructor. + * @param CreatesJobResult $createsJobResult + */ + public function __construct(CreatesJobResult $createsJobResult) + { + $this->createsJobResult = $createsJobResult; + } + + /** * @param Request $request * @return JsonResponse @@ -30,10 +44,21 @@ class ListTransactionsJobLogic extends AbstractControllerLogic { $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(), - $jobId + $requestSignature, + null, + $jobId, + $userInfo ); ListTransactionsJob::dispatch($listGenericJobObject); @@ -41,6 +66,8 @@ class ListTransactionsJobLogic extends AbstractControllerLogic $result = []; $result['job_id'] = $jobId; + $this->createsJobResult->execute($listGenericJobObject); + return $this->response(['data' => $result]); } diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php similarity index 99% rename from app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php rename to app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php index 27dfbe59..612033f8 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php @@ -21,7 +21,7 @@ use App\Classes\ValueObjects\Constants\DocumentType; use App\Models\Booking; use App\Models\SegmentConstant; -class CreateInvoiceTransactionProcessorWithInvoiceNo +class CreateInvoiceTransactionWithInvoiceNoProcessor { /** @var CreatesTransaction */ diff --git a/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php b/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php index 36671c89..475d4715 100644 --- a/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/ListTransactionsJobProcessor.php @@ -3,14 +3,10 @@ namespace App\Classes\Modules\Transactions\Processors; use App\Classes\Modules\Transactions\Services\ListsTransactions; -use App\Classes\Modules\Jobs\Services\CreatesJobResult; -use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\Modules\Jobs\Processors\UpdateJobResultProcessor; use App\Classes\General\Helper; -use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Log; use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject; -use Illuminate\Http\Resources\Json\ResourceCollection; -use App\Http\Resources\TransactionResource; +use App\Http\Resources\ListTransactionJobResource; class ListTransactionsJobProcessor { @@ -18,33 +14,32 @@ class ListTransactionsJobProcessor /** @var ListsTransactions */ private $listsTransactions; - /** @var CreatesJobResult */ - private $createsJobResult; + /** @var UpdateJobResultProcessor */ + private $updateJobResultProcessor; /** * ListTransactionsJobProcessor constructor. * @param ListsTransactions $listsTransactions - * @param CreatesJobResult $createsJobResult + * @param UpdateJobResultProcessor $updateJobResultProcessor */ - public function __construct(ListsTransactions $listsTransactions, CreatesJobResult $createsJobResult) + public function __construct(ListsTransactions $listsTransactions, UpdateJobResultProcessor $updateJobResultProcessor) { $this->listsTransactions = $listsTransactions; - $this->createsJobResult = $createsJobResult; + $this->updateJobResultProcessor = $updateJobResultProcessor; } /** * @param ListGenericJobObject $listGenericJobObject - * @return null|object + * @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']]); - $result = Helper::collectionResponse(TransactionResource::collection($query)); - - $create = $this->createsJobResult->execute($listGenericJobObject, json_encode($result)); - - return $create; + $resultCurrent = Helper::collectionResponse(ListTransactionJobResource::collection($query)); + $this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent); } } + diff --git a/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php b/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php new file mode 100644 index 00000000..f09fa38a --- /dev/null +++ b/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php index 7dfe0485..733c84fa 100644 --- a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php +++ b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php @@ -17,6 +17,7 @@ use Illuminate\Support\Facades\Auth; use Maatwebsite\Excel\Excel; use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds; use App\Models\TransactionMappingLog; +use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions; class ExportCustomersToExcelController { @@ -61,7 +62,14 @@ class ExportCustomersToExcelController public function invoiceTransactions(Request $request){ $exportsTransactions = new ExportsInvoiceTransactions($request); - $response = $exportsTransactions->download(($request->input('type') == 'invoices' ? 'invoice-transactions' : 'receipt-transactions').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + $response = $exportsTransactions->download('invoice-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } + + public function receiptTransactions(Request $request){ + $exportsTransactions = new ExportsReceiptTransactions($request); + $response = $exportsTransactions->download('receipt-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); ob_end_clean(); return $response; } diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index 7ea3454e..75953f2b 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -34,99 +34,123 @@ class ImportStatementInvoiceController $this->responseMessage = 'You have successfully imported invoice mapping'; } + public function mapping($row) { + // Shipping Info + // TOPUP -> map with transaction.bill_no + if (str_starts_with($row['shipping_info'], 'TOPUP')) { + // find in exchange first, if cannont then find in izyim + foreach (['exchange','izyim'] as $system) { + [$returnReference, $transactionDate] = $this->mappingTopUp($row, $system); + if ($returnReference) { + // $row['mapped_result_reference'] = $data['owner_reference']; + // $row['payment_received_date'] = date('Y-m-d', strtotime($data['created_at'])); + $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = $transactionDate ? date('d-m-Y', strtotime($transactionDate)) : null; + $row['mapped_status'] = 'success'; + return $row; + } + } + } + + [$returnReference, $transactionDate] = $this->mappingExchange($row); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = date('d-m-Y', strtotime($transactionDate)); + $row['mapped_status'] = 'success'; + return $row; + } + + // if still unable to map, will try to check the shipping_info without TOPUP + // foreach (['exchange','izyim'] as $system) { + // $returnReference = $this->mappingTopUp($row, $system); + // if ($returnReference) { + // $row['mapped_result_reference'] = $returnReference; + // $row['mapped_status'] = 'success'; + // } + // } + + return $row; + } + /** * @param Request $request * @return array - * @throws \App\Classes\Exceptions\MalformedRequestException */ public function import(Request $request) : JsonResponse { - ini_set('memory_limit', '-1'); - $importDate = date('Y-m-d H:i:s'); - $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); - $file = json_decode($object->getFiles()[0])->file_info->original->file; + try { + ini_set('memory_limit', '-1'); + $importDate = date('Y-m-d H:i:s'); + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + $file = json_decode($object->getFiles()[0])->file_info->original->file; - $import = new GenericImport(); - Excel::import($import, $file); - $excelRows = $import->rows; - $excelRows = $excelRows->toArray(); + $import = new GenericImport(); + Excel::import($import, $file); + $excelRows = $import->rows; + $excelRows = $excelRows->toArray(); + + $data = []; + foreach ($excelRows as $row) { + $row['mapped_result_reference'] = null; + $row['payment_received_date'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = in_array(gettype($row['date']), ['integer', 'double']) ? $this->changeExcelDate($row['date']) : date('Y-m-d', strtotime($row['date'])); + + $row = $this->mapping($row); + + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'data'=>$row, + ]); + array_push($data, $row); + + + // if 5 digits -> exchange booking reference + // find transation + // find statement_transaction_owners, and fill up the details + + // if <5 digits, find the transaction id (order number in izyim), find the payment in izyim + // find transation + // find statement_transaction_owners, and fill up the details + + // dd([ + // 'type' => $statementTransactionOwnerType, + // 'system' => $system, + // // 'owner_type' => Transaction::class, + // // todo-new: make sure owner_type is a class + // 'owner_type' => $owner_type, + // 'owner_id' => $owner_id, + // 'owner_reference' => $owner_reference + // ]); + + // $bankStatementTransaction->owners()->firstOrCreate([ + // 'type' => $statementTransactionOwnerType, + // 'system' => $system, + // // 'owner_type' => Transaction::class, + // // todo-new: make sure owner_type is a class + // 'owner_type' => $owner_type, + // 'owner_id' => $owner_id, + // 'owner_reference' => $owner_reference + // ]); - $data = []; - foreach ($excelRows as $row) { - $row['mapped_result_reference'] = null; - $row['mapped_status'] = 'failed'; - $row['date'] = $this->changeExcelDate($row['date']); - // Shipping Info - // TOPUP -> map with transaction.bill_no - if (str_starts_with($row['shipping_info'], 'TOPUP')) { - // find in exchange first, if cannont then find in izyim - foreach (['exchange','izyim'] as $system) { - $returnReference = $this->mappingTopUp($row, $system); - if ($returnReference) { - $row['mapped_result_reference'] = $returnReference; - $row['mapped_status'] = 'success'; - } - } - } else { - $returnReference = $this->mappingExchange($row); - if ($returnReference) { - $row['mapped_result_reference'] = $returnReference; - $row['mapped_status'] = 'success'; - } } - TransactionMappingLog::create([ - 'imported_date'=>$importDate, - 'data'=>$row, - ]); - array_push($data, $row); - - - // if 5 digits -> exchange booking reference - // find transation - // find statement_transaction_owners, and fill up the details - - // if <5 digits, find the transaction id (order number in izyim), find the payment in izyim - // find transation - // find statement_transaction_owners, and fill up the details - - // dd([ - // 'type' => $statementTransactionOwnerType, - // 'system' => $system, - // // 'owner_type' => Transaction::class, - // // todo-new: make sure owner_type is a class - // 'owner_type' => $owner_type, - // 'owner_id' => $owner_id, - // 'owner_reference' => $owner_reference - // ]); - - // $bankStatementTransaction->owners()->firstOrCreate([ - // 'type' => $statementTransactionOwnerType, - // 'system' => $system, - // // 'owner_type' => Transaction::class, - // // todo-new: make sure owner_type is a class - // 'owner_type' => $owner_type, - // 'owner_id' => $owner_id, - // 'owner_reference' => $owner_reference - // ]); - - + return $this->response($this->responseTitle, $this->responseMessage, HttpStatus::OK_WITH_MESSAGE, ['data'=>$data,'importedDate'=>$importDate]); + } catch (\Exception $exception){ + return $this->response('import invoice failed',$exception->getMessage(), ($exception->getCode()? $exception->getCode() : HttpStatus::SERVER_ERROR)); } - - return $this->response(['data'=>$data,'importedDate'=>$importDate]); } - public function response(?array $data = []) : JsonResponse { - return (new ApiResponseObject($this->responseTitle, - $this->responseMessage, - HttpStatus::OK_WITH_MESSAGE, $data))->handler(); + public function response(String $responseTitle, String $responseMessage, int $httpStatus, ?array $data = []) : JsonResponse { + return (new ApiResponseObject($responseTitle, $responseMessage, $httpStatus, $data))->handler(); } private function mappingTopUp(Array $row, String $system) { try { if ($data = (App()->make(ChecksBillNumber::class))->execute($row['shipping_info'], $system)) { - if ($system == 'izyim' && isset($data['owner_reference'])) return $data['owner_reference']; + // if ($system == 'izyim' && isset($data['owner_reference'])) return $data; + if ($system == 'izyim' && isset($data['owner_reference'])) return [$data['owner_reference'], null]; if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']); } @@ -137,33 +161,32 @@ class ImportStatementInvoiceController private function mappingExchange(Array $row) { $date = $row['date']; - $transactions = Transaction::where('original_amount', $row['net_total'])->whereRaw("DATE(created_at) = '$date'") - ->whereHas('receiverCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - })->get(); - - if ($transactions && $transactions->count() == 0) { - $transactions = Transaction::where(DB::raw('FLOOR(original_amount)'), floor($row['net_total']))->whereRaw("DATE(created_at) = '$date'") - ->whereHas('receiverCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - })->get(); + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('owner_reference', $row['shipping_info'])->first(); + + if ($transaction && $transaction->count() == 0) { + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['net_total'])->whereRaw("DATE(posting_date) = '$date'")->first(); } - if ($transactions && $transactions->count() == 1) { - foreach ($transactions as $key => $transaction) { - return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); - } + if ($transaction && $transaction->count() == 0) { + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->first(); } - return false; + + if ($transaction && $transaction->count() > 0) { + return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); + } + return [false, false]; } public function updateTransactionOwnerReference($transaction, String $docNo) { $transactionOwner = $transaction->transaction_owner; if ($transactionOwner) { - $transactionOwner->update(['invoice_reference'=>$docNo]); - return $transactionOwner->owner_reference; + $transactionOwner->update([ + 'invoice_reference'=>$docNo, + 'status'=>ApprovalStatus::COMPLETED + ]); + return [$transactionOwner->owner_reference, $transaction->created_at]; } - return false; + return [false, false]; } public function changeExcelDate($date) diff --git a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php index 8021e3a9..a43f2dda 100644 --- a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php +++ b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php @@ -2,31 +2,35 @@ namespace App\Http\Controllers\Imports; -use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; -use App\Classes\Modules\Imports\Services\GenericImport; -use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Models\Segment; -use App\Models\User; -use Carbon\Carbon; use DateTime; +use Carbon\Carbon; +use App\Models\User; +use App\Models\Company; +use App\Models\Segment; +use App\Models\Transaction; use Illuminate\Http\Request; +use App\Models\SeasonalSegment; +use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\DB; use Maatwebsite\Excel\Facades\Excel; +use App\Models\TransactionMappingLog; +use App\Models\StatementTransactionOwner; +use App\Classes\ValueObjects\Constants\HttpStatus; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\Modules\Imports\Services\GenericImport; +use App\Classes\ValueObjects\Response\ApiResponseObject; use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment; use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor; -use App\Models\Company; -use App\Models\SeasonalSegment; -use App\Models\Transaction; -use App\Models\TransactionMappingLog; -use App\Classes\ValueObjects\Response\ApiResponseObject; -use App\Classes\ValueObjects\Constants\HttpStatus; -use Illuminate\Http\JsonResponse; +use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; +use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; class ImportStatementReceiptsController { private $responseTitle; private $responseMessage; + private $removeStr = 'Payment for '; + public function __construct() { $this->responseTitle = 'Import Receipt Mapping'; $this->responseMessage = 'You have successfully imported receipt mapping'; @@ -39,63 +43,68 @@ class ImportStatementReceiptsController */ public function import(Request $request) { - $importDate = date('Y-m-d H:i:s'); - $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); - $file = json_decode($object->getFiles()[0])->file_info->original->file; + try { + $importDate = date('Y-m-d H:i:s'); + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + $file = json_decode($object->getFiles()[0])->file_info->original->file; - $import = new GenericImport(); - Excel::import($import, $file); - $excelRows = $import->rows; - $excelRows = $excelRows->toArray(); + $import = new GenericImport(); + Excel::import($import, $file); + $excelRows = $import->rows; + $excelRows = $excelRows->toArray(); - $data = []; - foreach ($excelRows as $row) { - $row['mapped_result_reference'] = null; - $row['mapped_status'] = 'failed'; - $row['date'] = $this->changeExcelDate($row['doc_date']); + $data = []; + foreach ($excelRows as $row) { + $row['mapped_result_reference'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = in_array(gettype($row['doc_date']), ['integer', 'double']) ? $this->changeExcelDate($row['doc_date']) : date('Y-m-d', strtotime($row['doc_date'])); - $returnReference = $this->mappingExchange($row); - if ($returnReference) { - $row['mapped_result_reference'] = $returnReference; - $row['mapped_status'] = 'success'; - } + if ($invRefer = $this->getInvoiceReference($row['description'])) { + $returnReference = $this->mappingExchange($invRefer, $row['doc_no']); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['mapped_status'] = 'success'; + } + } - TransactionMappingLog::create([ - 'imported_date'=>$importDate, - 'data'=>$row, - ]); - array_push($data, $row); - } - - return $this->response(['data'=>$data,'importedDate'=>$importDate]); - } - - public function response(?array $data = []) : JsonResponse { - return (new ApiResponseObject($this->responseTitle, - $this->responseMessage, - HttpStatus::OK_WITH_MESSAGE, $data))->handler(); - } - - private function mappingExchange(Array $row) { - $date = $row['date']; - $transactions = Transaction::where('original_amount', $row['local_payment_amount'])->whereRaw("DATE(created_at) = '$date'") - ->whereHas('issuerCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - }) - ->get(); - - if ($transactions && $transactions->count() == 1) { - foreach ($transactions as $key => $transaction) { - return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'data'=>$row, + ]); + array_push($data, $row); } + + return $this->response($this->responseTitle, $this->responseMessage, HttpStatus::OK_WITH_MESSAGE, ['data'=>$data,'importedDate'=>$importDate]); + } catch (\Exception $exception){ + return $this->response('import invoice failed',$exception->getMessage(), ($exception->getCode()? $exception->getCode() : HttpStatus::SERVER_ERROR)); + } + } + + private function getInvoiceReference($invRefer) { + $arrStr = explode($this->removeStr, $invRefer); + if (isset($arrStr[1])) return $arrStr[1]; + return null; + } + + public function response(String $responseTitle, String $responseMessage, int $httpStatus, ?array $data = []) : JsonResponse { + return (new ApiResponseObject($responseTitle, $responseMessage, $httpStatus, $data))->handler(); + } + + private function mappingExchange($invRefer, $docNo) { + $transactionOwner = StatementTransactionOwner::where('invoice_reference',$invRefer)->whereNull('receipt_reference')->where('status', ApprovalStatus::COMPLETED)->first(); + + if ($transactionOwner) { + return $this->updateTransactionOwnerReference($transactionOwner, $docNo); } return false; } - public function updateTransactionOwnerReference($transaction, String $docNo) { - $transactionOwner = $transaction->transaction_owner; + public function updateTransactionOwnerReference($transactionOwner, String $docNo) { if ($transactionOwner) { - $transactionOwner->update(['receipt_reference'=>$docNo]); + $transactionOwner->update([ + 'receipt_reference'=>$docNo, + 'status'=>ApprovalStatus::COMPLETED + ]); return $transactionOwner->owner_reference; } return false; diff --git a/app/Http/Resources/BankStatementTransactionResource.php b/app/Http/Resources/BankStatementTransactionResource.php index 993b8c93..8f5e0193 100644 --- a/app/Http/Resources/BankStatementTransactionResource.php +++ b/app/Http/Resources/BankStatementTransactionResource.php @@ -34,7 +34,8 @@ class BankStatementTransactionResource extends JsonResource 'owners' => [ 'approved' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::APPROVED])->get()), 'pending_verification' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION])->get()), - 'rejected' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::REJECTED])->get()) + 'rejected' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::REJECTED])->get()), + 'completed' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::COMPLETED])->get()), ] ]; } diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index c3c2e24d..020db09c 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -11,19 +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\Http\Resources\Json\AnonymousResourceCollection; -use Illuminate\Support\Facades\Log; class BookingResource extends JsonResource { - private $userInfo; - - public function __construct($resource, $userInfo = null) - { - parent::__construct($resource); - $this->userInfo = $userInfo ?? ($resource->userInfo ?? null); - } - /** * Transform the resource into an array. * diff --git a/app/Http/Resources/CompanyResource.php b/app/Http/Resources/CompanyResource.php index df3bcf49..55043f85 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 6f9ade71..075e27f3 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; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Auth; 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/AccountStatement.php b/app/Models/AccountStatement.php index d9e53d60..2f5b0e8c 100644 --- a/app/Models/AccountStatement.php +++ b/app/Models/AccountStatement.php @@ -16,6 +16,8 @@ class AccountStatement extends Model 'total_amount', 'begin_balance', 'end_balance', + 'total_rows', + 'mapped_rows', ]; protected $casts = [ diff --git a/app/Models/Company.php b/app/Models/Company.php index 8b2e6081..54ae1e23 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -109,7 +109,7 @@ class Company extends AbstractModel implements Documentable { return $this->hasManyDeep(Transaction::class, [Booking::class], ['company_id', 'owner_id'], ['id', 'id']); } - + /** * @return HasMany */ @@ -130,13 +130,25 @@ class Company extends AbstractModel implements Documentable * @return Builder */ public function services(): Builder { - return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { - $query->Where(function($query){ - $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); - })->orWhere(function($query) { - $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true)->whereIn('segment_id', $this->segments->pluck('id')); + + if ($this->business_type === 3) { + return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { + $query->where(function($query) { + $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); + })->orWhere(function($query) { + $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true); + }); }); - }); + } else { + // Existing logic for other company types + return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { + $query->Where(function($query){ + $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); + })->orWhere(function($query) { + $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true)->whereIn('segment_id', $this->segments->pluck('id')); + }); + }); + } } public function servicesConfigurations(): Collection { diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index eb4bcdc8..4bba7903 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -49,6 +49,11 @@ class StatementTransaction extends Model return $this->hasMany(StatementTransactionOwner::class); } + public function owner_status() + { + return $this->owners()->whereIn('status',[ApprovalStatus::APPROVED,ApprovalStatus::COMPLETED,ApprovalStatus::PENDING_VERIFICATION]); + } + public function scopeDoesntMapStatement($query) { $query->whereDoesntHave('owners', function($query){ diff --git a/app/Models/StatementTransactionOwner.php b/app/Models/StatementTransactionOwner.php index fb13f4b4..bd96efff 100644 --- a/app/Models/StatementTransactionOwner.php +++ b/app/Models/StatementTransactionOwner.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphTo; class StatementTransactionOwner extends Model { diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 631a5fa5..185fdb36 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -221,6 +221,22 @@ class Transaction extends AbstractModel implements Documentable, Transactionable return $query->whereIn('status', [ApprovalStatus::APPROVED]); } + /** + * @param Builder $query + * @return Builder + */ + public function scopeGetReceiverWithJoinStatementTransactionAndOwner(Builder $query, Array $row) { + $query->join('companies',function($q) use ($row) { + $q->on('companies.id','=','transactions.receiver'); + $q->where('debtor',$row['debtor_code']); + }) + ->join('statement_transaction_owners', function ($q) { + $q->on('statement_transaction_owners.owner_id','=','transactions.id'); + $q->where('statement_transaction_owners.owner_type','=',Transaction::class); + }) + ->join('statement_transactions','statement_transactions.id','=','statement_transaction_owners.statement_transaction_id'); + } + /** * @return MorphMany */ diff --git a/database/migrations/2023_08_08_124848_create_job_results_table.php b/database/migrations/2023_08_08_124848_create_job_results_table.php index ee3553bf..ef448407 100644 --- a/database/migrations/2023_08_08_124848_create_job_results_table.php +++ b/database/migrations/2023_08_08_124848_create_job_results_table.php @@ -16,7 +16,7 @@ class CreateJobResultsTable extends Migration Schema::create('job_results', function (Blueprint $table) { $table->id(); $table->string('job_id', 50); - $table->longText('result'); + $table->longText('result')->nullable(); $table->timestamps(); // $table->foreign('job_id')->references('id')->on('jobs')->onDelete('cascade'); diff --git a/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php new file mode 100644 index 00000000..f6a8e7e7 --- /dev/null +++ b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php @@ -0,0 +1,34 @@ +integer('total_rows')->unsigned()->default(0)->after('end_balance'); + $table->integer('mapped_rows')->unsigned()->default(0)->after('end_balance'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_statements', function (Blueprint $table) { + $table->dropColumn('total_rows'); + $table->dropColumn('mapped_rows'); + }); + } +} 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/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index 1caef408..0c193871 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -4,6 +4,8 @@
{{ item.posting_date }}
{{ item.transaction_description_1 + ' - ' + item.transaction_description_2 }}
+ +
{{item.owners.pending_verification[0].system}}
@@ -51,6 +53,7 @@
+
@@ -93,6 +96,7 @@
+
@@ -126,7 +130,7 @@
- +
Pending...
diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionMappedComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionMappedComponent.vue index e4186bb6..e37e4f3b 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionMappedComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionMappedComponent.vue @@ -6,11 +6,11 @@
{{ item.transaction_description_1 + ' - ' + item.transaction_description_2 }}
-
{{item.owners.approved[0].system}}
-
{{ typeString(item.owners.approved[0].type) }}
- -
{{item.owners.approved[0].invoice_reference}}
-
{{item.owners.approved[0].receipt_reference}}
+
{{item.owners.completed[0].system}}
+
{{ typeString(item.owners.completed[0].type) }}
+ +
{{item.owners.completed[0].invoice_reference}}
+
{{item.owners.completed[0].receipt_reference}}
diff --git a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue index 3e52b70b..f10f9181 100644 --- a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue +++ b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue @@ -8,6 +8,11 @@

{{ componentTitle }}

+
+
+ {{error}} +
+
+ + +
+
+
+ + + + +
+
+ + + + +
+
+
+ + Search + +
+
+
+
+
@@ -202,6 +228,10 @@ export default { data(){ return { + parameters: { + startDate: '', + endDate: '', + }, type: null, stage: null, exportStage: 0, @@ -215,6 +245,14 @@ export default { } }, validations: { + parameters: { + startDate: { + required + }, + endDate: { + required + }, + }, files: { // required // todo-new: set required if is pdf section } @@ -227,17 +265,33 @@ export default { this.mappedTrue = true; }, exportInvoiceToAutoCount(){ - window.open(this.route('invoiceTransactions.export')+'?bankStatementOwnerId='+this.getCheckedStatementOwners()+'&type=invoices', '_blank'); + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + let route = this.route('invoiceTransactions.export')+'?filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); }, exportReceiptToAutoCount(){ - window.open(this.route('invoiceTransactions.export')+'?bankStatementOwnerId='+this.getCheckedStatementOwners()+'&type=receipts', '_blank'); + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + this.filter['where_has_owners_and_null'] = 'statement_transaction_owners.receipt_reference'; + this.filter['where_has_owners_and_not_null'] = 'statement_transaction_owners.invoice_reference'; + let route = this.route('receiptTransactions.export')+'?filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); }, getCheckedStatementOwners() { - let bankStatementOwnerId = []; + let bankStatementTransactionId = []; $('.request_export_item:checked').each(function() { - bankStatementOwnerId.push($(this).val()); + bankStatementTransactionId.push($(this).val()); }); - return JSON.stringify(bankStatementOwnerId); + return (bankStatementTransactionId.length > 0 ? JSON.stringify(bankStatementTransactionId) : null); }, successHandler(){ this.step += 1; @@ -259,10 +313,14 @@ export default { this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 3: - this.filter = {min_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 4: this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; break; } } @@ -280,6 +338,11 @@ export default { break; case 4: this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; + break; } } diff --git a/resources/assets/vue/components/bookings/elements/BookingComponent.vue b/resources/assets/vue/components/bookings/elements/BookingComponent.vue index 9ff3fe9c..7e675646 100644 --- a/resources/assets/vue/components/bookings/elements/BookingComponent.vue +++ b/resources/assets/vue/components/bookings/elements/BookingComponent.vue @@ -22,7 +22,7 @@
-
+
Marking
{{this.item.company.reference}} @@ -34,7 +34,7 @@ {{this.item.convertible_currency.short_code}}
-
+
Transfer Type
{{this.item.service.name}}
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..03244ff4 --- /dev/null +++ b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue @@ -0,0 +1,136 @@ + + diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index a65c2ce8..a2762ce7 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -289,6 +289,22 @@
+
+
+
Delete Transfer
+
+ + + + +
diff --git a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue index 6c64fdee..528e870b 100644 --- a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue @@ -117,6 +117,12 @@
+ +