Merge branch 'development' of gitlab.com:CIEFWorldwideSdnBhd/exchange-2.0 into wallet-ui

# Conflicts:
#	resources/views/partials/header.blade.php
#	routes/web.php
This commit is contained in:
edmondlang
2022-02-04 22:22:07 +08:00
parent 9cf30d559e
commit e3e4b490b0
126 changed files with 3295 additions and 563 deletions
-2
View File
@@ -56,5 +56,3 @@ 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"
BILLPLZ_REDIRECT_URL="http://localhost:9003/bookings/billplz"
BILLPLZ_CALLBACK_URL="localhost:9003/api/v1/billplz/callback"
@@ -17,7 +17,6 @@ abstract class AbstractUpdateRecord
*/
public function handler(Model $model){
try{
if($model->save()){ return $model; }
} catch (QueryException $exception){
@@ -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
{
/**
@@ -14,7 +14,7 @@ class PaymentReference implements Filter
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('payment_reference', $value);
return $builder->where('payment_reference', '=', $value);
}
}
@@ -5,6 +5,7 @@ namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
@@ -19,7 +20,7 @@ class WithTotalPayments implements Filter
public static function apply(Builder $builder, $value)
{
return $builder->leftJoin('bookings', 'companies.id', '=', 'bookings.company_id')->rightJoin('transactions', function ($join) {
$join->on('bookings.id', '=', 'transactions.booking_id')->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
})->addSelect(['companies.*', DB::raw('SUM(transactions.amount) as total_payments')])->groupBy(['companies.id']);
$join->on('bookings.id', '=', 'transactions.owner_id')->where('owner_type', '=', Booking::class)->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
})->addSelect(['companies.*', DB::raw('SUM(transactions.amount) as total_payments'), DB::raw('SUM(transactions.amount / DATEDIFF(companies.created_at, CURRENT_DATE)) as spending_average_per_day'), DB::raw('SUM(transactions.amount) / count(distinct bookings.id) as spending_average_booking')])->groupBy(['companies.id']);
}
}
@@ -53,24 +53,18 @@ class DeleteUserLogic extends AbstractControllerLogic
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
try {
DB::beginTransaction();
$user = $this->fetchesUser->execute(['id' => $request->route('id')]);
$this->canDeleteUser->passes();
$this->deletesUser->execute($user);
$user = $this->fetchesUser->execute(['id' => $request->route('id')]);
$this->canDeleteUser->passes();
$this->deletesUser->execute($user);
DB::commit();
return $this->resourceResponse(new UserResource($user));
} catch (\Exception $exception){
throw new ErrorException($exception->getMessage(), $exception->getCode());
}
return $this->resourceResponse(new UserResource($user));
}
}
@@ -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)
{
@@ -22,7 +22,7 @@ class AddressObject implements DataTransferObject
/** @var int */
private $districtId;
/** @var int */
/** @var string */
private $postCode;
/**
@@ -32,9 +32,9 @@ class AddressObject implements DataTransferObject
* @param int $countryId
* @param int $stateId
* @param int $districtId
* @param int $postCode
* @param string $postCode
*/
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, int $postCode)
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, string $postCode)
{
$this->streetOne = $streetOne;
$this->streetTwo = $streetTwo;
@@ -85,9 +85,9 @@ class AddressObject implements DataTransferObject
}
/**
* @return int
* @return string
*/
public function getPostCode(): int
public function getPostCode(): string
{
return $this->postCode;
}
@@ -2,8 +2,12 @@
namespace App\Classes\Modules\Billplzs\ControllersLogic;
use ErrorException;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Wallets\Services\UpdatesWallet;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Http\Resources\TransactionResource;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
@@ -14,19 +18,12 @@ 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 extends AbstractControllerLogic
class CallbackBillplzLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Callback Billplz',
'message' => 'You have successfully receive Billplz callback'
];
}
/** @var GetBillplzBill */
private $getBillplzBill;
@@ -37,44 +34,68 @@ class CallbackBillplzLogic extends AbstractControllerLogic
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var UpdatesWallet */
private $updatesWallet;
/**
* CreateBookingLogic constructor.
* @param CreateGetBillplzBillsBillplzBill $getBillplzBill
* @param GetBillplzBill $getBillplzBill
* @param FetchesTransaction $fetchesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
*/
public function __construct(GetBillplzBill $getBillplzBill, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus)
public function __construct(GetBillplzBill $getBillplzBill, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, UpdatesWallet $updatesWallet)
{
$this->getBillplzBill = $getBillplzBill;
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->updatesWallet = $updatesWallet;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @return bool|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws MalformedRequestException
* @throws ResourceNotFoundException
*/
public function logic(Request $request) : JsonResponse
public function execute(Request $request)
{
$billplzXSignatureObject = new BillplzXSignatureObject($request);
if(!$billplzXSignatureObject->isValidSignature()) throw new MalformedRequestException('Unable to get correct response from billplz server.');
if(!$billplzXSignatureObject->isValidSignature()){
throw new MalformedRequestException('Billplz Payment validation failed.');
}
$billPlz = $this->getBillplzBill->execute($billplzXSignatureObject->getBillPlzId());
if(!$billPlz) throw new MalformedRequestException('Unable to get correct response from billplz server.');
if(!$billPlz) throw new ResourceNotFoundException('Billplz bill not found.');
$transaction = $this->fetchesTransaction->execute(['payment_reference' => $billplzXSignatureObject->getBillPlzId()]);
if($billPlz->state == 'paid') $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED);
return $this->response(['data' => $billPlz]);
if($billPlz->state === 'paid') {
$status = ApprovalStatus::APPROVED;
if (
$transaction->owner_type == 'App\Models\Wallet' &&
$transaction->status == ApprovalStatus::PENDING_VERIFICATION
) {
$wallet = $transaction->owner;
$updateWalletAmount = $wallet->amount + $transaction->amount;
$walletOject = new WalletObject($wallet->company->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
$wallet = $this->updatesWallet->execute($wallet, $walletOject);
}
}
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]);
}
}
@@ -40,9 +40,7 @@ class CreateBillplzBillLogic extends AbstractControllerLogic
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
@@ -4,6 +4,7 @@ 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
{
@@ -11,6 +12,9 @@ class BillplzXSignatureObject implements DataTransferObject
/** @var string */
private $billPlzId;
/** @var string */
private $status;
/** @var array */
private $billPlzConstructArray;
@@ -20,6 +24,9 @@ class BillplzXSignatureObject implements DataTransferObject
/** @var string */
private $billPlzComputedXSignature;
/** @var string */
private $type;
/** @var Request */
private $request;
@@ -28,22 +35,26 @@ class BillplzXSignatureObject implements DataTransferObject
public function __construct(Request $request)
{
$this->request = $request;
$this->billPlzId = $request->id ? $request->id : $request->{'billplz[id]'};
$this->type = $request->exists('billplz') ? 'redirect' : 'callback';
$this->requestXSignature = $request->x_signature ? $request->x_signature : $request->{'billplz[x_signature]'};
$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(){
foreach($this->request->all() as $key => $value){
if($key != 'x_signature' && $key != 'billplz[x_signature]'){
$key = str_replace(']', '', str_replace('[', '', $key));
$this->billPlzConstructArray[] = $key.$value;
}
}
$this->billPlzConstructArray = collect($this->request)->forget('x_signature')->map(function($item, $key){
return $this->type === 'redirect' ? 'billplz'.$key.$item : $key.$item;
})->toArray();
return $this;
}
@@ -72,6 +83,11 @@ class BillplzXSignatureObject implements DataTransferObject
return $this->billPlzId;
}
public function getStatus(): string
{
return $this->status;
}
/**
* @return array
*/
@@ -98,7 +114,7 @@ class BillplzXSignatureObject implements DataTransferObject
public function isValidSignature(): bool
{
return $this->billPlzComputedXSignature == $this->requestXSignature ? true : false;
return $this->billPlzComputedXSignature === $this->requestXSignature ? true : false;
}
}
@@ -7,22 +7,30 @@ use App\Classes\Exceptions\MalformedRequestException;
class CreatesBillplzBill
{
/**
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
* @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) {
public function execute(string $name, string $email, string $description, float $amount, string $billNumber, ?string $bankCode = null) {
try{
$response = Http::withBasicAuth(config('billplz.api_key').':', '')->withOptions(["verify"=>false])->post(config('billplz.base_url').'/api/v3/bills', [
// config('billplz.maybank')
$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' => $amount,
'redirect_url' => config('billplz.redirect_url'),
'callback_url' => config('billplz.callback_url'),
'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_1' => $bankCode ? $bankCode : '',
'reference_2_label' => 'Bill Number',
'reference_2' => $billNumber
]);
@@ -40,4 +48,9 @@ class CreatesBillplzBill
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;
}
}
@@ -2,13 +2,16 @@
namespace App\Classes\Modules\Billplzs\Services;
use App\Classes\Exceptions\MalformedRequestException;
use Illuminate\Support\Facades\Http;
class GetBillplzBill
{
/**
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
* @param string $billPlzId
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $billPlzId) {
try{
@@ -61,7 +61,11 @@ class ApprovePurchaseOrderLogic extends AbstractControllerLogic
$booking = $this->fetchesBooking->execute(['id' => $request->route('id')]);
$this->updatesTransactionStatus->execute($booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(), ApprovalStatus::APPROVED);
$purchaseOrder = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
$booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->where('id', '!=', $purchaseOrder->id)->delete();
$this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED);
$this->createInvoiceTransactionProcessor->execute($booking);
@@ -0,0 +1,113 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\ControllersLogic\CreatePurchaseOrderTransactionLogic;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
use App\Classes\Modules\Transactions\Services\GeneratesPurchaseOrderProducts;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use App\Models\Transaction;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AutoPurchaseOrderFillLogic extends AbstractControllerLogic
{
/**
* AutoPurchaseOrderFillLogic constructor.
* @param GeneratesPurchaseOrderProducts $generatesPurchaseOrderProducts
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
*/
public function __construct(GeneratesPurchaseOrderProducts $generatesPurchaseOrderProducts, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor)
{
$this->generatesPurchaseOrderProducts = $generatesPurchaseOrderProducts;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
}
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Purchase Order Approval',
'message' => 'You have successfully updated the Purchase order status'
];
}
/** @var GeneratesPurchaseOrderProducts */
private $generatesPurchaseOrderProducts;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatePurchaseOrderTransactionProcessor */
private $createPurchaseOrderTransactionProcessor;
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$bookings = Booking::whereMonth('created_at', 7)
->whereYear('created_at', 2021)
->whereDoesntHave('transactions', function($q){
$q->where('type', TransactionType::PURCHASE_ORDER);
$q->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED]);
})->get();
foreach ($bookings as $booking) {
$po = Transaction::where('type', TransactionType::PURCHASE_ORDER)
->where('status', ApprovalStatus::APPROVED)->where('issuer', $booking->company_id)
->select('*', DB::raw('abs(amount - ' . $booking->fix_amount . ') as nearest_price'))->orderBy('nearest_price')->first();
if (!$po) {
$po = Transaction::where('type', TransactionType::PURCHASE_ORDER)
->where('status', ApprovalStatus::APPROVED)->select('*', DB::raw('abs(amount - ' . $booking->fix_amount . ') as nearest_price'))->orderBy('nearest_price')->first();
}
$products = $this->generatesPurchaseOrderProducts->execute($po, $booking->fix_amount);
$deference = $booking->fix_amount - $products->sum('total');
if($deference > -150 && $deference < 150 && $deference != 0) {
$products->push([
'description' => $deference < 0 ? 'Discount':'Shipping Fee',
'quantity' => 1,
'stockCode' => '',
'total' => $deference,
'unit_price' => $deference
]);
}
$billNumber = $this->generatesTransactionBillNumber->execute('XPO-');
$total = $products->sum('total');
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
1, PaymentMethodType::CASH,
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products->toArray());
$this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
}
return $this->response([]);
}
}
@@ -99,7 +99,7 @@ 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 on behave '.$booking->company->name, $configurations->getTotal(), $billNumber, $request->input('bank_code'));
$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,
@@ -109,7 +109,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
$configurations->getTax(), $configurations->getServiceCharge(), Carbon::now()->addMinutes($paymentAttemptLimit), ApprovalStatus::PENDING_SUBMISSION, [], isset($billPlzBill) ? $billPlzBill->id : NULL);
$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\Bookings\Services\FetchesBookingQuotation;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
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 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
{
@@ -47,6 +48,9 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CalculatesBookingRefundAmount */
private $calculatesBookingRefundAmount;
/**
* CreateBookingPaymentLogic constructor.
* @param FetchesBookingQuotation $fetchBookingQuotation
@@ -54,14 +58,16 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount
*/
public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, 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->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount;
}
/**
@@ -82,6 +88,11 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$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();
@@ -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);
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Bookings\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject;
use Illuminate\Support\Facades\Auth;
class CanDeleteBooking extends AbstractRule
{
@@ -14,7 +15,7 @@ class CanDeleteBooking extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('delete booking')) {
if (!Auth::user()->can('delete booking')) {
return false;
}
@@ -5,6 +5,7 @@ namespace App\Classes\Modules\Bookings\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Bookings\Standards\Validators\BookingValidation;
use Illuminate\Support\Facades\Auth;
class CanUpdateBooking extends AbstractRule
{
@@ -29,7 +30,7 @@ class CanUpdateBooking extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('edit booking')) {
if (!Auth::user()->can('edit booking')) {
return false;
}
@@ -5,6 +5,7 @@ namespace App\Classes\Modules\Currencies\Standards\Rules\Rates;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Currencies\Standards\Validators\Rates\RateValidation;
use App\Classes\Modules\Currencies\DataTransferObjects\RateObject;
use Illuminate\Support\Facades\Auth;
class CanCreateRate extends AbstractRule
{
@@ -27,7 +28,7 @@ class CanCreateRate extends AbstractRule
protected function authorized(): bool
{
// TODO Set Authorization rules
if (!\Auth::user()->can('add currency_rate')) {
if (!Auth::user()->can('add currency_rate')) {
return false;
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Currencies\Standards\Rules\Rates;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Currencies\DataTransferObjects\RateObject;
use Illuminate\Support\Facades\Auth;
class CanDeleteRate extends AbstractRule
{
@@ -14,7 +15,7 @@ class CanDeleteRate extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('delete currency_rate')) {
if (!Auth::user()->can('delete currency_rate')) {
return false;
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Currencies\Standards\Rules\Rates;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyObject;
use Illuminate\Support\Facades\Auth;
class CanListRates extends AbstractRule
{
@@ -14,7 +15,7 @@ class CanListRates extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('view currency_rate')) {
if (!Auth::user()->can('view currency_rate')) {
return false;
}
@@ -6,6 +6,7 @@ namespace App\Classes\Modules\Currencies\Standards\Rules\Rates;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Currencies\Standards\Validators\Rates\RateValidation;
use App\Classes\Modules\Currencies\DataTransferObjects\RateObject;
use Illuminate\Support\Facades\Auth;
class CanUpdateRate extends AbstractRule
{
@@ -29,7 +30,7 @@ class CanUpdateRate extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('view currency_rate')) {
if (!Auth::user()->can('view currency_rate')) {
return false;
}
@@ -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);
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\BusinessType;
use App\Classes\ValueObjects\Constants\CompanyType;
use App\Models\Company;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMapping;
class ExportsProducts implements FromQuery, WithHeadingRow, WithMapping
{
use Exportable;
public function headings(): array
{
return [
'HS Code',
'Name',
'price'
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
return \App\Models\TransactionDetail::inRandomOrder()->whereHas('transaction', function($query){
return $query->where('type', \App\Classes\ValueObjects\Constants\TransactionType::PURCHASE_ORDER)->where('status', ApprovalStatus::APPROVED);
})->limit(50);
}
/**
* @param $product
* @return array
*/
public function map($product): array
{
return [
$product->product_code,
$product->product_name,
$product->price,
];
}
}
@@ -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',
@@ -5,6 +5,7 @@ namespace App\Classes\Modules\Segments\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Segments\DataTransferObjects\SegmentObject;
use App\Classes\Modules\Segments\Standards\Validators\SegmentValidation;
use Illuminate\Support\Facades\Auth;
class CanCreateSegment extends AbstractRule
{
@@ -27,7 +28,7 @@ class CanCreateSegment extends AbstractRule
protected function authorized(): bool
{
// TODO Set Authorization rules
if (!\Auth::user()->can('add segment')) {
if (!Auth::user()->can('add segment')) {
return false;
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Segments\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Segments\DataTransferObjects\SegmentObject;
use Illuminate\Support\Facades\Auth;
class CanDeleteSegment extends AbstractRule
{
@@ -14,7 +15,7 @@ class CanDeleteSegment extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('delete segment')) {
if (!Auth::user()->can('delete segment')) {
return false;
}
@@ -6,6 +6,7 @@ namespace App\Classes\Modules\Segments\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Segments\DataTransferObjects\SegmentObject;
use App\Classes\Modules\Segments\Standards\Validators\SegmentValidation;
use Illuminate\Support\Facades\Auth;
class CanUpdateSegment extends AbstractRule
{
@@ -30,7 +31,7 @@ class CanUpdateSegment extends AbstractRule
{
// TODO Set Authorization rules
if (!\Auth::user()->can('edit segment')) {
if (!Auth::user()->can('edit segment')) {
return false;
}
@@ -7,6 +7,7 @@ use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\CreatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\DeletesTransactionDetails;
@@ -25,26 +26,6 @@ use Illuminate\Http\Request;
class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
{
/**
* CreatePurchaseOrderTransactionLogic constructor.
* @param FetchesBooking $fetchesBooking
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesTransaction $createsTransaction
* @param CreatesTransactionDetail $createsTransactionDetail
* @param UpdatesTransaction $updatesTransaction
* @param DeletesTransactionDetails $deletesTransactionDetails
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
*/
public function __construct(FetchesBooking $fetchesBooking, UpdatesTransactionStatus $updatesTransactionStatus, CreatesTransaction $createsTransaction, CreatesTransactionDetail $createsTransactionDetail, UpdatesTransaction $updatesTransaction, DeletesTransactionDetails $deletesTransactionDetails, GeneratesTransactionBillNumber $generatesTransactionBillNumber)
{
$this->fetchesBooking = $fetchesBooking;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsTransaction = $createsTransaction;
$this->createsTransactionDetail = $createsTransactionDetail;
$this->updatesTransaction = $updatesTransaction;
$this->deletesTransactionDetails = $deletesTransactionDetails;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
}
/**
* @return array
@@ -59,37 +40,35 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
/** @var FetchesBooking */
private $fetchesBooking;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CreatesTransactionDetail */
private $createsTransactionDetail;
/** @var UpdatesTransaction */
private $updatesTransaction;
/** @var DeletesTransactionDetails */
private $deletesTransactionDetails;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatePurchaseOrderTransactionProcessor */
private $createPurchaseOrderTransactionProcessor;
/**
* CreatePurchaseOrderTransactionLogic constructor.
* @param FetchesBooking $fetchesBooking
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
*/
public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor)
{
$this->fetchesBooking = $fetchesBooking;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
}
/**
* @param Request $request
* @param string $id
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
public function logic(Request $request, $id = '') : JsonResponse
{
/** @var Booking $booking */
$booking = $this->fetchesBooking->execute(['id' => $request->route('id')]);
/** @var Transaction $transaction */
$transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
$booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]);
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
@@ -102,15 +81,8 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $request->input('products'));
!$transaction ? $transaction = $this->createsTransaction->execute($booking, $object) : $transaction = $this->updatesTransaction->execute($transaction, $object);
$this->updatesTransactionStatus->execute($transaction, (float) number_format($total, 2, '.', '') === (float) number_format((float)$booking->fix_amount, 2, '.', '') ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::PENDING_SUBMISSION);
$this->deletesTransactionDetails->execute($transaction);
foreach ($object->getDetails() as $product){
$this->createsTransactionDetail->execute($transaction, $product);
}
$transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
return $this->resourceResponse(new TransactionResource($transaction));
@@ -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([]);
}
}
@@ -0,0 +1,76 @@
<?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\Modules\Documents\Services\DeletesDocument;
use App\Models\Company;
use App\Models\Document;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
class UpdatePaymentTransactionStatusLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated Transaction',
'message' => 'You have successfully updated a transaction'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var DeletesDocument */
private $deletesDocument;
/**
* CreatePaymentVerificationDocumentLogic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param DeletesDocument $deletesDocument
*/
public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->deletesDocument = $deletesDocument;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
$status = $request->route('status');
$this->updatesTransactionStatus->execute($transaction, $status === 'pending' ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::COMPLETED);
if ($status == 'pending') {
$document = $transaction->documents()->first();
if ($document) {
$this->deletesDocument->execute($document);
}
}
return $this->response([]);
}
}
@@ -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,76 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\CreatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\DeletesTransactionDetails;
use App\Classes\Modules\Transactions\Services\UpdatesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use App\Models\Transaction;
class CreatePurchaseOrderTransactionProcessor
{
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CreatesTransactionDetail */
private $createsTransactionDetail;
/** @var UpdatesTransaction */
private $updatesTransaction;
/** @var DeletesTransactionDetails */
private $deletesTransactionDetails;
/**
* CreatePurchaseOrderTransactionProcessor constructor.
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesTransaction $createsTransaction
* @param CreatesTransactionDetail $createsTransactionDetail
* @param UpdatesTransaction $updatesTransaction
* @param DeletesTransactionDetails $deletesTransactionDetails
*/
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, CreatesTransaction $createsTransaction, CreatesTransactionDetail $createsTransactionDetail, UpdatesTransaction $updatesTransaction, DeletesTransactionDetails $deletesTransactionDetails)
{
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsTransaction = $createsTransaction;
$this->createsTransactionDetail = $createsTransactionDetail;
$this->updatesTransaction = $updatesTransaction;
$this->deletesTransactionDetails = $deletesTransactionDetails;
}
/**
* @param Booking $booking
* @param TransactionObject $object
* @return Transaction|\Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Booking $booking, TransactionObject $object){
/** @var Transaction $transaction */
$transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
!$transaction ? $transaction = $this->createsTransaction->execute($booking, $object) : $transaction = $this->updatesTransaction->execute($transaction, $object);
$this->updatesTransactionStatus->execute($transaction, (float) number_format($object->getAmount(), 2, '.', '') === (float) number_format((float)$booking->fix_amount, 2, '.', '') ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::PENDING_SUBMISSION);
$this->deletesTransactionDetails->execute($transaction);
foreach ($object->getDetails() as $product){
$this->createsTransactionDetail->execute($transaction, $product);
}
return $transaction;
}
}
@@ -5,12 +5,12 @@ namespace App\Classes\Modules\Transactions\Services;
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
@@ -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);
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use App\Models\Transaction;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class GeneratesPurchaseOrderProducts
{
/** @var Collection */
private $products;
/**
* GeneratesPurchaseOrderProducts constructor.
* @param Collection $products
*/
public function __construct(Collection $products)
{
$this->products = $products;
}
public function execute(Transaction $transaction, float $amount){
$products = collect();
$amountDifference = $amount - $transaction->amount;
$transactionDetails = $transaction->transactionDetails()->select('*', DB::raw('abs(price - '.abs($amountDifference).') as nearest_price'))->orderBy('nearest_price')->get();
foreach ($transactionDetails as $product) {
$units = floor(abs($amountDifference) / $product->price);
$quantity = $product->quantity;
if($product->price <= 0){
$amountDifference = $amountDifference + ($product->price * $product->quantity);
continue;
}
if($amountDifference > 0){
$quantity = $product->quantity + $units;
$amountDifference = $amountDifference - ($product->price * $units);
}
if($amountDifference < 0) {
$units = ceil(abs($amountDifference) / $product->price);
$quantity = $product->quantity - $units;
if($quantity <= 0){
$amountDifference = $amountDifference + ($product->price * $product->quantity);
continue;
}
$amountDifference = $amountDifference + ($product->price * $quantity);
}
$products->push([
'description' => $product->product_name,
'quantity' => (int) $quantity,
'stockCode' => $product->product_code,
'total' => $product->price * $quantity,
'unit_price' => (float) $product->price,
]);
}
return $products;
}
}
@@ -0,0 +1,107 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Wallets\Services\UpdatesWallet;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\WalletResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class CreditWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Credit into Company Wallet',
'message' => 'You have successfully credit company wallet'
];
}
/** @var FetchesWallet */
private $fetchesWallet;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var UpdatesWallet */
private $updatesWallet;
/**
* CreateWalletLogic constructor.
* @param FetchesWallet $fetchesWallet
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param UpdatesWallet $updatesWallet
*/
public function __construct(
FetchesWallet $fetchesWallet,
GeneratesTransactionBillNumber $generatesTransactionBillNumber,
CreatesTransaction $createsTransaction,
UpdatesWallet $updatesWallet
)
{
$this->fetchesWallet = $fetchesWallet;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->updatesWallet = $updatesWallet;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$wallet = $this->fetchesWallet->execute(['id' => $request->input('wallet_id')]);
$billNumber = $this->generatesTransactionBillNumber->execute('DEBIT-NOTE-');
$transaction_object = new TransactionObject(
$billNumber,
TransactionType::CREDIT_NOTE,
1,
$wallet->company->id,
1,
PaymentMethodType::WALLET,
$request->input('amount'),
$request->input('amount'),
1,
1,
1,
0,
0,
null,
ApprovalStatus::PENDING_SUBMISSION,
[]
);
$transaction = $this->createsTransaction->execute($wallet, $transaction_object);
$updateWalletAmount = $wallet->amount + $transaction->amount;
$walletOject = new WalletObject($wallet->company->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
$wallet = $this->updatesWallet->execute($wallet, $walletOject);
return $this->resourceResponse(new WalletResource($wallet));
}
}
@@ -0,0 +1,107 @@
<?php
namespace App\Classes\Modules\Wallets\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Wallets\Services\FetchesWallet;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Wallets\Services\UpdatesWallet;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\WalletResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class DebitWalletLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Debit into Company Wallet',
'message' => 'You have successfully debit company wallet'
];
}
/** @var FetchesWallet */
private $fetchesWallet;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var UpdatesWallet */
private $updatesWallet;
/**
* CreateWalletLogic constructor.
* @param FetchesWallet $fetchesWallet
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param UpdatesWallet $updatesWallet
*/
public function __construct(
FetchesWallet $fetchesWallet,
GeneratesTransactionBillNumber $generatesTransactionBillNumber,
CreatesTransaction $createsTransaction,
UpdatesWallet $updatesWallet
)
{
$this->fetchesWallet = $fetchesWallet;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->updatesWallet = $updatesWallet;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$wallet = $this->fetchesWallet->execute(['id' => $request->input('wallet_id')]);
$billNumber = $this->generatesTransactionBillNumber->execute('DEBIT-NOTE-');
$transaction_object = new TransactionObject(
$billNumber,
TransactionType::DEBIT_NOTE,
1,
$wallet->company->id,
1,
PaymentMethodType::WALLET,
$request->input('amount'),
$request->input('amount'),
1,
1,
1,
0,
0,
null,
ApprovalStatus::PENDING_SUBMISSION,
[]
);
$transaction = $this->createsTransaction->execute($wallet, $transaction_object);
$updateWalletAmount = $wallet->amount - $transaction->amount;
$walletOject = new WalletObject($wallet->company->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
$wallet = $this->updatesWallet->execute($wallet, $walletOject);
return $this->resourceResponse(new WalletResource($wallet));
}
}
@@ -3,15 +3,18 @@
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\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Wallets\Services\CreatesWallet;
use App\Classes\Modules\Wallets\Services\GeneratesWalletCode;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Billplzs\Services\CreatesBillplzBill;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Wallets\Standards\Rules\CanTopUpWallet;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\WalletResource;
use App\Classes\Modules\Transactions\Processors\CreateWalletTransactionProcessor;
use ErrorException;
use Illuminate\Http\JsonResponse;
@@ -30,26 +33,50 @@ class TopUpWalletLogic extends AbstractControllerLogic
];
}
/** @var FetchesWallet */
private $fetchesWallet;
/** @var CanTopUpWallet */
private $canTopUpWallet;
/** @var FetchesCompany */
private $fetchesCompany;
/** @var CreateWalletTransactionProcessor */
private $createWalletTransactionProcessor;
/** @var GeneratesWalletCode */
private $generatesWalletCode;
/** @var CreatesWallet */
private $createsWallet;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatesWalletTransaction */
private $createsWalletTransaction;
/** @var CreatesBillplzBill */
private $createsBillplzBill;
/** @var CreatesTransaction */
private $createsTransaction;
/**
* CreateWalletLogic constructor.
* @param CreatesWallet $createsWallet
* @param FetchesCompany $fetchesCompany
* @param GeneratesWalletCode $generatesWalletCode
* @param CanCreateCompanyWallet $canCreateCompanyWallet
* @param CreatesWallet $createsWallet
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
*/
public function __construct(CanTopUpWallet $canTopUpWallet, FetchesWallet $fetchesWallet, CreateWalletTransactionProcessor $createWalletTransactionProcessor)
public function __construct(
FetchesCompany $fetchesCompany,
GeneratesWalletCode $generatesWalletCode,
CreatesWallet $createsWallet,
GeneratesTransactionBillNumber $generatesTransactionBillNumber,
CreatesBillplzBill $createsBillplzBill,
CreatesTransaction $createsTransaction
)
{
$this->canTopUpWallet = $canTopUpWallet;
$this->fetchesWallet = $fetchesWallet;
$this->createWalletTransactionProcessor = $createWalletTransactionProcessor;
$this->fetchesCompany = $fetchesCompany;
$this->generatesWalletCode = $generatesWalletCode;
$this->createsWallet = $createsWallet;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsBillplzBill = $createsBillplzBill;
$this->createsTransaction = $createsTransaction;
}
/**
@@ -59,13 +86,45 @@ class TopUpWalletLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$wallet = $this->fetchesWallet->execute(['id' => $request->input('wallet_id')]);
$company = $this->fetchesCompany->execute(['id' => $request->input('company_id')]);
if (!$company->wallets()->first()) {
$object = new WalletObject($company->id, 1, $this->generatesWalletCode->execute());
$wallet = $this->createsWallet->execute($object, $company);
}
$walletOject = new WalletObject( $wallet->company->id, $wallet->currency_id, $wallet->code, $request->input('amount'));
$user = $company->employees()->first();
$billNumber = $this->generatesTransactionBillNumber->execute('TOPUP-');
$billPlzBill = $this->createsBillplzBill->execute(
$user->name,
$user->email,
'This payment is made for wallet topup. ' . $company->reference,
$request->input('amount'),
$billNumber,
$request->input('bank_code')
);
$this->canTopUpWallet->passes($walletOject);
$transaction_object = new TransactionObject(
$billNumber,
TransactionType::TOP_UP,
1,
$company->id,
1,
PaymentMethodType::PAYMENT_GATEWAY,
$request->input('amount'),
$request->input('amount'),
1,
1,
1,
0,
0,
null,
ApprovalStatus::PENDING_SUBMISSION,
[],
$billPlzBill->id
);
$transaction = $this->createWalletTransactionProcessor->execute($wallet, $walletOject, TransactionType::TOP_UP);
$transaction = $this->createsTransaction->execute($company->wallets()->first(), $transaction_object);
return $this->resourceResponse(new WalletResource($wallet));
}
@@ -21,8 +21,6 @@ class CreatesWallet extends AbstractUpdateRelationshipRecord
$model->code = $object->getCode();
$model->currency_id = $object->getCurrency();
return $this->handler($company->wallets(), $model);
}
}
@@ -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';
@@ -12,7 +12,7 @@ final class TransactionType {
public const BILL = 3;
public const PERFORMA = 4;
public const PROFORMA = 4;
public const TOP_UP = 5;
@@ -24,5 +24,7 @@ final class TransactionType {
public const CREDIT_NOTE = 9;
public const DEBIT_NOTE = 11;
public const WITHDRAW = 10;
}
@@ -1,19 +1,21 @@
<?php
namespace App\Http\Controllers\Billplzs;
namespace App\Http\Controllers\Billplz;
use App\Classes\Modules\Billplzs\ControllersLogic\CallbackBillplzLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CallbackBillplzController
{
/**
* @param Request $request
* @param BillplzBillLogic $logic
* @return JsonResponse
* @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): JsonResponse {
public function callback(Request $request, CallbackBillplzLogic $logic) {
return $logic->execute($request);
}
@@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Billplzs;
namespace App\Http\Controllers\Billplz;
use App\Classes\Modules\Billplzs\ControllersLogic\CreateBillplzBillLogic;
use Illuminate\Http\JsonResponse;
@@ -10,7 +10,7 @@ class CreateBillplzBillController
{
/**
* @param Request $request
* @param BillplzBillLogic $logic
* @param CreateBillplzBillLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateBillplzBillLogic $logic): JsonResponse {
@@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\AutoPurchaseOrderFillLogic;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class AutoPurchaseOrderFillController
{
/**
* @param Request $request
* @param AutoPurchaseOrderFillLogic $logic
* @return JsonResponse
*/
public function auto(Request $request, AutoPurchaseOrderFillLogic $logic): JsonResponse {
Auth()->login(User::find(1));
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\Transactions;
use App\Classes\Modules\Transactions\ControllersLogic\UpdatePaymentTransactionStatusLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdatePaymentTransactionStatusController
{
public function update(Request $request, UpdatePaymentTransactionStatusLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\CreditWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreditWalletController
{
public function credit(Request $request, CreditWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Wallets;
use App\Classes\Modules\Wallets\ControllersLogic\DebitWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DebitWalletController
{
public function debit(Request $request, DebitWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
+14 -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;
@@ -23,7 +24,6 @@ class BookingResource extends JsonResource
*/
public function toArray($request)
{
// dd($this->service);
return [
'id' => $this->id,
'company' => new CompanyResource($this->company),
@@ -32,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),
@@ -42,6 +42,7 @@ 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'),
@@ -56,9 +57,17 @@ class BookingResource extends JsonResource
'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())
])
+11 -4
View File
@@ -12,6 +12,7 @@ use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Currency;
use App\Models\SegmentConstant;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Auth;
@@ -26,6 +27,7 @@ class CompanyResource extends JsonResource
public function toArray($request)
{
$lastPayment = $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->orderBy('id', 'DESC')->first();
$totalPayments = $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount');
return [
'id' => $this->id,
'name' => $this->name,
@@ -38,7 +40,14 @@ class CompanyResource extends JsonResource
'employee' => new UserResource(Auth::user()->type === RoleTypes::USER ? $this->employees()->where('email', '=', Auth::user()->email)->first() : $this->employees()->orderBy('id', 'DESC')->first()),
'identification' => new DocumentResource($this->documents->whereIn('document_type', DocumentType::IDENTIFICATION_DOCUMENTS)->first()),
'bookings' => $this->whenLoaded('bookings', $this->bookings()->orderBy('id', 'DESC')->get(), []),
'total_payments' => (float) $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount'),
'confirmed_bookings' => $this->bookings()->whereHas('transactions', function ($query){
$query->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
})->count(),
'total_payments' => (float) $totalPayments,
'average_spending_per_day' => (float) $totalPayments / ($this->created_at->diff(Carbon::now())->days === 0 ? 1 : $this->created_at->diff(Carbon::now())->days),
'average_spending_per_booking' => (float) $totalPayments > 0 ? $totalPayments / $this->bookings()->whereHas('transactions', function ($query){
$query->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
})->count() : $totalPayments,
'last_payment' => $lastPayment ? $lastPayment->created_at->diffForHumans() : 'No Payments',
'personal_banks' => BankResource::collection($this->banks->where('type', BankAccountType::PERSONAL)),
'recipient_banks' => [
@@ -51,10 +60,8 @@ class CompanyResource extends JsonResource
$segment = SegmentConstant::where('reference', SegmentConstants::SUPPLIER_CURRENCIES)->where('detail->id', $this->id)->first();
return $segment ? CurrencyResource::collection(Currency::whereIn('id', $segment->detail->currencies)->get()) : [];
}),
'wallet' => WalletResource::collection($this->wallets),
'created_at' => $this->created_at->format('d-m-Y')
];
}
}
+7 -4
View File
@@ -3,7 +3,6 @@
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -23,9 +22,9 @@ class TransactionResource extends JsonResource
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
'payment_reference' => $this->payment_reference,
'payment_method' => $this->payment_method,
'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),
@@ -38,7 +37,11 @@ class TransactionResource extends JsonResource
'documents' => new DocumentResource($this->documents()->first()),
'customer_booking' => new TransactionResource($this->when((int) $this->type === TransactionType::BILL, $this->booking->transactions()->payments()->complete()->where('original_amount', '=', $this->original_amount)->where('id', '<', $this->id)->orderByDesc('id')->first())),
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:i:s A'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y h:i:s A')
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y h:i:s A'),
'interval' => [
'value' => (Carbon::parse($this->created_at)->addDays(3)->gt(Carbon::now()) ) ? '+' : '-' ,
'duration' => Carbon::parse($this->created_at)->addDays(3)->diff(Carbon::now())->format('%d'),
],
];
}
}
+12 -1
View File
@@ -2,6 +2,7 @@
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Http\Resources\Json\JsonResource;
class WalletResource extends JsonResource
@@ -19,7 +20,17 @@ class WalletResource extends JsonResource
'code' => $this->code,
'currency_id' => $this->currency_id,
'amount' => (double) $this->amount,
'company_id' => (int) $this->company_id
'company_id' => (int) $this->owner->id,
'transactions' => $this->transactions()->orderBy('id', 'DESC')->get(),
'topup_transactions' => $this->transactions()->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get(),
// 'transaction' => $this->whenLoaded('transactions', function() {
// return [
// 'topup' => $this->transactions
// ];
// }),
// 'transaction' // all
// 'top_transaction' // only topup
];
}
}
+2 -5
View File
@@ -6,11 +6,8 @@ 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;
/**
@@ -22,8 +19,8 @@ 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, Transactionable
{
+9 -1
View File
@@ -7,6 +7,7 @@ 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;
@@ -17,6 +18,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
class Transaction extends AbstractModel implements Documentable
{
use SoftDeletes;
protected $table = 'transactions';
public function owner(): morphTo
@@ -126,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);
}
+2 -1
View File
@@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Permission\Traits\HasRoles;
use Tymon\JWTAuth\Contracts\JWTSubject;
@@ -23,7 +24,7 @@ class User extends AbstractModel implements
AuthorizableContract,
CanResetPasswordContract
{
use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, SoftDeletes;
/**
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models;
use App\Classes\General\Interfaces\Transactionable;
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
class Wallet extends AbstractModel implements Transactionable
{
use SoftDeletes;
+1 -1
View File
@@ -14,7 +14,7 @@
"ext-zip": "*",
"barryvdh/laravel-dompdf": "^0.9.0",
"carlos-meneses/laravel-mpdf": "^2.1",
"doctrine/dbal": "2.*",
"doctrine/dbal": "^2.12.1",
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^1.0",
"guzzlehttp/guzzle": "^6.3",
+1 -1
View File
@@ -1,7 +1,7 @@
<?php
return [
'base_url' => env('BILLPLZ_BASE_URL', 'https://www.billplz-sandbox.com'),
'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'),
+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,
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+4
View File
@@ -120,6 +120,10 @@
button:focus{
outline: none !important;
}
button:disabled {
cursor: not-allowed;
}
/*
Alternate buttons
--------------------------------------------------
File diff suppressed because one or more lines are too long
@@ -1,79 +1,128 @@
<template>
<div class="row align-items-center m-b-15 parentContainer">
<div class="col-auto p-r-0">
<div class="padding-5 bg-master-lightest">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="30" height="30"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="86" y1="104.14063" x2="86" y2="140.57775" gradientUnits="userSpaceOnUse" id="color-1_44825_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="16.125" x2="86" y2="159.93044" gradientUnits="userSpaceOnUse" id="color-2_44825_gr2"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><path d="M121.41588,139.75h-70.83175c-2.53431,0 -3.66575,-3.18469 -1.6985,-4.78106l33.72544,-27.40175c1.97531,-1.60444 4.80256,-1.60444 6.77787,0l33.72544,27.40175c1.96725,1.59638 0.83581,4.78106 -1.6985,4.78106z" fill="url(#color-1_44825_gr1)"></path><path d="M148.135,71.77238l-8.385,-8.385v-28.42031c0,-4.46125 -3.63081,-8.09206 -8.09206,-8.09206h-2.65794v-2.65794c0,-4.46125 -3.63081,-8.09206 -8.09206,-8.09206h-69.81587c-4.46125,0 -8.09206,3.63081 -8.09206,8.09206v2.65794h-2.65794c-4.46125,0 -8.09206,3.63081 -8.09206,8.09206v28.42031l-8.385,8.385c-1.5265,1.52381 -2.365,3.55019 -2.365,5.70825v64.95688c0,7.40944 6.02806,13.4375 13.4375,13.4375h102.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-64.95688c0,-2.15806 -0.84119,-4.18444 -2.365,-5.70825zM77.60156,91.96356l-0.30906,0.24725c-1.28731,-1.79525 -2.0425,-3.92375 -2.0425,-6.21081c0,-5.92862 4.82138,-10.75 10.75,-10.75c5.92863,0 10.75,4.82138 10.75,10.75c0,2.26287 -0.70413,4.41019 -2.01294,6.235l-0.34131,-0.27412c-4.93962,-3.95063 -11.84919,-3.95063 -16.79419,0.00269zM86,69.875c-8.89294,0 -16.125,7.23206 -16.125,16.125c0,3.53406 1.14487,6.85581 3.18738,9.59438l-10.578,8.46025l-3.35937,-2.6875v-55.88388c6.95256,-1.06963 12.16094,-6.28069 13.23325,-13.23325h27.2835c1.06963,6.95256 6.28069,12.16094 13.23325,13.23325v55.88656l-3.35937,2.6875l-10.56994,-8.45488c2.07744,-2.79231 3.17931,-6.10869 3.17931,-9.60244c0,-8.89294 -7.23206,-16.125 -16.125,-16.125zM58.179,107.5l-31.304,25.04481v-50.08694zM145.125,82.45519v50.08963l-31.30669,-25.04481zM144.33488,75.5725c0.11825,0.11825 0.18006,0.27412 0.27412,0.4085l-4.859,3.88612v-8.8795zM131.65794,32.25c1.49962,0 2.71706,1.21744 2.71706,2.71706v49.20275l-5.375,4.3v-56.21981zM51.09206,21.5h69.81856c1.49694,0 2.71438,1.21744 2.71438,2.71706v68.55275l-5.375,4.3v-56.75731h-2.6875c-6.22694,0 -10.75,-4.52306 -10.75,-10.75v-2.6875h-37.625v2.6875c0,6.22694 -4.52306,10.75 -10.75,10.75h-2.6875v56.75731l-5.375,-4.3v-68.55275c0,-1.49962 1.21744,-2.71706 2.71706,-2.71706zM40.34206,32.25h2.65794v56.21981l-5.375,-4.3v-49.20275c0,-1.49963 1.21744,-2.71706 2.71706,-2.71706zM32.25,70.98763v8.88219l-4.859,-3.88881c0.09406,-0.13438 0.15587,-0.29025 0.27412,-0.4085zM137.0625,150.5h-102.125c-4.44513,0 -8.0625,-3.61738 -8.0625,-8.0625v-3.00463l54.08325,-43.27144c2.96969,-2.37306 7.11381,-2.37306 10.08081,0l54.08594,43.26875v3.00731c0,4.44513 -3.61737,8.0625 -8.0625,8.0625z" fill="url(#color-2_44825_gr2)"></path></g></g></svg>
</div>
</div>
<div class="col-auto">
<div class="row">
<div class="col-auto p-r-10 all-caps">
<div class="font-heading all-caps fs-11 bold">{{this.item.marking}}</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 muted">{{this.item.created_at}}</div>
</div>
</div>
</div>
<div class="col" v-if="$store.getters.isAdmin">
<div class="font-heading fs-10 muted all-caps">Marking</div>
<div class="font-heading fs-12">
<a :href="route('customer.profile', item.company.reference)">{{this.item.company.reference}}</a>
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Currency</div>
<div class="font-heading fs-12 bold">
<span class="flag-icon fs-12" :class="'flag-icon-'+item.convertible_currency.country.short_code.toLowerCase()"></span> {{this.item.convertible_currency.short_code}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Transfer Type</div>
<div class="font-heading fs-11">{{this.item.service.name}}</div>
</div>
<div class="col">
<div class="font-heading fs-10 muted all-caps">Payable Amount</div>
<div class="font-heading fs-11 text-success bold">{{this.item.amount}} {{this.item.fixed_currency.short_code}}</div>
</div>
<div class="col-auto" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">status</div>
<div class="font-heading fs-8 all-caps text-master btn-rounded p-l-10 p-r-10 lh-15 mt-1" :class="[{'bg-warning': item.status !== 3}, {'bg-success': item.status === 3} ]">
{{item.status === 3 ? 'Complete' : 'In Progress'}}
</div>
</div>
<div class="col-auto hide" :class="[{'invisible': !item.service.configurations.billable}]" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">Billing</div>
<div class="font-heading fs-8 all-caps text-danger btn-rounded bg-master-lightest p-l-10 p-r-10 lh-15 mt-1">
Pending...
</div>
</div>
<div class="col-2 p-r-5 parentContainer">
<div class="row align-items-center">
<div class="col-auto ml-auto">
<div class="btn btn-xs btn-default b-rad-none requestModal" v-if="item.status !== 5 && item.paid_amount === 0 && item.floating_amount === 0 && $store.getters.isAdmin" data-type="cancelBooking">
<i class="fa fa-fw fa-times text-danger"></i>
<div class="row">
<div class="col">
<div class="border-sm row align-items-center m-b-15 parentContainer position-relative">
<div class="col-auto p-r-0">
<div class="padding-5 bg-master-lightest">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="30" height="30"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="86" y1="104.14063" x2="86" y2="140.57775" gradientUnits="userSpaceOnUse" id="color-1_44825_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="16.125" x2="86" y2="159.93044" gradientUnits="userSpaceOnUse" id="color-2_44825_gr2"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><path d="M121.41588,139.75h-70.83175c-2.53431,0 -3.66575,-3.18469 -1.6985,-4.78106l33.72544,-27.40175c1.97531,-1.60444 4.80256,-1.60444 6.77787,0l33.72544,27.40175c1.96725,1.59638 0.83581,4.78106 -1.6985,4.78106z" fill="url(#color-1_44825_gr1)"></path><path d="M148.135,71.77238l-8.385,-8.385v-28.42031c0,-4.46125 -3.63081,-8.09206 -8.09206,-8.09206h-2.65794v-2.65794c0,-4.46125 -3.63081,-8.09206 -8.09206,-8.09206h-69.81587c-4.46125,0 -8.09206,3.63081 -8.09206,8.09206v2.65794h-2.65794c-4.46125,0 -8.09206,3.63081 -8.09206,8.09206v28.42031l-8.385,8.385c-1.5265,1.52381 -2.365,3.55019 -2.365,5.70825v64.95688c0,7.40944 6.02806,13.4375 13.4375,13.4375h102.125c7.40944,0 13.4375,-6.02806 13.4375,-13.4375v-64.95688c0,-2.15806 -0.84119,-4.18444 -2.365,-5.70825zM77.60156,91.96356l-0.30906,0.24725c-1.28731,-1.79525 -2.0425,-3.92375 -2.0425,-6.21081c0,-5.92862 4.82138,-10.75 10.75,-10.75c5.92863,0 10.75,4.82138 10.75,10.75c0,2.26287 -0.70413,4.41019 -2.01294,6.235l-0.34131,-0.27412c-4.93962,-3.95063 -11.84919,-3.95063 -16.79419,0.00269zM86,69.875c-8.89294,0 -16.125,7.23206 -16.125,16.125c0,3.53406 1.14487,6.85581 3.18738,9.59438l-10.578,8.46025l-3.35937,-2.6875v-55.88388c6.95256,-1.06963 12.16094,-6.28069 13.23325,-13.23325h27.2835c1.06963,6.95256 6.28069,12.16094 13.23325,13.23325v55.88656l-3.35937,2.6875l-10.56994,-8.45488c2.07744,-2.79231 3.17931,-6.10869 3.17931,-9.60244c0,-8.89294 -7.23206,-16.125 -16.125,-16.125zM58.179,107.5l-31.304,25.04481v-50.08694zM145.125,82.45519v50.08963l-31.30669,-25.04481zM144.33488,75.5725c0.11825,0.11825 0.18006,0.27412 0.27412,0.4085l-4.859,3.88612v-8.8795zM131.65794,32.25c1.49962,0 2.71706,1.21744 2.71706,2.71706v49.20275l-5.375,4.3v-56.21981zM51.09206,21.5h69.81856c1.49694,0 2.71438,1.21744 2.71438,2.71706v68.55275l-5.375,4.3v-56.75731h-2.6875c-6.22694,0 -10.75,-4.52306 -10.75,-10.75v-2.6875h-37.625v2.6875c0,6.22694 -4.52306,10.75 -10.75,10.75h-2.6875v56.75731l-5.375,-4.3v-68.55275c0,-1.49962 1.21744,-2.71706 2.71706,-2.71706zM40.34206,32.25h2.65794v56.21981l-5.375,-4.3v-49.20275c0,-1.49963 1.21744,-2.71706 2.71706,-2.71706zM32.25,70.98763v8.88219l-4.859,-3.88881c0.09406,-0.13438 0.15587,-0.29025 0.27412,-0.4085zM137.0625,150.5h-102.125c-4.44513,0 -8.0625,-3.61738 -8.0625,-8.0625v-3.00463l54.08325,-43.27144c2.96969,-2.37306 7.11381,-2.37306 10.08081,0l54.08594,43.26875v3.00731c0,4.44513 -3.61737,8.0625 -8.0625,8.0625z" fill="url(#color-2_44825_gr2)"></path></g></g></svg>
</div>
</div>
<div class="btn btn-xs btn-default b-rad-none requestModal" v-if="item.status === 5 && item.paid_amount === 0 && item.floating_amount === 0 && $store.getters.isAdmin" data-type="restoreBooking">
<i class="fa fa-fw fa-history text-success"></i>
<div class="col-6 col-sm-auto">
<div class="row">
<div class="col-auto p-r-10 all-caps">
<div class="font-heading all-caps fs-11 bold">{{this.item.marking}}</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 muted">{{this.item.created_at}}</div>
</div>
</div>
</div>
<div class="col-6 col-sm d-none d-lg-block" v-if="$store.getters.isAdmin">
<div class="font-heading fs-10 muted all-caps">Marking</div>
<div class="font-heading fs-12">
<a :href="route('customer.profile', item.company.reference)">{{this.item.company.reference}}</a>
</div>
</div>
<div class="col-6 col-sm-auto d-none d-lg-block">
<div class="font-heading fs-10 muted all-caps">Currency</div>
<div class="font-heading fs-12 bold">
<span class="flag-icon fs-12" :class="'flag-icon-'+item.convertible_currency.country.short_code.toLowerCase()"></span> {{this.item.convertible_currency.short_code}}
</div>
</div>
<div class="col-6 col-sm-auto d-none d-lg-block">
<div class="font-heading fs-10 muted all-caps">Transfer Type</div>
<div class="font-heading fs-11">{{this.item.service.name}}</div>
</div>
<div class="col-6 col-sm d-none d-lg-block">
<div class="font-heading fs-10 muted all-caps">Payable Amount</div>
<div class="font-heading fs-11 text-success bold">{{this.item.amount}} {{this.item.fixed_currency.short_code}}</div>
</div>
<div class="col-6 col-sm-auto d-none d-lg-block" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">status</div>
<div class="font-heading fs-8 all-caps text-master btn-rounded p-l-10 p-r-10 lh-15 mt-1" :class="[{'bg-warning': item.status !== 3}, {'bg-success': item.status === 3} ]">
{{item.status === 3 ? 'Complete' : 'In Progress'}}
</div>
</div>
<div class="col-auto hide d-none d-lg-block" :class="[{'invisible': !item.service.configurations.billable}]" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">Billing</div>
<div class="font-heading fs-8 all-caps text-danger btn-rounded bg-master-lightest p-l-10 p-r-10 lh-15 mt-1">
Pending...
</div>
</div>
<div class="col-2 p-r-5 parentContainer position-static">
<div class="row align-items-center">
<div class="col-auto ml-auto position-static">
<div class="btn btn-xs btn-default b-rad-none requestModal" v-if="item.status !== 5 && item.paid_amount === 0 && item.floating_amount === 0 && $store.getters.isAdmin" data-type="cancelBooking">
<i class="fa fa-fw fa-times text-danger"></i>
</div>
<div class="btn btn-xs btn-default b-rad-none requestModal" v-if="item.status === 5 && item.paid_amount === 0 && item.floating_amount === 0 && $store.getters.isAdmin" data-type="restoreBooking">
<i class="fa fa-fw fa-history text-success"></i>
</div>
<a class="btn btn-xs btn-info b-rad-none" :href="route('booking.details', item.marking)">
<i class="fa fa-angle-right fa-fw"></i>
</a>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="cancelBooking">
<cancel-booking-form-component :data="item" section="oderList" class="text-center"></cancel-booking-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="restoreBooking">
<restore-booking-form-component :data="item" section="oderList" class="text-center"></restore-booking-form-component>
</modal-component>
</div>
<div class="col-2 p-r-5 parentContainer position-static d-block d-sm-none">
<div class="btn btn-xs btn-default b-rad-none position-absolute" style="top: 7px; right: 10px;" @click="expanded = !expanded">
<i class="fa fa-fw" :class="[{'fa-angle-up': expanded}, {'fa-angle-down': !expanded}]"></i>
</div>
</div>
</div>
<div class="row" v-if="expanded">
<div class="col b-b b-grey m-l-10 m-r-10 m-b-10 p-b-10" style="margin-top:-15px">
<div class="row">
<div class="col-6 col-sm" v-if="$store.getters.isAdmin">
<div class="font-heading fs-10 muted all-caps">Marking</div>
<div class="font-heading fs-12">
<a :href="route('customer.profile', item.company.reference)">{{this.item.company.reference}}</a>
</div>
</div>
<div class="col-6 col-sm-auto">
<div class="font-heading fs-10 muted all-caps">Currency</div>
<div class="font-heading fs-12 bold">
<span class="flag-icon fs-12" :class="'flag-icon-'+item.convertible_currency.country.short_code.toLowerCase()"></span> {{this.item.convertible_currency.short_code}}
</div>
</div>
<div class="col-6 col-sm-auto">
<div class="font-heading fs-10 muted all-caps">Transfer Type</div>
<div class="font-heading fs-11">{{this.item.service.name}}</div>
</div>
<div class="col-6 col-sm">
<div class="font-heading fs-10 muted all-caps">Payable Amount</div>
<div class="font-heading fs-11 text-success bold">{{this.item.amount}} {{this.item.fixed_currency.short_code}}</div>
</div>
<div class="col-6 col-sm-auto" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">status</div>
<div class="font-heading fs-8 all-caps text-master btn-rounded p-l-10 p-r-10 lh-15 mt-1" :class="[{'bg-warning': item.status !== 3}, {'bg-success': item.status === 3} ]">
{{item.status === 3 ? 'Complete' : 'In Progress'}}
</div>
</div>
<div class="col-auto hide" :class="[{'invisible': !item.service.configurations.billable}]" v-if="$store.getters.isCustomer">
<div class="font-heading fs-10 muted all-caps">Billing</div>
<div class="font-heading fs-8 all-caps text-danger btn-rounded bg-master-lightest p-l-10 p-r-10 lh-15 mt-1">
Pending...
</div>
</div>
</div>
</div>
<a class="btn btn-xs btn-info b-rad-none" :href="route('booking.details', item.marking)">
<i class="fa fa-angle-right fa-fw"></i>
</a>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="cancelBooking">
<cancel-booking-form-component :data="item" section="oderList" class="text-center"></cancel-booking-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="restoreBooking">
<restore-booking-form-component :data="item" section="oderList" class="text-center"></restore-booking-form-component>
</modal-component>
</div>
</div>
</template>
<script>
@@ -1,53 +1,94 @@
<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="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 ? '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-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 class="col-auto" v-if="$store.getters.isAdmin">
<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">
<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">
@@ -57,7 +98,7 @@
<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 +136,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 +149,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,7 +172,7 @@
</div>
</div>
</div>
<div class="row m-t-10">
<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">
@@ -41,10 +41,18 @@
</div>
</div>
<bank-in-component :data="item"></bank-in-component>
<div class="row" v-if="item.status === 2">
<div class="col">
<span class="text-complete fs-10 pointer requestModal" data-type="topUpModal">Cancel this order?</span>
</div>
</div>
<modal-component type="topUpModal">
<delete-transaction-form-component :data="item" section="section" class="text-center"></delete-transaction-form-component>
</modal-component>
</div>
</div>
</div>
<div class="col-2 b-a b-dashed b-success requestModal pointer" v-if="item.status !== 3" @click="selectedID(item.id)" data-type="paymentProofModal">
<div class="col-2 b-a b-dashed b-success requestModal pointer" v-if="item.status === 1" @click="selectedID(item.id)" data-type="paymentProofModal">
<div class="row align-item-center justify-content-center h-100">
<div class="col-auto" >
<div class="row align-items-center h-100">
@@ -61,6 +69,20 @@
</modal-component>
</div>
</div>
<div class="col-auto" v-if="item.status === 2">
<button class="btn btn-xs btn-default bg-success b-rad-none no-border requestModal" data-type="approvePaymentTransaction">
<i class="fa fa-check text-white fa-fw"></i>
</button>
<modal-component type="approvePaymentTransaction">
<approve-payment-transaction-form-component :data="item" section="section" class="text-center"></approve-payment-transaction-form-component>
</modal-component>
<button class="btn btn-xs btn-default bg-danger b-rad-none no-border requestModal" data-type="deletePaymentTransaction">
<i class="fa fa-times text-white fa-fw"></i>
</button>
<modal-component type="deletePaymentTransaction">
<reject-payment-transaction-form-component :data="item" section="section" class="text-center"></reject-payment-transaction-form-component>
</modal-component>
</div>
</div>
</div>
</div>
@@ -7,13 +7,13 @@
<div class="row align-items-center">
<div class="col p-t-5 p-b-5">
<div class="row">
<div class="col-auto">
<div class="col-6 col-md-6 col-lg-3">
<div class="font-heading fs-10 muted all-caps">Reference</div>
<div class="font-heading fs-10">
{{item.bill_no}}
</div>
</div>
<div class="col-auto">
<div class="col-6 col-md-6 col-lg-3">
<div class="font-heading fs-10 muted all-caps">Transfer No.</div>
<a :href="route('booking.details', item.booking.marking)">
<div class="font-heading fs-10">
@@ -21,24 +21,24 @@
</div>
</a>
</div>
<div class="col-auto">
<div class="col-6 col-md-auto">
<div class="font-heading fs-10 muted all-caps">Marking</div>
<div class="font-heading fs-10">
{{item.booking.company.reference}}
</div>
</div>
<div class="col text-right">
<div class="col text-lg-right">
<div class="font-heading fs-10 muted all-caps">Date</div>
<div class="font-heading fs-10">
{{item.documents.created_at}}
{{item.documents ? item.documents.created_at : item.updated_at}}
</div>
</div>
</div>
<div class="row m-t-10">
<div class="col-auto">
<div class="col-6 col-md-6 col-lg-3">
<div class="font-heading fs-10 muted all-caps">Payment Proof</div>
<div class="row no-margin" v-if="item.documents != null">
<div v-for="file in item.documents.files" v-bind:key="file.id" class="col-auto no-padding">
<div class="row no-margin" v-if="item.payment_method !== 5">
<div v-for="file in item.documents.files" v-bind:key="file.id" class="col-6 col-md-auto no-padding">
<document-file-viewer-component :file="file">
<template slot="button">
<div class="icon-thumbnail fs-11 text-white icon-25 bg-primary btn-rounded float-left m-r-5">
@@ -48,8 +48,15 @@
</document-file-viewer-component>
</div>
</div>
<div class="row no-margin" v-if="item.payment_method ===5">
<a :href="'https://www.billplz.com/bills/'+item.payment_reference" target="_blank">
<div class="icon-thumbnail fs-11 text-white icon-25 bg-complete btn-rounded float-left m-r-5">
Bz
</div>
</a>
</div>
</div>
<div class="col-auto">
<div class="col-6 col-md-6 col-lg-3" >
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-12 text-success bold">
MYR {{(Math.round((item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
@@ -61,7 +68,15 @@
{{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 v-if="!no_action" class="col-auto text-right">
<div class="col text-lg-right">
<div class="font-heading fs-10 muted all-caps">Service</div>
<div class="font-heading fs-10">
{{item.booking.service.name}}
</div>
</div>
</div>
<div class="row m-t-10">
<div v-if="!no_action" class="col-6 col-md-auto text-right">
<button class="btn btn-xs btn-outline-danger b-rad-none m-r-5 requestModal" data-type="rejectPayment">
<i class="fa fa-times fa-fw"></i>
</button>
@@ -25,12 +25,39 @@
<a :href="route('customer.profile', item.booking.company.reference)">{{item.booking.company.reference}}</a>
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Payment Proof</div>
<div class="row no-margin" v-if="item.payment_method !==5">
<div v-for="file in item.documents.files" v-bind:key="file.id" class="col-auto no-padding">
<document-file-viewer-component :file="file">
<template slot="button">
<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>
</template>
</document-file-viewer-component>
</div>
</div>
<div class="row no-margin" v-if="item.payment_method ===5">
<a :href="'https://www.billplz.com/bills/'+item.payment_reference" target="_blank">
<div class="icon-thumbnail fs-11 text-white icon-25 bg-complete btn-rounded float-left m-r-5">
Bz
</div>
</a>
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Service</div>
<div class="font-heading fs-10">
{{item.booking.service.name}}
</div>
</div>
</div>
<div class="row">
<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">
@@ -39,12 +66,20 @@
<span class="flag-icon" :class="'flag-icon-'+item.original_currency.country.short_code.toLowerCase()"></span> {{item.original_currency.short_code}}
</div>
</div>
<div class="col">
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-12 text-success bold">
{{(Math.round((item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col">
<div class="font-heading fs-10 muted all-caps">timer</div>
<div class="font-heading fs-10" :class="[{'text-success': item.interval.value === '+'}, {'text-danger': item.interval.value === '-'}]">
{{item.interval.value}}
{{item.interval.duration}}
days
</div>
</div>
</div>
</div>
</div>
@@ -1,7 +1,10 @@
<template>
<tr>
<td class="v-align-middle">
<p>{{item.documents.created_at}}</p>
<p>{{item.documents ? item.documents.created_at : item.updated_at}}</p>
</td>
<td class="v-align-middle ">
<p v-if="item.booking.bank.bank_name.includes('浙江网商银行')">1688.com</p>
</td>
<td class="v-align-middle ">
<p>{{item.booking.marking}}</p>
@@ -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 approve this transaction?</div>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-default bg-master-lighter 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="submit(route('api.transaction.bill.status', item.id, 'complete'), 'put', 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>
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,
}
}
},
@@ -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 delete this transaction? You will not be able to recover your booking after confirming your action.</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.transaction.bill.delete', item.id), 'delete', 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>
@@ -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>
@@ -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 reject this transaction?</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.transaction.bill.status', item.id, 'pending'), 'put', 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>
@@ -1,5 +1,5 @@
<template>
<div class="row">
<div class="row mt-3 mt-md-0">
<div class="col">
<div class="row">
<div class="col">
@@ -4,7 +4,7 @@
<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="row m-b-50" v-if="booking.status === 3">
<div class="col-10 no-padding">
<div class="row">
<div class="col">
@@ -29,7 +29,7 @@
<div class="row">
<div class="col">
<div class="row justify-content-center">
<div class="col-2 p-r-0">
<div class="col-4 col-sm-2 p-r-0 h-100">
<document-file-viewer-component :file="booking.documents.invoice.files[0]" v-if="booking.documents.invoice">
<template slot="button">
<div class="bg-white text-center padding-20 pointer b-grey">
@@ -44,7 +44,7 @@
</template>
</document-file-viewer-component>
</div>
<div class="col-2 p-r-0">
<div class="col-4 col-sm-2 p-r-0 h-100">
<document-file-viewer-component :file="booking.documents.purchase_order.files[0]" v-if="booking.documents.purchase_order">
<template slot="button">
<div class="bg-white text-center padding-20 pointer b-grey">
@@ -59,7 +59,7 @@
</template>
</document-file-viewer-component>
</div>
<div class="col-2 p-r-0">
<div class="col-4 col-sm-2 p-r-0 h-100">
<document-file-viewer-component :file="booking.documents.delivery_order.files[0]" v-if="booking.documents.delivery_order">
<template slot="button">
<div class="bg-white text-center padding-20 pointer b-grey">
@@ -203,8 +203,12 @@
<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">
<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>
<div class="row m-t-20" v-if="booking.payment_attempts.length">
<div class="col">
@@ -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>
@@ -4,34 +4,34 @@
<div class="row">
<div class="col p-r-5">
<div class="row m-b-20">
<div class="col-7">
<div class="col-12 col-md-7">
<div class="row m-b-15">
<div class="col">
<div class="row">
<div class="col-8 p-r-0">
<div class="btn btn-xs btn-outline-primary btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="selectedSupplier.status = !selectedSupplier.status">
<div class="col p-r-0">
<div class="btn btn-xs btn-outline-primary btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="serviceDropdownLaunch.status = ! serviceDropdownLaunch.status">
<div class="row">
<div class="col p-t-5 p-b-5 fs-9">
{{selectedSupplier.name}}
<div class="col p-t-5 p-b-5">
{{selectedService.name}}
</div>
<div class="col-auto b-l b-success">
<div class="col-auto b-l b-primary">
<div class="row h-100 align-items-center">
<div class="col">
<i class="fa" :class="[{'fa-angle-down': !selectedSupplier.status}, {'fa-angle-up': selectedSupplier.status}]"></i>
<i class="fa" :class="[{'fa-angle-down': !serviceDropdownLaunch.status}, {'fa-angle-up': serviceDropdownLaunch.status}]"></i>
</div>
</div>
</div>
</div>
</div>
<div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-primary" :class="[{'hide': !selectedSupplier.status}]" style="top: 100%; right: 0; z-index: 1;">
<div class="absolute w-100 b-l b-b b-r b-success" v-show="serviceDropdownLaunch.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" v-for="supplier in suppliers" v-bind:key="supplier.id" :data="supplier">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10" :class="[{'bg-primary-light': selectedSupplier.id === supplier.id}, {'text-white': selectedSupplier.id === supplier.id}, {'hover-primary': selectedSupplier.id !== supplier.id}, {'pointer': selectedSupplier.id !== supplier.id}]" @click="updateSupplier(supplier)">
<div class="row no-margin" v-for="service in selectedSupplier.services" v-bind:key="service.id" :data="service">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10" :class="[{'bg-primary-light': selectedService.id === service.id}, {'text-white': selectedService.id === service.id}, {'hover-primary': selectedService.id !== service.id}, {'pointer': selectedService.id !== service.id}]" @click="updateService(service)">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">{{supplier.name}}</div>
<div class="font-heading fs-10">{{service.name}}</div>
</div>
</div>
</div>
@@ -41,7 +41,7 @@
</div>
</div>
</div>
<div class="col-4 p-r-0">
<div class="col p-r-0">
<div class="btn btn-xs btn-outline-primary btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="currencyDropdownLaunch.status = ! currencyDropdownLaunch.status">
<div class="row">
<div class="col p-t-5 p-b-5">
@@ -75,11 +75,46 @@
</div>
</div>
</div>
<div class="row m-t-5">
<div class="col p-r-0">
<div class="btn btn-xs btn-outline-primary btn-block text-left b-rad-none p-t-0 p-b-0 p-l-15 p-r-15" @click="selectedSupplier.status = !selectedSupplier.status">
<div class="row">
<div class="col p-t-5 p-b-5 fs-9">
{{selectedSupplier.name}}
</div>
<div class="col-auto b-l b-success">
<div class="row h-100 align-items-center">
<div class="col">
<i class="fa" :class="[{'fa-angle-down': !selectedSupplier.status}, {'fa-angle-up': selectedSupplier.status}]"></i>
</div>
</div>
</div>
</div>
</div>
<div class="relative w-100">
<div class="absolute w-100 b-l b-b b-r b-primary" :class="[{'hide': !selectedSupplier.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" v-for="supplier in suppliers" v-bind:key="supplier.id" :data="supplier">
<div class="col b-b b-grey p-t-10 p-b-10 pointer hover-t-10 p-b-10" :class="[{'bg-primary-light': selectedSupplier.id === supplier.id}, {'text-white': selectedSupplier.id === supplier.id}, {'hover-primary': selectedSupplier.id !== supplier.id}, {'pointer': selectedSupplier.id !== supplier.id}]" @click="updateSupplier(supplier)">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="font-heading fs-10">{{supplier.name}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 10000, status: 2, type: 1, original_currency_id_in: [selectedCurrency.id]}">
<list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 10000, status: 2, type: 1, original_currency_id_in: [selectedCurrency.id], service_type_id_in: [selectedService.id]}">
<template slot="list" slot-scope="{data}">
<supplier-pending-order-component :data="data" v-on:input="updateOrder($event)"></supplier-pending-order-component>
</template>
@@ -87,7 +122,7 @@
</div>
</div>
</div>
<div class="col">
<div class="col-12 col-md">
<supplier-place-order-form-component :payments="payments" :currency="selectedCurrency" :supplier="selectedSupplier" section="pendingOrdersSection"></supplier-place-order-form-component>
<div class="row m-t-20">
<div class="col">
@@ -124,6 +159,14 @@
currencyDropdownLaunch: {
status: false
},
serviceDropdownLaunch: {
status: false
},
selectedService: {
id: 1,
name: '',
status: false
},
payments: []
}
},
@@ -135,6 +178,7 @@
this.suppliers = response.payload.data;
this.updateSupplier(this.suppliers[0]);
this.updateCurrency(this.suppliers[0].currencies[0]);
this.updateService(this.suppliers[0].services[0]);
},
updateSupplier(supplier){
this.selectedSupplier = supplier;
@@ -151,6 +195,10 @@
this.payments = [];
},
updateService(service){
this.selectedService = service;
this.serviceDropdownLaunch.status = false;
},
updateOrder(payment){
this.payments.includes(payment) ? this.payments.splice(this.payments.indexOf(payment), 1) : this.payments.push(payment);
}
@@ -8,6 +8,7 @@
<thead>
<tr>
<th style="width:20%">Date</th>
<th style="width:20%">Label</th>
<th style="width:20%">Reference</th>
<th style="width:29%">Marking</th>
<th style="width:15%">Amount</th>
@@ -1,6 +1,6 @@
<template>
<div class="row m-b-15 align-items-end">
<div class="col">
<div class="col-auto">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Marking</div>
@@ -12,7 +12,7 @@
</div>
</div>
</div>
<div class="col-3 text-center">
<div class="col-2 text-center">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Payments</div>
@@ -25,6 +25,30 @@
</div>
</div>
<div class="col-2 text-center">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Average Daily Spending</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading fs-11">MYR {{(Math.round((this.item.average_spending_per_day + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
</div>
<div class="col-2 text-center">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Average Booking Spending</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading fs-11">MYR {{(Math.round((this.item.average_spending_per_booking + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
</div>
<div class="col-auto text-center">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Last Payment</div>
@@ -36,7 +60,7 @@
</div>
</div>
</div>
<div class="col-2 text-center">
<div class="col-auto text-center">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Bookings</div>
@@ -44,7 +68,7 @@
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-11">{{this.item.bookings.length}}</div>
<div class="font-heading all-caps fs-11"><span v-if="item.confirmed_bookings">{{this.item.confirmed_bookings}} / </span>{{this.item.bookings.length}}</div>
</div>
</div>
</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>
@@ -3,6 +3,40 @@
<div class="col">
<div class="row">
<div class="col-12 col-md-10 ">
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row" style="background-image: url('/images/—Pngtree—2019 chinese new year lantern_951828.jpg'); background-size: cover;">
<div class="col no-padding">
<div class="text-white text-center p-t-25 p-l-25 p-r-25" style="background-color: rgba(0,0,0,0.4);">
<div class="row">
<div class="col">
<div class="row m-b-20">
<div class="col">
<p class="m-b-0">新年快乐</p>
<p class="m-b-15">CIEF祝您春节快乐万事如意财运亨通虎虎生威<br>在此想通知您公司复工日期如下 :-</p>
<p class="m-b-15 bold">客服团队 2022年2月7日</p>
<p class="bold">* 假期期间 Exchange 照常可以下单人民币复工之后就可以安排汇款</p>
</div>
</div>
<div class="row m-b-20">
<div class="col">
<p class="m-b-0">Happy Chinese New Year!</p>
<p class="m-b-15">CIEF wishes you a successful & prosperous Chinese New Year.. may your business prosper with every opportunity that comes your way. <br>We would like to also update you about our company's operation resume dates as below :-</p>
<p class="m-b-15 bold">Customer Service : 07 February 2022</p>
<p class="bold">* EXCHANGE bookings can be placed as usual during the holidays , RMB transfers will be arranged after operation resume.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<list-component style="min-height: auto;" section="customerAnnouncements" :emptyListSection=false :endpoint="route('api.announcement.list')" :options="{has_segments:true,is_published:true}">
<template slot="list" slot-scope="{data}">
<view-announcement-form-component :data="data" section="customerAnnouncements"></view-announcement-form-component>
@@ -10,8 +10,8 @@
</div>
<div class="row m-b-10">
<div class="col">
<div class="fs-12">Full Name</div>
<validation-wrapper-component :validator="$v.parameters.name">
<label>Full Name</label>
<input type="text" class="form-control" v-model="parameters.name">
</validation-wrapper-component>
</div>
@@ -1,11 +1,17 @@
@extends('layouts.base')
@section('content')
<div class="row d-md-none" v-if="$store.getters.isShowing('sideMenu')">
<div class="col absolute bg-master w-100 h-100" style="opacity: 0.3; z-index: 9998; left: 0px;"></div>
<div class="col-8 bg-master-lightest position-fixed h-100" style="z-index: 9999" >
@include('partials.menu')
</div>
</div>
@include('partials.header')
<div class="page-container">
<div class="page-content-wrapper p-b-50" style="padding-top: 70px;">
<div class="content pt-md-auto pt-4">
<div class="container-fluid p-l-30 p-r-30 container-fixed-lg">
<div class="container-fluid p-0 px-sm-5 container-fixed-lg">
<div class="row no-margin">
<div class="col">
@yield('inner_content')

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