Merge branch 'development' into 'improve-responsive-ui'

# Conflicts:
#   resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue
This commit is contained in:
omair saleh
2021-12-23 03:52:55 +00:00
110 changed files with 4081 additions and 282 deletions
+6 -1
View File
@@ -50,4 +50,9 @@ FILESYSTEM_DRIVER="documents"
JWT_SECRET=
JWT_TTL=1440
IS_PRODUCTION=false
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"
@@ -17,7 +17,6 @@ abstract class AbstractUpdateRecord
*/
public function handler(Model $model){
try{
if($model->save()){ return $model; }
} catch (QueryException $exception){
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class BillNo implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('bill_no', $value);
}
}
@@ -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
{
/**
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class PaymentReference implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('payment_reference', '=', $value);
}
}
@@ -0,0 +1,13 @@
<?php
namespace App\Classes\General\Interfaces;
use Illuminate\Database\Eloquent\Relations\MorphMany;
interface Transactionable
{
public function transactions(): morphMany;
}
@@ -4,7 +4,7 @@ namespace App\Classes\Modules\Accounts\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class FullnameObject implements DataTransferObject
class FullNameObject implements DataTransferObject
{
/** @var string */
private $name;
@@ -12,11 +12,6 @@ class FullnameObject implements DataTransferObject
/**
* UserObject constructor.
* @param string $name
* @param string $email
* @param string $password
* @param string $passwordConfirmation
* @param int|null $type
* @param int|null $status
*/
public function __construct(string $name)
{
@@ -0,0 +1,87 @@
<?php
namespace App\Classes\Modules\Billplzs\ControllersLogic;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Http\Resources\TransactionResource;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Billplzs\Services\GetBillplzBill;
use App\Classes\Modules\Billplzs\DataTransferObjects\BillplzXSignatureObject;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class CallbackBillplzLogic
{
/** @var GetBillplzBill */
private $getBillplzBill;
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/**
* CreateBookingLogic constructor.
* @param GetBillplzBill $getBillplzBill
* @param FetchesTransaction $fetchesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
*/
public function __construct(GetBillplzBill $getBillplzBill, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus)
{
$this->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]);
}
}
@@ -0,0 +1,56 @@
<?php
namespace App\Classes\Modules\Billplzs\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Billplzs\Services\CreatesBillplzBill;
use ErrorException;
use App\Classes\Exceptions\MalformedRequestException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateBillplzBillLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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]);
}
}
@@ -0,0 +1,120 @@
<?php
namespace App\Classes\Modules\Billplzs\DataTransferObjects;
use Illuminate\Http\Request;
use App\Classes\General\Interfaces\DataTransferObject;
use function PHPSTORM_META\map;
class BillplzXSignatureObject implements DataTransferObject
{
/** @var string */
private $billPlzId;
/** @var string */
private $status;
/** @var array */
private $billPlzConstructArray;
/** @var string */
private $billPlzConstructString;
/** @var string */
private $billPlzComputedXSignature;
/** @var string */
private $type;
/** @var Request */
private $request;
/** @var string */
private $requestXSignature;
public function __construct(Request $request)
{
$this->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;
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Billplzs\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
class CreatesBillplzBill
{
/**
* @param string $name
* @param string $email
* @param string $description
* @param float $amount
* @param string $billNumber
* @param null|string $bankCode
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $name, string $email, string $description, float $amount, string $billNumber, ?string $bankCode = null) {
try{
$response = Http::withBasicAuth(config('billplz.api_key').':', '')->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;
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Modules\Billplzs\Services;
use App\Classes\Exceptions\MalformedRequestException;
use Illuminate\Support\Facades\Http;
class GetBillplzBill
{
/**
* @param string $billPlzId
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $billPlzId) {
try{
$response = Http::withBasicAuth(config('billplz.api_key').':', '')->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');
}
}
}
@@ -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);
@@ -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));
}
@@ -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);
@@ -0,0 +1,71 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Bookings\Standards\Rules\CanFetchBooking;
use App\Classes\Modules\Transactions\Processors\CreateProformaInvoiceTransactionProcessor;
use App\Http\Resources\BookingResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateProformaInvoiceTransactionLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -0,0 +1,110 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Bookings\Standards\Rules\CanFetchBooking;
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Documents\Services\DeletesDocument;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
use App\Http\Resources\BookingResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -0,0 +1,100 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\Modules\Bookings\Services\UpdatesBookingFixedAmount;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Http\Resources\BookingResource;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Bookings\Standards\Rules\CanUpdateBooking;
use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject;
use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Classes\Exceptions\MalformedRequestException;
class UpdateBookingAmountLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -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');
}
}
@@ -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');
}
}
@@ -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();
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\Modules\Bookings\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject;
use App\Models\Booking;
class UpdatesBookingFixedAmount extends AbstractUpdateRecord
{
/**
* @param Booking $model
* @param float $fixedAmount
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Booking $model, float $fixedAmount)
{
$model->fix_amount = $fixedAmount;
return $this->handler($model);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\Modules\Documents\Services;
use App\Classes\General\Eloquent\AbstractDeleteRecord;
use App\Models\Document;
class DeletesDocument extends AbstractDeleteRecord
{
/**
* @param Document $model
* @return mixed
*/
public function execute(Document $model) {
return $this->handler($model);
}
}
@@ -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',
@@ -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);
@@ -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);
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\CompanyType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Company;
use App\Models\Document;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
class DeleteTransactionLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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([]);
}
}
@@ -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;
}
@@ -0,0 +1,176 @@
<?php
namespace App\Classes\Modules\Transactions\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
use App\Models\Transaction;
use App\Models\Booking;
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject;
class TransactionRefundCalculationObject implements DataTransferObject
{
private $booking;
private $transaction;
private $amount;
private $currency_rate;
private $unrequested_amount;
private $conversionObject;
private $configurations;
private $refund_amount;
private $refund_service_charge;
private $refund_tax;
private $refund_total_amount;
private $refund_conversion_amount;
/**
* TransactionRefundCalculationObject constructor.
* @param float $price
*/
public function __construct(Booking $booking, Transaction $transaction, ?float $amount = 0.00, ?float $currency_rate = 0.00)
{
$this->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();
}
}
@@ -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;
@@ -0,0 +1,188 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount;
use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation;
use App\Classes\Modules\Bookings\Services\GeneratesBookingQuotation;
use App\Classes\Modules\Companies\Services\FetchesCompanyPaymentAttemptLimit;
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Bookings\Services\CalculatesBookingCurrencyAverageRate;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Booking;
use App\Models\Document;
use Carbon\Carbon;
use Meneses\LaravelMpdf\Facades\LaravelMpdf;
class CreateProformaInvoiceTransactionProcessor
{
/** @var CreatesTransaction */
private $createsTransaction;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CalculatesBookingPayableAmount */
private $calculatesBookingPayableAmount;
/** @var CalculatesBookingCurrencyAverageRate */
private $calculatesBookingCurrencyAverageRate;
/** @var FetchesCompany */
private $fetchesCompany;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFile;
/** @var CalculatesBookingOutstanding */
private $calculatesBookingOutstanding;
/** @var GeneratesBookingQuotation */
private $generatesBookingQuotation;
/** @var FetchesBookingQuotation */
private $fetchesBookingQuotation;
/** @var FetchesCompanyPaymentAttemptLimit */
private $fetchesCompanyPaymentAttemptLimit;
/**
* CreateProformaInvoiceTransactionProcessor constructor.
* @param CreatesTransaction $createsTransaction
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount
* @param CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate
* @param FetchesCompany $fetchesCompany
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param CalculatesBookingOutstanding $calculatesBookingOutstanding
* @param GeneratesBookingQuotation $generatesBookingQuotation
* @param FetchesBookingQuotation $fetchesBookingQuotation
* @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit
*/
public function __construct(CreatesTransaction $createsTransaction, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate, FetchesCompany $fetchesCompany, CreatesDocument $createsDocument, CreatesFiles $createsFile, CalculatesBookingOutstanding $calculatesBookingOutstanding, GeneratesBookingQuotation $generatesBookingQuotation, FetchesBookingQuotation $fetchesBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit)
{
$this->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);
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\Services\CreatesWalletTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Wallet;
class CreateWalletTransactionProcessor
{
/** @var CreatesWalletTransaction */
private $createsWalletTransaction;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
public function __construct(CreatesWalletTransaction $createsWalletTransaction, GeneratesTransactionBillNumber $generatesTransactionBillNumber)
{
$this->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;
}
}
@@ -0,0 +1,68 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\Modules\Wallets\Services\UpdatesWallet;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Wallet;
class UpdateWalletTransactionProcessor
{
/** @var CreatesWalletTransaction */
private $createsWalletTransaction;
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var ListWallet */
private $fetchesWallet;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, UpdatesWallet $updatesWallet, FetchesTransaction $fetchesTransaction)
{
$this->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;
}
}
@@ -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);
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Models\Wallet;
use App\Models\Transaction;
class CreatesWalletTransaction extends AbstractUpdateRelationshipRecord
{
/**
* @param TransactionObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Wallet $wallet, TransactionObject $object) {
$model = new Transaction();
$model->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);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use App\Classes\General\Eloquent\AbstractDeleteRecord;
use App\Models\Transaction;
class DeletesTransaction extends AbstractDeleteRecord
{
/**
* @param Transaction $model
* @return mixed
*/
public function execute(Transaction $model) {
return $this->handler($model);
}
}
@@ -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));
}
}
}
@@ -0,0 +1,60 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Services\ListsWallet;
use App\Classes\Modules\Wallets\Standards\Rules\CanListWallet;
use App\Http\Resources\WalletResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ListWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Services\ListsWallet;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Wallets\Standards\Rules\CanTopUpWallet;
use App\Http\Resources\WalletResource;
use App\Classes\Modules\Transactions\Processors\CreateWalletTransactionProcessor;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class TopUpWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -0,0 +1,69 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Services\ListsWallet;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Wallets\Standards\Rules\CanListWallet;
use App\Http\Resources\WalletResource;
use App\Classes\Modules\Transactions\Processors\UpdateWalletTransactionProcessor;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class UpdateStatusWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Services\ListsWallet;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Wallets\Standards\Rules\CanWithdrawWallet;
use App\Http\Resources\WalletResource;
use App\Classes\Modules\Transactions\Processors\CreateWalletTransactionProcessor;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class WithdrawWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '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));
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Modules\Wallets\Services;
use Illuminate\Database\Eloquent\Builder;
use App\Classes\General\Eloquent\AbstractListRecord;
use App\Models\Wallet;
class ListsWallet extends AbstractListRecord
{
/** @var Booking */
private $repository;
/**
* ListsBookings constructor.
* @param Booking $repository
*/
public function __construct(Wallet $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,27 @@
<?php
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 UpdatesWallet extends AbstractUpdateRecord
{
/**
* @param WalletObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Wallet $model, WalletObject $object) {
$model->amount = $object->getAmount();
$model->code = $object->getCode();
$model->currency_id = $object->getCurrency();
return $this->handler($model);
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Standards\Validators\ListWalletValidation;
class CanListWallet extends AbstractRule
{
/** @var ListWalletValidation */
private $listWalletValidation;
public function __construct(ListWalletValidation $listWalletValidation)
{
$this->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;
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Standards\Validators\TopUpWalletValidation;
class CanTopUpWallet extends AbstractRule
{
/** @var TopUpWalletValidation */
private $topUpWalletValidation;
public function __construct(TopUpWalletValidation $topUpWalletValidation)
{
$this->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;
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Standards\Validators\WithdrawWalletValidation;
class CanWithdrawWallet extends AbstractRule
{
/** @var WithdrawWalletValidation */
private $witdrawWalletValidation;
public function __construct(WithdrawWalletValidation $witdrawWalletValidation)
{
$this->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;
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
class ListWalletValidation extends AbstractValidation
{
protected function data($object): array
{
return [];
}
/**
* @return array
*/
protected function rules(): array
{
return [];
}
/**
* @return array
*/
protected function messages(): array
{
return [];
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
class TopUpWalletValidation extends AbstractValidation
{
protected function data($object): array
{
return [];
}
/**
* @return array
*/
protected function rules(): array
{
return [];
}
/**
* @return array
*/
protected function messages(): array
{
return [];
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Modules\Wallets\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
class WithdrawWalletValidation extends AbstractValidation
{
protected function data($object): array
{
return [];
}
/**
* @return array
*/
protected function rules(): array
{
return [];
}
/**
* @return array
*/
protected function messages(): array
{
return [];
}
}
@@ -17,6 +17,7 @@ final class DocumentType {
public const WALLET_TOP_UP_PAYMENT_PROOF = 'WALLET_TOP_UP_PAYMENT_PROOF';
public const WALLET_REFUND_PAYMENT_PROOF = 'WALLET_REFUND_PAYMENT_PROOF';
public const PROFORMA_INVOICE = 'PROFORMA_INVOICE';
public const PURCHASE_ORDER = 'PURCHASE_ORDER';
public const DELIVER_ORDER = 'DELIVER_ORDER';
public const INVOICE = 'INVOICE';
@@ -19,7 +19,7 @@ final class PaymentMethodType {
'cheque' => 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'
];
}
@@ -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;
}
+5 -11
View File
@@ -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
}
}
}
+1 -1
View File
@@ -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();
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Billplz;
use App\Classes\Modules\Billplzs\ControllersLogic\CallbackBillplzLogic;
use Illuminate\Http\Request;
class CallbackBillplzController
{
/**
* @param Request $request
* @param CallbackBillplzLogic $logic
* @return bool|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\ResourceNotFoundException
*/
public function callback(Request $request, CallbackBillplzLogic $logic) {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Billplz;
use App\Classes\Modules\Billplzs\ControllersLogic\CreateBillplzBillLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateBillplzBillController
{
/**
* @param Request $request
* @param CreateBillplzBillLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateBillplzBillLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\CreateProformaInvoiceTransactionLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateProformaInvoiceTransaction
{
/**
* @param Request $request
* @param CreateProformaInvoiceTransactionLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateProformaInvoiceTransactionLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\RegenerateInvoiceBookingLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class RegenerateInvoiceBookingController
{
/**
* @param Request $request
* @param RegenerateInvoiceBookingLogic $logic
* @return JsonResponse
*/
public function regenerate(Request $request, RegenerateInvoiceBookingLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingAmountLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateBookingAmountController
{
/**
* @param Request $request
* @param CreateBookingRefundLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateBookingAmountLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -10,6 +10,6 @@ class CreateTransactionController
{
public function create(Request $request, CreateTransactionLogic $logic): JsonResponse {
return $logic->execute($request);
return $logic->logic($request);
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Transactions;
use App\Classes\Modules\Transactions\ControllersLogic\DeleteTransactionLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeletePaymentProofDocumentController
{
public function delete(Request $request, DeleteTransactionLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\ListWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListWalletController
{
public function list(Request $request, ListWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\TopUpWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class TopUpWalletController
{
public function topUp(Request $request, TopUpWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\UpdateStatusWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateStatusWalletController
{
public function updateStatus(Request $request, UpdateStatusWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\WithdrawWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class WithdrawWalletController
{
public function withdraw(Request $request, WithdrawWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
+20 -5
View File
@@ -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())
])
+3 -1
View File
@@ -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),
+7 -9
View File
@@ -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()
+9 -1
View File
@@ -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');
}
/**
+34 -4
View File
@@ -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]);
}
}
+23 -5
View File
@@ -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');
}
}
+1
View File
@@ -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",
+12
View File
@@ -0,0 +1,12 @@
<?php
return [
'base_url' => 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'
];
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class DropWalletTransactionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::dropIfExists('wallet_transaction');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
@@ -0,0 +1,44 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AlterWalletCompanyId extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasColumn('wallets', 'company_id')) {
Schema::table('wallets', function (Blueprint $table) {
$table->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()
{
//
}
}
@@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class AlterTransactionBookingId extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (!Schema::hasColumn('transactions', 'owner_id')) {
Schema::table('transactions', function (Blueprint $table) {
$table->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()
{
//
}
}
+1 -1
View File
@@ -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,
+4
View File
@@ -120,6 +120,10 @@
button:focus{
outline: none !important;
}
button:disabled {
cursor: not-allowed;
}
/*
Alternate buttons
--------------------------------------------------
@@ -0,0 +1,196 @@
<template>
<div class="row h-100 parentContainer">
<div class="col">
<div class="col-auto p-l-0 p-r-10">
<div class="btn btn-xs btn-primary p-t-0 p-b-0 text-primary-lighter requestModal" style="background-color: rgba(255, 255, 255, 0.2);" data-type="topUpModal">
<i class="fa fa-plus fs-14 m-t-5"></i>
</div>
</div>
<modal-component styleType="fill-in" type="topUpModal">
<div class="row zig-zag-top">
<div class="col bg-white padding-25">
<div class="row m-b-20">
<div class="col">
<div class="row">
<div class="col-8">
<div class="btn btn-xs btn-complete no-border btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="paymentMethod.status = !paymentMethod.status">
<div class="row">
<div class="col p-t-10 p-b-10">
{{paymentMethod.name}}
</div>
<div class="col-auto bg-complete-light">
<div class="row h-100 align-items-center">
<div class="col">
<i class="fa" :class="[{'fa-angle-down': !paymentMethod.status}, {'fa-angle-up': paymentMethod.status}]"></i>
</div>
</div>
</div>
</div>
</div>
<div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-complete" :class="[{'hide': !paymentMethod.status}]" style="top: 100%; right: 0; z-index: 1;">
<div class="row text-left no-margin bg-white">
<div class="col no-padding">
<div class="row no-margin" :class="[{'bg-complete-light': paymentMethod.name === 'Bank Transfer'}, {'text-white': paymentMethod.name === 'Bank Transfer'}, {'hover-complete': paymentMethod.name !== 'Bank Transfer'}]" @click="updatePaymentType({name: 'Bank Transfer', id: 'cash'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Bank Transfer</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': paymentMethod.name === 'Cash Deposit'}, {'text-white': paymentMethod.name === 'Cash Deposit'}, {'hover-complete': paymentMethod.name !== 'Cash Deposit'}]" @click="updatePaymentType({name: 'Cash Deposit', id: 'cash'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Cash Deposit</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': paymentMethod.name === 'Cheque'}, {'text-white': paymentMethod.name === 'Cheque'}, {'hover-complete': paymentMethod.name !== 'Cheque'}]" @click="updatePaymentType({name: 'Cheque', id: 'cheque'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Cheque</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': paymentMethod.name === 'Banker\'s Acceptance'}, {'text-white': paymentMethod.name === 'Banker\'s Acceptance'}, {'hover-complete': paymentMethod.name !== 'Banker\'s Acceptance'}]" @click="updatePaymentType({name: 'Banker\'s Acceptance', id: 'ba'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Banker's Acceptance</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': paymentMethod.name === 'Online Transfer'}, {'text-white': paymentMethod.name === 'Online Transfer'}, {'hover-complete': paymentMethod.name !== 'Online Transfer'}]" @click="updatePaymentType({name: 'Online Transfer', id: 'ot'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Online Transfer</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-r-0">
<div class="col p-r-0">
<validation-wrapper-component :validator="$v.amount">
<label>Amount</label>
<input class="form-control" name="amount" v-model.lazy="amount">
<!-- <input class="form-control" name="amount" v-model.lazy="amount" v-money="{decimal: '.',thousands: ',', precision: 2}"> -->
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<!-- <div class="font-heading fs-10 muted">{{this.data.fixed_currency.short_code}}</div> -->
</div>
</div>
</div>
</div>
<div class="row" v-if="paymentMethod.name == 'Online Transfer'">
<div class="col">
<div class="row m-t-10">
<div class="col">
<div class="row">
<div class="col-8">
<div class="btn btn-xs btn-block text-left b-rad-none p-t-10 p-b-10 p-l-15 p-r-15" :class="[{'b-complete': onlinePayment.bankName === 'Maybank'}]" @click="selectOnlinePaymentBank({bankName: 'Maybank', id: 'maybank'})">
<img src="https://shopee.com.my/static/images/bank_logo/img_bankmy_maybank.png" alt="">
Maybank2u
</div>
</div>
</div>
</div>
</div>
<div class="row m-t-10">
<div class="col">
<div class="row">
<div class="col-8">
<div class="btn btn-xs btn-block text-left b-rad-none p-t-10 p-b-10 p-l-15 p-r-15" :class="[{'b-complete': onlinePayment.bankName === 'Cimb'}]" @click="selectOnlinePaymentBank({bankName: 'Cimb', id: 'cimb'})">
<img src="https://shopee.com.my/static/images/bank_logo/img_bankmy_cimb.png" alt="">
Cimb
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-4 p-r-0">
<button class="btn btn-xs all-caps b-rad-none btn-default bg-master-lighter btn-block" data-dismiss="modal">Cancel</button>
</div>
<div class="col p-l-0">
<button class="btn btn-xs all-caps b-rad-none btn-success btn-block" v-if="!(paymentMethod.name === 'Online Transfer' && onlinePayment.status === false)" @click="submitForm()">Confirm</button>
</div>
</div>
</div>
</div>
</modal-component>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
data(){
return {
loading: false,
// amount: (Math.round((this.data.outstanding_amount + Number.EPSILON) * 100) / 100).toFixed(2),
amount: (Math.round(1000 * 100) / 100).toFixed(2),
paymentMethod: {
name: 'Bank Transfer',
id: 'cash',
status: false
},
onlinePayment: {
bankName: '',
id: '',
status: false
},
}
},
validations () {
return {
amount: { required }
}
},
methods:{
updatePaymentType(payment){
this.paymentMethod = {
name: payment.name,
id: payment.id,
status: false,
}
},
selectOnlinePaymentBank(bankName){
this.onlinePayment = {
bankName: bankName.bankName,
id: bankName.id,
status: true,
}
},
}
}
</script>
@@ -1,63 +1,98 @@
<template>
<div class="row m-l-0 m-b-10 m-r-0 parentContainer" :class="[{'b-a': item.status === 4}, {'b-danger': item.status === 4}]" >
<div class="col">
<div class="row">
<div class="col p-t-10 p-b-10 p-r-0 pointer" @click="expanded = !expanded" :class="[{'bg-master-lighter': item.status === 1}, {'bg-white': item.status !== 1 && item.status !== 4}]">
<div class="row m-b-5">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Status</div>
<div class="font-heading fs-10 bold" :class="[{'text-danger': item.status === 1 || item.status === 4}, {'text-success': item.status !== 1 && item.status !== 4}]">
{{ item.status === 1 ? 'Pending Verification' : item.status === 2 ? 'Processing Payment' : item.status === 4 ? 'Rejected' : 'Transferred'}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
{{ item.type === 3 ? item.original_currency.short_code : item.currency.short_code}} {{(Math.round((item.type === 3 ? item.original_amount : item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
<div class="row m-b-5">
<div class="col" v-if="$store.getters.isAdmin && item.type === 3">
<div class="font-heading fs-8 muted all-caps">Supplier</div>
<div class="font-heading fs-10 bold">
{{item.issuer_name}}
</div>
</div>
</div>
<div class="row" v-if="item.type === 1">
<div class="col">
<div class="row">
<div class="col">
<div class="font-heading fs-8 all-caps" :class="[{'text-danger': item.status === 4}, {'text-primary': item.status !== 4}]">{{ item.status === 1 ? 'Submitted' : item.status === 2 ? 'Received' : item.status === 4 ? 'Rejected' : 'Paid'}} On: {{item.updated_at}}</div>
</div>
</div>
</div>
<div class="col-auto" v-if="item.status !== 3" :class="[{'bg-master-light': item.status === 1}, {'bg-master-lighter': item.status === 2}]">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa" :class="[{'fa-cloud-download': item.status === 1 || item.status === 2}, {'fa-ban': item.status === 4}, {'muted': item.status === 1 || item.status === 2}, {'text-danger': item.status === 4}]"></i>
</div>
</div>
</div>
<div class="col-auto bg-success" v-if="item.status === 3">
<document-file-viewer-component class="h-100" :file="item.documents.files[0]">
<template slot="button">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-cloud-download text-white"></i>
<div class="col p-t-10 p-b-10 p-r-0 pointer" @click="clickExpand()" :class="[{'bg-master-lighter': item.status === 1}, {'bg-white': item.status !== 1 && item.status !== 4}]">
<div class="row m-b-5">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Status</div>
<div class="font-heading fs-10 bold" v-if="item.type === 1" :class="[{'text-danger': item.status === 1 || item.status === 4}, {'text-success': item.status !== 1 && item.status !== 4}]">
{{ item.status === 1 ? 'Pending Verification' : item.status === 4 ? 'Rejected' : 'Processing Payment'}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
{{item.currency.short_code}} {{(Math.round((item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
</template>
</document-file-viewer-component>
<div class="row">
<div class="col">
<div class="font-heading fs-8 all-caps" :class="[{'text-danger': item.status === 4}, {'text-primary': item.status !== 4}]">{{ item.status === 2 ? 'Received' : item.status === 4 ? 'Rejected' : 'Submitted'}} On: {{item.updated_at}}</div>
</div>
</div>
</div>
<div class="col-auto" v-if="item.status !== 3" :class="[{'bg-master-light': item.status === 1}, {'bg-master-lighter': item.status === 2}]">
<div class="row align-items-center h-100" v-if="item.status !== 1 || item.payment_method !== 5">
<div class="col">
<i class="fa" :class="[{'fa-cloud-download': item.status === 1 || item.status === 2}, {'fa-ban': item.status === 4}, {'muted': item.status === 1 || item.status === 2}, {'text-danger': item.status === 4}]"></i>
</div>
</div>
<div class="row align-items-center h-100" v-if="item.payment_method === 5 && item.status === 1">
<div class="col">
<a :href="'https://www.billplz.com/bills/'+item.payment_reference"><i class="fa fa-repeat text-success"></i></a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="expanded">
<div class="row" v-if="item.type === 3">
<div class="col">
<div class="row">
<div class="col p-t-10 p-b-10 p-r-0 pointer" @click="clickExpand()" :class="[{'bg-master-lighter': item.status === 1}, {'bg-white': item.status !== 1 && item.status !== 4}]">
<div class="row m-b-5">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Status</div>
<div class="font-heading fs-10 bold" :class="[{'text-danger': item.status === 1 || item.status === 4}, {'text-success': item.status !== 1 && item.status !== 4}]">
{{ item.status === 1 ? 'Processing Payment' : 'Transferred'}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
{{item.original_currency.short_code}} {{(Math.round((item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading fs-8 all-caps" >{{ item.status === 1 ? 'Paid On: ' + customerBooking.updated_at : 'Transferred On:' + item.updated_at }}</div>
</div>
</div>
</div>
<div class="col-auto" v-if="item.status !== 3 && item.status !== 2" :class="[{'bg-master-light': item.status === 1}, {'bg-master-lighter': item.status === 2}]">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa" :class="[{'fa-cloud-download': item.status === 1 || item.status === 2}, {'fa-ban': item.status === 4}, {'muted': item.status === 1 || item.status === 2}, {'text-danger': item.status === 4}]"></i>
</div>
</div>
</div>
<div class="col-auto bg-success" v-if="item.status === 2 || item.status === 3">
<document-file-viewer-component class="h-100" :file="item.documents.files[0]">
<template slot="button">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-cloud-download text-white"></i>
</div>
</div>
</template>
</document-file-viewer-component>
</div>
</div>
</div>
</div>
<div class="row" v-if="expandPaymentDetails">
<div class="col bg-white padding-15">
<div class="row align-items-end m-b-10 text-success bold">
<div class="col">
<div class="font-heading all-caps fs-10">Recipient Gets</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-10">{{this.customerBooking.original_currency.short_code}} {{(Math.round((item.type === 3 ? customerBooking.original_amount : item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
<div class="font-heading fs-10">{{this.customerBooking.original_currency.short_code}} {{(item.original_amount).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end bold m-b-10 text-primary">
@@ -95,7 +130,7 @@
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 m-b-5">Your Payment Proof</div>
<div class="row no-margin">
<div class="row no-margin" v-if="customerBooking.payment_method !== 5">
<div v-if="customerBooking.documents != null">
<div v-for="file in customerBooking.documents.files" v-bind:key="file.id" class="col-auto no-padding m-r-5">
<document-file-viewer-component :file="file">
@@ -108,10 +143,17 @@
</div>
</div>
</div>
<div class="row no-margin" v-if="customerBooking.payment_method === 5 && (customerBooking.status === 2 || customerBooking.status === 3)">
<a :href="'https://www.billplz.com/bills/'+customerBooking.payment_reference" target="_blank">
<div class="icon-thumbnail fs-11 text-white icon-25 bg-primary btn-rounded float-left m-r-5">
<i class="fa fa-file-image-o fs-10"></i>
</div>
</a>
</div>
</div>
<div class="col text-right">
<div class="font-heading all-caps fs-10 m-b-5">Our Payment Proof</div>
<div class="row no-margin justify-content-end" v-if="item.status === 3">
<div class="row no-margin justify-content-end" v-if="item.type === 3 && (item.status === 2 || item.status === 3)">
<div v-for="file in item.documents.files" v-bind:key="file.id" class="col-auto no-padding m-l-5">
<document-file-viewer-component :file="file">
<template slot="button">
@@ -124,6 +166,110 @@
</div>
</div>
</div>
<div class="row m-t-10 hide">
<div class="col">
<button class="btn btn-xs all-caps b-rad-none btn-success btn-block requestModal" data-type="transferSummary">Request Refund</button>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="transferSummary" size="large">
<refund-confirmation-component :data="data" :section="section"></refund-confirmation-component>
</modal-component>
</div>
</div>
</div>
</div>
<!-- <div class="row" v-show="expandRefund"> -->
<div class="row" v-show="false">
<div class="col bg-white padding-15">
<div class="row m-b-10">
<div class="col-8">
<div class="font-heading all-caps fs-10 m-b-5">Refund Type: </div>
<div class="btn btn-xs btn-complete no-border btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="refundMethod.status = !refundMethod.status">
<div class="row">
<div class="col p-t-10 p-b-10">
{{refundMethod.name}}
</div>
<div class="col-auto bg-complete-light">
<div class="row h-100 align-items-center">
<div class="col">
<i class="fa" :class="[{'fa-angle-down': !refundMethod.status}, {'fa-angle-up': refundMethod.status}]"></i>
</div>
</div>
</div>
</div>
</div>
<div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-complete" :class="[{'hide': !refundMethod.status}]" style="top: 100%; right: 0; z-index: 1;">
<div class="row text-left no-margin bg-white">
<div class="col no-padding">
<div class="row no-margin" :class="[{'bg-complete-light': refundMethod.name === 'Fully Refund'}, {'text-white': refundMethod.name === 'Fully Refund'}, {'hover-complete': refundMethod.name !== 'Fully Refund'}]" @click="updateRefundType({name: 'Fully Refund'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Fully Refund</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': refundMethod.name === 'Partially Refund'}, {'text-white': refundMethod.name === 'Partially Refund'}, {'hover-complete': refundMethod.name !== 'Partially Refund'}]" @click="updateRefundType({name: 'Partially Refund'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Partially Refund</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-r-0 m-b-10" v-if="refundMethod.name == 'Fully Refund'">
<div class="col p-r-0">
<validation-wrapper-component :validator="parameters.amount" v-if="refundMethod.name == 'Fully Refund'">
<label>Amount</label>
<input class="form-control disabled" name="amount" v-model.lazy="amount" disabled>
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">{{''}}</div>
</div>
</div>
</div>
</div>
<div class="row m-r-0 m-b-10" v-if="refundMethod.name == 'Partially Refund'">
<div class="col p-r-0">
<validation-wrapper-component :validator="parameters.amount">
<label>Amount</label>
<input class="form-control" name="amount">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">{{''}}</div>
</div>
</div>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<div class="form-group no-margin form-group-default">
<label>Account No.</label>
<input type="text" class="form-control">
</div>
</div>
</div>
<div class="row">
<div class="col-4 p-r-0">
<button class="btn btn-xs all-caps b-rad-none btn-default bg-master-lighter btn-block" @click="requestRefund()">Cancel</button>
</div>
<div class="col p-l-0">
<button class="btn btn-xs all-caps b-rad-none btn-success btn-block" @click="submitForm()">Refund</button>
</div>
</div>
</div>
</div>
</div>
@@ -135,7 +281,19 @@
export default {
data(){
return {
expanded: false
expandPaymentDetails: false,
expandRefund: false,
refundMethod: {
name: 'Fully Refund',
status: false
},
amount: (Math.round(1000 * 100) / 100).toFixed(2),
parameters: {
amount: (Math.round(1000 * 100) / 100).toFixed(2),
bank_id: 1
},
expanded: false,
section: 'bookingDetailSection',
}
},
computed: {
@@ -143,6 +301,29 @@
return this.item.type === 1 ? this.item : this.item.customer_booking;
}
},
methods: {
submitForm(){
this.submit(this.route('api.booking.refund.create', this.data.booking.id, this.data.id), 'post', this.section, true, true);
},
requestRefund(){
this.expandRefund = !this.expandRefund;
this.expandPaymentDetails = !this.expandPaymentDetails;
},
clickExpand(){
if (this.expandPaymentDetails == false && this.expandRefund == false) {
this.expandPaymentDetails = !this.expandPaymentDetails;
} else {
this.expandRefund = false;
this.expandPaymentDetails = false;
}
},
updateRefundType(refund){
this.refundMethod = {
name: refund.name,
status: !this.refundMethod.status
}
},
},
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,337 @@
<template>
<div class="row zig-zag-top">
<div class="col bg-white padding-25">
<div class="row p-b-10">
<div class="col">
<div class="row m-b-5">
<div class="col">
<div class="font-heading all-caps bold fs-10">Request Refund</div>
</div>
</div>
</div>
</div>
<div class="row p-b-20 b-b b-dashed b-grey m-b-20">
<div class="col">
<div class="row">
<div class="col">
<div class="row m-b-10">
<div class="col">
<div class="row parentContainer">
<div class="col">
<div class="row" >
<div class="col-7 p-r-0">
<div class="row m-b-10">
<div class="col">
<div class="font-heading all-caps fs-10 m-b-5">Refund Type: </div>
<!-- <div class="btn btn-xs btn-complete no-border btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="refundMethod.status = !refundMethod.status">
<div class="row">
<div class="col p-t-10 p-b-10">
{{refundMethod.name}}
</div>
<div class="col-auto bg-complete-light">
<div class="row h-100 align-items-center">
<div class="col">
<i class="fa" :class="[{'fa-angle-down': !refundMethod.status}, {'fa-angle-up': refundMethod.status}]"></i>
</div>
</div>
</div>
</div>
</div> -->
<!-- <div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-complete" :class="[{'hide': !refundMethod.status}]" style="top: 100%; right: 0; z-index: 1;">
<div class="row text-left no-margin bg-white">
<div class="col no-padding">
<div class="row no-margin" :class="[{'bg-complete-light': refundMethod.name === 'Fully Refund'}, {'text-white': refundMethod.name === 'Fully Refund'}, {'hover-complete': refundMethod.name !== 'Fully Refund'}]" @click="updateRefundType({name: 'Fully Refund'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Fully Refund</div>
</div>
</div>
</div>
</div>
<div class="row no-margin" :class="[{'bg-complete-light': refundMethod.name === 'Partially Refund'}, {'text-white': refundMethod.name === 'Partially Refund'}, {'hover-complete': refundMethod.name !== 'Partially Refund'}]" @click="updateRefundType({name: 'Partially Refund'})">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">Partially Refund</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div> -->
<div class="row">
<div class="col-auto b-a m-l-15 padding-5 p-l-10 p-r-10 rounded b-grey pointer" :class="[{'b-complete': refundMethod.name === 'Fully Refund'}]" @click="updateRefundType({name: 'Fully Refund'})">
Fully Refund
</div>
<div class="col-auto b-a m-l-10 padding-5 p-l-10 p-r-10 rounded b-grey pointer" :class="[{'b-complete': refundMethod.name === 'Partially Refund'}]" @click="updateRefundType({name: 'Partially Refund'})">
Partially Refund
</div>
</div>
</div>
</div>
<div class="row m-r-0 m-b-10" v-if="refundMethod.name == 'Partially Refund'">
<div class="col p-r-0">
<validation-wrapper-component :validator="$v.parameters.refundAmount">
<label>Amount</label>
<input class="form-control disabled" name="amount" v-model="data.booking.amount">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">{{data.booking.fixed_currency.short_code}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="!createBank">
<div class="col-7 p-r-0">
<div class="row">
<div class="col">
<div class="form-group no-margin form-group-default">
<label>Account No.</label>
<input type="text" class="form-control" v-model="account_no" @keyup="parameters.bankAccount = {}" @focus="dropdownStatus = true">
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-grey" :class="[{'hide': !dropdownStatus}]" style="top: 100%; right: 0; z-index: 1;">
<div class="row text-left no-margin bg-white">
<div class="col no-padding">
<div class="row no-margin" v-for="bank in data.booking.company.personal_banks.accounts" v-bind:key="bank.id" >
<!-- <div class="col b-b b-grey p-t-10 p-b-10 pointer p-t-10 p-b-10" :class="[{'bg-master-lightest': parameters.bankAccount.id === bank.id}, {'text-master': parameters.bankAccount.id === bank.id}, {'hover-primary': parameters.bankAccount.id !== bank.id}, {'pointer': parameters.bankAccount.id !== bank.id}]" @click="selectBank(bank)"> -->
<div class="col b-b b-grey p-t-10 p-b-10 pointer p-t-10 p-b-10" @click="selectBank(bank)">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="row">
<div class="col">
<div class="font-heading bold lh-15 fs-13">{{bank.reference ? bank.reference + ' - ':''}}{{bank.holder_name}}</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-13 muted"><b class="m-r-5 text-primary">{{bank.account_no}}</b> {{bank.bank_name}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-auto p-l-0" v-show="!createBank && account_no && !Object.keys(parameters.bankAccount).length">
<button class="btn btn-sm h-100 btn-primary b-rad-none all-caps" @click="createBank = !createBank; dropdownStatus = false">
<i class="fa fa-plus m-r-5"></i>
Create New
</button>
</div>
</div>
<div class="row" v-show="createBank">
<div class="col">
<!-- <bank-account-form-component section="customerProfileSection" :company_id="data.booking.company.id" :data="{account_no: account_no, company_id: data.booking.company.id, country_id: 1, account_type: 1}" :type='1'></bank-account-form-component> -->
<bank-account-form-component section="customerProfileSection" :company_id="data.booking.company.id" :data="{account_no: account_no, company_id: data.booking.company.id, country_id: 1, account_type: 1}" :type='2'></bank-account-form-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-b-20" v-show="createBank">
<div class="col">
<div class="row align-items-end no-margin">
<div class="col">
<div class="row align-items-end bg-master-lightest p-t-10 p-b-10">
<div class="col">
<div class="font-heading fs-10 all-caps">Amount you are Transferring</div>
</div>
<div class="col-1 no-padding text-center">
<!-- <div class="font-heading fs-10 bold">{{this.parameters.type === 0 ? 'MYR': parameters.serviceType.selectedCurrency.short_code}}</div> -->
<div class="font-heading fs-10 bold">short_code</div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading fs-10 bold">{{(Math.round((parseFloat(this.parameters.amount.replace(",", ""))+ Number.EPSILON) * 100) / 100).toFixed(2)}}</div> -->
<div class="font-heading fs-10 bold">amount</div>
</div>
</div>
<div class="row align-items-end p-t-10 p-b-10">
<div class="col">
<div class="font-heading fs-10 all-caps text-primary">Exchange Rate</div>
</div>
<div class="col-1 no-padding text-center">
<div class="font-heading fs-10"></div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading fs-10 text-primary bold">{{(Math.round((this.parameters.calculation.rate + Number.EPSILON) * 100000) / 100000).toFixed(5)}}</div> -->
<div class="font-heading fs-10 text-primary bold">rate</div>
</div>
</div>
<div class="row align-items-end bg-master-lightest p-t-10 p-b-10">
<div class="col">
<div class="font-heading fs-10 all-caps">Money Transfer Fee</div>
</div>
<div class="col-1 no-padding text-center">
<div class="font-heading fs-10">MYR</div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading fs-10">{{(Math.round((this.parameters.calculation.service_charge + Number.EPSILON) * 100) / 100).toFixed(2)}}</div> -->
<div class="font-heading fs-10">amount</div>
</div>
</div>
<div class="row align-items-end p-t-10 p-b-10">
<div class="col text-right">
<div class="font-heading fs-10 all-caps">Sub-Total</div>
</div>
<div class="col-1 no-padding text-center">
<div class="font-heading fs-10">MYR</div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading fs-10">{{(Math.round((this.parameters.calculation.sub_total + Number.EPSILON) * 100) / 100).toFixed(2)}}</div> -->
<div class="font-heading fs-10">Sub-Total</div>
</div>
</div>
<div class="row align-items-end bg-master-lightest p-t-10 p-b-10">
<div class="col text-right">
<div class="font-heading fs-10 all-caps">Tax</div>
</div>
<div class="col-1 no-padding text-center">
<!-- <div class="font-heading fs-10">{{Math.round((this.parameters.calculation.tax + Number.EPSILON) * 100) / 100}}%</div> -->
<div class="font-heading fs-10">some%</div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading fs-10">{{(Math.round((this.parameters.calculation.tax_total + Number.EPSILON) * 100) / 100).toFixed(2)}}</div> -->
<div class="font-heading fs-10">some tax</div>
</div>
</div>
<div class="row align-items-end p-t-10 p-b-10">
<div class="col text-right">
<div class="font-heading all-caps bold">Amount you are Paying</div>
</div>
<div class="col-1 no-padding text-center">
<div class="font-heading bold">MYR</div>
</div>
<div class="col-3 text-right">
<!-- <div class="font-heading text-success bold">{{(Math.round((this.parameters.calculation.total + Number.EPSILON) * 100) / 100).toFixed(2)}}</div> -->
<div class="font-heading text-success bold">payming amount</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <confirm-booking-component :section="section" :data="data" v-if="parameters.bankAccount"></confirm-booking-component> -->
<div class="row">
<div class="col-auto">
<button class="btn btn-lg btn-default bg-master-lightest b-rad-none all-caps fs-12" data-dismiss="modal">Cancel</button>
</div>
<div class="col text-right">
<!-- <button class="btn btn-lg btn-success b-rad-none all-caps fs-12" v-if="Object.keys(data.bankAccount).length" @click="submitForm()">Confirm & Proceed</button> -->
<button class="btn btn-lg btn-success b-rad-none all-caps fs-12" @click="submitForm()">Confirm & Proceed</button>
</div>
</div>
</div>
</div>
</template>
<script>
import FormHandler from '../../../general/mixins/formHandler';
// import ConfirmBookingComponent from "../forms/confirmBookingComponent";
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
import { required } from "vuelidate/lib/validators";
export default {
// components: {ConfirmBookingComponent},
data(){
return {
createBank: false,
recipientBanks: [],
dropdownStatus: false,
account_no: '',
parameters: {
bankAccount: '',
refundAmount: this.data.booking.amount,
bank_id: '',
},
expandRefund: false,
refundMethod: {
name: 'Fully Refund',
status: false
},
}
},
validations: {
parameters: {
bankAccount: { required },
refundAmount: { required },
}
},
computed: {
formDisabled(){
return !!Object.keys(this.parameters.bankAccount).length;
}
},
created(){
this.recipientBanks = this.data.recipientBanks;
},
methods: {
AccountNumber(bank){
return bank.account_no.startsWith(this.account_no)
},
updateBank(bank){
this.selectBank(bank);
this.recipientBanks.push(bank);
this.parameters.bankAccount = bank;
},
selectBank(bank){
console.log(bank);
this.account_no = bank.account_no;
this.createBank = true;
this.parameters.bankAccount = bank;
this.dropdownStatus = false;
},
clearAccount(){
this.createBank = false;
this.account_no = '';
this.parameters.bankAccount = {};
},
submitForm(){
// this.parameters = {
// company_id: this.data.company.id,
// type: this.data.type,
// fix_amount: this.data.amount,
// service_id: this.data.serviceType.id,
// transferable_bank_id: this.data.bankAccount.id,
// convertible_currency_id: this.data.serviceType.selectedCurrency.id,
// };
this.submit(route('api.booking.create'), 'post', this.section, true, true)
},
updateRefundType(refund){
this.refundMethod = {
name: refund.name,
status: !this.refundMethod.status
}
},
successHandler(response){
window.location.href = this.route('booking.details', response.payload.data.marking)
}
},
mixins: [FormHandler, ModalFormHandler]
}
</script>
@@ -30,7 +30,7 @@
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Date</div>
<div class="font-heading fs-10">
{{item.documents.created_at}}
{{item.payment_method === 5 ? item.updated_at : item.documents.created_at}}
</div>
</div>
<div class="col-auto">
File diff suppressed because one or more lines are too long
@@ -8,12 +8,17 @@
<div class="font-heading all-caps fs-12 bold">Congratulation, you have got great rates.</div>
</div>
</div>
<div class="row m-b-25">
<div class="row m-b-25" v-if="payment_method !== 'payment_gateway'">
<div class="col">
<div class="font-heading fs-11">You can proceed by bank in <span class="text-success bold">{{(Math.round((calculation.total + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} MYR</span> to the bank account detailed below and upload your payment proof to proceed with your transfer after clicking on the confirm button below.</div>
</div>
</div>
<div class="row align-items-center m-b-25">
<div class="row m-b-25" v-if="payment_method === 'payment_gateway'">
<div class="col">
<div class="font-heading fs-11">You will be redirected to your bank to complete the payment of <span class="text-success bold">{{(Math.round((calculation.total + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} MYR</span> after clicking on the confirm button below. please follow your bank instruction to complete the payment</div>
</div>
</div>
<div class="row align-items-center m-b-25" v-if="payment_method !== 'payment_gateway'">
<div class="col-auto p-r-0">
<div class="icon-thumbnail icon-50 bg-master-lightest">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
@@ -42,7 +47,7 @@
</div>
<div class="row m-b-20">
<div class="col">
<div class="font-heading text-danger fs-10 m-b-5">Please upload your payment proof before the booking expires within {{calculation.payment_attempt_limit}}.</div>
<div class="font-heading text-danger fs-10 m-b-5">Please <span v-if="payment_method !== 'payment_gateway'">upload your payment proof </span><span v-if="payment_method === 'payment_gateway'">complete your payment</span> before the booking expires within {{calculation.payment_attempt_limit}}.</div>
</div>
</div>
<div class="row m-b-5">
@@ -77,6 +82,9 @@
payment_method: {
required: true
},
bank_code: {
required: false
},
id: {
type: Number,
required: true
@@ -91,6 +99,7 @@
parameters: {
payment_method: this.payment_method,
amount: this.amount,
bank_code: this.bank_code,
}
}
},
@@ -98,10 +107,14 @@
submitForm(){
this.submit(route('api.booking.payment.create', this.id), 'post', this.section, false, false);
},
successHandler(){
successHandler(response){
this.$emit('cancelQuotation');
this.updateList();
this.closeModal();
if (response.payload.data.payment_method === 5) {
window.location.href = 'https://www.billplz.com/bills/' + response.payload.data.payment_reference + '?auto_submit=true';
}
}
}
}
@@ -0,0 +1,68 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row m-b-10">
<div class="col">
<h3 class="all-caps m-b-5 bold no-margin">Edit Booking Amount</h3>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.fix_amount">
<label class="muted">Booking Amount ({{data.fixed_currency.short_code}})</label>
<input type="text" class="form-control" v-model="fix_amount" v-money="money">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-5 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-default bg-master-lightest btn-block b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-success btn-block b-rad-none" @click="submitForm()">Update</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
import FormHandler from '../../../general/mixins/formHandler';
export default {
data(){
return {
error: '',
fix_amount: (Math.round((this.data.amount + Number.EPSILON) * 100) / 100).toFixed(2)
}
},
validations: {
fix_amount: { required }
},
watch: {
'data': function() {
this.fix_amount = (Math.round((this.data.amount + Number.EPSILON) * 100) / 100).toFixed(2);
}
},
methods: {
submitForm(){
this.parameters = {fix_amount : parseFloat((this.fix_amount).toString().replace(',', ''))}
this.submit(this.route('api.booking.booking_amount.update', this.data.id), 'put', this.section, true, true)
},
successHandler(){
this.closeModal();
this.formHandler('');
},
},
mixins: [FormHandler]
}
</script>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,97 @@
<template>
<div class="row align-items-center">
<div class="col-auto p-r-0" style="min-width: 40px;">
<div class="font-heading all-caps fs-10">{{index + 1}}</div>
</div>
<div class="col p-r-5">
<div v-if="!isEdit" class="font-heading all-caps fs-10">{{product.stockCode}}</div>
<input v-if="isEdit" type="text" class="form-control fs-10 b-rad-none" placeholder="Stock Code" v-model="product.stockCode" />
</div>
<div class="col-4 p-r-5 p-l-5">
<div v-if="!isEdit" class="font-heading all-caps fs-10">{{product.description}}</div>
<textarea v-if="isEdit" class="form-control fs-10 b-rad-none" placeholder="Description" rows="1" @keyup="onlyEnglish($event)" v-model="product.description"></textarea>
</div>
<div class="col text-center p-r-5 p-l-5">
<div v-if="!isEdit" class="font-heading all-caps fs-10">{{product.quantity}}</div>
<input v-if="isEdit" type="text" class="form-control fs-10 b-rad-none text-center" placeholder="Quantity" v-model.lazy="product.quantity" v-mask="'#########'"/>
</div>
<div class="col text-center p-r-5 p-l-5">
<div v-if="!isEdit" class="font-heading all-caps fs-10">{{product.unit_price}}</div>
<input v-if="isEdit" type="text" class="form-control fs-10 b-rad-none text-center" placeholder="Unit Price" v-model.lazy="product.unit_price" v-money="productPrice" />
</div>
<div class="col-1 text-center p-r-5 p-l-5">
<div class="font-heading all-caps fs-10">{{currency}}</div>
</div>
<div class="col-1 text-right p-r-5 p-l-5">
<div class="font-heading all-caps fs-10">{{(Math.round((productTotal + Number.EPSILON) * 100) / 100).toFixed(2) }}</div>
</div>
<div class="col-auto" :class="[{'invisible': !editable}]">
<button class="btn btn-xs btn-outline-danger b-rad-none" @click="$emit('remove')"><i class="fa fa-times"></i></button>
<button v-if="!isEdit" class="btn btn-xs btn-outline-warning b-rad-none" @click="isEdit = !isEdit"><i class="fa fa-pencil"></i></button>
<button v-if="isEdit" class="btn btn-xs btn-outline-success b-rad-none" @click="updateProduct()"><i class="fa fa-check"></i></button>
</div>
</div>
</template>
<script>
import formHandler from '../../../general/mixins/formHandler';
export default {
props: {
editable: {
type: Boolean,
default: false
},
currency:{
type: String,
required: true
},
index:{
type: Number,
required: true
}
},
data(){
return {
isEdit: false,
product: {
stockCode: '',
description: '',
unit_price: 0,
},
products: []
}
},
created() {
this.product = this.data;
this.product.unit_price = (Math.round((this.product.unit_price+ Number.EPSILON) * 1000) / 1000).toFixed(3)
},
computed: {
productTotal(){
return this.product.quantity * parseFloat((this.product.unit_price).toString().replace(',', ''));
},
},
methods: {
updateProduct(){
this.isEdit = !this.isEdit;
this.$emit('change', {
stockCode: this.product.stockCode,
description: this.product.description,
quantity: this.product.quantity,
unit_price: parseFloat((this.product.unit_price).toString().replace(',', '')),
total: this.productTotal
}, this.index);
},
onlyEnglish(event){
let value = event.target.value,
regex = /^[^~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/;
event.preventDefault();
if(regex.test(value)){
this.product.description = value.replace(regex, '');
}
},
},
mixins: [formHandler]
}
</script>
@@ -0,0 +1,33 @@
<template>
<div class="row">
<div class="col">
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="isLoading" ></loading-component>
<div class="row justify-content-center" v-show="!isLoading">
<div class="col">
<div class="row m-b-20">
<div class="col">
<h3 class="all-caps">Are you Sure?</h3>
<div class="fs-11">Are you sure you want to regenerate the invoices for this transfer?</div>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-success btn-block b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-danger btn-block b-rad-none" @click="submit(route('api.booking.regenerate.invoice', data.id), 'post', section, true, true)">Confirm</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
mixins: [componentHandler, ModalFormHandler]
}
</script>
@@ -4,8 +4,8 @@
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
<div class="row" v-if="booking">
<div class="col">
<div class="row m-b-50" v-if="booking.status === 3 && transactionsComplete">
<div class="col-10 no-padding m-auto">
<div class="row m-b-50" v-if="booking.status === 3">
<div class="col-10 no-padding">
<div class="row">
<div class="col">
<div class="row">
@@ -203,6 +203,10 @@
<purchase-order-form-component :data="booking" :section="section"></purchase-order-form-component>
</div>
</div>
<div class="btn btn-xs all-caps b-rad-none btn-danger pointer requestModal" data-type="regenerateInvoices" v-if="booking.status === 3 && $store.getters.isSuperAdmin">Regenerate Invoices</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="regenerateInvoices">
<regenerate-booking-invoices-component :data="booking" :section="section" class="text-center"></regenerate-booking-invoices-component>
</modal-component>
</div>
<div class="col-12 col-sm-12 col-md-3 mt-3 mt-sm-0">
<booking-payment-quotation-component :data="booking" :section="section"></booking-payment-quotation-component>
@@ -250,7 +254,16 @@
</div>
</div>
</div>
<div class="col-auto p-l-5 p-r-5 bg-success requestModal pointer" data-type="identificationVerificationModal">
<div class="col-auto p-l-5 p-r-5 bg-success pointer" v-if="item.payment_method === 5">
<a :href="'https://www.billplz.com/bills/'+item.payment_reference">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-repeat fs-20 text-white p-l-10 p-r-10"></i>
</div>
</div>
</a>
</div>
<div class="col-auto p-l-5 p-r-5 bg-success requestModal pointer" v-if="item.payment_method !== 5" data-type="paymentProofModal">
<div @click="selectedID(item.id)" class="row align-items-center h-100">
<div class="col">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
@@ -263,7 +276,7 @@
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteAttempt">
<delete-payment-attempt-form-component :data="item" :section="section" class="text-center"></delete-payment-attempt-form-component>
</modal-component>
<modal-component type="identificationVerificationModal">
<modal-component type="paymentProofModal">
<payment-verification-form-component v-if="selected_id == item.id" :section="section" :id="booking.id" :data="item"></payment-verification-form-component>
</modal-component>
</div>
@@ -38,7 +38,7 @@
<i class="fa fa-circle text-success m-r-5" :class="[{'text-success': item.status === 2}, {'text-danger-darker': item.status === 5}, {'text-danger': item.status !== 2 || item.status !== 5}]"></i>{{item.status === 2 ? 'Active' : item.status === 5 ? 'Suspended' : 'Inactive'}}
</div>
</div>
<div class="col m-l-50">
<div class="col-auto m-l-50">
<div class="row align-items-center parentContainer">
<div class="col-auto padding-5 b-a b-grey b-rad-lg pointer requestModal" data-type="assignSegment">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
@@ -64,6 +64,23 @@
</modal-component>
</div>
</div>
<div class="col m-l-50">
<div class="row">
<div class="col">
<p class="m-b-0 fs-11 muted bold"><b>Last Payment: </b>{{item.last_payment}}</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="m-b-0 fs-11 muted bold"><b>Payment Amount: </b>MYR {{(Math.round((item.total_payments + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="m-b-0 fs-11 muted bold"><b>Created at: </b>{{item.created_at}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -75,9 +75,11 @@
</div>
<div class="row">
<div class="col-4 p-l-5 p-r-5 m-b-10" v-for="(rate, method) in item.rates">
<validation-wrapper-component :validator="$v.parameters.currencies.$each[index].rates.$each[method].selling.value" :class="[{'hint-text': rate.payment_method === 'wallet' || rate.payment_method === 'payment gateway'}]">
<!-- <validation-wrapper-component :validator="$v.parameters.currencies.$each[index].rates.$each[method].selling.value" :class="[{'hint-text': rate.payment_method === 'wallet' || rate.payment_method === 'payment gateway'}]"> -->
<validation-wrapper-component :validator="$v.parameters.currencies.$each[index].rates.$each[method].selling.value" :class="[{'hint-text': rate.payment_method === 'wallet'}]">
<label class="all-caps">{{rate.payment_method}}</label>
<input type="text" class="form-control" v-model.lazy="rate.selling.value" v-money="exchangeRate" :disabled="!item.active || rate.payment_method === 'wallet' || rate.payment_method === 'payment gateway'">
<!-- <input type="text" class="form-control" v-model.lazy="rate.selling.value" v-money="exchangeRate" :disabled="!item.active || rate.payment_method === 'wallet' || rate.payment_method === 'payment gateway'"> -->
<input type="text" class="form-control" v-model.lazy="rate.selling.value" v-money="exchangeRate" :disabled="!item.active || rate.payment_method === 'wallet'">
</validation-wrapper-component>
</div>
</div>
@@ -202,7 +204,7 @@
}
},
{
payment_method: 'payment gateway',
payment_method: 'payment_gateway',
selling: {
type: 'rate',
value: 0
@@ -0,0 +1,33 @@
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// var url_string = window.location.href
// var url = new URL(url_string);
// var billplz = url.searchParams.get("billplz[id]");
// console.log(billplz);
function getQueryParams(qs) {
qs = qs.split('+').join(' ');
var params = {},
tokens,
re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
return params;
}
var query = getQueryParams(document.location.search);
console.log(query);
axios.post('/api/v1/billplz/bill/callback', query)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
</script>
@@ -4,7 +4,7 @@
<div class="col">
<booking-details-section-component :marking={{$marking}}></booking-details-section-component>
@if(!env('IS_PRODUCTION'))
<a class="btn btn-xs all-caps b-rad-none btn-warning" href="{{ route('booking.merge', $marking)}}">Merge Transfer Orders</a>
{{--<a class="btn btn-xs all-caps b-rad-none btn-warning" href="{{ route('booking.merge', $marking)}}">Merge Transfer Orders</a>--}}
@endif
</div>
</div>
@@ -3,10 +3,10 @@
<div class="row">
<div class="col p-t-15 p-b-15">
<div class="row no-margin">
<div class="col">
<div class="col-12 col-md">
<div class="row tabsContainer">
<div class="col">
<div class="row m-l-0 m-r-0 d-none d-md-flex">
<div class="row m-l-0 m-r-0 d-flex">
<div class="col">
<div class="row justify-content-end">
<div class="col-4 b-r b-white">
@@ -75,7 +75,7 @@
</div>
</div>
<div class="row no-margin" v-if="$store.getters.isAdmin">
<div class="col bg-white padding-25">
<div class="col-12 col-md bg-white padding-25">
<div class="row tabsContainer tabContent m-l-0 m-r-0" tab-name="customer-list">
<list-component key="2" section="customerListSection" :endpoint="route('api.company.list')" :options="{'business_type': 2, with_bookings:true}">
<template slot="list" slot-scope="{data}">
@@ -105,7 +105,7 @@
<div class="col">
<div class="row tabsContainer">
<div class="col">
<div class="row m-l-0 m-r-0 d-none d-md-flex">
<div class="row m-l-0 m-r-0 d-flex">
<div class="col">
<div class="row justify-content-end">
<div class="col">
@@ -328,7 +328,7 @@
<div class="col">
<div class="row">
<div class="col">
<list-component ref="paymentProofList" section="paymentProofSection" :endpoint="route('api.transaction.list')" :options="{status: 2, type: 3, issuer_in: [2]}">
<list-component ref="paymentProofList" section="paymentProofSection" :endpoint="route('api.transaction.list')" :options="{status: 1, type: 3, issuer_in: [2, 1937]}">
<template slot="list" slot-scope="{data}">
<payment-proof-component :data="data"></payment-proof-component>
</template>
File diff suppressed because one or more lines are too long
@@ -33,7 +33,7 @@
<div class="number">EDO: {{ $invoice_transaction->bill_no }}</div>
<div class="ref">REF: {{ $invoice_transaction->payment_reference ?? '-' }}</div>
<div class="ref">REF: {{ $invoice_transaction->booking->marking }}</div>
<div class="date">Date: {{ $po_order_transaction->created_at }}</div>
<div>&nbsp;</div>
</div>
@@ -52,7 +52,7 @@
</div>
<div class="address">
@php
$addresses = $supplier->addresses()->first();
$addresses = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }} ,
+2 -2
View File
@@ -32,7 +32,7 @@
<div class="number">EI#: {{ $invoice_transaction->bill_no }}</div>
<div class="ref">Ref# {{ $invoice_transaction->payment_reference ?? '-' }}</div>
<div class="ref">Ref# {{ $po_order_transaction->booking->marking }}</div>
<div class="date">Date: {{ $po_order_transaction->booking->created_at }}</div>
<div>&nbsp;</div>
</div>
@@ -51,7 +51,7 @@
</div>
<div class="address">
@php
$addresses = $supplier->addresses()->first();
$addresses = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }} ,

Some files were not shown because too many files have changed in this diff Show More