diff --git a/.env.example b/.env.example index 47a20e74..f3d4fd56 100644 --- a/.env.example +++ b/.env.example @@ -50,4 +50,9 @@ FILESYSTEM_DRIVER="documents" JWT_SECRET= JWT_TTL=1440 -IS_PRODUCTION=false \ No newline at end of file +IS_PRODUCTION=false + +BILLPLZ_BASE_URL="https://www.billplz-sandbox.com" +BILLPLZ_API_KEY="0fa4c710-761b-4a7a-a501-c2c2d02643d5" +BILLPLZ_X_SIGNATURE_KEY="S-pbNVthVRsvnPfZlgLwqqOg" +BILLPLZ_COLLECTION_ID="hev2wdjy" diff --git a/app/Classes/General/Eloquent/AbstractUpdateRecord.php b/app/Classes/General/Eloquent/AbstractUpdateRecord.php index 44129c92..17690ce4 100644 --- a/app/Classes/General/Eloquent/AbstractUpdateRecord.php +++ b/app/Classes/General/Eloquent/AbstractUpdateRecord.php @@ -17,7 +17,6 @@ abstract class AbstractUpdateRecord */ public function handler(Model $model){ try{ - if($model->save()){ return $model; } } catch (QueryException $exception){ diff --git a/app/Classes/General/Eloquent/Filters/BillNo.php b/app/Classes/General/Eloquent/Filters/BillNo.php new file mode 100644 index 00000000..167dcd51 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/BillNo.php @@ -0,0 +1,20 @@ +where('bill_no', $value); + } + +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/IsPublished.php b/app/Classes/General/Eloquent/Filters/IsPublished.php index 9b5b23c1..3e9c8ca4 100644 --- a/app/Classes/General/Eloquent/Filters/IsPublished.php +++ b/app/Classes/General/Eloquent/Filters/IsPublished.php @@ -5,7 +5,7 @@ namespace App\Classes\General\Eloquent\Filters; use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; -class isPublished implements Filter +class IsPublished implements Filter { /** diff --git a/app/Classes/General/Eloquent/Filters/PaymentReference.php b/app/Classes/General/Eloquent/Filters/PaymentReference.php new file mode 100644 index 00000000..5f5d53f5 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/PaymentReference.php @@ -0,0 +1,20 @@ +where('payment_reference', '=', $value); + } + +} \ No newline at end of file diff --git a/app/Classes/General/Interfaces/Transactionable.php b/app/Classes/General/Interfaces/Transactionable.php new file mode 100644 index 00000000..174cb48d --- /dev/null +++ b/app/Classes/General/Interfaces/Transactionable.php @@ -0,0 +1,13 @@ +getBillplzBill = $getBillplzBill; + $this->fetchesTransaction = $fetchesTransaction; + $this->updatesTransactionStatus = $updatesTransactionStatus; + } + + + /** + * @param Request $request + * @return bool|\Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws MalformedRequestException + * @throws ResourceNotFoundException + */ + public function execute(Request $request) + { + + $billplzXSignatureObject = new BillplzXSignatureObject($request); + + if(!$billplzXSignatureObject->isValidSignature()){ + throw new MalformedRequestException('Billplz Payment validation failed.'); + } + + $billPlz = $this->getBillplzBill->execute($billplzXSignatureObject->getBillPlzId()); + + if(!$billPlz) throw new ResourceNotFoundException('Billplz bill not found.'); + + $transaction = $this->fetchesTransaction->execute(['payment_reference' => $billplzXSignatureObject->getBillPlzId()]); + + if($billPlz->state === 'paid') { + $status = ApprovalStatus::APPROVED; + } + + if($billPlz->state === 'due') { + $status = $billplzXSignatureObject->getStatus() === 'failed' ? ApprovalStatus::REJECTED : ApprovalStatus::PENDING_VERIFICATION; + } + + $this->updatesTransactionStatus->execute($transaction, $status); + + $token = Auth::fromUser(User::find(1)); + $request->headers->set('Authorization', 'Bearer '.$token); + + return $request->method() === 'POST' ? true : view('pages.payments_redirect', ['marking' => $transaction->booking->marking, 'payment_reference' => $transaction->payment_reference, 'status' => $status, 'amount' => $transaction->amount]); + + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Billplzs/ControllersLogic/CreateBillplzBillLogic.php b/app/Classes/Modules/Billplzs/ControllersLogic/CreateBillplzBillLogic.php new file mode 100644 index 00000000..7aabd468 --- /dev/null +++ b/app/Classes/Modules/Billplzs/ControllersLogic/CreateBillplzBillLogic.php @@ -0,0 +1,56 @@ + 'Created Billplz Bill', + 'message' => 'You have successfully created a new Bill' + ]; + } + + /** @var CreatesBillplzBill */ + private $createsBillplzBill; + + /** + * CreateBookingLogic constructor. + * @param CreatesBillplzBill $createsBillplzBill + */ + public function __construct(CreatesBillplzBill $createsBillplzBill) + { + $this->createsBillplzBill = $createsBillplzBill; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + $billPlz = $this->createsBillplzBill->execute($request->user()->name, $request->user()->email, $request->input('description'), 200, $request->input('bankName')); + + if(!$billPlz) throw new MalformedRequestException('Unable to get correct response from billplz server.'); + + return $this->response(['data' => $billPlz]); + + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Billplzs/DataTransferObjects/BillplzXSignatureObject.php b/app/Classes/Modules/Billplzs/DataTransferObjects/BillplzXSignatureObject.php new file mode 100644 index 00000000..c1295886 --- /dev/null +++ b/app/Classes/Modules/Billplzs/DataTransferObjects/BillplzXSignatureObject.php @@ -0,0 +1,120 @@ +type = $request->exists('billplz') ? 'redirect' : 'callback'; + + $this->request = $this->type === 'redirect' ? $request->input('billplz') : $request; + + $this->billPlzId = $this->request['id']; + + $this->status = $this->request['transaction_status']; + + $this->requestXSignature = $this->request['x_signature']; + + $this->_constructBillplzArray()->_natSortBillplzArray()->_constructBillplzString()->_computeBillplzXSignature(); + } + + private function _constructBillplzArray(){ + + $this->billPlzConstructArray = collect($this->request)->forget('x_signature')->map(function($item, $key){ + return $this->type === 'redirect' ? 'billplz'.$key.$item : $key.$item; + })->toArray(); + + return $this; + } + + private function _natCaseSortBillplzArray(){ + natcasesort($this->billPlzConstructArray); + return $this; + } + + private function _natSortBillplzArray(){ + natsort($this->billPlzConstructArray); + return $this; + } + + private function _constructBillplzString(){ + $this->billPlzConstructString = implode('|', $this->billPlzConstructArray); + return $this; + } + + private function _computeBillplzXSignature(){ + $this->billPlzComputedXSignature = hash_hmac('sha256', $this->billPlzConstructString, config('billplz.x_signature_key')); + return $this; + } + + public function getBillPlzId(): string + { + return $this->billPlzId; + } + + public function getStatus(): string + { + return $this->status; + } + + /** + * @return array + */ + public function getBillPlzConstructArray(): array + { + return $this->billPlzConstructArray; + } + + /** + * @return string + */ + public function getBillPlzConstructString(): string + { + return $this->billPlzConstructString; + } + + /** + * @return string + */ + public function getBillPlzComputedXSignature(): string + { + return $this->billPlzComputedXSignature; + } + + public function isValidSignature(): bool + { + return $this->billPlzComputedXSignature === $this->requestXSignature ? true : false; + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Billplzs/Services/CreatesBillplzBill.php b/app/Classes/Modules/Billplzs/Services/CreatesBillplzBill.php new file mode 100644 index 00000000..c97ff13a --- /dev/null +++ b/app/Classes/Modules/Billplzs/Services/CreatesBillplzBill.php @@ -0,0 +1,55 @@ +post(config('billplz.base_url').'/api/v3/bills', [ + 'collection_id' => config('billplz.collection_id'), + 'name' => $name, + 'email' => $email, + 'description' => $description, + 'amount' => $this->finalizeAmount($amount), + 'redirect_url' => route('online_payment.redirect'), + 'callback_url' => route('api.online_payment.callback'), + 'reference_1_label' => 'Bank Code', + 'reference_1' => $bankCode ? $bankCode : config('billplz.maybank'), + 'reference_2_label' => 'Bill Number', + 'reference_2' => $billNumber + ]); + + if($response->successful()){ + $data = $response->json(); + + $data['url'] = $data['url'].'?auto_submit=true'; + + return (object) $data; + }else{ + return null; + } + }catch(\Exception $exception){ + throw new MalformedRequestException('Unable to get correct response from billplz server' . $exception->getMessage()); + } + } + + protected function finalizeAmount($amount){ + $number = round($amount, 2) * 100; + return (string) $number; + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Billplzs/Services/GetBillplzBill.php b/app/Classes/Modules/Billplzs/Services/GetBillplzBill.php new file mode 100644 index 00000000..2a86b403 --- /dev/null +++ b/app/Classes/Modules/Billplzs/Services/GetBillplzBill.php @@ -0,0 +1,31 @@ +get(config('billplz.base_url').'/api/v3/bills/'.$billPlzId); + + if($response->successful()){ + $data = $response->json(); + + return (object) $data; + }else{ + return null; + } + }catch(\Exception $exception){ + throw new MalformedRequestException('Unable to get correct response from billplz server'); + } + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php index df2a7960..a16be8d2 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php @@ -11,7 +11,9 @@ use App\Classes\Modules\Companies\Services\FetchesCompanyPaymentAttemptLimit; use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; use App\Classes\Modules\Transactions\Services\CreatesTransaction; +use App\Classes\Modules\Transactions\Services\UpdatesTransaction; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; +use App\Classes\Modules\Billplzs\Services\CreatesBillplzBill; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\PaymentMethodType; use App\Classes\ValueObjects\Constants\TransactionType; @@ -46,9 +48,15 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic /** @var CreatesTransaction */ private $createsTransaction; + /** @var UpdatesTransaction */ + private $updatesTransaction; + /** @var CalculatesBookingOutstanding */ private $calculatesBookingOutstanding; + /** @var CreatesBillplzBill */ + private $createsBillplzBill; + /** * CreateBookingPaymentLogic constructor. * @param FetchesBookingQuotation $fetchBookingQuotation @@ -56,14 +64,17 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction * @param CalculatesBookingOutstanding $calculatesBookingOutstanding + * @param CreatesBillplzBill $createsBillplzBill */ - public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingOutstanding $calculatesBookingOutstanding) + public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, UpdatesTransaction $updatesTransaction, CalculatesBookingOutstanding $calculatesBookingOutstanding, CreatesBillplzBill $createsBillplzBill) { $this->fetchBookingQuotation = $fetchBookingQuotation; $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; + $this->updatesTransaction = $updatesTransaction; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->createsBillplzBill = $createsBillplzBill; } /** @@ -73,7 +84,6 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - $booking = Booking::find($request->route('id')); $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $request->input('amount'))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')]); @@ -88,11 +98,15 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $billNumber = $this->generatesTransactionBillNumber->execute('PYMT-'); + if(PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')] == PaymentMethodType::PAYMENT_GATEWAY){ + $billPlzBill = $this->createsBillplzBill->execute($request->user()->name, $request->user()->email, 'This payment is made for transfer ref. '.$booking->marking, $configurations->getTotal(), $billNumber, $request->input('bank_code')); + } + $object = new TransactionObject($billNumber, TransactionType::PAYMENT, 1, $booking->company->id, $configurations->getConfigurations()->getBankId(), $configurations->getConversionObject()->getPaymentMethod(), $configurations->getTotal(), $configurations->getForeignTotal(), 1, $configurations->getConversionObject()->getCurrencyId(), $configurations->getConfigurations()->getRate(), - $configurations->getTax(), $configurations->getServiceCharge(), Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_SUBMISSION); + $configurations->getTax(), $configurations->getServiceCharge(), Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_SUBMISSION, [], isset($billPlzBill) ? $billPlzBill->id : NULL); $transaction = $this->createsTransaction->execute($booking, $object); diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundCreditNoteLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundCreditNoteLogic.php index 9c66abc5..e78a9690 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundCreditNoteLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundCreditNoteLogic.php @@ -7,15 +7,14 @@ use App\Classes\Exceptions\MalformedRequestException; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Transactions\Services\FetchesTransaction; use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; -use App\Classes\Modules\Companies\Services\FetchesCompanyPaymentAttemptLimit; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; +use App\Classes\Modules\Transactions\DataTransferObjects\TransactionRefundCalculationObject; use App\Classes\Modules\Transactions\Services\CreatesTransaction; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\TransactionResource; use App\Models\Booking; -use Carbon\Carbon; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -38,9 +37,6 @@ class CreateBookingRefundCreditNoteLogic extends AbstractControllerLogic /** @var UpdatesTransactionStatus */ private $updatesTransactionStatus; - /** @var FetchesCompanyPaymentAttemptLimit */ - private $fetchesCompanyPaymentAttemptLimit; - /** @var GeneratesTransactionBillNumber */ private $generatesTransactionBillNumber; @@ -51,15 +47,13 @@ class CreateBookingRefundCreditNoteLogic extends AbstractControllerLogic * CreateBookingPaymentLogic constructor. * @param FetchesTransaction $fetchesTransaction * @param UpdatesTransactionStatus $updatesTransactionStatus - * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction */ - public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction) + public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction) { $this->fetchesTransaction = $fetchesTransaction; $this->updatesTransactionStatus = $updatesTransactionStatus; - $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; } @@ -76,19 +70,24 @@ class CreateBookingRefundCreditNoteLogic extends AbstractControllerLogic $transaction = $this->fetchesTransaction->execute(['id' => $request->route('payment_id')]); - $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::REFUNDED); + $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED); - $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); + $paymentReferenceTransaction = $this->fetchesTransaction->execute(['bill_no' => $transaction->payment_reference]); - $billNumber = $this->generatesTransactionBillNumber->execute('CDTN-'); - - $object = new TransactionObject($billNumber, TransactionType::CREDIT_NOTE, 1, $booking->company->id, - $booking->bank_id, $transaction->payment_method, - $transaction->amount, $transaction->original_amount, 1, - $transaction->original_currency_id, $transaction->currency_rate, - $transaction->tax, $transaction->service_charge, Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_VERIFICATION); + if((int) $paymentReferenceTransaction->type === TransactionType::BILL){ + $transactionRefundCalculationObject = new TransactionRefundCalculationObject($booking, $transaction, $transaction->original_amount, $paymentReferenceTransaction->currency_rate); + $transactionRefundCalculationObject->setRefundConversionAmount(); - $transaction = $this->createsTransaction->execute($booking, $object); + $billNumber = $this->generatesTransactionBillNumber->execute('CRDNT-'); + + $object = new TransactionObject($billNumber, TransactionType::CREDIT_NOTE, 1, $booking->company->id, + $booking->bank_id, $paymentReferenceTransaction->payment_method, + $transactionRefundCalculationObject->getRefundConversionAmount(), $transaction->original_amount, 1, + $paymentReferenceTransaction->original_currency_id, $paymentReferenceTransaction->currency_rate, + $paymentReferenceTransaction->tax, $paymentReferenceTransaction->service_charge, null, ApprovalStatus::PENDING_VERIFICATION, [], $paymentReferenceTransaction->bill_no); + + $transaction = $this->createsTransaction->execute($booking, $object); + } return $this->resourceResponse(new TransactionResource($transaction)); } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php index 843ecb88..411b9163 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php @@ -3,21 +3,22 @@ namespace App\Classes\Modules\Bookings\ControllersLogic; +use App\Models\Booking; +use Illuminate\Http\Request; +use Illuminate\Http\JsonResponse; +use App\Http\Resources\TransactionResource; use App\Classes\Exceptions\MalformedRequestException; -use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Transactions\Services\FetchesTransaction; -use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; -use App\Classes\Modules\Companies\Services\FetchesCompanyPaymentAttemptLimit; -use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; -use App\Classes\Modules\Transactions\Services\CreatesTransaction; -use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; -use App\Http\Resources\TransactionResource; -use App\Models\Booking; -use Carbon\Carbon; -use Illuminate\Http\JsonResponse; -use Illuminate\Http\Request; +use App\Classes\General\Abstracts\AbstractControllerLogic; +use App\Classes\Modules\Transactions\Services\CreatesTransaction; +use App\Classes\Modules\Transactions\Services\FetchesTransaction; +use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation; +use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; +use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; +use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; +use App\Classes\Modules\Transactions\DataTransferObjects\TransactionRefundCalculationObject; class CreateBookingRefundLogic extends AbstractControllerLogic { @@ -32,36 +33,41 @@ class CreateBookingRefundLogic extends AbstractControllerLogic ]; } + /** @var FetchesBookingQuotation */ + private $fetchBookingQuotation; + /** @var FetchesTransaction */ private $fetchesTransaction; /** @var UpdatesTransactionStatus */ private $updatesTransactionStatus; - /** @var FetchesCompanyPaymentAttemptLimit */ - private $fetchesCompanyPaymentAttemptLimit; - /** @var GeneratesTransactionBillNumber */ private $generatesTransactionBillNumber; /** @var CreatesTransaction */ private $createsTransaction; + /** @var CalculatesBookingRefundAmount */ + private $calculatesBookingRefundAmount; + /** * CreateBookingPaymentLogic constructor. + * @param FetchesBookingQuotation $fetchBookingQuotation * @param FetchesTransaction $fetchesTransaction * @param UpdatesTransactionStatus $updatesTransactionStatus - * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction + * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount */ - public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction) + public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) { + $this->fetchBookingQuotation = $fetchBookingQuotation; $this->fetchesTransaction = $fetchesTransaction; $this->updatesTransactionStatus = $updatesTransactionStatus; - $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; + $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** @@ -75,18 +81,26 @@ class CreateBookingRefundLogic extends AbstractControllerLogic $booking = Booking::find($request->route('id')); $transaction = $this->fetchesTransaction->execute(['id' => $request->route('payment_id')]); - - $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::REFUNDED); - - $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); $billNumber = $this->generatesTransactionBillNumber->execute('RFD-'); - + + if((int) $transaction->type === TransactionType::BILL){ + $customerBooking = $booking->transactions()->payments()->complete()->where('original_amount', '=', $transaction->original_amount)->where('id', '<', $transaction->id)->orderByDesc('id')->first(); + } + + $refund = $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id, $transaction->bill_no); + dd($refund); + + if($refund + $request->input('amount') > $transaction->original_amount) throw new MalformedRequestException('Your refund must not be greater than '. $transaction->original_amount .'.'); + + $transactionRefundCalculationObject = new TransactionRefundCalculationObject($booking, (int) $transaction->type === TransactionType::BILL ? $customerBooking : $transaction, $request->input('amount')); + $transactionRefundCalculationObject->init(); + $object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id, - $booking->bank_id, $transaction->payment_method, - $transaction->amount, $transaction->original_amount, 1, - $transaction->original_currency_id, $transaction->currency_rate, - $transaction->tax, $transaction->service_charge, Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_VERIFICATION); + $request->input('bank_id'),$transactionRefundCalculationObject->getConversionObject()->getPaymentMethod(), + $transactionRefundCalculationObject->getRefundTotalAmount(), $transactionRefundCalculationObject->getAmount(), 1, + $transactionRefundCalculationObject->getConversionObject()->getCurrencyId(), $transactionRefundCalculationObject->getTransaction()->currency_rate, + $transactionRefundCalculationObject->getRefundTax(), $transactionRefundCalculationObject->getRefundServiceCharge(), null, ApprovalStatus::PENDING_VERIFICATION, [], $transaction->bill_no); $transaction = $this->createsTransaction->execute($booking, $object); diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateProformaInvoiceTransactionLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateProformaInvoiceTransactionLogic.php new file mode 100644 index 00000000..b37019a5 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateProformaInvoiceTransactionLogic.php @@ -0,0 +1,71 @@ + 'Create Proforma Invoice Transaction', + 'message' => 'You have successfully create proforma invoice transaction' + ]; + } + + /** @var CanFetchBooking */ + private $canFetchBooking; + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var CreateProformaInvoiceTransactionProcessor */ + private $CreateProformaInvoiceTransactionProcessor; + + /** + * FetchBookingLogic constructor. + * @param CanFetchBooking $canFetchBooking + * @param FetchesBooking $fetchesBooking + * @param CreateProformaInvoiceTransactionProcessor $CreateProformaInvoiceTransactionProcessor + */ + public function __construct( + CanFetchBooking $canFetchBooking, + FetchesBooking $fetchesBooking, + CreateProformaInvoiceTransactionProcessor $CreateProformaInvoiceTransactionProcessor + ) + { + $this->canFetchBooking = $canFetchBooking; + $this->fetchesBooking = $fetchesBooking; + $this->CreateProformaInvoiceTransactionProcessor = $CreateProformaInvoiceTransactionProcessor; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + $this->canFetchBooking->passes(); + + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $this->CreateProformaInvoiceTransactionProcessor->execute($booking); + + return $this->resourceResponse(new BookingResource($booking)); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php new file mode 100644 index 00000000..d1cdbada --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -0,0 +1,110 @@ + 'Regenerate Booking Invoice', + 'message' => 'You have successfully regenerate booking invoice' + ]; + } + + /** @var CanFetchBooking */ + private $canFetchBooking; + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var DeletesTransaction */ + private $deletesTransaction; + + /** @var UpdatesBookingStatus */ + private $updatesBookingStatus; + + /** @var DeletesDocument */ + private $deletesDocument; + + /** @var CreateInvoiceTransactionProcessor */ + private $createInvoiceTransactionProcessor; + + /** + * FetchBookingLogic constructor. + * @param CanFetchBooking $canFetchBooking + * @param FetchesBooking $fetchesBooking + * @param DeletesTransaction $deletesTransaction + * @param UpdatesBookingStatus $updatesBookingStatus + * @param DeletesDocument $deletesDocument + * @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor + */ + public function __construct( + CanFetchBooking $canFetchBooking, + FetchesBooking $fetchesBooking, + DeletesTransaction $deletesTransaction, + UpdatesBookingStatus $updatesBookingStatus, + DeletesDocument $deletesDocument, + CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor + ) + { + $this->canFetchBooking = $canFetchBooking; + $this->fetchesBooking = $fetchesBooking; + $this->deletesTransaction = $deletesTransaction; + $this->updatesBookingStatus = $updatesBookingStatus; + $this->deletesDocument = $deletesDocument; + $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + $this->canFetchBooking->passes(); + + $booking = $this->fetchesBooking->execute([ + 'id' => $request->route('id'), + 'status' => ApprovalStatus::COMPLETED, + 'with_transactions' => true] + ); + + $this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED); + + $transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get(); + foreach ($transaction as $key => $row) { + $this->deletesTransaction->execute($row); + } + + $document = $booking->documents()->get(); + foreach ($document as $key => $row) { + $this->deletesDocument->execute($row); + } + + $this->createInvoiceTransactionProcessor->execute($booking); + + return $this->resourceResponse(new BookingResource($booking)); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php new file mode 100644 index 00000000..fabdd058 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php @@ -0,0 +1,100 @@ + 'Updated Booking', + 'message' => 'You have successfully updated the Booking' + ]; + } + + /** @var CanUpdateBooking */ + private $canUpdateBooking; + + /** @var UpdatesBookingFixedAmount */ + private $updatesBookingFixedAmount; + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var CalculatesBookingOutstanding */ + private $calculatesBookingOutstanding; + + /** @var UpdatesTransactionStatus */ + private $updatesTransactionStatus; + + /** + * UpdateBookingAmountLogic constructor. + * @param CanUpdateBooking $canUpdateBooking + * @param UpdatesBookingFixedAmount $updatesBookingFixedAmount + * @param FetchesBooking $fetchesBooking + * @param CalculatesBookingOutstanding $calculatesBookingOutstanding + * @param UpdatesTransactionStatus $updatesTransactionStatus + */ + public function __construct(CanUpdateBooking $canUpdateBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, FetchesBooking $fetchesBooking, CalculatesBookingOutstanding $calculatesBookingOutstanding, UpdatesTransactionStatus $updatesTransactionStatus) + { + $this->canUpdateBooking = $canUpdateBooking; + $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; + $this->fetchesBooking = $fetchesBooking; + $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->updatesTransactionStatus = $updatesTransactionStatus; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $input_amount = number_format( floatval(str_replace(',', '', $request->input('fix_amount', $booking->fix_amount))), 5, '.', ''); + + $minimum_amount = $booking->fix_amount - $this->calculatesBookingOutstanding->execute($booking); + + if ((float)$input_amount < $minimum_amount) { + throw new MalformedRequestException('Booking Amount cannot be less than '. $minimum_amount .'.'); + } + + $poTransaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); + $booking->transactions()->where('type', TransactionType::PROFORMA)->delete(); + + if($poTransaction) { + $this->updatesTransactionStatus->execute($poTransaction, ApprovalStatus::PENDING_SUBMISSION); + } + + $booking = $this->updatesBookingFixedAmount->execute($booking, $input_amount); + + return $this->resourceResponse(new BookingResource($booking)); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php index 2dec77fa..14a4a9ef 100644 --- a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php +++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php @@ -11,8 +11,10 @@ use Carbon\Carbon; class CalculatesBookingRefundAmount { - public function execute(Booking $booking){ - return $booking->transactions()->refunds()->complete()->sum('original_amount'); + public function execute(Booking $booking, int $type, ?string $payment_reference = NULL){ + return $type === 1 ? + $booking->transactions()->refunds($payment_reference) + ->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total') : $booking->transactions()->refunds($payment_reference)->sum('original_amount'); } } \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php index 5224e044..57a5525c 100644 --- a/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php +++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php @@ -12,7 +12,7 @@ class CalculatesBookingTransferredAmount { public function execute(Booking $booking){ - return $booking->transactions()->bills()->transferred()->sum('original_amount'); + return $booking->transactions()->bills()->complete()->sum('original_amount'); } } \ No newline at end of file diff --git a/app/Classes/Modules/Bookings/Services/UpdatesBooking.php b/app/Classes/Modules/Bookings/Services/UpdatesBooking.php index 37ca5b7c..2c0ec871 100644 --- a/app/Classes/Modules/Bookings/Services/UpdatesBooking.php +++ b/app/Classes/Modules/Bookings/Services/UpdatesBooking.php @@ -17,8 +17,8 @@ class UpdatesBooking extends AbstractUpdateRecord */ public function execute(Booking $model, BookingObject $object) { - $model->transferable_bank_id = $object->getTransferableBankId(); - $model->reference = $object->getReference(); + $model->bank_id = $object->getTransferableBankId(); + $model->marking = $object->getMarking(); $model->fix_amount = $object->getFixAmount(); $model->fix_currency_id = $object->getFixCurrencyId(); $model->convertible_currency_id = $object->getConvertibleCurrencyId(); diff --git a/app/Classes/Modules/Bookings/Services/UpdatesBookingFixedAmount.php b/app/Classes/Modules/Bookings/Services/UpdatesBookingFixedAmount.php new file mode 100644 index 00000000..24be06f4 --- /dev/null +++ b/app/Classes/Modules/Bookings/Services/UpdatesBookingFixedAmount.php @@ -0,0 +1,23 @@ +fix_amount = $fixedAmount; + return $this->handler($model); + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Documents/Services/DeletesDocument.php b/app/Classes/Modules/Documents/Services/DeletesDocument.php new file mode 100644 index 00000000..e0f02819 --- /dev/null +++ b/app/Classes/Modules/Documents/Services/DeletesDocument.php @@ -0,0 +1,19 @@ +handler($model); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Exports/Services/ExportsTransactions.php b/app/Classes/Modules/Exports/Services/ExportsTransactions.php index 4fd48239..a49d1f85 100644 --- a/app/Classes/Modules/Exports/Services/ExportsTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsTransactions.php @@ -36,7 +36,7 @@ class ExportsTransactions implements FromQuery, WithHeadingRow, WithMapping 1 => 'PAYMENT', 2 => 'INVOICE', 3 => 'BILL', - 4 => 'PERFORMA', + 4 => 'PROFORMA', 5 => 'TOP_UP', 6 => 'REFUND', 7 => 'PURCHASE_ORDER', diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php index 111cd0db..81eb0c8a 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php @@ -83,7 +83,7 @@ class CreatePaymentProofDocumentLogic extends AbstractControllerLogic $this->createsFile->execute($document, $object); - $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::COMPLETED); + $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED); $this->createInvoiceTransactionProcessor->execute($transaction->booking); diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php index 01e18b40..f496ab4f 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php @@ -101,7 +101,7 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic /** @var Transaction $payment */ $payment = $this->fetchesTransaction->execute(['id' => $payment['id']]); - + if($payment->status !== ApprovalStatus::APPROVED) continue; $this->updatesTransactionStatus->execute($payment, ApprovalStatus::COMPLETED); @@ -109,7 +109,7 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic $object = new TransactionObject($billNumber, TransactionType::BILL, $supplier->id, 1, $supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH, $payment->original_amount * (1 / $rate), $payment->original_amount, 1, $payment->original_currency_id, - $rate, 0, 0, null, ApprovalStatus::APPROVED); + $rate, 0, 0, null, ApprovalStatus::PENDING_VERIFICATION); $transactions[] = $this->createsTransaction->execute($payment->booking, $object); } diff --git a/app/Classes/Modules/Transactions/ControllersLogic/DeleteTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/DeleteTransactionLogic.php new file mode 100644 index 00000000..7995e447 --- /dev/null +++ b/app/Classes/Modules/Transactions/ControllersLogic/DeleteTransactionLogic.php @@ -0,0 +1,72 @@ + 'Deleted Transaction', + 'message' => 'You have successfully deleted a transaction' + ]; + } + + /** @var FetchesTransaction */ + private $fetchesTransaction; + + /** @var DeletesTransaction */ + private $deletesTransaction; + + /** @var UpdatesTransactionStatus */ + private $updatesTransactionStatus; + + /** + * CreatePaymentVerificationDocumentLogic constructor. + * @param FetchesTransaction $fetchesTransaction + * @param DeletesTransaction $deletesTransaction + */ + public function __construct(FetchesTransaction $fetchesTransaction, DeletesTransaction $deletesTransaction, UpdatesTransactionStatus $updatesTransactionStatus) + { + $this->fetchesTransaction = $fetchesTransaction; + $this->deletesTransaction = $deletesTransaction; + $this->updatesTransactionStatus = $updatesTransactionStatus; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]); + + $this->deletesTransaction->execute($transaction); + + $payment_transaction = $transaction->booking->transactions()->payments()->complete()->where('original_amount', '=', $transaction->original_amount)->where('id', '<', $transaction->id)->orderByDesc('id')->first(); + + $this->updatesTransactionStatus->execute($payment_transaction, ApprovalStatus::APPROVED); + + return $this->response([]); + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Transactions/DataTransferObjects/TransactionObject.php b/app/Classes/Modules/Transactions/DataTransferObjects/TransactionObject.php index 8fcf4ece..6b097b9e 100644 --- a/app/Classes/Modules/Transactions/DataTransferObjects/TransactionObject.php +++ b/app/Classes/Modules/Transactions/DataTransferObjects/TransactionObject.php @@ -57,6 +57,9 @@ class TransactionObject implements DataTransferObject /** @var array|null */ private $details; + /** @var string */ + private $paymentReference; + /** * TransactionObject constructor. * @param string $billNo @@ -75,8 +78,9 @@ class TransactionObject implements DataTransferObject * @param Carbon|null $expiresOn * @param int|null $status * @param array|null $details + * @param string $paymentReference */ - public function __construct(string $billNo, string $transactionType, int $issuer, int $receiver, int $recipientBankAccountId, int $paymentMethod, float $amount, float $originalAmount, int $currencyId, int $originalCurrencyId, float $currencyRate, float $tax, float $serviceCharge, ?Carbon $expiresOn, ?int $status = ApprovalStatus::PENDING_SUBMISSION, ?array $details = []) + public function __construct(string $billNo, string $transactionType, int $issuer, int $receiver, int $recipientBankAccountId, int $paymentMethod, float $amount, float $originalAmount, int $currencyId, int $originalCurrencyId, float $currencyRate, float $tax, float $serviceCharge, ?Carbon $expiresOn, ?int $status = ApprovalStatus::PENDING_SUBMISSION, ?array $details = [], ?string $paymentReference = null) { $this->billNo = $billNo; $this->transactionType = $transactionType; @@ -94,6 +98,7 @@ class TransactionObject implements DataTransferObject $this->expiresOn = $expiresOn; $this->status = $status; $this->details = $details; + $this->paymentReference = $paymentReference; } /** @@ -226,6 +231,14 @@ class TransactionObject implements DataTransferObject }, $this->details); } + /** + * @return string|null + */ + public function getPaymentReference(): ?string + { + return $this->paymentReference; + } + diff --git a/app/Classes/Modules/Transactions/DataTransferObjects/TransactionRefundCalculationObject.php b/app/Classes/Modules/Transactions/DataTransferObjects/TransactionRefundCalculationObject.php new file mode 100644 index 00000000..6da9a37d --- /dev/null +++ b/app/Classes/Modules/Transactions/DataTransferObjects/TransactionRefundCalculationObject.php @@ -0,0 +1,176 @@ +booking = $booking; + $this->transaction = $transaction; + $this->amount = $amount; + $this->currency_rate = $currency_rate; + } + + /** + * @return Booking + */ + public function getBooking(): Booking + { + return $this->booking; + } + + /** + * @return Transaction + */ + public function getTransaction(): Transaction + { + return $this->transaction; + } + + public function getAmount(): float + { + return $this->amount; + } + + public function getCurrencyRate(): float + { + return $this->currency_rate; + } + + /** + * @return float + */ + public function setUnrequestedAmount() + { + $this->unrequested_amount = $this->transaction->original_amount == $this->amount ? $this->transaction->original_amount : $this->transaction->original_amount - $this->amount; + return $this; + } + + public function getUnrequestedAmount() + { + return $this->unrequested_amount; + } + + public function setConversionObject() + { + $this->conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $this->getUnrequestedAmount())), $this->booking->convertible_currency_id, $this->booking->service_id, $this->booking->fix_currency_id === 1 ? 0 : 1); + return $this; + } + + public function getConversionObject() + { + return $this->conversionObject; + } + + public function setConfigurations() + { + $this->configurations = app('App\Classes\Modules\Bookings\Services\FetchesBookingQuotation')->execute($this->booking->company, $this->getConversionObject()); + return $this; + } + + public function getConfigurations() + { + return $this->configurations; + } + + public function setRefundAmount() + { + $this->refund_amount = $this->transaction->amount == $this->getConfigurations()->getLocalTotal() ? $this->transaction->amount : $this->transaction->amount - $this->getConfigurations()->getLocalTotal(); + return $this; + } + + public function getRefundAmount() + { + return $this->refund_amount; + } + + public function setRefundServiceCharge() + { + $this->refund_service_charge = $this->transaction->service_charge == $this->getConfigurations()->getServiceCharge() ? $this->transaction->service_charge : $this->transaction->service_charge - $this->getConfigurations()->getServiceCharge(); + return $this; + } + + public function getRefundServiceCharge() + { + return $this->refund_service_charge; + } + + public function setRefundTax() + { + $this->refund_tax = $this->transaction->tax == $this->getConfigurations()->getTax() ? $this->transaction->tax : $this->transaction->tax - $this->getConfigurations()->getTax(); + return $this; + } + + public function getRefundTax() + { + return $this->refund_tax; + } + + public function setRefundTotalAmount() + { + $this->refund_total_amount = $this->getRefundAmount() + $this->getRefundServiceCharge() + $this->getRefundTax(); + return $this; + } + + public function getRefundTotalAmount() + { + return $this->refund_total_amount; + } + + public function setRefundConversionAmount() + { + $this->refund_conversion_amount = $this->getCurrencyRate() ? $this->transaction->original_amount * (1 / $this->getCurrencyRate()) : $this->transaction->original_amount; + return $this; + } + + public function getRefundConversionAmount() + { + return $this->refund_conversion_amount; + } + + public function init(){ + $this->setUnrequestedAmount(); + $this->setConversionObject(); + $this->setConfigurations(); + $this->setRefundAmount(); + $this->setRefundServiceCharge(); + $this->setRefundTax(); + $this->setRefundTotalAmount(); + $this->setRefundConversionAmount(); + } +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php index ff76d197..e583eaf9 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php @@ -115,7 +115,6 @@ class CreateInvoiceTransactionProcessor if ((float) $booking_amount > (float) $payable_amount) { return; } - // confirm that all payments has been transferred if($this->calculatesBookingTransferredAmount->execute($booking) !== $this->calculatesBookingPaidAmount->execute($booking)){ return; diff --git a/app/Classes/Modules/Transactions/Processors/CreateProformaInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateProformaInvoiceTransactionProcessor.php new file mode 100644 index 00000000..3e7e8137 --- /dev/null +++ b/app/Classes/Modules/Transactions/Processors/CreateProformaInvoiceTransactionProcessor.php @@ -0,0 +1,188 @@ +createsTransaction = $createsTransaction; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount; + $this->calculatesBookingCurrencyAverageRate = $calculatesBookingCurrencyAverageRate; + $this->fetchesCompany = $fetchesCompany; + $this->createsDocument = $createsDocument; + $this->createsFile = $createsFile; + $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->generatesBookingQuotation = $generatesBookingQuotation; + $this->fetchesBookingQuotation = $fetchesBookingQuotation; + $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; + } + + + /** + * @param Booking $booking + * @return void + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(Booking $booking) + { + + $po_order_transaction = $booking->transactions() + ->where('type', TransactionType::PURCHASE_ORDER) + ->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED]) + ->first(); + + $outstanding = $this->calculatesBookingOutstanding->execute($booking); + + $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $outstanding)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::CASH); + + $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject); + + $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); + + $billNumber = $this->generatesTransactionBillNumber->execute('PYMT-'); + + + $object = new TransactionObject($billNumber, TransactionType::PAYMENT, 1, $booking->company->id, + $configurations->getConfigurations()->getBankId(), $configurations->getConversionObject()->getPaymentMethod(), + $configurations->getTotal(), $configurations->getForeignTotal(), 1, + $configurations->getConversionObject()->getCurrencyId(), $configurations->getConfigurations()->getRate(), + $configurations->getTax(), $configurations->getServiceCharge(), Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_SUBMISSION, [], isset($billPlzBill) ? $billPlzBill->id : NULL); + + $this->createsTransaction->execute($booking, $object); + + $billNumber = $this->generatesTransactionBillNumber->execute('PROFORMA-'); + + $payable_amount = $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->sum('amount'); + $booking_amount = $booking->fix_amount; + + $transaction = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->first(); + + $booking_currency_average_rate = $booking_amount / $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total'); + + $total_service_charge = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED]) + ->sum('service_charge'); + + $total_tax = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->whereIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED]) + ->sum('tax'); + + $transaction_object = new TransactionObject( + $billNumber, + TransactionType::PROFORMA, + $transaction->issuer, + $transaction->receiver, + $transaction->recipient_bank_account_id, + $transaction->payment_method, + $payable_amount, + $booking_amount, + $transaction->currency_id, + $transaction->original_currency_id, + $booking_currency_average_rate, + $total_tax, + $total_service_charge, + null, + ApprovalStatus::APPROVED + ); + + $perofrma_transaction = $this->createsTransaction->execute($po_order_transaction->booking, $transaction_object); + + $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); + + $purchase_order_pdf = LaravelMpdf::loadView('pages.pdfs.proforma_invoice', ['invoice_transaction' => $perofrma_transaction, 'po_order_transaction' => $po_order_transaction, 'supplier' => $supplier]); + $document_object = new DocumentObject( + DocumentType::PROFORMA_INVOICE, + [chunk_split('data:application/pdf;base64,'.base64_encode($purchase_order_pdf->output()))], + '', + ApprovalStatus::COMPLETED, + 'proforma_invoices' + ); + + /** @var Document $document */ + $document = $this->createsDocument->execute($po_order_transaction->booking, $document_object); + $this->createsFile->execute($document, $document_object); + + + } +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateWalletTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateWalletTransactionProcessor.php new file mode 100644 index 00000000..7297c670 --- /dev/null +++ b/app/Classes/Modules/Transactions/Processors/CreateWalletTransactionProcessor.php @@ -0,0 +1,61 @@ +generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->createsWalletTransaction = $createsWalletTransaction; + } + + + /** + * @param Booking $booking + * @return void + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(Wallet $wallet, WalletObject $walletOject, int $transactionType) + { + + $billNumber = $this->generatesTransactionBillNumber->execute('WAL-'); + + $transaction_object = new TransactionObject( + $billNumber, + $transactionType, + $wallet->company->id, + 1, + 1, + PaymentMethodType::BA, + $walletOject->getAmount(), + $walletOject->getAmount(), + $wallet->currency_id, + $wallet->currency_id, + 0, + 0, + 0, + null, + ApprovalStatus::PENDING_SUBMISSION + ); + $walletTransaction = $this->createsWalletTransaction->execute($wallet, $transaction_object); + + return $walletTransaction; + } +} diff --git a/app/Classes/Modules/Transactions/Processors/UpdateWalletTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/UpdateWalletTransactionProcessor.php new file mode 100644 index 00000000..7c7277f8 --- /dev/null +++ b/app/Classes/Modules/Transactions/Processors/UpdateWalletTransactionProcessor.php @@ -0,0 +1,68 @@ +fetchesTransaction = $fetchesTransaction; + $this->updatesTransactionStatus = $updatesTransactionStatus; + $this->updatesWallet = $updatesWallet; + } + + + /** + * @param Booking $booking + * @return void + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(int $transactionId, int $transactionStatus) + { + + $transaction = $this->fetchesTransaction->execute(['id' => $transactionId]); + $wallet = $transaction->wallet; + + switch($transaction->type){ + case TransactionType::TOP_UP: + $updateWalletAmount = $transaction->amount + $wallet->amount; + break; + case TransactionType::WITHDRAW: + $updateWalletAmount = $wallet->amount - $transaction->amount; + break; + default: + break; + } + + $walletOject = new WalletObject( $wallet->company->id, $wallet->currency_id, $wallet->code, $updateWalletAmount); + + $this->updatesTransactionStatus->execute($transaction, $transactionStatus); + + $this->updatesWallet->execute($wallet, $walletOject); + + return $wallet; + } +} diff --git a/app/Classes/Modules/Transactions/Services/CreatesTransaction.php b/app/Classes/Modules/Transactions/Services/CreatesTransaction.php index ddebf0d5..06530564 100644 --- a/app/Classes/Modules/Transactions/Services/CreatesTransaction.php +++ b/app/Classes/Modules/Transactions/Services/CreatesTransaction.php @@ -2,20 +2,20 @@ namespace App\Classes\Modules\Transactions\Services; -use App\Classes\General\Eloquent\AbstractUpdateRecord; use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord; +use App\Classes\General\Interfaces\Transactionable; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; -use App\Models\Booking; use App\Models\Transaction; class CreatesTransaction extends AbstractUpdateRelationshipRecord { /** + * @param Transactionable $transactionable * @param TransactionObject $object * @return \Illuminate\Database\Eloquent\Model * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute(Booking $booking, TransactionObject $object) { + public function execute(Transactionable $transactionable, TransactionObject $object) { $model = new Transaction(); $model->bill_no = $object->getBillNo(); $model->type = $object->getTransactionType(); @@ -32,9 +32,9 @@ class CreatesTransaction extends AbstractUpdateRelationshipRecord $model->service_charge = $object->getServiceCharge(); $model->expires_on = $object->getExpiresOn(); $model->status = $object->getStatus(); + $model->payment_reference = $object->getPaymentReference(); - - return $this->handler($booking->transactions(), $model); + return $this->handler($transactionable->transactions(), $model); } } \ No newline at end of file diff --git a/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php b/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php new file mode 100644 index 00000000..6c5003c8 --- /dev/null +++ b/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php @@ -0,0 +1,39 @@ +bill_no = $object->getBillNo(); + $model->type = $object->getTransactionType(); + $model->issuer = $object->getIssuer(); + $model->receiver = $object->getReceiver(); + $model->recipient_bank_account_id = $object->getRecipientBankAccountId(); + $model->payment_method = $object->getPaymentMethod(); + $model->amount = $object->getAmount(); + $model->original_amount = $object->getOriginalAmount(); + $model->currency_id = $object->getCurrencyId(); + $model->original_currency_id = $object->getOriginalCurrencyId(); + $model->currency_rate = $object->getCurrencyRate(); + $model->tax = $object->getTax(); + $model->service_charge = $object->getServiceCharge(); + $model->expires_on = $object->getExpiresOn(); + $model->status = $object->getStatus(); + + return $this->handler($wallet->transactions(), $model); + + } +} diff --git a/app/Classes/Modules/Transactions/Services/DeletesTransaction.php b/app/Classes/Modules/Transactions/Services/DeletesTransaction.php new file mode 100644 index 00000000..66416d60 --- /dev/null +++ b/app/Classes/Modules/Transactions/Services/DeletesTransaction.php @@ -0,0 +1,19 @@ +handler($model); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Wallets/ControllersLogic/CreateWalletLogic.php b/app/Classes/Modules/Wallets/ControllersLogic/CreateWalletLogic.php index efcff6b3..9a613b43 100644 --- a/app/Classes/Modules/Wallets/ControllersLogic/CreateWalletLogic.php +++ b/app/Classes/Modules/Wallets/ControllersLogic/CreateWalletLogic.php @@ -9,6 +9,7 @@ use App\Classes\Modules\Wallets\Services\CreatesWallet; use App\Classes\Modules\Wallets\Services\GeneratesWalletCode; use App\Classes\Modules\Wallets\Standards\Rules\CanCreateCompanyWallet; use App\Http\Resources\WalletResource; +use App\Classes\Modules\Companies\Services\FetchesCompany; use ErrorException; use Illuminate\Http\JsonResponse; @@ -38,14 +39,18 @@ class CreateWalletLogic extends AbstractControllerLogic /** @var CanCreateCompanyWallet */ private $canCreateCompanyWallet; + /** @var FetchesCompany */ + private $fetchesCompany; + /** * CreateWalletLogic constructor. * @param CreatesWallet $createsWallet * @param GeneratesWalletCode $generatesWalletCode * @param CanCreateCompanyWallet $canCreateCompanyWallet */ - public function __construct(CreatesWallet $createsWallet, GeneratesWalletCode $generatesWalletCode, CanCreateCompanyWallet $canCreateCompanyWallet) + public function __construct(CreatesWallet $createsWallet, GeneratesWalletCode $generatesWalletCode, CanCreateCompanyWallet $canCreateCompanyWallet, FetchesCompany $fetchesCompany) { + $this->fetchesCompany = $fetchesCompany; $this->createsWallet = $createsWallet; $this->generatesWalletCode = $generatesWalletCode; $this->canCreateCompanyWallet = $canCreateCompanyWallet; @@ -58,24 +63,14 @@ class CreateWalletLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - try { + $object = new WalletObject($request->input('company_id'), $request->input('currency_id'), $this->generatesWalletCode->execute()); - DB::beginTransaction(); + $this->canCreateCompanyWallet->passes($object); + $company = $this->fetchesCompany->execute(['id' => $request->input('company_id')]); - $object = new WalletObject($request->input('currency_id'), $request->input('company_id'), $this->generatesWalletCode->execute()); - - $this->canCreateCompanyWallet->passes($object); - - $wallet = $this->createsWallet->execute($object); - - DB::commit(); - - return $this->resourceResponse(new WalletResource($wallet)); - - } catch (\Exception $exception) { - throw new ErrorException($exception->getMessage(), $exception->getCode()); - } + $wallet = $this->createsWallet->execute($object, $company); + return $this->resourceResponse(new WalletResource($wallet)); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Wallets/ControllersLogic/ListWalletLogic.php b/app/Classes/Modules/Wallets/ControllersLogic/ListWalletLogic.php new file mode 100644 index 00000000..cf6b86bb --- /dev/null +++ b/app/Classes/Modules/Wallets/ControllersLogic/ListWalletLogic.php @@ -0,0 +1,60 @@ + 'List Company Wallet', + 'message' => 'You have successfully list company wallet' + ]; + } + + /** @var ListWallet */ + private $listsWallet; + + /** @var CanCreateCompanyWallet */ + private $canListWallet; + + /** + * CreateWalletLogic constructor. + * @param CreatesWallet $createsWallet + * @param GeneratesWalletCode $generatesWalletCode + * @param CanCreateCompanyWallet $canCreateCompanyWallet + */ + public function __construct(CanListWallet $canListWallet, ListsWallet $listsWallet) + { + $this->canListWallet = $canListWallet; + $this->listsWallet = $listsWallet; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + //$this->canListWallet->passes(); + + $query = $this->listsWallet->execute($this->listsWallet->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(WalletResource::collection($query)); + } +} diff --git a/app/Classes/Modules/Wallets/ControllersLogic/TopUpWalletLogic.php b/app/Classes/Modules/Wallets/ControllersLogic/TopUpWalletLogic.php new file mode 100644 index 00000000..8497ec32 --- /dev/null +++ b/app/Classes/Modules/Wallets/ControllersLogic/TopUpWalletLogic.php @@ -0,0 +1,72 @@ + 'TopUp into Company Wallet', + 'message' => 'You have successfully topup company wallet' + ]; + } + + /** @var FetchesWallet */ + private $fetchesWallet; + + /** @var CanTopUpWallet */ + private $canTopUpWallet; + + /** @var CreateWalletTransactionProcessor */ + private $createWalletTransactionProcessor; + + /** + * CreateWalletLogic constructor. + * @param CreatesWallet $createsWallet + * @param GeneratesWalletCode $generatesWalletCode + * @param CanCreateCompanyWallet $canCreateCompanyWallet + */ + public function __construct(CanTopUpWallet $canTopUpWallet, FetchesWallet $fetchesWallet, CreateWalletTransactionProcessor $createWalletTransactionProcessor) + { + $this->canTopUpWallet = $canTopUpWallet; + $this->fetchesWallet = $fetchesWallet; + $this->createWalletTransactionProcessor = $createWalletTransactionProcessor; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $wallet = $this->fetchesWallet->execute(['id' => $request->input('wallet_id')]); + + $walletOject = new WalletObject( $wallet->company->id, $wallet->currency_id, $wallet->code, $request->input('amount')); + + $this->canTopUpWallet->passes($walletOject); + + $transaction = $this->createWalletTransactionProcessor->execute($wallet, $walletOject, TransactionType::TOP_UP); + + return $this->resourceResponse(new WalletResource($wallet)); + } +} diff --git a/app/Classes/Modules/Wallets/ControllersLogic/UpdateStatusWalletLogic.php b/app/Classes/Modules/Wallets/ControllersLogic/UpdateStatusWalletLogic.php new file mode 100644 index 00000000..b051d3e3 --- /dev/null +++ b/app/Classes/Modules/Wallets/ControllersLogic/UpdateStatusWalletLogic.php @@ -0,0 +1,69 @@ + 'Update Status Transaction Company Wallet', + 'message' => 'You have successfully status transaction company wallet' + ]; + } + + /** @var ListWallet */ + private $fetchesWallet; + + /** @var CanCreateCompanyWallet */ + private $canListWallet; + + /** @var UpdateWalletTransactionProcessor */ + private $updateWalletTransactionProcessor; + + /** + * CreateWalletLogic constructor. + * @param CreatesWallet $createsWallet + * @param GeneratesWalletCode $generatesWalletCode + * @param CanCreateCompanyWallet $canCreateCompanyWallet + */ + public function __construct(FetchesWallet $fetchesWallet, UpdateWalletTransactionProcessor $updateWalletTransactionProcessor) + { + $this->fetchesWallet = $fetchesWallet; + $this->updateWalletTransactionProcessor = $updateWalletTransactionProcessor; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $status = ($request->route('status')=='approve') ? 2 : 4; + + $wallet = $this->updateWalletTransactionProcessor->execute($request->route('transaction_id'), $status); + + return $this->resourceResponse(new WalletResource($wallet)); + + } +} diff --git a/app/Classes/Modules/Wallets/ControllersLogic/WithdrawWalletLogic.php b/app/Classes/Modules/Wallets/ControllersLogic/WithdrawWalletLogic.php new file mode 100644 index 00000000..b1491ab7 --- /dev/null +++ b/app/Classes/Modules/Wallets/ControllersLogic/WithdrawWalletLogic.php @@ -0,0 +1,72 @@ + 'Withdraw from Company Wallet', + 'message' => 'You have successfully withdraw company wallet' + ]; + } + + /** @var FetchesWallet */ + private $fetchesWallet; + + /** @var CanWithdrawWallet */ + private $canWithdrawWallet; + + /** @var CreateWalletTransactionProcessor */ + private $createWalletTransactionProcessor; + + /** + * CreateWalletLogic constructor. + * @param CreatesWallet $createsWallet + * @param GeneratesWalletCode $generatesWalletCode + * @param CanCreateCompanyWallet $canCreateCompanyWallet + */ + public function __construct(CanWithdrawWallet $canWithdrawWallet, FetchesWallet $fetchesWallet, CreateWalletTransactionProcessor $createWalletTransactionProcessor) + { + $this->canWithdrawWallet = $canWithdrawWallet; + $this->fetchesWallet = $fetchesWallet; + $this->createWalletTransactionProcessor = $createWalletTransactionProcessor; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $wallet = $this->fetchesWallet->execute(['id' => $request->input('wallet_id')]); + + $walletOject = new WalletObject( $wallet->company->id, $wallet->currency_id, $wallet->code, $request->input('amount')); + + $this->canWithdrawWallet->passes($walletOject); + + $transaction = $this->createWalletTransactionProcessor->execute($wallet, $walletOject, TransactionType::WITHDRAW); + + return $this->resourceResponse(new WalletResource($wallet)); + } +} diff --git a/app/Classes/Modules/Wallets/DataTransferObjects/WalletObject.php b/app/Classes/Modules/Wallets/DataTransferObjects/WalletObject.php index 6f4fcd83..4bfae2f4 100644 --- a/app/Classes/Modules/Wallets/DataTransferObjects/WalletObject.php +++ b/app/Classes/Modules/Wallets/DataTransferObjects/WalletObject.php @@ -16,17 +16,20 @@ class WalletObject implements DataTransferObject /** @var int */ private $code; + private $amount; + /** * WalletObject constructor. * @param int $company_id * @param int $currency * @param int $code */ - public function __construct(int $company_id, int $currency, int $code) + public function __construct(int $company_id, int $currency, int $code, float $amount=0) { $this->company_id = $company_id; $this->currency_id = $currency; $this->code = $code; + $this->amount = $amount; } /** @@ -53,7 +56,10 @@ class WalletObject implements DataTransferObject return $this->code; } + public function getAmount(): float + { + return $this->amount; + } - -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Wallets/Services/CreatesWallet.php b/app/Classes/Modules/Wallets/Services/CreatesWallet.php index 720049cb..c114b9de 100644 --- a/app/Classes/Modules/Wallets/Services/CreatesWallet.php +++ b/app/Classes/Modules/Wallets/Services/CreatesWallet.php @@ -3,24 +3,26 @@ namespace App\Classes\Modules\Wallets\Services; use App\Classes\General\Eloquent\AbstractUpdateRecord; +use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord; use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject; use App\Models\Wallet; +use App\Models\Company; -class CreatesWallet extends AbstractUpdateRecord +class CreatesWallet extends AbstractUpdateRelationshipRecord { /** * @param WalletObject $object * @return \Illuminate\Database\Eloquent\Model * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute(WalletObject $object) { + public function execute(WalletObject $object, Company $company) { $model = new Wallet(); - $model->company_id = $object->getCompanyId(); + //$model->company_id = $object->getCompanyId(); $model->code = $object->getCode(); $model->currency_id = $object->getCurrency(); - return $this->handler($model); + return $this->handler($company->wallets(), $model); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Wallets/Services/ListsWallet.php b/app/Classes/Modules/Wallets/Services/ListsWallet.php new file mode 100644 index 00000000..c11e2063 --- /dev/null +++ b/app/Classes/Modules/Wallets/Services/ListsWallet.php @@ -0,0 +1,30 @@ +repository = $repository; + } + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Wallets/Services/UpdatesWallet.php b/app/Classes/Modules/Wallets/Services/UpdatesWallet.php new file mode 100644 index 00000000..8b268fab --- /dev/null +++ b/app/Classes/Modules/Wallets/Services/UpdatesWallet.php @@ -0,0 +1,27 @@ +amount = $object->getAmount(); + $model->code = $object->getCode(); + $model->currency_id = $object->getCurrency(); + + + return $this->handler($model); + + } +} diff --git a/app/Classes/Modules/Wallets/Standards/Rules/CanListWallet.php b/app/Classes/Modules/Wallets/Standards/Rules/CanListWallet.php new file mode 100644 index 00000000..c87cb316 --- /dev/null +++ b/app/Classes/Modules/Wallets/Standards/Rules/CanListWallet.php @@ -0,0 +1,51 @@ +listWalletValidation = $listWalletValidation; + } + + + /** + * @return bool + */ + protected function authorized(): bool + { + // TODO Set Authorization rules + return true; + } + + /** + * @param WalletObject $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->listWalletValidation->validate($object); + } + + /** + * @param WalletTransactionObject $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} diff --git a/app/Classes/Modules/Wallets/Standards/Rules/CanTopUpWallet.php b/app/Classes/Modules/Wallets/Standards/Rules/CanTopUpWallet.php new file mode 100644 index 00000000..9a005498 --- /dev/null +++ b/app/Classes/Modules/Wallets/Standards/Rules/CanTopUpWallet.php @@ -0,0 +1,51 @@ +topUpWalletValidation = $topUpWalletValidation; + } + + + /** + * @return bool + */ + protected function authorized(): bool + { + // TODO Set Authorization rules + return true; + } + + /** + * @param WalletObject $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->topUpWalletValidation->validate($object); + } + + /** + * @param WalletTransactionObject $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} diff --git a/app/Classes/Modules/Wallets/Standards/Rules/CanWithdrawWallet.php b/app/Classes/Modules/Wallets/Standards/Rules/CanWithdrawWallet.php new file mode 100644 index 00000000..6fb4019d --- /dev/null +++ b/app/Classes/Modules/Wallets/Standards/Rules/CanWithdrawWallet.php @@ -0,0 +1,51 @@ +witdrawWalletValidation = $witdrawWalletValidation; + } + + + /** + * @return bool + */ + protected function authorized(): bool + { + // TODO Set Authorization rules + return true; + } + + /** + * @param WalletObject $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->witdrawWalletValidation->validate($object); + } + + /** + * @param WalletTransactionObject $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} diff --git a/app/Classes/Modules/Wallets/Standards/Validators/ListWalletValidation.php b/app/Classes/Modules/Wallets/Standards/Validators/ListWalletValidation.php new file mode 100644 index 00000000..1f75aa54 --- /dev/null +++ b/app/Classes/Modules/Wallets/Standards/Validators/ListWalletValidation.php @@ -0,0 +1,30 @@ + self::CHEQUE, 'ba' => self::BA, 'wallet' => self::WALLET, - 'payment gateway' => self::PAYMENT_GATEWAY, + 'payment_gateway' => self::PAYMENT_GATEWAY, ]; public const PAYMENT_METHODS_ID = [ @@ -27,7 +27,7 @@ final class PaymentMethodType { self::CHEQUE => 'cheque', self::BA => 'ba', self::WALLET => 'wallet', - self::PAYMENT_GATEWAY => 'payment gateway' + self::PAYMENT_GATEWAY => 'payment_gateway' ]; } diff --git a/app/Classes/ValueObjects/Constants/TransactionType.php b/app/Classes/ValueObjects/Constants/TransactionType.php index c3d9eb64..698abd76 100644 --- a/app/Classes/ValueObjects/Constants/TransactionType.php +++ b/app/Classes/ValueObjects/Constants/TransactionType.php @@ -12,7 +12,7 @@ final class TransactionType { public const BILL = 3; - public const PERFORMA = 4; + public const PROFORMA = 4; public const TOP_UP = 5; @@ -23,4 +23,6 @@ final class TransactionType { public const SUPPLIER_DELIVER = 8; public const CREDIT_NOTE = 9; + + public const WITHDRAW = 10; } diff --git a/app/Console/Commands/EmailDoToVTCommand.php b/app/Console/Commands/EmailDoToVTCommand.php index d9d463f0..66e4f7b4 100644 --- a/app/Console/Commands/EmailDoToVTCommand.php +++ b/app/Console/Commands/EmailDoToVTCommand.php @@ -5,19 +5,10 @@ namespace App\Console\Commands; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\DocumentType; use App\Classes\ValueObjects\Constants\TransactionType; -use App\Models\Document; -use App\Models\State; -use App\Http\Helpers\General; -use App\Models\Transaction; use App\Models\User; use Carbon\Carbon; use Illuminate\Console\Command; -use App\Classes\Jobs\FetchContainersStatusUpdateFromVTPortalJob; -use App\Classes\Jobs\FetchDeliveryListFromVTPortalJob; -use App\Classes\Jobs\FetchLoadedContainersFromVTPortalJob; -use App\Classes\Jobs\FetchPackingListFromVTPortalJob; -use App\Classes\Jobs\FetchWarehouseReceiveListFromVTPortalJob; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Mail; @@ -62,14 +53,16 @@ class EmailDoToVTCommand extends Command Auth::login(User::findOrFail(1)); $zip_file = 'do_'.Carbon::yesterday()->format('Y_m_d').'.zip'; $attachment = storage_path().'/'.$zip_file; + $zip = new ZipArchive(); if ($zip->open($attachment, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE)) { + $bookings = \App\Models\Booking::where('status', ApprovalStatus::COMPLETED)->whereDate('updated_at', Carbon::yesterday()) ->whereHas('transactions', function ($query){ return $query->where('type', TransactionType::BILL)->where('issuer', 2); })->get(); - if(!$bookings){ return; } + if(!count($bookings)){ return; } foreach ($bookings as $booking) { $file = $booking->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()->files()->first(); @@ -82,7 +75,7 @@ class EmailDoToVTCommand extends Command Mail::raw( "Attention to VT Admin team:\r\n\r\nKindly refer to the attachment for our DAILY DO COMPILATION ".Carbon::yesterday()->format('d-m-Y').".\r\n\r\n**This is an automatically generated email – please do not reply to it. If you have any queries kindly contact our admin team through Wechat.\r\n\r\n\r\nCIEF WORLDWIDE SDN BHD", function($message) use ($attachment){ $message->from('exchange@cief-malaysia.com'); $message->to(['vtnation16@gmail.com', 'vtnation@gmail.com', 'atvantic04@gmail.com', 'vtnation2@gmail.com']); - $message->cc(['shafiqa_sukeri@cief-malaysia.com', 'frontendcief@gmail.com', 'pm@cief-malaysia.com', 'hasan@cief-malaysia.com', 'shipping_admin@cief-malaysia.com', 'hasanakbar27@gmail.com', 'pmwong2019@gmail.com']); + $message->cc(['shafiqa_sukeri@cief-malaysia.com', 'frontendcief@gmail.com', 'pm@cief-malaysia.com', 'hasan@cief-malaysia.com', 'shipping_admin@cief-malaysia.com', 'hasanakbar27@gmail.com', 'pmwong2019@gmail.com', 'uldvstar@gmail.com']); $message->subject('CIEF DO COMPILATION '.Carbon::yesterday()->format('d-m-Y')); $message->attach($attachment); @@ -94,4 +87,5 @@ class EmailDoToVTCommand extends Command } } + } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 75c6edf1..8edaaa22 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -32,7 +32,7 @@ class Kernel extends ConsoleKernel { // $schedule->command('inspire')->hourly(); - $schedule->command('mail:EmailDoToVTCommand')->dailyAt('10:00'); + $schedule->command('mail:EmailDoToVTCommand')->dailyAt('10:00')->withoutOverlapping(); } diff --git a/app/Http/Controllers/Billplz/CallbackBillplzController.php b/app/Http/Controllers/Billplz/CallbackBillplzController.php new file mode 100644 index 00000000..9ee281e6 --- /dev/null +++ b/app/Http/Controllers/Billplz/CallbackBillplzController.php @@ -0,0 +1,22 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Billplz/CreateBillplzBillController.php b/app/Http/Controllers/Billplz/CreateBillplzBillController.php new file mode 100644 index 00000000..c10bad79 --- /dev/null +++ b/app/Http/Controllers/Billplz/CreateBillplzBillController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Bookings/CreateProformaInvoiceTransaction.php b/app/Http/Controllers/Bookings/CreateProformaInvoiceTransaction.php new file mode 100644 index 00000000..11b0739c --- /dev/null +++ b/app/Http/Controllers/Bookings/CreateProformaInvoiceTransaction.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Bookings/RegenerateInvoiceBookingController.php b/app/Http/Controllers/Bookings/RegenerateInvoiceBookingController.php new file mode 100644 index 00000000..d63c1b9c --- /dev/null +++ b/app/Http/Controllers/Bookings/RegenerateInvoiceBookingController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Bookings/UpdateBookingAmountController.php b/app/Http/Controllers/Bookings/UpdateBookingAmountController.php new file mode 100644 index 00000000..d0f6dd6c --- /dev/null +++ b/app/Http/Controllers/Bookings/UpdateBookingAmountController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Transactions/CreateTransactionController.php b/app/Http/Controllers/Transactions/CreateTransactionController.php index c311ca19..fa67604a 100644 --- a/app/Http/Controllers/Transactions/CreateTransactionController.php +++ b/app/Http/Controllers/Transactions/CreateTransactionController.php @@ -10,6 +10,6 @@ class CreateTransactionController { public function create(Request $request, CreateTransactionLogic $logic): JsonResponse { - return $logic->execute($request); + return $logic->logic($request); } } \ No newline at end of file diff --git a/app/Http/Controllers/Transactions/DeletePaymentProofDocumentController.php b/app/Http/Controllers/Transactions/DeletePaymentProofDocumentController.php new file mode 100644 index 00000000..d90cf1df --- /dev/null +++ b/app/Http/Controllers/Transactions/DeletePaymentProofDocumentController.php @@ -0,0 +1,14 @@ +execute($request); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Wallets/ListWalletController.php b/app/Http/Controllers/Wallets/ListWalletController.php new file mode 100644 index 00000000..45b2f1d1 --- /dev/null +++ b/app/Http/Controllers/Wallets/ListWalletController.php @@ -0,0 +1,14 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Wallets/TopUpWalletController.php b/app/Http/Controllers/Wallets/TopUpWalletController.php new file mode 100644 index 00000000..aaa707bd --- /dev/null +++ b/app/Http/Controllers/Wallets/TopUpWalletController.php @@ -0,0 +1,15 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Wallets/UpdateStatusWalletController.php b/app/Http/Controllers/Wallets/UpdateStatusWalletController.php new file mode 100644 index 00000000..21eea924 --- /dev/null +++ b/app/Http/Controllers/Wallets/UpdateStatusWalletController.php @@ -0,0 +1,14 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Wallets/WithdrawWalletController.php b/app/Http/Controllers/Wallets/WithdrawWalletController.php new file mode 100644 index 00000000..7c7b944a --- /dev/null +++ b/app/Http/Controllers/Wallets/WithdrawWalletController.php @@ -0,0 +1,15 @@ +execute($request); + } +} diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index cc5f0dca..80199df9 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -5,6 +5,7 @@ namespace App\Http\Resources; use App\Classes\Modules\Bookings\Services\CalculatesBookingFloatingAmount; use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding; use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\DocumentType; @@ -31,8 +32,8 @@ class BookingResource extends JsonResource '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)), - 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)), + '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), @@ -41,18 +42,32 @@ class BookingResource extends JsonResource '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()), ], 'status' => $this->status, 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'), $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()), + '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())->get()), 'payment_history' => TransactionResource::collection($this->transactions()->where(function($query){ $query->where(function($query){ - $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED]); + $query->where(function($query){ + $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED]); + })->orWhere(function($query){ + $query->where('type', TransactionType::BILL)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }); })->orWhere(function($query){ - $query->where('type', TransactionType::BILL)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + $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/TransactionResource.php b/app/Http/Resources/TransactionResource.php index 18658d33..633985cf 100644 --- a/app/Http/Resources/TransactionResource.php +++ b/app/Http/Resources/TransactionResource.php @@ -21,8 +21,10 @@ class TransactionResource extends JsonResource 'booking' => new BookingResource($this->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($this->when((int) $this->type === TransactionType::BILL, $this->booking->bank)), 'issuer_name' => $this->issuerCompany->name, - 'recipient_bank_account' => new BankResource($this->when((int) $this->type === TransactionType::BILL,$this->booking->bank)), 'amount' => (double) $this->amount, 'original_amount' => (double) $this->original_amount, 'currency' => new CurrencyResource($this->currency), diff --git a/app/Models/Booking.php b/app/Models/Booking.php index 33c33341..ea01b302 100644 --- a/app/Models/Booking.php +++ b/app/Models/Booking.php @@ -3,13 +3,11 @@ namespace App\Models; use App\Classes\General\Interfaces\Documentable; +use App\Classes\General\Interfaces\Transactionable; use App\Classes\ValueObjects\Constants\RoleTypes; use App\Scopes\CustomerBookingsScope; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; -use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\SoftDeletes; /** @@ -21,10 +19,10 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property string marking * @property string reference * @property float fix_amount - * @property \App\Models\Currency convertible_currency_id - * @property \App\Models\Currency conversion_currency_id + * @property int convertible_currency_id + * @property int conversion_currency_id */ -class Booking extends AbstractModel implements Documentable +class Booking extends AbstractModel implements Documentable, Transactionable { use SoftDeletes; @@ -89,11 +87,11 @@ class Booking extends AbstractModel implements Documentable } /** - * @return HasMany + * @return MorphMany */ - public function transactions(): HasMany + public function transactions(): MorphMany { - return $this->HasMany(Transaction::class, 'booking_id'); + return $this->MorphMany(Transaction::class, 'owner'); } protected static function booted() diff --git a/app/Models/Company.php b/app/Models/Company.php index e2c9dda4..7b8e4387 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -99,7 +99,15 @@ class Company extends AbstractModel implements Documentable */ public function transactions(): hasManyDeep { - return $this->hasManyDeep(Transaction::class, [Booking::class], ['company_id', 'booking_id'], ['id', 'id']); + return $this->hasManyDeep(Transaction::class, [Booking::class], ['company_id', 'owner_id'], ['id', 'id']); + } + + /** + * @return MorphMany + */ + public function wallets(): morphMany + { + return $this->morphMany(Wallet::class, 'owner'); } /** diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 6a9c0282..a3e16c79 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -7,23 +7,48 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\MorphMany; +use Illuminate\Database\Eloquent\Relations\MorphTo; class Transaction extends AbstractModel implements Documentable { + use SoftDeletes; + protected $table = 'transactions'; + public function owner(): morphTo + { + return $this->morphTo(); + } + /** - * @return BelongsTo + * @return MorphMany */ public function booking(): BelongsTo { - return $this->BelongsTo( Booking::class, 'booking_id', 'id'); + return $this->BelongsTo(Booking::class, 'owner_id', 'id'); + } + + /** + * @return MorphMany + */ + public function wallets(): morphMany + { + return $this->morphMany(Wallet::class, 'owner'); + } + + /** + * @return BelongsTo + */ + public function wallet(): BelongsTo + { + return $this->BelongsTo(Wallet::class, 'owner_id', 'id'); } /** @@ -104,10 +129,15 @@ class Transaction extends AbstractModel implements Documentable /** * @param Builder $query + * @param string $payment_reference * @return Builder */ - public function scopeRefunds(Builder $query) + public function scopeRefunds(Builder $query, ?string $payment_reference = NULL) { + if($payment_reference){ + $query->where('payment_reference', $payment_reference); + } + return $query->where('type', TransactionType::REFUND); } @@ -143,6 +173,6 @@ class Transaction extends AbstractModel implements Documentable */ public function scopeTransferred(Builder $query) { - return $query->whereIn('status', [ApprovalStatus::COMPLETED]); + return $query->whereIn('status', [ApprovalStatus::APPROVED]); } } diff --git a/app/Models/Wallet.php b/app/Models/Wallet.php index f9808e9e..52d8f718 100644 --- a/app/Models/Wallet.php +++ b/app/Models/Wallet.php @@ -2,16 +2,34 @@ namespace App\Models; -use Illuminate\Database\Eloquent\Relations\HasOne; - +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\MorphTo; +use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphMany; class Wallet extends AbstractModel { - protected $table = 'wallets'; + use SoftDeletes; - public function company(): HasOne + protected $table = 'wallets'; + /** + * @return \Illuminate\Database\Eloquent\Relations\MorphTo + */ + public function owner(): morphTo { - return $this->hasOne(Company::class, 'company_id', 'id'); + return $this->morphTo(); + } + public function company(): BelongsTo + { + return $this->BelongsTo(Company::class, 'owner_id', 'id'); } + /** + * @return morphMany + */ + public function transactions(): morphMany + { + return $this->morphMany(Transaction::class, 'owner'); + } } diff --git a/composer.json b/composer.json index 377c8932..32f52d83 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "ext-zip": "*", "barryvdh/laravel-dompdf": "^0.9.0", "carlos-meneses/laravel-mpdf": "^2.1", + "doctrine/dbal": "^2.12.1", "fideloper/proxy": "^4.2", "fruitcake/laravel-cors": "^1.0", "guzzlehttp/guzzle": "^6.3", diff --git a/config/billplz.php b/config/billplz.php new file mode 100644 index 00000000..fb8ed920 --- /dev/null +++ b/config/billplz.php @@ -0,0 +1,12 @@ + env('BILLPLZ_BASE_URL', 'https://www.billplz.com'), + 'api_key' => env('BILLPLZ_API_KEY', '0fa4c710-761b-4a7a-a501-c2c2d02643d5'), + 'x_signature_key' => env('BILLPLZ_X_SIGNATURE_KEY', 'S-pbNVthVRsvnPfZlgLwqqOg'), + 'collection_id' => env('BILLPLZ_COLLECTION_ID', 'hev2wdjy'), + 'redirect_url' => env('BILLPLZ_REDIRECT_URL', 'localhost'), + 'callback_url' => env('BILLPLZ_CALLBACK_URL', 'localhost'), + 'maybank' => 'MB2U0227', + 'cimb' => 'BCBB0235' +]; \ No newline at end of file diff --git a/database/migrations/2021_10_02_082211_drop_wallet_transactions_table.php b/database/migrations/2021_10_02_082211_drop_wallet_transactions_table.php new file mode 100644 index 00000000..f16eeba3 --- /dev/null +++ b/database/migrations/2021_10_02_082211_drop_wallet_transactions_table.php @@ -0,0 +1,28 @@ +dropForeign('wallets_company_id_foreign'); + $table->dropColumn('company_id'); + }); + } + + if (!Schema::hasColumn('wallets', 'owner_id')) { + Schema::table('wallets', function (Blueprint $table) { + $table->morphs('owner'); + }); + + //In-case the model name lengthy + Schema::table('wallets', function (Blueprint $table) { + $table->string('owner_type', 250)->change(); + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2021_10_02_083144_alter_transaction_booking_id.php b/database/migrations/2021_10_02_083144_alter_transaction_booking_id.php new file mode 100644 index 00000000..a37da4e4 --- /dev/null +++ b/database/migrations/2021_10_02_083144_alter_transaction_booking_id.php @@ -0,0 +1,45 @@ +morphs('owner'); + }); + + //In-case the model name lengthy + Schema::table('transactions', function (Blueprint $table) { + $table->string('owner_type', 250)->change(); + }); + + DB::statement("UPDATE transactions SET owner_type='App\\\\Models\\\\Booking', owner_id = booking_id"); + + Schema::table('transactions', function (Blueprint $table) { + $table->dropForeign('transactions_booking_id_foreign'); + $table->dropColumn('booking_id'); + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/seeds/FakeBookingTransactions.php b/database/seeds/FakeBookingTransactions.php index 08ff95f7..7eafda1d 100644 --- a/database/seeds/FakeBookingTransactions.php +++ b/database/seeds/FakeBookingTransactions.php @@ -230,7 +230,7 @@ class FakeBookingTransactions extends Seeder Constants\TransactionType::PAYMENT, Constants\TransactionType::INVOICE, Constants\TransactionType::BILL, - Constants\TransactionType::PERFORMA, + Constants\TransactionType::PROFORMA, Constants\TransactionType::TOP_UP, Constants\TransactionType::REFUND, Constants\TransactionType::PURCHASE_ORDER, diff --git a/resources/assets/sass/modules/_buttons.scss b/resources/assets/sass/modules/_buttons.scss index e4c1e5b4..3a9879eb 100644 --- a/resources/assets/sass/modules/_buttons.scss +++ b/resources/assets/sass/modules/_buttons.scss @@ -120,6 +120,10 @@ button:focus{ outline: none !important; } + +button:disabled { + cursor: not-allowed; +} /* Alternate buttons -------------------------------------------------- diff --git a/resources/assets/vue/components/accounts/forms/TopUpAccountComponent.vue b/resources/assets/vue/components/accounts/forms/TopUpAccountComponent.vue new file mode 100644 index 00000000..af8a43b7 --- /dev/null +++ b/resources/assets/vue/components/accounts/forms/TopUpAccountComponent.vue @@ -0,0 +1,196 @@ + + \ No newline at end of file diff --git a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue index 6f1c723c..fb157182 100644 --- a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue +++ b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue @@ -1,63 +1,98 @@