Merge branch 'master' into dillon/34.3-jenkins-vapor

This commit is contained in:
Dillon Ngo
2024-05-17 14:55:01 +08:00
115 changed files with 5119 additions and 122 deletions
@@ -27,7 +27,7 @@ abstract class AbstractRule
public function passes(?DataTransferObject $object = null): bool {
try {
if(!$this->authorized()){
throw new AccessForbiddenException('You don\'t have permission to preform this action');
throw new AccessForbiddenException('You don\'t have permission to perform this action');
}
$this->validators($object);
@@ -36,7 +36,7 @@ abstract class AbstractRule
return true;
} catch(AccessForbiddenException $exception){
throw new AccessForbiddenException('You don\'t have permission to preform this action');
throw new AccessForbiddenException('You don\'t have permission to perform this action');
} catch(\Exception $exception){
throw new RequestValidationException($exception->getMessage());
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class CurrencyRateIsNotEqual implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('currency_rate', '!=', $value);
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Database\Eloquent\Builder;
class HasPendingVerifyTransaction implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('transactions', function ($q) {
$q->where('status', ApprovalStatus::PENDING_VERIFICATION);
});
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class IsPartialRefund implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('owner', function ($q) use ($value) {
if ($value) {
$q->where('original_amount', '!=', DB::raw('transactions.original_amount'));
} else {
$q->where('original_amount', DB::raw('transactions.original_amount'));
}
});
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class OwnerDoesNotHaveTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereDoesntHave('owner', function($query) use($value) {
return $query->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
});
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class OwnerHasTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('owner', function($query) use($value) {
return $query->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
});
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class ReceiverIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereIn('receiver', $value);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class WithoutBillGroup implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereDoesntHave('billGroup');
}
}
@@ -0,0 +1,13 @@
<?php
namespace App\Classes\General\Interfaces;
use Illuminate\Database\Eloquent\Relations\MorphMany;
interface Remarkable
{
public function remarks(): morphMany;
}
@@ -14,11 +14,14 @@ 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\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Transactions\ControllersLogic\UpdateRefundTransactionStatusLogic;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionRefundCalculationObject;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor;
class CreateBookingRefundLogic extends AbstractControllerLogic
{
@@ -48,6 +51,12 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
/** @var CreatesTransaction */
private $createsTransaction;
/** @var UpdateRefundTransactionStatusLogic */
private $updateRefundTransactionStatusLogic;
/** @var CreateRemarkProcessor */
private $createRemarkProcessor;
/**
* CreateBookingPaymentLogic constructor.
* @param FetchesBookingQuotation $fetchBookingQuotation
@@ -55,14 +64,18 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param UpdateRefundTransactionStatusLogic $updateRefundTransactionStatusLogic
* @param CreateRemarkProcessor $createRemarkProcessor
*/
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, UpdateRefundTransactionStatusLogic $updateRefundTransactionStatusLogic, CreateRemarkProcessor $createRemarkProcessor)
{
$this->fetchBookingQuotation = $fetchBookingQuotation;
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->updateRefundTransactionStatusLogic = $updateRefundTransactionStatusLogic;
$this->createRemarkProcessor = $createRemarkProcessor;
}
/**
@@ -75,12 +88,14 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('payment_id')]);
if ($transaction->transactions()->bills()->first()) {
throw new MalformedRequestException('Booking under white form cannot request for refund');
}
$booking = $transaction->owner;
$invoice = $booking->transactions()->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first();
if(auth()->user()->type === 3) {
throw new MalformedRequestException('You do not have the permission to refund the order.');
}
$billNumber = $this->generatesTransactionBillNumber->execute('RFD-');
$refund = $transaction->transactions()->refunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->sum('original_amount');
@@ -92,7 +107,8 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$refundAmount = bcdiv($request->input('amount'), $transaction->currency_rate, 7);
// refund service charges if is fully refund
$refundTotal = ($refund + $request->input('amount')) == $transaction->original_amount ? $refundAmount + $transaction->service_charge + $transaction->tax : $refundAmount;
$isFullyRefund = ($refund + $request->input('amount')) == $transaction->original_amount;
$refundTotal = $isFullyRefund ? $refundAmount + $transaction->service_charge + $transaction->tax : $refundAmount;
$object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id,
1, PaymentMethodType::CASH,
@@ -100,9 +116,35 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$transaction->original_currency_id, $transaction->currency_rate,
0, 0, null, ApprovalStatus::PENDING_VERIFICATION, [], $transaction->bill_no);
$transaction = $this->createsTransaction->execute($transaction, $object);
$refund_transaction = $this->createsTransaction->execute($transaction, $object);
return $this->resourceResponse(new TransactionResource($transaction));
$bookingInWhiteForm = $transaction->transactions()->bills()->first();
// create supplier refund
if ($bookingInWhiteForm) {
$billNumber = $this->generatesTransactionBillNumber->execute('SRFD-');
$supplierRefundTotal = bcdiv($request->input('amount'), $bookingInWhiteForm->currency_rate, 7);
$object = new TransactionObject($billNumber, TransactionType::SUPPLIER_REFUND, 1, $bookingInWhiteForm->issuer,
1, PaymentMethodType::CASH,
$supplierRefundTotal, $request->input('amount'), 1,
$transaction->original_currency_id, $bookingInWhiteForm->currency_rate,
0, 0, null, ApprovalStatus::PENDING_VERIFICATION, [], $transaction->bill_no);
$transaction = $this->createsTransaction->execute($transaction, $object);
} else {
$request->route()->setParameter('id', $refund_transaction->id);
$request->route()->setParameter('status', ApprovalStatus::APPROVED);
$this->updateRefundTransactionStatusLogic->execute($request);
}
if($request->input('refundRemark')){
$remarkObject = new RemarkObject($request->input('refundRemark'), Auth()->user()->id);
$this->createRemarkProcessor->execute($this->fetchesTransaction->execute(['id' => $refund_transaction->id]), $remarkObject);
}
return $this->resourceResponse(new TransactionResource($refund_transaction));
}
@@ -45,7 +45,7 @@ class ExpireBookingPaymentControllerLogic extends AbstractControllerLogic
$booking = $this->fetchesBooking->execute(['id' => $request->route('id')]);
$payment = $booking->transactions()
->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->payments()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->first();
$payment->status = ApprovalStatus::EXPIRED;
@@ -81,7 +81,7 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic
$minimum_amount = $booking->fix_amount - $this->calculatesBookingOutstanding->execute($booking);
if ((float)$input_amount < $minimum_amount) {
if (((float)$input_amount + 0.01) < (float)$minimum_amount) {
throw new MalformedRequestException('Booking Amount cannot be less than '. $minimum_amount .'.');
}
@@ -24,10 +24,22 @@ class CalculatesBookingCurrencyAverageRate
public function execute(Booking $booking, $type){
$transaction = $booking->transactions()
->where('type', TransactionType::PAYMENT)
->latest()->get()[0];
$voucherRedemption = $transaction->voucherRedemption;
$discount = 0;
if ($voucherRedemption) {
$discount = $voucherRedemption->value;
}
if ($type == TransactionType::PAYMENT) {
$totalPayment = $booking->fix_currency_id === 1 ? $booking->transactions()->payments()->complete()->sum('original_amount') :
$booking->transactions()->payments()->complete()->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
return $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id) / $totalPayment;
return $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id) / ($totalPayment + $discount);
}
else if ($type == TransactionType::BILL) {
@@ -13,20 +13,25 @@ class CalculatesBookingOutstanding
/** @var CalculatesBookingFloatingAmount */
private $calculatesBookingFloatingAmount;
/** @var CalculatesBookingRefundAmount */
private $calculatesBookingRefundAmount;
/**
* CalculatesBookingOutstanding constructor.
* @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount
* @param CalculatesBookingFloatingAmount $calculatesBookingFloatingAmount
* @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount
*/
public function __construct(CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingFloatingAmount $calculatesBookingFloatingAmount)
public function __construct(CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingFloatingAmount $calculatesBookingFloatingAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount)
{
$this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount;
$this->calculatesBookingFloatingAmount = $calculatesBookingFloatingAmount;
$this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount;
}
public function execute(Booking $booking){
return $booking->fix_amount - $this->calculatesBookingFloatingAmount->execute($booking, $booking->fix_currency_id) - $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id);
return $booking->fix_amount - $this->calculatesBookingFloatingAmount->execute($booking, $booking->fix_currency_id) - $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id) + $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id);
}
}
@@ -9,7 +9,7 @@ class CalculatesBookingRefundAmount
{
public function execute(Booking $booking, int $type, ?string $payment_reference = null): float
{
$refundAmounts = $booking->transactions()->payments()->get()->map(function ($payment) use ($type) {
$refundAmounts = $booking->transactions()->payments()->complete()->get()->map(function ($payment) use ($type) {
return $this->calculateRefundAmount($payment, $type);
});
@@ -13,7 +13,7 @@ class CalculatesBookingTransferredAmount
public function execute(Booking $booking){
return $booking->transactions()->payments()->complete()->whereHas('transactions', function($query){
return $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
return $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->where('type', TransactionType::BILL);
})->sum('original_amount');
}
@@ -19,7 +19,31 @@ class GeneratesBookingQuotation
$hours = $date->diffInHours($date->copy()->addMinutes($paymentAttemptLimit)->subDays($days)) ;
$minutes = $date->diffInMinutes($date->copy()->addMinutes($paymentAttemptLimit)->subDays($days)->subHours($hours));
$receive_date = $currencyConversionObject ? Carbon::now()->endOfDay()->addWeekdays($currencyConversionObject->getServiceId() === 3 ? 3 : 1)->timezone('Asia/Singapore')->format('4:00 \P\M, jS M, Y \G\M\T T') : null;
// Initialize $receive_date to null by default
$receive_date = null;
if ($currencyConversionObject) {
$serviceId = $currencyConversionObject->getServiceId();
switch ($serviceId) {
case 3:
$daysToAdd = 3;
break;
case 5:
$daysToAdd = 7;
break;
default:
$daysToAdd = 1;
break;
}
$receive_date = Carbon::now()
->endOfDay()
->addWeekdays($daysToAdd)
->timezone('Asia/Singapore')
->format('4:00 \P\M, jS M, Y \G\M\T T');
}
return [
'bank' => new BankResource(Bank::find($calculationObject->getConfigurations()->getBankId())),
@@ -0,0 +1,99 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Group;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Illuminate\Http\Request;
use Carbon\Carbon;
class ExportsWhiteFormTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
private $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function headings(): array
{
return [
'Bank Name',
'Bank Details',
'Bank Acc No.',
'Order amount',
'Booking Reference',
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
$start_date = $this->request->input('startDate', null);
if ($start_date) {
$start_date = Carbon::parse($this->request->input('startDate'))->format('Y-m-d');
}
$end_date = $this->request->input('endDate', null);
if ($end_date) {
$end_date = Carbon::parse($this->request->input('endDate'))->format('Y-m-d');
}
$query = Group::query();
// todo-new: confirm this
// $query->where('type', ::PAYMENT)->where('payment_method', '!=', PaymentMethodType::WALLET);
// $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
if ($start_date && $end_date) {
$query->whereBetween('created_at', [
Carbon::parse($start_date)->format('Y-m-d 0:00:00'),
Carbon::parse($end_date)->format('Y-m-d 23:59:59')
]);
} elseif ($start_date && !$end_date) {
$query->where('created_at', '>=', Carbon::parse($start_date)->format('Y-m-d 0:00:00'));
} elseif (!$start_date && $end_date) {
$query->where('created_at', '<=', Carbon::parse($end_date)->format('Y-m-d 23:59:59'));
}
return $query;
}
/**
* @param Company $group
*
* @return array
*/
public function map($group): array
{
$supplier = $group->issuerCompany;
$supplerBank = $supplier->banks->first();
$bank_name = $supplerBank->bank_name;
$holder_name = $supplerBank->holder_name;
$account_no = $supplerBank->account_no;
$bookingReference = $group->transactions()->get()->pluck('owner.owner.marking')->toArray();
return [
$bank_name,
$holder_name,
$account_no,
$group->amount,
implode(",", $bookingReference)
];
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Classes\Modules\Remarks\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Classes\Exceptions\MalformedRequestException;
use App\Http\Resources\RemarkResource;
class CreateRemarkLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Created Remark',
'message' => 'You have successfully created a new Remark'
];
}
/** @var CreateRemarkProcessor */
private $createRemarkProcessor;
/**
* CreateRemarkLogic constructor.
* @param CreateRemarkProcessor $createRemarkProcessor
*/
public function __construct(CreateRemarkProcessor $createRemarkProcessor)
{
$this->createRemarkProcessor = $createRemarkProcessor;
}
/**
* @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
{
$classs = '\\App\\Models\\' . Str::studly($request->input('model_type'));
if (!class_exists($classs)) {
throw new MalformedRequestException('Unable to process this entity');
}
$remarkOwner = $classs::find($request->route('id'));
$remarkObject = new RemarkObject($request->input('content'), auth()->user()->id);
$remmark = $this->createRemarkProcessor->execute($remarkOwner, $remarkObject);
return $this->resourceResponse(new RemarkResource($remmark));
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Classes\Modules\Remarks\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Remarks\Services\DeletesRemark;
use App\Classes\Modules\Remarks\Services\FetchesRemark;
use App\Classes\Modules\Remarks\Standards\Rules\CanDeleteRemark;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeleteRemarkLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Deleted Remark',
'message' => 'You have successfully deleted a Remark'
];
}
/** @var CanDeleteRemark */
private $canDeleteRemark;
/** @var DeletesRemark */
private $deletesRemark;
/** @var FetchesRemark */
private $fetchesRemark;
/**
* DeleteRemarkControllersLogic constructor.
* @param CanDeleteRemark $canDeleteRemark
* @param DeletesRemark $deletesRemark
* @param FetchesRemark $fetchesRemark
*/
public function __construct(CanDeleteRemark $canDeleteRemark, DeletesRemark $deletesRemark, FetchesRemark $fetchesRemark)
{
$this->canDeleteRemark = $canDeleteRemark;
$this->deletesRemark = $deletesRemark;
$this->fetchesRemark = $fetchesRemark;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canDeleteRemark->passes();
$query = $this->fetchesRemark->execute(['id' => $request->route('id')]);
$this->deletesRemark->execute($query);
return $this->response([]);
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Remarks\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Remarks\Services\FetchesRemark;
use App\Classes\Modules\Remarks\Standards\Rules\CanFetchRemark;
use App\Http\Resources\RemarkResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchRemarkLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Remark',
'message' => 'You have successfully retrieved a Remark'
];
}
/** @var CanFetchRemark */
private $canFetchRemark;
/** @var FetchesRemark */
private $fetchesRemark;
/**
* FetchRemarkControllersLogic constructor.
* @param CanFetchRemark $canFetchRemark
* @param FetchesRemark $fetchesRemark
*/
public function __construct(CanFetchRemark $canFetchRemark, FetchesRemark $fetchesRemark)
{
$this->canFetchRemark = $canFetchRemark;
$this->fetchesRemark = $fetchesRemark;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchRemark->passes();
$query = $this->fetchesRemark->execute(['id' => $request->route('id')]);
return $this->resourceResponse(new RemarkResource($query));
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Remarks\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Remarks\Services\ListsRemarks;
use App\Classes\Modules\Remarks\Standards\Rules\CanListRemarks;
use App\Http\Resources\RemarkResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListRemarksLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Remarks',
'message' => 'You have successfully retrieved a list of Remarks'
];
}
/** @var CanListRemarks */
private $canListRemarks;
/** @var ListsRemarks */
private $listsRemarks;
/**
* ListRemarksLogic constructor.
* @param CanListRemarks $canListRemarks
* @param ListsRemarks $listsRemarks
*/
public function __construct(CanListRemarks $canListRemarks, ListsRemarks $listsRemarks)
{
$this->canListRemarks = $canListRemarks;
$this->listsRemarks = $listsRemarks;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListRemarks->passes();
$query = $this->listsRemarks->execute($this->listsRemarks->deserializeFilters($request->input('filters')));
return $this->collectionResponse(RemarkResource::collection($query));
}
}
@@ -0,0 +1,71 @@
<?php
namespace App\Classes\Modules\Remarks\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Remarks\Services\UpdatesRemark;
use App\Classes\Modules\Remarks\Services\FetchesRemark;
use App\Classes\Modules\Remarks\Standards\Rules\CanUpdateRemark;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Http\Resources\RemarkResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateRemarkLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated Remark',
'message' => 'You have successfully updated the Remark'
];
}
/** @var CanUpdateRemark */
private $canUpdateRemark;
/** @var UpdatesRemark */
private $updatesRemark;
/** @var FetchesRemark */
private $fetchesRemark;
/**
* UpdateRemarkLogic constructor.
* @param CanUpdateRemark $canUpdateRemark
* @param UpdatesRemark $updatesRemark
* @param FetchesRemark $fetchesRemark
*/
public function __construct(CanUpdateRemark $canUpdateRemark, UpdatesRemark $updatesRemark, FetchesRemark $fetchesRemark)
{
$this->canUpdateRemark = $canUpdateRemark;
$this->updatesRemark = $updatesRemark;
$this->fetchesRemark = $fetchesRemark;
}
/**
* @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
{
$object = new RemarkObject($request->input('content'), auth()->user()->id);
$this->canUpdateRemark->passes($object);
$query = $this->fetchesRemark->execute(['id' => $request->route('id')]);
$query = $this->updatesRemark->execute($query, $object);
return $this->resourceResponse(new RemarkResource($query));
}
}
@@ -0,0 +1,38 @@
<?php
namespace App\Classes\Modules\Remarks\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class RemarkObject implements DataTransferObject
{
/** @var int */
private $commenterID;
/** @var string*/
private $content;
public function __construct(string $content, int $commenterID)
{
$this->commenterID = $commenterID;
$this->content = $content;
}
/**
* @return int
*/
public function getCommenterId(): string
{
return $this->commenterID;
}
/**
* @return string
*/
public function getContent(): ?string
{
return $this->content;
}
}
@@ -0,0 +1,47 @@
<?php
namespace App\Classes\Modules\Remarks\Processors;
use App\Classes\General\Interfaces\Remarkable;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Services\CreatesRemark;
use App\Classes\Modules\Remarks\Standards\Rules\CanCreateRemark;
class CreateRemarkProcessor
{
/** @var CreatesRemark */
private $createsRemark;
/** @var CanCreateRemark */
private $canCreateRemark;
/**
* CreateRemarkProcessor constructor.
* @param CreatesRemark $createsRemark
* @param CanCreateRemark $canCreateRemark
*/
public function __construct(CreatesRemark $createsRemark, CanCreateRemark $canCreateRemark)
{
$this->createsRemark = $createsRemark;
$this->canCreateRemark = $canCreateRemark;
}
/**
* @param Remarkable $remarkable
* @param RemarkObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function execute(Remarkable $remarkable, RemarkObject $object){
$this->canCreateRemark->passes($object);
return $this->createsRemark->execute($remarkable, $object);
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Modules\Remarks\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\General\Interfaces\Remarkable;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Models\Container;
use App\Models\Remark;
use App\Models\User;
class CreatesRemark extends AbstractUpdateRelationshipRecord
{
/**
* @param Remarkable $remarkable
* @param RemarkObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Remarkable $remarkable, RemarkObject $object) {
$model = new Remark();
$model->commenter_id = $object->getCommenterId();
$model->content = $object->getContent();
return $this->handler($remarkable->remarks(), $model);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\Modules\Remarks\Services;
use App\Classes\General\Eloquent\AbstractDeleteRecord;
use App\Models\Remark;
class DeletesRemark extends AbstractDeleteRecord
{
/**
* @param Remark $model
* @return mixed
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Remark $model) {
return $this->handler($model);
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Classes\Modules\Remarks\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Remark;
class FetchesRemark extends AbstractFetchRecord
{
/** @var Remark */
private $repository;
/**
* FetchesRemark constructor.
* @param Remark $repository
*/
public function __construct(Remark $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Classes\Modules\Remarks\Services;
use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Remark;
class ListsRemarks extends AbstractListRecord
{
/** @var Remark */
private $repository;
/**
* ListsRemarks constructor.
* @param Remark $repository
*/
public function __construct(Remark $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Classes\Modules\Remarks\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Models\Remark;
class UpdatesRemark extends AbstractUpdateRecord
{
/**
* @param Remark $model
* @param RemarkObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Remark $model, RemarkObject $object) {
$model->commenter_id = $object->getCommenterId();
$model->content = $object->getContent();
return $this->handler($model);
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Standards\Validators\RemarkValidation;
class CanCreateRemark extends AbstractRule
{
/** @var RemarkValidation */
private $RemarkValidation;
/**
* CanCreateRemark constructor.
* @param RemarkValidation $RemarkValidation
*/
public function __construct(RemarkValidation $RemarkValidation)
{
$this->RemarkValidation = $RemarkValidation;
}
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param RemarkObject $object
* @return bool
* @throws \App\Classes\Exceptions\RequestValidationException
*/
protected function validators($object): bool
{
return $this->RemarkValidation->validate($object);
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
class CanDeleteRemark extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
class CanFetchRemark extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
class CanListRemarks extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Standards\Validators\RemarkValidation;
class CanUpdateRemark extends AbstractRule
{
/** @var RemarkValidation */
private $RemarkValidation;
/**
* CanUpdateRemark constructor.
* @param RemarkValidation $RemarkValidation
*/
public function __construct(RemarkValidation $RemarkValidation)
{
$this->RemarkValidation = $RemarkValidation;
}
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param RemarkObject $object
* @return bool
* @throws \App\Classes\Exceptions\RequestValidationException
*/
protected function validators($object): bool
{
return $this->RemarkValidation->validate($object);
}
/**
* @param RemarkObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,41 @@
<?php
namespace App\Classes\Modules\Remarks\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
class RemarkValidation extends AbstractValidation
{
/**
* @param RemarkObject $object
* @return array
*/
protected function data($object): array {
return [
'commenter_id' => $object->getCommenterId(),
'content' => $object->getContent(),
];
}
/**
* @return array
*/
protected function rules(): array {
return [
'commenter_id' => 'required',
'content' => 'required',
];
}
/**
* @return array
*/
protected function messages(): array {
return [];
}
}
@@ -0,0 +1,93 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\Services\ApprovesDocument;
use App\Classes\Modules\Documents\Services\RejectsDocument;
use App\Classes\Modules\Transactions\Services\CalculatesBillGroupPaymentAmount;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ApproveBillGroupPaymentVerificationLogic extends AbstractControllerLogic
{
/**
* ApproveBillGroupPaymentVerificationLogic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param ApprovesDocument $approvesDocument
* @param RejectsDocument $rejectsDocument
* @param CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount
*/
public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, ApprovesDocument $approvesDocument, RejectsDocument $rejectsDocument, CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->approvesDocument = $approvesDocument;
$this->rejectsDocument = $rejectsDocument;
$this->calculatesBillGroupPaymentAmount = $calculatesBillGroupPaymentAmount;
}
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Payment Status',
'message' => 'You have successfully updated the payment status'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var ApprovesDocument */
private $approvesDocument;
/** @var RejectsDocument */
private $rejectsDocument;
/** @var CalculatesBillGroupPaymentAmount */
private $calculatesBillGroupPaymentAmount;
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$status = $request->route('status');
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
$status === 'approve' ? $this->approvesDocument->execute($transaction->documents()->first()) : $this->rejectsDocument->execute($transaction->documents()->first());
$this->updatesTransactionStatus->execute($transaction, $status === 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
$billGroup = $transaction->owner;
$billGroupPayment = $this->calculatesBillGroupPaymentAmount->execute($billGroup);
if ($status === 'reject') {
$billGroup->status = ApprovalStatus::PENDING_SUBMISSION;
$billGroup->save();
} else {
if ($billGroupPayment['outstanding_amount'] <= 0 && $billGroupPayment['floating_amount'] <= 0) {
$billGroup->status = ApprovalStatus::APPROVED;
$billGroup->save();
}
}
return $this->response([]);
}
}
@@ -0,0 +1,94 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Transactions\Services\CalculatesBillGroupPaymentAmount;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Document;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateBillGroupPaymentProofDocumentLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Payment Proof Document',
'message' => 'You have successfully submitted your payment proof document'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFile;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CalculatesBillGroupPaymentAmount */
private $calculatesBillGroupPaymentAmount;
/**
* CreateBillGroupPaymentProofDocumentLogic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount
*/
public function __construct(FetchesTransaction $fetchesTransaction, CreatesDocument $createsDocument, CreatesFiles $createsFile, UpdatesTransactionStatus $updatesTransactionStatus, CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->calculatesBillGroupPaymentAmount = $calculatesBillGroupPaymentAmount;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
$object = new DocumentObject(DocumentType::BILL_GROUP_PAYMENT_PROOF, $request->input('files'), '', ApprovalStatus::PENDING_VERIFICATION, 'bill_group_payments');
/** @var Document $document */
$document = $this->createsDocument->execute($transaction, $object);
$this->createsFile->execute($document, $object);
$this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_VERIFICATION);
$billGroup = $transaction->owner;
$billGroupPayment = $this->calculatesBillGroupPaymentAmount->execute($billGroup);
if ($billGroupPayment['outstanding_amount'] <= 0 && $billGroup->transactions()->where('status', ApprovalStatus::PENDING_SUBMISSION)->count() === 0) {
$billGroup->status = ApprovalStatus::PENDING_VERIFICATION;
$billGroup->save();
}
return $this->response([]);
}
}
@@ -0,0 +1,95 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\CalculatesBillGroupPaymentAmount;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\FetchesBillGroup;
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\Http\Resources\BillGroupResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateBillGroupPaymentTransactionLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Create Bill Group Payment Transaction',
'message' => 'You have successfully created payment for this Bill Group'
];
}
/** @var FetchesBillGroup */
private $fetchesBillGroup;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CalculatesBillGroupPaymentAmount */
private $calculatesBillGroupPaymentAmount;
/**
* CreateBillGroupPaymentTransactionLogic constructor.
* @param FetchesBillGroup $fetchesBillGroup
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount
*/
public function __construct(FetchesBillGroup $fetchesBillGroup, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBillGroupPaymentAmount $calculatesBillGroupPaymentAmount)
{
$this->fetchesBillGroup = $fetchesBillGroup;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->calculatesBillGroupPaymentAmount = $calculatesBillGroupPaymentAmount;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$billGroup = $this->fetchesBillGroup->execute(['id' => $request->route('id')]);
$billGroupPayment = $this->calculatesBillGroupPaymentAmount->execute($billGroup);
$outstanding_amount = $billGroupPayment['outstanding_amount'];
if ($billGroupPayment['outstanding_amount'] <= 0) {
if ($billGroup->transactions()->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->count() !== 0) {
throw new MalformedRequestException('Invalid bill group, payment transaction already exist.');
}
}
$payAmount = floatval(str_replace(',', '', $request->input('payAmount')));
if($payAmount > round($outstanding_amount, 2)) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding_amount .'.');
if ($billGroupPayment['outstanding_amount'] == 0 && $payAmount == 0) {
$billGroup->status = ApprovalStatus::APPROVED;
$billGroup->save();
} else {
$billNumber = $this->generatesTransactionBillNumber->execute('SPLR-PYMT-');
$transaction_object = new TransactionObject($billNumber, TransactionType::SUPPLIER_PAYMENT, $billGroup->issuer,
$billGroup->receiver, $billGroup->issuerCompany->banks()->where('default', true)->first()->id, PaymentMethodType::CASH,
$payAmount, $payAmount, 1, 1, 1,
0, 0, null, ApprovalStatus::PENDING_SUBMISSION, [], '');
$this->createsTransaction->execute($billGroup, $transaction_object);
}
return $this->resourceResponse(new BillGroupResource($billGroup));
}
}
@@ -0,0 +1,195 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Transactions\Processors\CreateSupplierTransactionProcessor;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Models\Document;
use App\Models\Group;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\BillGroup;
use App\Models\Transaction;
class CreateSupplierBillGroupLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Create Supplier White Form Order',
'message' => 'You have successfully created currency supplier white form order'
];
}
/** @var FetchesCompany */
private $fetchesCompany;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFile;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var UpdateGroupLogic */
private $updateGroupLogic;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/**
* CreateSupplierBillGroupLogic constructor.
* @param FetchesCompany $fetchesCompany
* @param CreatesTransaction $createsTransaction
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param UpdateGroupLogic $updateGroupLogic
* @param UpdatesTransactionStatus $updatesTransactionStatus
*/
public function __construct(FetchesCompany $fetchesCompany, CreatesTransaction $createsTransaction, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber, UpdateGroupLogic $updateGroupLogic, UpdatesTransactionStatus $updatesTransactionStatus)
{
$this->fetchesCompany = $fetchesCompany;
$this->createsTransaction = $createsTransaction;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->updateGroupLogic = $updateGroupLogic;
$this->updatesTransactionStatus = $updatesTransactionStatus;
}
public function logic(Request $request) : JsonResponse
{
$supplier = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$payments = $request->input('payments');
$supplierRefunds = $request->input('supplierRefunds');
foreach ($supplierRefunds as $supplierRefund) {
$refund = Transaction::find($supplierRefund['id']);
if ($refund->owner->transactions()->where('type', TransactionType::BILL)->first()->issuer !== $supplier->id) {
throw new MalformedRequestException('The supplier refund and bill group does not belongs to same supplier.');
}
if ($refund->type !== TransactionType::SUPPLIER_REFUND) {
throw new MalformedRequestException('Only transaction type supplier refund can be used for bill refund.');
}
if ($refund->currency_rate == 1) {
throw new MalformedRequestException('Supplier refund with currecy rate 1 cannot be used for bill refund.');
}
}
$amount = 0;
$original_amount = 0;
foreach ($payments as $payment) {
$amount += round($payment['amount'], 2);
$original_amount += round($payment['original_amount'], 2);
}
$service_charges = 0;
if ($supplier->id === 4548 || $supplier->id === 2729) {
$amount = round(floatval(str_replace(',', '', $request->input('payment_total'))), 2);
} else {
$service_charges = round(floatval(str_replace(',', '', $request->input('service_charges'))), 2);
}
$rate = $original_amount / $amount;
if ($supplier->id === 4548 || $supplier->id === 2729) {
$request['rate'] = $rate;
$request['supplier_id'] = $supplier->id;
foreach ($payments as $payment) {
$request->route()->setParameter('id', $payment['id']);
$this->updateGroupLogic->execute($request);
}
}
$billGroup = new BillGroup();
$billGroup->issuer = $supplier->id;
$billGroup->receiver = 1;
$billGroup->reference = $this->generatesTransactionBillNumber->execute('BSPO-');
$billGroup->amount = $amount;
$billGroup->original_amount = $original_amount;
$billGroup->currency_id = 1;
$billGroup->original_currency_id = $payments[0]['original_currency']['id'];
$billGroup->currency_rate = $rate;
$billGroup->tax = 0;
$billGroup->service_charge = $service_charges;
$billGroup->status = ApprovalStatus::PENDING_SUBMISSION;
$billGroup->save();
foreach ($payments as $payment) {
$billGroup->groups()->sync($payment['id'], false);
}
//create bill refund
$amount += $service_charges;
foreach ($supplierRefunds as $supplierRefund) {
$refund = Transaction::find($supplierRefund['id']);
$deductedRefunds = $refund->transactions()->where('type', TransactionType::BILL_REFUND)->where('status', ApprovalStatus::APPROVED)->get();
$refundDeductableAmount = round(($refund->amount - $deductedRefunds->sum('amount')), 2);
$refundDeductableOriginalAmount = round(($refund->original_amount - $deductedRefunds->sum('original_amount')), 2);
$amount -= $refundDeductableAmount;
$original_amount -= $refundDeductableOriginalAmount;
if ($amount > 0) {
$deductedRefundAmount = $refundDeductableAmount;
$deductedRefundOriginalAmount = $refundDeductableOriginalAmount;
$this->updatesTransactionStatus->execute($refund, ApprovalStatus::COMPLETED);
}
if ($amount < 0) {
$deductedRefundAmount = $refundDeductableAmount + $amount;
$deductedRefundOriginalAmount = $refundDeductableOriginalAmount + $original_amount;
}
$billNumber = $this->generatesTransactionBillNumber->execute('BRFD-');
$object = new TransactionObject($billNumber, TransactionType::BILL_REFUND, $supplier->id, 1,
1, PaymentMethodType::CASH,
$deductedRefundAmount, $deductedRefundOriginalAmount, $refund->currency_id,
$refund->original_currency_id, $deductedRefundOriginalAmount / $deductedRefundAmount,
0, 0, null, ApprovalStatus::APPROVED, []);
$transaction = $this->createsTransaction->execute($refund, $object);
$billGroup->billRefunds()->sync($transaction->id, false);
}
return $this->response([]);
}
}
@@ -129,6 +129,10 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic
$service_charge += $row->service_charge;
}
$transferFee = (float)$this->createSupplierTransactionProcessor->getTransferTransactions()->sum('service_charge');
$original_amount += $transferFee;
$amount += $transferFee / $currency_rate;
$group->issuer = $issuer;
$group->receiver = $receiver;
$group->reference = $this->generatesTransactionBillNumber->execute('SPO-');
@@ -0,0 +1,83 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesBillGroup;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\BillGroupResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeleteBillGroupLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Delete Bill Group Transaction',
'message' => 'You have successfully deleted this Bill Group Transaction'
];
}
/** @var FetchesBillGroup */
private $fetchesBillGroup;
/** @var DeletesTransaction */
private $deletesTransaction;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/**
* DeleteBillGroupLogic constructor.
* @param FetchesBillGroup $fetchesBillGroup
* @param DeletesTransaction $deletesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
*/
public function __construct(FetchesBillGroup $fetchesBillGroup, DeletesTransaction $deletesTransaction, UpdatesTransactionStatus $updatesTransactionStatus)
{
$this->fetchesBillGroup = $fetchesBillGroup;
$this->deletesTransaction = $deletesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$billGroup = $this->fetchesBillGroup->execute(['id' => $request->route('id')]);
$transactions = $billGroup->transactions()->get();
foreach($transactions as $transaction) {
$this->deletesTransaction->execute($transaction);
}
$groups = $billGroup->groups()->get();
foreach($groups as $group) {
$billGroup->groups()->detach($group->id);
}
$billRefunds = $billGroup->billRefunds()->get();
foreach($billRefunds as $billRefund) {
$billGroup->billRefunds()->detach($billRefund->id);
$this->deletesTransaction->execute($billRefund);
$this->updatesTransactionStatus->execute($billRefund->owner, ApprovalStatus::APPROVED);
}
$billGroup->delete();
return $this->resourceResponse(new BillGroupResource($billGroup));
}
}
@@ -0,0 +1,42 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\ListsBillGroups;
use App\Http\Resources\BillGroupResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListBillGroupsLogic extends AbstractControllerLogic
{
/**
* ListTransactionsLogic constructor.
* @param ListsBillGroups $listsBillGroups
*/
public function __construct(ListsBillGroups $listsBillGroups)
{
$this->listsBillGroups = $listsBillGroups;
}
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Bill Groups',
'message' => 'You have successfully retrieved a list of bill groups'
];
}
/** @var ListsBillGroups */
private $listsBillGroups;
public function logic(Request $request) : JsonResponse
{
$query = $this->listsBillGroups->execute($this->listsBillGroups->deserializeFilters($request->input('filters')));
return $this->collectionResponse(BillGroupResource::collection($query));
}
}
@@ -125,6 +125,18 @@ class UpdateGroupLogic extends AbstractControllerLogic
$billTransaction = $this->updatesTransaction->execute($transaction, $object);
$supplierRefundTransactions = $transaction->owner->transactions()->supplierRefunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->get();
foreach ($supplierRefundTransactions as $supplierRefundTransaction) {
$claimBefore = $supplierRefundTransaction->transactions()->where('type', TransactionType::BILL_REFUND)->where('status', ApprovalStatus::APPROVED)->exists();
if (!$claimBefore) {
$supplierRefundTransaction->currency_rate = $rate;
$supplierRefundTransaction->amount = $supplierRefundTransaction->original_amount / $rate;
$supplierRefundTransaction->save();
}
}
$transferTransaction = $transaction->transactions()->where('type', TransactionType::TRANSFER_FEE)->first();
$transferFee = $this->calculatesTransactionTransferFee->execute($billTransaction->original_amount, $constant);
@@ -0,0 +1,101 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Http\Resources\GroupResource;
use App\Classes\Modules\Transactions\Services\FetchesGroup;
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\Transaction;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateGroupTransferFeeLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Update Group Transfer Fee',
'message' => 'You have successfully updated transfer fee for this Group Transaction'
];
}
/** @var FetchesGroup */
private $fetchesGroup;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/**
* UpdateGroupTransferFeeLogic constructor.
* @param FetchesGroup $fetchesGroup
* @param CreatesTransaction $createsTransaction
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
*/
public function __construct(FetchesGroup $fetchesGroup, CreatesTransaction $createsTransaction, GeneratesTransactionBillNumber $generatesTransactionBillNumber)
{
$this->fetchesGroup = $fetchesGroup;
$this->createsTransaction = $createsTransaction;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$group = $this->fetchesGroup->execute(['id' => $request->route('id')]);
$supplier = $group->issuerCompany;
$fee = $request->input('fee');
$transfer_fee = $group->morphTransactions()->where('type', TransactionType::TRANSFER_FEE)->first();
if ($transfer_fee) {
$transfer_fee->amount = $fee;
$transfer_fee->original_amount = $fee;
$transfer_fee->save();
} else {
$transferFeeNumber = $this->generatesTransactionBillNumber->execute('TRFR-');
$object = new TransactionObject($transferFeeNumber, TransactionType::TRANSFER_FEE, 1, $supplier->id,
$supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH,
$fee, $fee, $group->original_currency_id, $group->original_currency_id,
1, 0, 0, null, ApprovalStatus::APPROVED);
$model = new Transaction();
$model->bill_no = $object->getBillNo();
$model->type = $object->getTransactionType();
$model->issuer = $object->getIssuer();
$model->receiver = $object->getReceiver();
$model->recipient_bank_account_id = $object->getRecipientBankAccountId();
$model->payment_method = $object->getPaymentMethod();
$model->amount = $object->getAmount();
$model->original_amount = $object->getOriginalAmount();
$model->currency_id = $object->getCurrencyId();
$model->original_currency_id = $object->getOriginalCurrencyId();
$model->currency_rate = $object->getCurrencyRate();
$model->tax = $object->getTax();
$model->service_charge = $object->getServiceCharge();
$model->expires_on = $object->getExpiresOn();
$model->status = $object->getStatus();
$model->payment_reference = $object->getPaymentReference();
$group->morphTransactions()->save($model);
}
return $this->resourceResponse(new GroupResource($group));
}
}
@@ -2,8 +2,9 @@
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingAmountLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
@@ -15,7 +16,8 @@ use Illuminate\Http\Request;
use App\Classes\Modules\Wallets\Processors\CreditWalletProcessor;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Support\Facades\Auth;
class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
{
@@ -51,6 +53,9 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
/** @var CalculatesBookingRefundAmount */
private $calculatesBookingRefundAmount;
/** @var UpdateBookingAmountLogic */
private $updateBookingAmountLogic;
/**
* CreatePaymentVerificationDocumentLogic constructor.
* @param FetchesCompany $fetchesCompany
@@ -60,8 +65,9 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
* @param CreditWalletProcessor $creditWalletProcessor
* @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount
* @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount
* @param UpdateBookingAmountLogic $updateBookingAmountLogic
*/
public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount)
public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount, UpdateBookingAmountLogic $updateBookingAmountLogic)
{
$this->fetchesCompany = $fetchesCompany;
$this->fetchesTransaction = $fetchesTransaction;
@@ -70,6 +76,7 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
$this->creditWalletProcessor = $creditWalletProcessor;
$this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount;
$this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount;
$this->updateBookingAmountLogic = $updateBookingAmountLogic;
}
/**
@@ -79,21 +86,43 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
if(auth()->user()->type === 3) {
throw new MalformedRequestException('You do not have the permission to refund the order.');
}
$refundTransaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
$refundTransaction = $this->updatesTransactionStatus->execute($refundTransaction, $request->route('status'));
$paymentTransaction = $refundTransaction->owner;
$supplierRefundTransaction = $paymentTransaction->transactions()->supplierRefunds()->where('status', [ApprovalStatus::PENDING_VERIFICATION])->first();
$booking = $paymentTransaction->owner;
$reference = $refundTransaction->amount == $paymentTransaction->amount ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking;
$reference = $refundTransaction->amount - $paymentTransaction->amount < 0.01 ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking;
$refundAmount = $this->calculatesBookingRefundAmount->calculateRefundAmount($paymentTransaction, $booking->fix_currency_id);
$paidAmount = $paymentTransaction->original_amount - $refundAmount;
if ($refundTransaction->status == ApprovalStatus::APPROVED) {
$this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference);
$po_transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
if ($po_transaction) {
$this->updatesTransactionStatus->execute($po_transaction, (float) number_format($po_transaction->amount, 2, '.', '') === (float) number_format((float)$booking->fix_amount - $refundTransaction->original_amount, 2, '.', '') ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::PENDING_SUBMISSION);
}
$request['fix_amount'] = $booking->fix_amount - $refundTransaction->original_amount;
$request->route()->setParameter('id', $booking->id);
$this->updateBookingAmountLogic->execute($request);
}
if ($supplierRefundTransaction) {
$this->updatesTransactionStatus->execute($supplierRefundTransaction, $request->route('status'));
}
$paidAmount = $paymentTransaction->original_amount - $this->calculatesBookingRefundAmount->calculateRefundAmount($paymentTransaction, $booking->fix_currency_id);
if (!$paidAmount > 0) {
$this->updatesTransactionStatus->execute($paymentTransaction, ApprovalStatus::REFUNDED);
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\BillGroup;
class CalculatesBillGroupPaymentAmount
{
public function execute(BillGroup $billGroup)
{
$bill_refund_amount = round(floatval($billGroup->billRefunds->sum('amount')), 7);
$floating_amount = round(floatval($billGroup->transactions()->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION])->sum('amount')), 7);
$paid_amount = round(floatval($billGroup->transactions()->where('status', ApprovalStatus::APPROVED)->sum('amount')), 7);
$outstanding_amount = $billGroup->amount - $bill_refund_amount - $paid_amount - $floating_amount + $billGroup->service_charge;
$outstanding_amount = round($outstanding_amount, 7);
return [
'bill_refund_amount' => $bill_refund_amount,
'floating_amount' => $floating_amount,
'paid_amount' => $paid_amount,
'outstanding_amount' => $outstanding_amount,
];
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use Illuminate\Database\Eloquent\Builder;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use App\Models\BillGroup;
class FetchesBillGroup extends AbstractFetchRecord
{
/** @var BillGroup */
private $repository;
/**
* FetchesBillGroup constructor.
* @param BillGroup $repository
*/
public function __construct(BillGroup $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Modules\Transactions\Services;
use Illuminate\Database\Eloquent\Builder;
use App\Classes\General\Eloquent\AbstractListRecord;
use App\Models\BillGroup;
class ListsBillGroups extends AbstractListRecord
{
/** @var BillGroup */
private $repository;
/**
* ListsBookings constructor.
* @param Group $repository
*/
public function __construct(BillGroup $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -25,4 +25,6 @@ final class DocumentType {
public const INVOICE = 'INVOICE';
public const SUPPLIER_DELIVER_ORDER = 'SUPPLIER_DELIVER_ORDER';
public const BULK_PURCHASE_ORDER = 'BULK_PURCHASE_ORDER';
public const BILL_GROUP_PAYMENT_PROOF = 'BILL_GROUP_PAYMENT_PROOF';
}
@@ -0,0 +1,13 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class RemarkTypes
{
public const INTERNAL = 0;
public const EXTERNAL = 1;
}
@@ -31,4 +31,11 @@ final class TransactionType {
public const TRANSFER_FEE = 12;
public const CASH_BACK = 13;
public const SUPPLIER_PAYMENT = 14;
public const SUPPLIER_REFUND = 15;
public const BILL_REFUND = 16;
}
@@ -95,7 +95,7 @@ class ExpiredRefundedBookingCommand extends Command
if (!$bookingPayment) {
$bookingPaymentCount = $booking->transactions()->payments()->count();
if ($bookingPaymentCount > 1) {
Log::info("Credit note transaction id: {$transaction->id}, there are {$bookingPaymentCount} payment for the booking.");
$this->info("Credit note transaction id: {$transaction->id}, there are {$bookingPaymentCount} payment for the booking.");
foreach ($booking->transactions()->payments()->get() as $bp) {
if ($transaction->amount - $bp->amount < 0.01) {
$bookingPayment = $bp;
@@ -107,55 +107,90 @@ class ExpiredRefundedBookingCommand extends Command
if (!$bookingPayment) {
$bookingPayment = $booking->transactions()->payments()->whereIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED, ApprovalStatus::REJECTED])->orderBy('id', 'DESC')->first();
}
}
if ($bookingPayment) {
$status = ApprovalStatus::APPROVAL_STATUS_ID[$bookingPayment->status];
Log::info("Credit note transaction id: {$transaction->id}, the payment for the booking is in status {$status}");
}
$bookingPaymentAmount = $bookingPayment->amount;
// check if the booking is fully refund
$amountDifference = bcsub($transaction->amount, $bookingPaymentAmount, 7);
$this->info("Credit note transaction id: {$transaction->id}, the payment for the booking is in status {$status}");
if (abs($amountDifference) < 0.01) {
// rejecting booking payment transaction
// $bookingPayment->status = ApprovalStatus::REJECTED;
// $bookingPayment->save();
//expired booking
// $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED);
Log::info("Credit note transaction id: {$transaction->id} is fully refunded, the refunded amount was {$transaction->amount} the payment reference is: {$transaction->payment_reference}");
// Log::info("Credit note transaction id: {$transaction->id}, Rejected Booking Transaction Payment id: {$bookingPayment->id}, the payment amount was {$bookingPayment->amount}");
// Log::info("Credit note transaction id: {$transaction->id}, Expired Booking id: {$booking->id}");
} else {
Log::info("Credit note transaction id: {$transaction->id} is not fully refunded, the refunded amount was {$transaction->amount}, the payment amount was {$bookingPayment->amount}, the payment reference is: {$transaction->payment_reference}");
}
$refund = $bookingPayment->transactions()->refunds()->where('amount', $transaction->amount)->where('status', ApprovalStatus::APPROVED)->first();
$bookingInWhiteForm = $bookingPayment->transactions()->bills()->first();
if ($refund) {
Log::info("Credit note transaction id: {$transaction->id}, already created same amount of refund transaction for same booking payment transaction");
}
if ($bookingInWhiteForm) {
Log::info("Credit note transaction id: {$transaction->id}, booking is in white form");
}
if (!$refund && !$bookingInWhiteForm) {
$billNumber = $this->generatesTransactionBillNumber->execute('RFD-');
$object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id,
1, PaymentMethodType::CASH,
$transaction->amount, $transaction->amount * $bookingPayment->currency_rate, 1,
$bookingPayment->original_currency_id, $bookingPayment->currency_rate,
0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);
$bookingPaymentAmount = $bookingPayment->amount;
// check if the booking is fully refund
$amountDifference = bcsub($transaction->amount, $bookingPaymentAmount, 7);
$transaction = $this->createsTransaction->execute($bookingPayment, $object);
$isFullyRefund = false;
if (abs($amountDifference) < 0.01) {
$isFullyRefund = true;
// update fully refunded booking payment transaction
$bookingPayment->status = ApprovalStatus::REFUNDED;
$bookingPayment->save();
//expired booking
// $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED);
$this->info("Credit note transaction id: {$transaction->id} is fully refunded, the refunded amount was {$transaction->amount} the payment reference is: {$transaction->payment_reference}");
// $this->info("Credit note transaction id: {$transaction->id}, Rejected Booking Transaction Payment id: {$bookingPayment->id}, the payment amount was {$bookingPayment->amount}");
// $this->info("Credit note transaction id: {$transaction->id}, Expired Booking id: {$booking->id}");
} else {
$this->info("Credit note transaction id: {$transaction->id} is not fully refunded, the refunded amount was {$transaction->amount}, the payment amount was {$bookingPayment->amount}, the payment reference is: {$transaction->payment_reference}");
}
$refund = $bookingPayment->transactions()->refunds()->where('amount', $transaction->amount)->where('status', ApprovalStatus::APPROVED)->first();
$bookingInWhiteForm = $bookingPayment->transactions()->bills()->first();
if ($refund) {
$this->info("Credit note transaction id: {$transaction->id}, already created same amount of refund transaction for same booking payment transaction");
}
if (!$refund) {
$billNumber = $this->generatesTransactionBillNumber->execute('RFD-');
$object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id,
1, PaymentMethodType::CASH,
$transaction->amount, $isFullyRefund ? $bookingPayment->original_amount : $transaction->amount * $bookingPayment->currency_rate, 1,
$bookingPayment->original_currency_id, $bookingPayment->currency_rate,
0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);
$transaction = $this->createsTransaction->execute($bookingPayment, $object);
}
if ($bookingInWhiteForm) {
$original_amount = $isFullyRefund ? $bookingPayment->original_amount : bcmul($transaction->amount, $bookingPayment->currency_rate, 7);
$supplier_refund_amount = bcdiv($original_amount, $bookingInWhiteForm->currency_rate, 7);
$this->info("Credit note transaction id: {$transaction->id}, booking is in white form, white form currency rate is {$bookingInWhiteForm->currency_rate}");
// if ($isFullyRefund && $bookingInWhiteForm->currency_rate == 1) {
// dd ($bookingInWhiteForm->owner_id);
// }
$refund = $bookingPayment->transactions()->supplierRefunds()->where('original_amount', $original_amount)->first();
if (!$refund) {
$billNumber = $this->generatesTransactionBillNumber->execute('SRFD-');
$object = new TransactionObject($billNumber, TransactionType::SUPPLIER_REFUND, 1, $bookingInWhiteForm->issuer,
1, PaymentMethodType::CASH,
$supplier_refund_amount, $original_amount, 1,
$bookingPayment->original_currency_id, $bookingInWhiteForm->currency_rate,
0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);
$transaction = $this->createsTransaction->execute($bookingPayment, $object);
}
}
} else {
// $bookingPayment = $booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)->orderBy('id', 'DESC')->first();
// if ($bookingPayment) {
// $this->info("Credit note transaction id: {$transaction->id}, booking payment refunded");
// } else {
$this->info("Credit note transaction id: {$transaction->id}, booking payment not found, the payment reference is: {$transaction->payment_reference}");
// }
}
} else {
Log::info("Credit note transaction id: {$transaction->id}, booking marking not found, the payment reference is: {$transaction->payment_reference}");
$this->info("Credit note transaction id: {$transaction->id}, booking marking not found, the payment reference is: {$transaction->payment_reference}");
}
} else {
Log::info("Credit note transaction id: {$transaction->id} does not have booking marking, the payment reference is: {$transaction->payment_reference}");
$this->info("Credit note transaction id: {$transaction->id} does not have booking marking, the payment reference is: {$transaction->payment_reference}");
}
}
}
@@ -0,0 +1,68 @@
<?php
namespace App\Console\Commands;
use App\Models\SeasonalSegment;
use Illuminate\Console\Command;
use Carbon\Carbon;
use App\Classes\Modules\Companies\Services\RemovesCompanyFromSegment;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Group;
use App\Models\Transaction;
use App\Models\Wallet;
use Illuminate\Support\Facades\Log;
class UpdateGroupWithTransferFee extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'updateGroupWithTransferFee';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update group with transfer fee';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
ini_set('max_execution_time', 0);
set_time_limit(0);
$groups = Group::whereDate('updated_at', '<', Carbon::now())->get();
foreach ($groups as $group) {
$originalTransferFees = (float)Transaction::where('type', TransactionType::TRANSFER_FEE)->whereIn('owner_id', $group->transactions->pluck('id'))->sum('service_charge');
$correctOriginalAmount = $group->transactions()->sum('original_amount');
$correctOriginalAmount += $originalTransferFees;
$correctAmount = $group->transactions()->sum('amount');
$transferFees = $originalTransferFees / $group->currency_rate;
$correctAmount += $transferFees;
if ($group->original_amount != $correctOriginalAmount) {
$group->original_amount = $correctOriginalAmount;
$group->amount = $correctAmount;
$group->save();
}
}
}
}
@@ -19,6 +19,7 @@ use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds;
use App\Models\TransactionMappingLog;
use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions;
use App\Classes\Modules\Exports\Services\ExportsImportedReceiptMappeds;
use App\Classes\Modules\Exports\Services\ExportsWhiteFormTransactions;
class ExportCustomersToExcelController
{
@@ -54,6 +55,13 @@ class ExportCustomersToExcelController
return $response;
}
public function whiteFormTransactions(Request $request){
$exportsTransactions = new ExportsWhiteFormTransactions($request);
$response = $exportsTransactions->download('white-form-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
}
public function walletTransactions(Request $request){
$exportsTransactions = new ExportsWalletTransactions($request);
$response = $exportsTransactions->download('wallet-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\Modules\Remarks\ControllersLogic\CreateRemarkLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateRemarkController
{
/**
* @param Request $request
* @param CreateRemarkLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateRemarkLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\Modules\Remarks\ControllersLogic\DeleteRemarkLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeleteRemarkController
{
/**
* @param Request $request
* @param DeleteRemarkLogic $logic
* @return JsonResponse
*/
public function delete(Request $request, DeleteRemarkLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\Modules\Remarks\ControllersLogic\FetchRemarkLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchRemarkController
{
/**
* @param Request $request
* @param FetchRemarkLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchRemarkLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\Modules\Remarks\ControllersLogic\ListRemarksLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListRemarksController
{
/**
* @param Request $request
* @param ListRemarksLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListRemarksLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\Modules\Remarks\ControllersLogic\UpdateRemarkLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateRemarkController
{
/**
* @param Request $request
* @param UpdateRemarkLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateRemarkLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Transactions;
use App\Classes\Modules\Transactions\ControllersLogic\ApproveBillGroupPaymentVerificationLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ApproveBillGroupPaymentVerificationController
{
/**
* @param Request $request
* @param ApproveBillGroupPaymentVerificationLogic $logic
* @return JsonResponse
*/
public function approve(Request $request, ApproveBillGroupPaymentVerificationLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\CreateBillGroupPaymentProofDocumentLogic;
class CreateBillGroupPaymentProofDocumentController
{
/**
* @param Request $request
* @param CreateBillGroupPaymentProofDocumentLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateBillGroupPaymentProofDocumentLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\CreateBillGroupPaymentTransactionLogic;
class CreateBillGroupPaymentTransactionController
{
/**
* @param Request $request
* @param DeleteGroupTransactionLogic $logic
* @return JsonResponse
*/
public function pay(Request $request, CreateBillGroupPaymentTransactionLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\CreateSupplierBillGroupLogic;
class CreateSupplierBillGroupController
{
/**
* @param Request $request
* @param CreateSupplierBillGroupLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateSupplierBillGroupLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\DeleteBillGroupLogic;
class DeleteBillGroupController
{
/**
* @param Request $request
* @param DeleteGroupTransactionLogic $logic
* @return JsonResponse
*/
public function delete(Request $request, DeleteBillGroupLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\ListBillGroupsLogic;
class ListBillGroupsController
{
/**
* @param Request $request
* @param ListBillGroupsLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListBillGroupsLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\UpdateGroupTransferFeeLogic;
class UpdateGroupTransferFeeController
{
/**
* @param Request $request
* @param DeleteGroupTransactionLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateGroupTransferFeeLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
namespace App\Http\Resources;
use App\Classes\Modules\Transactions\Services\CalculatesBillGroupPaymentAmount;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
class BillGroupResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$billGroupPayment = (App()->make(CalculatesBillGroupPaymentAmount::class))->execute($this->resource);
$bill_refund_amount = $billGroupPayment['bill_refund_amount'];
$floating_amount = $billGroupPayment['floating_amount'];
$paid_amount = $billGroupPayment['paid_amount'];
$outstanding_amount = $billGroupPayment['outstanding_amount'];
return [
'id' => $this->id,
'reference' => $this->reference,
'original_amount' => (float) $this->original_amount,
'original_currency' => new CurrencyResource($this->original_currency),
'issuer_name' => $this->issuerCompany->name,
'issuer_id' => $this->issuerCompany->id,
'amount' => (float) $this->amount,
'service_charge' => (float) $this->service_charge,
'currency' => new CurrencyResource($this->currency),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y h:i:s A'),
'currency_rate' => (float) $this->currency_rate,
'status' => $this->status,
'groups' => GroupResource::collection($this->groups),
'bill_refund_amount' => $bill_refund_amount,
'floating_amount' => $floating_amount,
'paid_amount' => $paid_amount,
'outstanding_amount' => $outstanding_amount,
'payment_history' => $this->transactions->map(function ($transaction) {
return [
'id' => $transaction->id,
'type' => (int) $transaction->type,
'bill_no' => $transaction->bill_no,
'payment_method' => (float) $transaction->payment_method,
'amount' => (double) $transaction->amount,
'original_amount' => (double) $transaction->original_amount,
'currency' => new CurrencyResource($transaction->currency),
'original_currency' => new CurrencyResource($transaction->original_currency),
'service_charge' => (double) $transaction->service_charge,
'tax' => (double) $transaction->tax,
'status' => (int) $transaction->status,
'statusText' => ApprovalStatus::APPROVAL_STATUS_ID[(int) $transaction->status],
'documents' => $transaction->documents()->first() ? new DocumentResource($transaction->documents()->first()) : null,
'updated_at' => Carbon::parse($transaction->updated_at)->format('d-m-Y h:i:s A'),
];
}),
'bill_refunds' => $this->billRefunds->map(function ($transaction) {
return [
'id' => $transaction->id,
'type' => (int) $transaction->type,
'bill_no' => $transaction->bill_no,
'payment_method' => (float) $transaction->payment_method,
'amount' => (double) $transaction->amount,
'original_amount' => (double) $transaction->original_amount,
'currency' => new CurrencyResource($transaction->currency),
'original_currency' => new CurrencyResource($transaction->original_currency),
'service_charge' => (double) $transaction->service_charge,
'tax' => (double) $transaction->tax,
'status' => (int) $transaction->status,
'statusText' => ApprovalStatus::APPROVAL_STATUS_ID[(int) $transaction->status],
'updated_at' => Carbon::parse($transaction->updated_at)->format('d-m-Y h:i:s A'),
];
}),
];
}
}
+8
View File
@@ -21,6 +21,13 @@ class GroupResource extends JsonResource
*/
public function toArray($request)
{
$transfer_fee = $this->morphTransactions()->where('type', TransactionType::TRANSFER_FEE)->first();
if ($transfer_fee) {
$transfer_fee = (float) $transfer_fee->amount;
} else {
$transfer_fee = 0;
}
if(!$this->issuerCompany){
dd($this->id);
@@ -36,6 +43,7 @@ class GroupResource extends JsonResource
'currency' => new CurrencyResource($this->currency),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
'currency_rate' => (float) $this->currency_rate,
'transfer_fee' => $transfer_fee,
'transactions' => $this->transactions()->get()->pluck('owner.owner.marking'),
'complete_transactions' => $this->transactions()->whereHasMorph('owner', [Transaction::class], function($query){
return $query->whereHas('booking', function($query){
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class RemarkResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'commenter' => new UserResource($this->commenter),
'owner_id' => $this->owner_id,
'content' => $this->content,
'created_at' => $this->created_at->format('d-m-Y H:i'),
'long_ago' => $this->created_at->diffForHumans()
];
}
}
+5 -3
View File
@@ -3,6 +3,7 @@
namespace App\Http\Resources;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use Carbon\Carbon;
@@ -19,7 +20,7 @@ class TransactionResource extends JsonResource
public function toArray($request)
{
$booking = in_array((int)$this->type, [TransactionType::BILL, TransactionType::REFUND])? $this->owner->owner : $this->owner;
$booking = in_array((int)$this->type, [TransactionType::BILL, TransactionType::REFUND, TransactionType::SUPPLIER_REFUND])? $this->owner->owner : $this->owner;
$days = $this->created_at->endOfDay()->addWeekdays($booking->service_id === 3 ? 3 : 1);
return [
@@ -32,8 +33,8 @@ class TransactionResource extends JsonResource
'recipient_bank_account' => new BankResource($booking->bank),
'issuer_name' => $this->issuerCompany->name,
'issuer_id' => $this->issuerCompany->id,
'amount' => (double) $this->amount,
'original_amount' => (double) $this->original_amount,
'amount' => (double) ($this->type === TransactionType::SUPPLIER_REFUND ? $this->amount - $this->transactions()->where('type', TransactionType::BILL_REFUND)->where('status', ApprovalStatus::APPROVED)->sum('amount') : $this->amount),
'original_amount' => (double) ($this->type === TransactionType::SUPPLIER_REFUND ? $this->original_amount - $this->transactions()->where('type', TransactionType::BILL_REFUND)->where('status', ApprovalStatus::APPROVED)->sum('original_amount') : $this->original_amount),
'currency' => new CurrencyResource($this->currency),
'original_currency' => new CurrencyResource($this->original_currency),
'service_charge' => (double) $this->service_charge,
@@ -52,6 +53,7 @@ class TransactionResource extends JsonResource
'value' => $days->gt(Carbon::now()) ? '+' : '-',
'duration' => $days->diff(Carbon::now())->format('%d'),
],
'remarks' => RemarkResource::collection($this->remarks),
'redemption' => new VoucherRedemptionResource($this->voucherRedemption)
];
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace App\Models;
use App\Classes\General\Traits\LogData;
use Illuminate\Database\Eloquent\Model;
use App\Classes\General\Interfaces\Documentable;
use App\Classes\General\Interfaces\Transactionable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Staudenmeir\EloquentHasManyDeep\HasManyDeep;
use Staudenmeir\EloquentHasManyDeep\HasRelationships;
class BillGroup extends Model implements Documentable, Transactionable
{
use SoftDeletes;
protected $table = 'bill_groups';
protected $dates = ['deleted_at'];
/**
* @return MorphMany
*/
public function transactions(): MorphMany
{
return $this->MorphMany(Transaction::class, 'owner');
}
use HasRelationships;
use \Staudenmeir\EloquentHasManyDeep\HasTableAlias;
public function billRefunds()
{
return $this->belongsToMany(Transaction::class, BillGroupRefund::class);
}
/**
* @return MorphMany
*/
public function documents(): morphMany
{
return $this->morphMany(Document::class, 'owner');
}
/**
* @return BelongsTo
*/
public function currency(): BelongsTo
{
return $this->BelongsTo(Currency::class, 'currency_id', 'id');
}
/**
* @return BelongsTo
*/
public function issuerCompany(): BelongsTo
{
return $this->BelongsTo( Company::class, 'issuer', 'id');
}
/**
* @return BelongsTo
*/
public function original_currency(): BelongsTo
{
return $this->BelongsTo(Currency::class, 'original_currency_id', 'id');
}
public function groups()
{
return $this->belongsToMany(Group::class, BillGroupPayment::class, 'bill_group_id', 'group_id');
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BillGroupPayment extends Model
{
protected $table = 'bill_group_payments';
/**
* @return BelongsTo
*/
public function billGroup(): BelongsTo
{
return $this->BelongsTo(BillGroup::class, 'bill_group_id', 'id');
}
/**
* @return BelongsTo
*/
public function group(): BelongsTo
{
return $this->BelongsTo(Group::class, 'group_id', 'id');
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BillGroupRefund extends Model
{
protected $table = 'bill_group_refunds';
/**
* @return BelongsTo
*/
public function billGroup(): BelongsTo
{
return $this->BelongsTo(BillGroup::class, 'bill_group_id', 'id');
}
/**
* @return BelongsTo
*/
public function transaction(): BelongsTo
{
return $this->BelongsTo(Transaction::class, 'transaction_id', 'id');
}
}
+17
View File
@@ -6,6 +6,7 @@ use App\Classes\General\Traits\LogData;
use Illuminate\Database\Eloquent\Model;
use App\Classes\General\Interfaces\Documentable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Staudenmeir\EloquentHasManyDeep\HasManyDeep;
use Staudenmeir\EloquentHasManyDeep\HasRelationships;
@@ -20,6 +21,14 @@ class Group extends Model implements Documentable
return $this->belongsToMany(Transaction::class, GroupTransaction::class);
}
/**
* @return MorphMany
*/
public function morphTransactions(): MorphMany
{
return $this->MorphMany(Transaction::class, 'owner');
}
/**
* @return MorphMany
*/
@@ -60,4 +69,12 @@ class Group extends Model implements Documentable
{
return $this->BelongsTo(Currency::class, 'original_currency_id', 'id');
}
/**
* @return BelongsToMany
*/
public function billGroup(): BelongsToMany
{
return $this->belongsToMany(BillGroup::class, BillGroupPayment::class, 'group_id', 'bill_group_id');
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Remark extends AbstractModel
{
use SoftDeletes;
protected $table = 'remarks';
public function owner(): morphTo
{
return $this->morphTo();
}
/**
* @return BelongsTo
*/
public function commenter(): BelongsTo
{
return $this->BelongsTo(User::class, 'commenter_id', 'id');
}
}
+24 -1
View File
@@ -3,6 +3,7 @@
namespace App\Models;
use App\Classes\General\Interfaces\Documentable;
use App\Classes\General\Interfaces\Remarkable;
use App\Classes\General\Interfaces\Transactionable;
use App\Classes\General\Interfaces\Voucherifiable;
use App\Classes\General\Traits\LogData;
@@ -21,7 +22,7 @@ use Staudenmeir\EloquentHasManyDeep\HasTableAlias;
use App\Models\StatementTransactionOwner;
class Transaction extends AbstractModel implements Documentable, Transactionable, Voucherifiable
class Transaction extends AbstractModel implements Documentable, Transactionable, Voucherifiable, Remarkable
{
use HasTableAlias;
use SoftDeletes;
@@ -186,6 +187,20 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
return $query->where('type', TransactionType::REFUND);
}
/**
* @param Builder $query
* @param string $payment_reference
* @return Builder
*/
public function scopeSupplierRefunds(Builder $query, ?string $payment_reference = NULL)
{
if($payment_reference){
$query->where('payment_reference', $payment_reference);
}
return $query->where('type', TransactionType::SUPPLIER_REFUND);
}
/**
* @param Builder $query
@@ -245,4 +260,12 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
return $this->morphMany(VoucherEntityMapping::class, 'owner');
}
/**
* @return MorphMany
*/
public function remarks(): morphMany
{
return $this->morphMany(Remark::class, 'owner');
}
}
@@ -0,0 +1,44 @@
<?php
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBillGroupsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('bill_groups', function (Blueprint $table) {
$table->id();
$table->string('reference')->unique();
$table->foreignId('issuer')->unsigned();
$table->foreignId('receiver')->unsigned();
$table->decimal('amount', 14, 5)->default(0.00);
$table->decimal('original_amount', 14, 5)->default(0.00);
$table->foreignId('currency_id')->unsigned();
$table->foreignId('original_currency_id')->unsigned();
$table->decimal('currency_rate', 14, 5)->default(0.00);
$table->decimal('tax', 14, 5)->default(0.00);
$table->decimal('service_charge', 14, 5)->default(0.00);
$table->integer('status')->default(ApprovalStatus::PENDING_VERIFICATION);
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('bill_groups');
}
}
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBillGroupPaymentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('bill_group_payments', function (Blueprint $table) {
$table->id();
$table->foreignId('bill_group_id')->constrained('bill_groups');
$table->foreignId('group_id')->constrained('groups');
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('bill_group_payments');
}
}
@@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBillGroupRefundsTable extends Migration
{
public function up()
{
Schema::create('bill_group_refunds', function (Blueprint $table) {
$table->id();
$table->foreignId('bill_group_id')->unsigned()->on('bill_groups');
$table->foreignId('transaction_id')->unsigned()->on('transactions');
});
}
public function down()
{
Schema::dropIfExists('bill_group_refunds');
}
}
@@ -0,0 +1,41 @@
<?php
use App\Classes\ValueObjects\Constants\RemarkTypes;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRemarksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('remarks', function (Blueprint $table) {
$table->id();
$table->morphs('owner');
$table->bigInteger('commenter_id')->unsigned()->index();
$table->string('content',200);
$table->integer('type')->default(RemarkTypes::INTERNAL);
$table->softDeletes();
$table->timestamps();
});
Schema::table('remarks', function (Blueprint $table) {
$table->string('owner_type', 191)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('remarks');
}
}
+1 -1
View File
@@ -48,6 +48,6 @@ class DatabaseSeeder extends Seeder
$this->call(DummyDataSeeder::class);
}
DB::commit();
// DB::commit();
}
}
@@ -0,0 +1,296 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row parentContainer m-b-10">
<div class="col p-l-0">
<div class="row m-l-15 p-t-10 b-a align-items-center pointer shadow bg-white rounded" :class="{'b-white': !(this.selectedBillGroup.id === item.id), 'b-primary': this.selectedBillGroup.id === item.id}" @click="select()">
<div class="col-12">
<div class="row m-b-10">
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Date</div>
<div class="font-heading fs-12">
{{item.updated_at}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Reference</div>
<div class="font-heading fs-12">
{{item.reference}}
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<div class="font-heading fs-12 muted all-caps">Supplier</div>
<div class="font-heading fs-12">
{{item.issuer_name}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Amount</div>
<div class="font-heading fs-12">
{{ item.currency.short_code }} {{formatAmount(item.amount)}}
</div>
</div>
<div class="col parentContainer position-static">
<div class="row align-items-center justify-content-end">
<div class="col-auto position-static no-padding requestModal" data-type="deleteBillGroup" v-if="section !== 'paidBillGroupList'">
<div class="btn bg-grey no-border">
<i class="fa fa-times text-danger"></i>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" type="deleteBillGroup">
<general-confirmation-form-component
contentText="Are you sure you want to delete this Bill Group?"
modalType="delete"
class="text-center"
:apiRoute="route('api.transaction.group.bill.delete', item.id)"
apiMethod="delete"
:section="section"
>
</general-confirmation-form-component>
</modal-component>
</div>
<div class="col-auto no-padding">
<div class="btn btn-sm btn-default b-rad-none no-border" @click="expanded = !expanded">
<i class="fa fa-fw" :class="[{'fa-angle-up': expanded}, {'fa-angle-down': !expanded}]"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded">
<div class="row m-b-10">
<div class="font-heading fs-12 all-caps text-underline">Bill Refunds</div>
</div>
<div class="row m-b-10" v-for="refund in item.bill_refunds">
<div class="col-3">
<div class="font-heading fs-12 muted all-caps">Date</div>
<div class="font-heading fs-12">
{{refund.updated_at}}
</div>
</div>
<div class="col-3">
<div class="font-heading fs-12 muted all-caps">Reference</div>
<div class="font-heading fs-12">
{{refund.bill_no}}
</div>
</div>
<div class="col-3" v-if="$store.getters.isAdmin">
<div class="font-heading fs-12 muted all-caps">Amount</div>
<div class="font-heading fs-12">
{{ refund.currency.short_code }} {{ formatAmount(refund.amount) }}
</div>
</div>
<div class="col-3" v-if="$store.getters.isAdmin">
<div class="font-heading fs-12 muted all-caps">Status</div>
<div class="font-heading fs-12" :class="[{'text-danger': refund.status === 0 || refund.status === 4}, {'text-success': refund.status === 2 || refund.status === 3}, {'text-warning': refund.status === 1}]">
{{ refund.statusText }}
</div>
</div>
</div>
<div class="row m-t-20 m-b-20" v-if="item.bill_refunds.length === 0">
<div class="col">
<div class="font-heading fs-12 text-center all-caps">No Selected Refunds</div>
</div>
</div>
</div>
<div class="col b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded">
<div class="row m-b-10">
<div class="font-heading fs-12 all-caps text-underline">Payment History</div>
</div>
<div class="row m-b-10" v-for="payment in item.payment_history">
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Date</div>
<div class="font-heading fs-12">
{{payment.updated_at}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Reference</div>
<div class="font-heading fs-12">
{{payment.bill_no}}
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<div class="font-heading fs-12 muted all-caps">Amount</div>
<div class="font-heading fs-12">
{{ payment.currency.short_code }} {{ formatAmount(payment.amount) }}
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<div class="font-heading fs-12 muted all-caps">Status</div>
<div class="font-heading fs-12" :class="[{'text-danger': payment.status === 0 || payment.status === 4}, {'text-success': payment.status === 2 || payment.status === 3}, {'text-warning': payment.status === 1}]">
{{ payment.statusText }}
</div>
</div>
<div class="col parentContainer position-static align-items-center">
<div class="row align-items-center justify-content-end">
<div v-if="!payment.documents && section === 'paymentInProgressBillGroupList'">
<div class="btn no-border muted btn-success requestModal" data-type="paymentProofModal" @click="selectedTransactionID(payment.id)">
<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="70.76994" x2="86" y2="116.46013" gradientUnits="userSpaceOnUse" id="color-1_52139_gr1"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="61.8125" y1="34.48869" x2="61.8125" y2="144.97181" gradientUnits="userSpaceOnUse" id="color-2_52139_gr2"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="130.34375" y1="34.48869" x2="130.34375" y2="144.97181" gradientUnits="userSpaceOnUse" id="color-3_52139_gr3"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></stop></linearGradient><linearGradient x1="86" y1="32.25" x2="86" y2="148.71013" gradientUnits="userSpaceOnUse" id="color-4_52139_gr4"><stop offset="0" stop-color="#ffffff"></stop><stop offset="1" stop-color="#ffffff"></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="M102.45825,99.43213h-5.70825c-1.4835,0 -2.6875,1.16637 -2.6875,2.65256v8.10013c0,1.48081 -1.19862,2.68481 -2.67944,2.68481h-10.76612c-1.48081,0 -2.67944,-1.204 -2.67944,-2.68481v-8.10013c0,-1.48619 -1.204,-2.65256 -2.6875,-2.65256h-5.70825c-1.93769,0 -3.04225,-2.39188 -1.88125,-4.05275l14.577,-20.855c1.8275,-2.61494 5.69481,-2.61763 7.52231,-0.00538l14.577,20.86306c1.16369,1.66088 0.05644,4.05006 -1.87856,4.05006z" fill="url(#color-1_52139_gr1)"></path><path d="M51.0625,67.1875h5.375c0,-8.0625 7.23206,-16.12231 16.125,-16.12231v-5.375c-11.85456,0 -21.5,10.74731 -21.5,21.49731z" fill="url(#color-2_52139_gr2)"></path><path d="M139.75,80.625c0,-10.75 -8.44144,-18.80981 -18.8125,-18.80981v5.375c7.40944,0 13.4375,5.37231 13.4375,13.43481z" fill="url(#color-3_52139_gr3)"></path><path d="M148.09738,92.27263c1.59369,-3.68188 2.40263,-7.59219 2.40263,-11.64494c0,-16.29969 -13.26281,-29.5625 -29.5625,-29.5625c-6.5145,0 -12.68769,2.08819 -17.78588,5.96088c-4.30269,-13.03438 -16.52006,-22.08587 -30.58912,-22.08587c-17.78319,0 -32.25,14.46681 -32.25,32.25c0,4.14681 0.16662,8.05981 1.42437,10.74731h-1.42437c-13.33806,0 -24.1875,10.84944 -24.1875,24.1875c0,11.56431 8.16194,21.24737 19.0275,23.62044c1.02394,6.39894 6.53869,11.31706 13.2225,11.31706h56.4375h16.125h5.375c6.54944,0 12.00238,-4.71388 13.18488,-10.92469c9.2235,-1.20131 16.37762,-9.08913 16.37762,-18.63513c0,-6.09256 -2.924,-11.72019 -7.77762,-15.23006zM126.3125,131.6875h-5.375h-16.125h-56.4375c-3.49912,0 -6.45538,-2.6875 -7.568,-5.375h93.0735c-1.11263,2.6875 -4.06888,5.375 -7.568,5.375zM137.0625,120.9375h-96.75c-10.37106,0 -18.8125,-8.44144 -18.8125,-18.8125c0,-10.37106 8.44144,-18.8125 18.8125,-18.8125h9.51375l-1.68506,-3.78131c-2.23063,-5.01488 -2.45369,-7.48737 -2.45369,-12.341c0,-14.81888 12.05613,-26.875 26.875,-26.875c13.01825,0 24.13106,9.29875 26.42619,22.11275l0.92719,5.17075l3.64962,-3.77325c4.60638,-4.76225 10.77687,-7.38525 17.372,-7.38525c13.33806,0 24.1875,10.84944 24.1875,24.1875c0,3.6765 -0.81431,7.21056 -2.37575,10.41944l-1.763,3.32713l2.37037,1.26044c4.40481,2.34081 7.14338,6.88806 7.14338,11.868c0,7.40944 -6.02806,13.43481 -13.4375,13.43481z" fill="url(#color-4_52139_gr4)"></path></g></g></svg>
</div>
<modal-component type="paymentProofModal">
<bill-group-payment-proof-form-component v-if="selected_transaction_id === payment.id" :section="section" :data="{item}" :id="payment.id"></bill-group-payment-proof-form-component>
</modal-component>
</div>
<div v-if="payment.documents">
<document-file-viewer-component :file="payment.documents.files[0]">
<template slot="button">
<div class="btn no-border muted btn-success">
<i class="fa fa-file-pdf-o"></i>
</div>
</template>
</document-file-viewer-component>
</div>
<div v-if="section === 'paymentVerificationBillGroupList' && payment.status === 1">
<div class="col-auto">
<div class="row">
<div 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>
<button class="btn btn-xs btn-success b-rad-none requestModal" data-type="approvePayment">
<i class="fa fa-check fa-fw"></i>
</button>
<modal-component small type="rejectPayment">
<general-confirmation-form-component
contentText="Are you sure you want to reject this payment?"
modalType="delete"
class="text-center"
:apiRoute="route('api.transaction.group.bill.payment_proof.approval', payment.id, 'reject')"
apiMethod="post"
:section="section"
>
</general-confirmation-form-component>
</modal-component>
<modal-component small type="approvePayment">
<general-confirmation-form-component
contentText="Are you sure you want to approve this payment?"
modalType="confirm"
class="text-center"
:apiRoute="route('api.transaction.group.bill.payment_proof.approval', payment.id, 'approve')"
apiMethod="post"
:section="section"
>
</general-confirmation-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-t-20 m-b-20" v-if="item.payment_history.length === 0">
<div class="col">
<div class="font-heading fs-12 text-center all-caps">No Payments</div>
</div>
</div>
</div>
<div class="col b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded">
<div class="row m-b-10">
<div class="font-heading fs-12 all-caps text-underline">Currency Orders</div>
</div>
<div class="row m-t-10 m-b-20" v-for="group in item.groups">
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Date</div>
<div class="font-heading fs-12">
{{group.created_at}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Currency Rate</div>
<div class="font-heading fs-12">
{{group.currency_rate}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">Original Amount</div>
<div class="font-heading fs-12">
{{ group.original_currency.short_code }} {{formatAmount(group.original_amount)}}
</div>
</div>
<div class="col-2">
<div class="font-heading fs-12 muted all-caps">Amount</div>
<div class="font-heading fs-12">
{{ group.currency.short_code }} {{formatAmount(group.amount)}}
</div>
</div>
<div class="col-2">
<div class="font-heading fs-12 muted all-caps">Transfer Fee</div>
<div class="font-heading fs-12">
{{ group.original_currency.short_code }} {{formatAmount(group.transfer_fee)}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-12 muted all-caps">PO Completion</div>
<div class="col">
<p class="font-heading fs-12 bold text-success pointer"><span :class="[{'text-danger': group.complete_transactions.length !== group.transactions.length}]">{{group.complete_transactions.length}}</span>/{{group.transactions.length}}</p>
</div>
</div>
<div class="col parentContainer position-static align-items-center">
<div class="row align-items-center justify-content-end">
<div v-if="group.documents.currency_order">
<document-file-viewer-component :file="group.documents.currency_order.files[0]">
<template slot="button">
<div class="btn no-border muted btn-success">
<i class="fa fa-file-pdf-o"></i>
</div>
</template>
</document-file-viewer-component>
</div>
<div v-else>
<div class="btn bg-grey no-border muted invisible">
<i class="fa fa-file-pdf-o"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
props: {
selectedBillGroup: {
type: Object,
required: true
},
section: {
type: String,
required: true
}
},
data(){
return {
selected_id: '',
selected: false,
expanded: false,
selected_transaction_id: '',
}
},
methods: {
selectedTransactionID(id){
this.selected_transaction_id = id;
},
formatAmount(amount) {
return (Math.round((amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
},
select(){
this.$emit('input', this.item)
this.selected = this.selectedBillGroup.id === this.item.id;
},
},
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,170 @@
<template>
<div class="row mt-3 mt-md-0">
<div class="col">
<div class="row m-l-10 p-t-20 p-b-20 shadow bg-white rounded">
<div class="col">
<div class="row align-items-end m-b-10 text-complete">
<div class="col">
<div class="font-heading all-caps fs-12">Transfer Total:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.original_currency.short_code}} {{formatAmount(selectedBillGroup.original_amount)}}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">CNY 0.00</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-complete">
<div class="col">
<div class="font-heading all-caps fs-12"></div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.currency.short_code}} {{formatAmount(selectedBillGroup.amount)}}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-complete">
<div class="col">
<div class="font-heading all-caps fs-12">Service Charge:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.currency.short_code}} {{formatAmount(selectedBillGroup.service_charge)}}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-danger">
<div class="col">
<div class="font-heading all-caps fs-12">Bill Refund Total:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">- {{selectedBillGroup.currency.short_code}} {{formatAmount(selectedBillGroup.bill_refund_amount)}}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-success">
<div class="col">
<div class="font-heading all-caps fs-12">Paid Total:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.currency.short_code}} {{ formatAmount(selectedBillGroup.paid_amount) }}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div class="row align-items-end m-b-10">
<div class="col">
<div class="font-heading all-caps fs-12">Floating Amount:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.currency.short_code}} {{ formatAmount(selectedBillGroup.floating_amount) }}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div class="row align-items-end bold text-danger">
<div class="col">
<div class="font-heading all-caps fs-12">OutStanding Total:</div>
</div>
<div class="col-auto text-right" v-if="selectedBillGroup.id">
<div class="font-heading fs-12">{{selectedBillGroup.currency.short_code}} {{ formatAmount(selectedBillGroup.outstanding_amount) }}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading fs-12">MYR 0.00</div>
</div>
</div>
<div v-if="selectedBillGroup.status === 0 && (selectedBillGroup.outstanding_amount > 0 || (selectedBillGroup.bill_refund_amount === (selectedBillGroup.amount + selectedBillGroup.service_charge) && !selectedBillGroup.payment_history.some((item)=> [0, 1, 2, 3].includes(item.status))))">
<div class="row p-r-15 m-t-20 m-b-10">
<div class="col p-r-0">
<validation-wrapper-component :validator="$v.parameters.payAmount">
<label>Amount</label>
<input class="form-control" v-model.lazy="parameters.payAmount" v-money="{decimal: '.',thousands: ',', precision: 2}">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">{{ selectedBillGroup.id ? selectedBillGroup.currency.short_code : "MYR" }}</div>
</div>
</div>
</div>
</div>
<div class="row m-t-20" v-if="selectedBillGroup.outstanding_amount > 0">
<div class="col">
<button id="payment-btn" class="btn btn-sm all-caps b-rad-none btn-success btn-block" @click="submitForm">Make Payment</button>
</div>
</div>
<div class="row m-t-20" v-if="(selectedBillGroup.bill_refund_amount === selectedBillGroup.amount + selectedBillGroup.service_charge)">
<div class="col">
<button id="payment-btn" class="btn btn-sm all-caps b-rad-none btn-success btn-block" @click="submitForm">Complete Order</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ModalComponent from "../../general/elements/ModalComponent";
import componentHandler from '../../../general/mixins/componentHandler';
import { required } from "vuelidate/lib/validators";
import {VMoney} from 'v-money'
export default {
props: {
selectedBillGroup: {
type: Object,
required: true
},
refreshList: {
type: Function,
required: true
},
},
watch: {
selectedBillGroup(){
this.parameters.payAmount = (Math.round((this.selectedBillGroup.outstanding_amount + Number.EPSILON) * 100) / 100).toFixed(2)
}
},
data(){
return {
parameters: {
payAmount: 0
}
}
},
validations: {
parameters: {
payAmount: {
required
}
}
},
methods: {
formatAmount(amount) {
return (Math.round((amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
},
submitForm(){
this.submit(route('api.transaction.group.bill.pay', this.selectedBillGroup.id), 'post', this.section, true, true)
},
successHandler(){
this.refreshList();
// this.$store.dispatch('toggleSection', {name: 'paymentInProgressBillGroupList', status: !this.$store.getters.isShowing('paymentInProgressBillGroupList')});
this.parameters = {
payments: [],
};
},
},
mixins: [componentHandler],
directives: {money: VMoney}
}
</script>
@@ -16,6 +16,12 @@
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
</validation-wrapper-component>
</div>
<div class="col-12 col-md mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<validation-wrapper-component selectable :validator="$v.parameters.reportType">
<label class="all-caps">Report Type</label>
<select-component :options="['Payments Report', 'Wallets Report', 'White Form Report']" v-model="parameters.reportType"></select-component>
</validation-wrapper-component>
</div>
<div class="col-12 col-md-auto p-l-3 p-r-3 p-md-0">
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="downloadReport()">
<span>
@@ -46,9 +52,20 @@ export default {
parameters: {
startDate: '',
endDate: '',
reportType: '',
},
}
},
mounted(){
switch(this.section) {
case 'paymentsReportSection':
this.parameters.reportType = 'Payments Report'
break;
case 'walletsReportSection':
this.parameters.reportType = 'Wallets Report'
break;
}
},
validations: {
parameters: {
startDate: {
@@ -57,19 +74,25 @@ export default {
endDate: {
required
},
reportType: {
required
},
}
},
methods: {
downloadReport(){
var apiRoute = '';
if(!this.validate()){ return; }
switch(this.section) {
case 'paymentsReportSection':
switch(this.parameters.reportType) {
case 'Payments Report':
apiRoute = route('paymentTransactions.export');
break;
case 'walletsReportSection':
case 'Wallets Report':
apiRoute = route('walletTransactions.export');
break;
case 'White Form Report':
apiRoute = route('whiteFormTransactions.export');
break;
}
window.open(apiRoute + '?startDate=' + this.parameters.startDate + '&endDate=' + this.parameters.endDate, '_blank');
},
@@ -4,25 +4,25 @@
<div class="row">
<div class="col-12">
<div class="row m-l-0 m-r-0">
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<div class="col-12 col-md mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<validation-wrapper-component selectable :validator="$v.parameters.supplier">
<label>Supplier</label>
<selectable-component :disableOnFetch="true" :endpoint="route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]})" section="exportSupplierFilterSection" valueColumn="id" :labelColumn="['name']" v-model="parameters.supplier"></selectable-component>
</validation-wrapper-component>
</div>
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<div class="col-12 col-md mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<validation-wrapper-component :validator="$v.parameters.startDate">
<label class="all-caps">Start Date</label>
<date-picker-component :parameters="parameters" v-model.lazy="parameters.startDate"></date-picker-component>
</validation-wrapper-component>
</div>
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<div class="col-12 col-md mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
<validation-wrapper-component :validator="$v.parameters.endDate">
<label class="all-caps">End Date</label>
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
</validation-wrapper-component>
</div>
<div class="col-auto p-l-3 p-r-3 p-md-0">
<div class="col-12 col-md-auto p-l-3 p-r-3 p-md-0">
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="bulkDownloadWhiteForm()">
<span>
Export
@@ -0,0 +1,79 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row m-b-10">
<div class="col">
<h5 class="all-caps m-b-5 bold no-margin">Edit Transaction Group Fee</h5>
</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 m-b-10">
<div class="col p-r-0">
<validation-wrapper-component :validator="$v.parameters.fee">
<label class="all-caps">Transfer Fee</label>
<input type="text" class="form-control" v-model.lazy="parameters.fee" v-money="{decimal: '.',thousands: ',', precision: 2}">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">CNY</div>
</div>
</div>
</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 ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
props: {
transfer_fee:{
type: Number,
required: true
},
id: {
type: Number,
required: true
}
},
data(){
return {
error: '',
parameters: {
fee: (Math.round((this.transfer_fee + Number.EPSILON) * 100) / 100).toFixed(2)
},
}
},
validations: {
parameters: {
fee: { },
},
},
methods: {
submitForm() {
this.submit(route('api.transaction.group.fee.update', this.id), 'put', this.section, true, true);
}
},
mixins: [ModalFormHandler]
}
</script>
@@ -18,13 +18,13 @@
<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, ",")}}
{{item.original_currency.short_code}} {{(Math.round((item.original_amount - item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto p-l-0" v-if="totalRefunds !== 0">
<div class="font-heading fs-8 muted all-caps">Refunded Amount</div>
<div class="font-heading fs-10 bold text-danger">
{{item.currency.short_code}} {{(Math.round((totalConvertRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
{{item.original_currency.short_code}} {{(Math.round((item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
@@ -68,15 +68,13 @@
<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, ",")}}
{{item.original_currency.short_code}} {{(Math.round((item.original_amount - item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="row align-items-end m-b-10 bold text-danger" v-if="totalRefunds !== 0">
<div class="col">
<div class="font-heading all-caps fs-10">Refunded Amount</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">{{item.original_currency.short_code}} {{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
<div class="col-auto p-l-0 text-danger" v-if="totalRefunds !== 0">
<div class="font-heading fs-8 muted all-caps">Refunded Amount</div>
<div class="font-heading fs-10 bold">
{{item.original_currency.short_code}} {{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
@@ -235,7 +233,7 @@
<div class="font-heading all-caps fs-10 m-b-5">Our Payment Proof</div>
<div class="row" v-if="item.transaction_bill">
<div class="col">
<div class="row" v-if="item.transaction_bill.status !== 2 && item.transaction_bill.status !== 3">
<div class="row hide" v-if="item.transaction_bill.status !== 2 && item.transaction_bill.status !== 3">
<div class="col">
<p class="fs-12 muted">Payment proof will be uploaded {{ (parseFloat(item.interval.duration) + 1) <= 0 ? 'today' : (parseFloat(item.interval.duration) + 1) === 2 ? 'tomorrow' : 'in '+(parseFloat(item.interval.duration) + 1)+' days'}} at 4:00 PM</p>
</div>
@@ -291,8 +289,8 @@
</div>
</div>
</div>
<div class="row m-t-10" v-show="[2, 3].includes(item.status) && (totalRequestedRefund + totalRefunds) < data.original_amount">
<div class="col" v-if="!item.transaction_bill && $store.getters.isAdmin">
<div class="row m-t-10" v-show="!hasRefundInProgress && [2, 3].includes(item.status) && (totalRequestedRefund + totalRefunds) < data.original_amount">
<div class="col" v-if="$store.getters.isAdmin">
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border requestModal" data-type="transferSummary">Request Refund</button>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="transferSummary" size="large">
<refund-confirmation-component :data="data" :section="section" :totalRefunds="totalRequestedRefund + totalRefunds"></refund-confirmation-component>
@@ -334,6 +332,14 @@
<div class="font-heading fs-10 bold" :class="[{'text-warning': refund.status === 1}, {'text-success': refund.status === 2}, {'text-danger': refund.status === 4}]">{{ refund.status === 1 ? 'Pending Verification' : refund.status === 2 ? 'Approved' : 'Rejected'}}</div>
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<span class="btn requestModal no-border" size="large" data-type="chatmodal">
<i class="fa fa-comment-o"></i>
</span>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="chatmodal">
<remark-component :section="section" :data="refund" module_type="Transaction"></remark-component>
</modal-component>
</div>
<div class="col text-right">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-10">
@@ -347,7 +353,7 @@
</div>
</div>
</div>
<div class="row m-b-15 text-right parentContainer" v-if="$store.getters.isAdmin && refund.status === 1">
<div class="row m-b-15 text-right parentContainer" v-if="$store.getters.isSuperAdmin && refund.status === 1">
<div class="col">
<button class="btn btn-xs btn-outline-danger b-rad-none m-r-5 requestModal" data-type="rejectRefund">
<i class="fa fa-times fa-fw"></i>
@@ -436,6 +442,10 @@
TotalRequestedRefund += refunds.status === 2 ? refunds.amount : 0;
});
return TotalRequestedRefund;
},
hasRefundInProgress() {
var refundTransactionsStatus = this.data.transaction_refunds.length > 0 ? this.data.transaction_refunds.map(refund => refund.status) : [];
return refundTransactionsStatus.includes(0) || refundTransactionsStatus.includes(1)
}
},
methods: {
@@ -35,9 +35,18 @@
</div>
</div>
</div>
<div class="row m-t-5 m-b-5">
<div class="col">
<validation-wrapper-component :validator="$v.refundRemark">
<label>Refund Remarks</label>
<input class="form-control" name="amount" v-model="refundRemark" >
</validation-wrapper-component>
</div>
</div>
<div class="row m-t-10 m-b-10">
<div class="col">
<div class="font-heading all-caps fs-10 m-b-5">Paid Amount: {{ paidAmount }}</div>
<div class="font-heading all-caps fs-10 m-b-5" v-if="this.data.refunded_amount > 0">Paid Amount: {{ (Math.round((this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2) }}</div>
<div class="font-heading all-caps fs-10 m-b-5">Refund Amount: {{ refundAmount }}</div>
</div>
</div>
@@ -69,10 +78,12 @@ export default {
},
data() {
return {
refundAmount: (Math.round((this.data.original_amount - this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2),
refundRemark: '',
refundMethod: { name: 'Fully Refund', status: false },
refundMethods: [
{ name: 'Fully Refund', label: 'Full Refund' },
// { name: 'Partially Refund', label: 'Partial Refund' }
{ name: 'Partially Refund', label: 'Partial Refund' }
]
}
},
@@ -80,16 +91,13 @@ export default {
return {
refundAmount: {
maxValue: maxValue(this.refundMaxValue)
}
},
refundRemark: {}
}
},
computed: {
refundAmount() {
// return (Math.round((this.data.booking.amount - this.totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2);
return (Math.round((this.data.original_amount - this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2);
},
refundMaxValue() {
return this.refundAmount;
return (Math.round((this.data.original_amount - this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2);
},
paidAmount() {
return this.data.original_amount;
@@ -98,6 +106,7 @@ export default {
methods: {
submitForm() {
this.parameters.amount = this.refundAmount;
this.parameters.refundRemark = this.refundRemark;
this.submit(this.route('api.booking.refund.create', this.data.booking.id, this.data.id), 'post', this.section, true, true)
},
updateRefundType(refund) {
@@ -34,7 +34,7 @@
</div>
<div class="row m-b-10">
<div class="col">
<div class="text-right">
<div class="text-right" v-if="$store.getters.isSuperAdmin">
<button class="btn btn-xs btn-outline-danger b-rad-none m-r-5 requestModal" data-type="rejectRefund">
<i class="fa fa-times fa-fw"></i>
</button>
@@ -56,7 +56,7 @@
<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 text-right" v-if="totalRefunds !== 0">
<!-- <div class="col text-right" v-if="totalRefunds !== 0">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Refunded Amount</div>
@@ -65,7 +65,7 @@
</div>
</div>
</div>
</div>
</div> -->
</div>
<div class="row">
<div class="col-auto">
@@ -0,0 +1,98 @@
<template>
<div class="row m-b-10 parentContainer">
<div class="col">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
<div class="row align-items-center p-b-5 b-b b-grey" :class="[{'pointer': clickable}]" v-show="!isLoading" @click="clickable ? activate() : undefined">
<div class="col-auto p-r-0">
<div class="b-grey b-a fs-10 btn-rounded icon-thumbnail icon-25 m-r-0" :class="[{'bg-primary': active}, {'bg-transparent': !active}]" v-if="clickable">
<i class="fa fa-check text-white fs-12 fa-fw"></i>
</div>
<div style="width: 25px;" v-else></div>
</div>
<div class="col">
<div class="row m-b-10">
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Date</div>
<div class="font-heading fs-10">
{{item.created_at}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Reference</div>
<div class="font-heading fs-10">
<a :href="route('booking.details', item.booking.marking)">{{item.booking.marking}}</a>
</div>
</div>
<div class="col text-right">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-14 text-success 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>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import staticFormHandler from '../../../general/mixins/staticFormHandler'
export default {
props: {
section:{
type: String,
required: true
},
is1688Supplier:{
type: Boolean,
required: true
},
payments:{
type: Array,
required: true
},
paymentTotal: {
type: Number,
required: true
},
inputPaymentTotal: {
type: Number,
required: true
},
refundTotal: {
type: Number,
required: true
},
supplierRefunds:{
type: Array,
required: true
}
},
computed: {
clickable(){
if (this.is1688Supplier) {
return this.refundTotal < this.inputPaymentTotal || this.supplierRefunds.some((i) => this.item.id === i.id );
} else {
return this.refundTotal < this.paymentTotal || this.supplierRefunds.some((i) => this.item.id === i.id );
}
}
},
data(){
return {
active: this.item ? this.supplierRefunds.some(supplierRefund => supplierRefund.id === this.item.id) : false,
}
},
created(){
this.active = this.supplierRefunds.some(supplierRefund => supplierRefund.id === this.item.id);
},
methods: {
activate(){
this.active = !this.active;
this.$emit('input', this.item)
},
},
mixins: [componentHandler, staticFormHandler]
}
</script>
@@ -0,0 +1,150 @@
<template>
<div class="row m-b-10 parentContainer">
<div class="col">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
<div class="row align-items-center pointer p-b-5 b-b b-grey" v-show="!isLoading" @click="activate()">
<div class="col-auto p-r-0">
<div class="b-grey b-a fs-10 btn-rounded icon-thumbnail icon-25 m-r-0" :class="[{'bg-primary': active}, {'bg-transparent': !active}]">
<i class="fa fa-check text-white fs-12 fa-fw"></i>
</div>
</div>
<div class="col">
<div class="row m-b-10">
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Date</div>
<div class="font-heading fs-10">
{{item.created_at}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Supplier</div>
<div class="font-heading fs-10">
{{item.issuer_name}}
</div>
</div>
</div>
<div class="row">
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Currency Rate</div>
<div class="font-heading fs-10">
{{item.currency_rate}}
</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">Currency Amount</div>
<div class="font-heading fs-10">
{{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">
<div class="font-heading fs-10 muted all-caps">Transfer Fee</div>
<div class="font-heading fs-10">
{{item.original_currency.short_code}} {{(Math.round((item.transfer_fee + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col text-right">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-14 text-success 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>
<div class="row">
<div class="col-auto">
<div class="font-heading fs-10 muted all-caps">reference</div>
<document-file-viewer-component v-if="item.documents.currency_order" :file="item.documents.currency_order.files[0]">
<template slot="button">
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
<i class="fa fa-eye"></i>
</button>
</template>
</document-file-viewer-component>
</div>
<div class="col">
<div class="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">PO Completion</div>
</div>
</div>
<div class="row">
<div class="col-auto p-r-0" v-if="item.documents.purchase_order" >
<document-file-viewer-component :file="item.documents.purchase_order.files[0]">
<template slot="button">
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
<i class="fa fa-file-pdf-o"></i>
</button>
</template>
</document-file-viewer-component>
</div>
<div class="col">
<p class="font-heading fs-12 bold text-success pointer" @click="expand($event)"><span :class="[{'text-danger': item.complete_transactions.length !== item.transactions.length}]">{{item.complete_transactions.length}}</span>/{{item.transactions.length}}</p>
</div>
</div>
</div>
<div class="col-auto">
<div class="row parentContainer">
<div class="col p-l-0">
<button class="btn btn-xs btn-primary b-rad-none requestModal" data-type="editTransactionGroup">
Edit Transfer Fee
</button>
<modal-component small type="editTransactionGroup">
<edit-transfer-fee-form-component :section="section" :transfer_fee="item.transfer_fee" :id="item.id"></edit-transfer-fee-form-component>
</modal-component>
</div>
</div>
</div>
</div>
<div class="row" v-if="expanded">
<div class="col">
<div class="row" v-for="transaction in item.transactions">
<div class="col">
<a :href="route('booking.details', transaction)" target="_blank">
<span :class="[{'text-success': item.complete_transactions.includes(transaction)}, {'text-danger': !item.complete_transactions.includes(transaction)}]">{{ transaction }}</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import staticFormHandler from '../../../general/mixins/staticFormHandler'
export default {
props: {
section:{
type: String,
required: true
},
payments:{
type: Array,
required: true
}
},
data(){
return {
expanded: false,
active: this.item ? this.payments.some(payment => payment.id === this.item.id) : false,
}
},
created(){
this.active = this.payments.some(payment => payment.id === this.item.id);
},
methods: {
activate(){
this.active = !this.active;
this.$emit('input', this.item)
},
expand(event){
this.expanded = !this.expanded;
event.stopPropagation();
}
},
mixins: [componentHandler, staticFormHandler]
}
</script>
@@ -0,0 +1,80 @@
<template>
<div class="row" @keyup.enter="submitForm">
<div class="col">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row m-b-10">
<div class="col">
<div class="font-heading fs-16 all-caps bold m-b-15">Payment Proof</div>
</div>
</div>
<error-message-component class="m-b-20" :error="error"></error-message-component>
<div class="row">
<div class="col">
<file-input-component :validator="$v.files" v-model="files">
<template slot="label">
<div class="font-heading fs-11 text-primary all-caps">Payment Proof</div>
</template>
</file-input-component>
</div>
</div>
<div class="row m-t-20">
<div class="col">
<div class="row">
<div class="col-auto">
<button type="button" class="btn btn-sm bg-master-lighter p-t-10 p-b-10 p-r-35 p-l-35 btn-default b-rad-none" data-dismiss="modal">Cancel</button>
</div>
<div class="col text-right">
<button type="button" class="btn btn-sm p-t-10 p-b-10 p-r-35 p-l-35 btn-success b-rad-none" @click="submitForm">Save and continue</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ModalFromHandler from '../../../general/mixins/modalFormHandler'
import { required } from "vuelidate/lib/validators";
export default {
props: {
id: {
required: true,
type: Number
}
},
data(){
return {
files: [],
parameters: {}
}
},
validations: {
files: {
required
}
},
methods: {
submitForm(){
this.parameters = {
files: this.files
};
this.submit(this.route('api.transaction.group.bill.payment_proof.create', this.id), 'post', this.section, true, true)
},
successHandler(){
this.closeModal();
this.$store.dispatch('toggleSection', {name: 'paymentInProgressBillGroupList', status: !this.$store.getters.isShowing('paymentInProgressBillGroupList')});
this.$store.dispatch('toggleSection', {name: 'paymentVerificationBillGroupList', status: !this.$store.getters.isShowing('paymentVerificationBillGroupList')});
this.files = []
},
},
mixins: [ModalFromHandler]
}
</script>
@@ -93,8 +93,8 @@
</div>
<div class="row m-b-20">
<div class="col">
<p class="no-margin" v-if="serviceType.id === 1">Recipient will receive the transfer on the <span class="text-success bold">next working day</span>. Check out our three-day transfer option to get a better rate!</p>
<p class="no-margin" v-if="serviceType.id === 3">Enjoy a <span class="bold text-underline">better rate</span> with this option! The recipient will receive the transfer after <span class="text-success bold">three working days</span>.</p>
<p class="no-margin" v-if="serviceType.id === 1">The recipient can expect to receive the transfer within <span class="text-success bold">1-3 working days</span>. Explore our BANK TRANSFER (SAVER) option for a better rate!</p>
<p class="no-margin" v-if="serviceType.id === 3">Enjoy a <span class="bold text-underline">better rate</span> with this option! The recipient will receive the transfer after <span class="text-success bold">3-5 working days.</span>.</p>
</div>
</div>
<div class="row">
@@ -6,7 +6,7 @@
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-15" v-show="calculation.date && !error">
<div class="row m-b-15 hide" v-show="calculation.date && !error">
<div class="col padding-15 bg-master-lightest text-center m-l-15 m-r-15">
<div class="fs-14 muted" >The recipient will receive the transfer amount by <br><span class="bold text-success">{{ this.calculation.receive_date }}</span></div>
</div>
@@ -225,7 +225,7 @@
if (!this.currentSegmentNames.includes('enable enter MYR rate')) {
return true;
}
return false;
},
},
@@ -242,6 +242,7 @@
'data': function () {
if (this.data && this.data.purchase_order && this.data.purchase_order.details) {
this.products = this.data.purchase_order.details;
this.submitted = this.data.purchase_order ? this.data.purchase_order.status === 1 || this.data.purchase_order.status === 2: false;
} else {
this.products = [];
}
@@ -0,0 +1,246 @@
<template>
<div class="row mt-3 mt-md-0">
<div class="col">
<div class="row">
<div class="col">
<div class="row align-items-end m-b-10">
<div class="col">
<div class="font-heading all-caps fs-10">Supplier:</div>
</div>
<div class="col-auto">
<div class="font-heading fs-10">{{this.supplier.name}}</div>
</div>
</div>
<div class="row align-items-end m-b-5 text-info">
<div class="col">
<div class="font-heading all-caps fs-10">Order Total:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-11">{{ this.payments.length > 0 ? this.payments[0].original_currency.short_code : "CNY"}} {{ formatNumber(this.originalTotal) }}</div>
</div>
</div>
<div class="row align-items-end m-b-5 text-info" v-if="!is1688Supplier">
<div class="col">
<div class="font-heading all-caps fs-10"></div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-11">MYR {{ formatNumber(this.total) }}</div>
</div>
</div>
<div class="row align-items-end m-b-5 text-info" v-if="!is1688Supplier">
<div class="col">
<div class="font-heading all-caps fs-10">Service Charges:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-11">MYR {{parameters.service_charges}}</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-primary" v-if="is1688Supplier">
<div class="col">
<div class="font-heading all-caps fs-10">Currency Rate:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading bold">{{ billGroupCurrencyRate }}</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-danger" v-if="refundTotal > 0">
<div class="col">
<div class="font-heading all-caps fs-10">Bill Refund Total:</div>
</div>
<div class="col-auto text-right" v-if="is1688Supplier">
<div class="font-heading bold">- {{ this.supplierRefunds.length > 0 ? this.supplierRefunds[0].currency.short_code : 'MYR' }} {{ this.inputPaymentTotal > 0 ? refundTotal > this.inputPaymentTotal ? this.inputPaymentTotal : formatNumber(refundTotal) : '0.00' }}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading bold">- {{ this.supplierRefunds[0].currency.short_code }} {{ formatNumber(refundTotal > paymentTotal ? paymentTotal : refundTotal) }}</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-success">
<div class="col">
<div class="font-heading all-caps fs-10">Payment Total:</div>
</div>
<div class="col-auto text-right" v-if="is1688Supplier">
<div class="font-heading bold">MYR {{ formatNumber(this.inputPaymentTotal) }}</div>
</div>
<div class="col-auto text-right" v-else>
<div class="font-heading bold">MYR {{ formatNumber(paymentTotal - refundTotal > 0 ? (paymentTotal - refundTotal) : 0) }}</div>
</div>
</div>
<div class="row align-items-end m-b-10 text-primary" v-if="refundTotal > 0 && is1688Supplier && this.inputPaymentTotal > 0">
<div class="col">
<div class="font-heading all-caps fs-10">Payment Total After Refund:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading bold">{{ this.supplierRefunds.length > 0 ? this.supplierRefunds[0].currency.short_code : 'MYR' }} {{ refundTotal > this.inputPaymentTotal ? '0.00' : formatNumber(this.inputPaymentTotal - refundTotal) }}</div>
</div>
</div>
</div>
</div>
<div class="row" v-if="is1688Supplier">
<div class="col p-r-0">
<validation-wrapper-component :validator="$v.parameters.payment_total">
<label class="all-caps">Payment Total</label>
<input type="text" class="form-control" v-model="parameters.payment_total" v-money="productPrice">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey m-r-15">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">MYR</div>
</div>
</div>
</div>
</div>
<div class="row" v-else>
<div class="col">
<validation-wrapper-component :validator="$v.parameters.service_charges">
<label class="all-caps">Service Charges</label>
<input type="text" class="form-control" v-model="parameters.service_charges" v-money="productPrice">
</validation-wrapper-component>
</div>
</div>
<div class="row" v-if="paymentTotal > 0">
<div class="col">
<button class="btn btn-xs btn-success b-rad-none p-t-5 p-b-5 all-caps fs-10 btn-block" @click="submitForm()">Create Bill Group</button>
</div>
</div>
<div class="row" v-if="this.supplier.id !== ''">
<div class="col mx-3 m-t-20">
<div class="m-b-20">
<small class="all-caps muted fs-15">Supplier Refund</small>
</div>
<list-component :key="supplierRefundListKey" section="supplierRefundListSection" :options="{'per_page': 20, 'type': 15, 'currency_rate_is_not_equal': 1, 'status': 2, 'receiver_in': [this.supplier.id]}" :endpoint="route('api.transaction.list')">
<template slot="list" slot-scope="{data}">
<supplier-refund-component section="supplierRefundListSection" :data="data" :is1688Supplier="is1688Supplier" :payments="payments" :supplierRefunds="supplierRefunds" :refundTotal="refundTotal" :paymentTotal="paymentTotal" :inputPaymentTotal="inputPaymentTotal" v-on:input="refundOrder($event)"></supplier-refund-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</template>
<script>
import FormHandler from '../../../general/mixins/formHandler';
import { required, minValue, requiredIf} from "vuelidate/lib/validators";
import ModalComponent from "../../general/elements/ModalComponent";
export default {
components: {ModalComponent},
props: {
payments: {
type: Array,
required: true
},
supplier: {
type: Object,
required: true
},
refreshList: {
type: Function,
required: true
},
},
watch: {
'supplier': function() {
this.supplierRefundListKey ++;
this.supplierRefunds = []
},
},
data(){
return {
supplierRefunds: [],
supplierRefundListKey: 1,
parameters: {
service_charges: '0',
payment_total: '0',
}
}
},
validations: {
parameters: {
service_charges: {
required: requiredIf(function () {
return !this.is1688Supplier;
})
},
payment_total: {
required: requiredIf(function () {
return this.is1688Supplier;
}),
minValue: function(value) {
const amount = parseFloat(value.replaceAll(',', ''))
return this.is1688Supplier ? amount >= 1 : true;
}
}
}
},
computed: {
inputPaymentTotal(){
return parseFloat(this.parameters.payment_total.replaceAll(',', ''));
},
originalTotal(){
return this.payments.reduce(function (total, currentValue) {
return total + currentValue.original_amount;
}, 0);
},
total(){
return this.payments.reduce(function (total, currentValue) {
return total + currentValue.amount;
}, 0);
},
paymentTotal(){
return this.total ? this.total + parseFloat(this.parameters.service_charges.replaceAll(',', '')) : 0;
},
refundOriginalTotal(){
return this.supplierRefunds.reduce(function (total, currentValue) {
return total + currentValue.original_amount;
}, 0);
},
refundTotal(){
return this.supplierRefunds.reduce(function (total, currentValue) {
return total + currentValue.amount;
}, 0);
},
billGroupCurrencyRate(){
const paymentTotal = this.inputPaymentTotal;
return this.originalTotal && paymentTotal > 0 ? (this.originalTotal / paymentTotal).toFixed(5) : 1;
},
is1688Supplier(){
return (this.supplier.id === 4548 || this.supplier.id === 2729)
}
},
methods: {
submitForm(){
this.parameters = {
payments: this.payments,
supplierRefunds: this.supplierRefunds.sort((a, b) => {
return a.amount - b.amount;
}),
service_charges: this.is1688Supplier ? '0' : this.parameters.service_charges,
payment_total: this.is1688Supplier ? this.parameters.payment_total : '0',
};
this.submit(route('api.transaction.supplier.bill_group.create', this.supplier.id), 'post', 'transactionGroupsListPaymentSection', true, true)
},
successHandler(){
this.refreshList();
this.supplierRefunds = []
this.supplierRefundListKey ++;
this.$store.dispatch('toggleSection', {name: 'paymentInProgressBillGroupList', status: !this.$store.getters.isShowing('paymentInProgressBillGroupList')});
this.parameters = {
payments: [],
service_charges: '0',
payment_total: '0',
};
},
refundOrder(supplierRefund){
this.supplierRefunds.some(item => item.id === supplierRefund.id) ? this.supplierRefunds = this.supplierRefunds.filter(item => item.id !== supplierRefund.id) : this.supplierRefunds.push(supplierRefund);
},
formatNumber(value) {
return (Math.round((value + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
},
mixins: [FormHandler]
}
</script>
@@ -0,0 +1,136 @@
<template>
<div class="row p-r-10">
<div class="col p-r-5">
<div class="row m-b-20">
<div class="col-7">
<div class="row m-b-15">
<div class="col-12">
<div class="row m-b-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}} - {{selectedSupplier.reference}}
</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}} - {{supplier.reference}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col" v-if="section === 'paymentInProgressBillGroupList'">
<list-component :key="key" section="paymentInProgressBillGroupListSection" :endpoint="route('api.transaction.group.bill.list')" :options="{per_page: 20, status: 0, ...this.selectedSupplier.id && {issuer_in: [this.selectedSupplier.id]}, order_by: {column: 'id', DESC: true}}">
<template slot="list" slot-scope="{data}">
<bill-group-component :data="data" :section="section" :selectedBillGroup="selectedBillGroup" v-on:input="selectBillGroup($event)"></bill-group-component>
</template>
</list-component>
</div>
<div class="col" v-if="section === 'paymentVerificationBillGroupList'">
<list-component :key="key" section="paymentVerificationBillGroupListSection" :endpoint="route('api.transaction.group.bill.list')" :options="{per_page: 20, has_pending_verify_transaction: true, ...this.selectedSupplier.id && {issuer_in: [this.selectedSupplier.id]}, order_by: {column: 'id', DESC: true}}">
<template slot="list" slot-scope="{data}">
<bill-group-component :data="data" :section="section" :selectedBillGroup="selectedBillGroup" v-on:input="selectBillGroup($event)"></bill-group-component>
</template>
</list-component>
</div>
<div class="col" v-if="section === 'paidBillGroupList'">
<list-component :key="key" section="paidBillGroupListSection" :endpoint="route('api.transaction.group.bill.list')" :options="{per_page: 20, status_in: [2, 3], ...this.selectedSupplier.id && {issuer_in: [this.selectedSupplier.id]}, order_by: {column: 'id', DESC: true}}">
<template slot="list" slot-scope="{data}">
<bill-group-component :data="data" :section="section" :selectedBillGroup="selectedBillGroup" v-on:input="selectBillGroup($event)"></bill-group-component>
</template>
</list-component>
</div>
</div>
</div>
<div class="col-12 col-md" v-if="section === 'paymentInProgressBillGroupList'">
<bill-group-payment-summary-component :selectedBillGroup="selectedBillGroup" :refreshList="updateList" section="paymentInProgressBillGroupList"></bill-group-payment-summary-component>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
section:{
type: String,
required: true
},
},
data(){
return {
suppliers: [],
selectedSupplier: {
id: '',
name: '',
status: false
},
selectedBillGroup: {
id: ''
},
key: 1
}
},
computed: {
pendingQueue() {
return this.$store.getters.isShowing(this.section);
}
},
watch: {
pendingQueue(){
this.updateList();
},
},
created(){
this.submit(route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]}), 'get', 'transactionGroupsListPaymentSection', false, false)
},
methods: {
successHandler(response){
this.suppliers = response.payload.data;
},
updateSupplier(supplier){
if(supplier !== this.selectedSupplier){
this.selectedSupplier = supplier;
this.updateList();
}
},
updateList(){
this.selectedSupplier.status = false;
this.selectedBillGroup = {
id: ''
};
this.key++;
},
selectBillGroup(billGroup){
this.selectedBillGroup = billGroup;
}
}
}
</script>
@@ -0,0 +1,113 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col p-r-5">
<div class="row m-b-20">
<div class="col-12 col-md-7">
<div class="row m-b-15">
<div class="col">
<div class="row m-b-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}} - {{selectedSupplier.reference}}
</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}} - {{supplier.reference}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-if="this.selectedSupplier.id !== ''">
<div class="col">
<list-component :key="currencyOrderKey" section="transactionGroupsListPaymentSection" :options="{'per_page': 20, 'without_bill_group': true, 'issuer_in': [this.selectedSupplier.id]}" :endpoint="route('api.transaction.group.list')">
<template slot="list" slot-scope="{data}">
<transaction-group-payment-component section="transactionGroupsListPaymentSection" :data="data" :payments="payments" v-on:input="updateOrder($event)"></transaction-group-payment-component>
</template>
</list-component>
</div>
</div>
<div class="row" v-else>
<div class="col">
<loading-component style="height: 200px; top: 0;" key="1" color="success"></loading-component>
</div>
</div>
</div>
<div class="col-12 col-md">
<supplier-white-form-place-order-form-component :payments="payments" :refreshList="updateList" :supplier="selectedSupplier" section="transactionGroupsListPaymentSection"></supplier-white-form-place-order-form-component>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
suppliers: [],
selectedSupplier: {
id: '',
name: '',
status: false
},
payments: [],
currencyOrderKey: 1,
}
},
created(){
this.submit(route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]}), 'get', 'transactionGroupsListPaymentSection', false, false)
},
methods: {
successHandler(response){
this.suppliers = response.payload.data;
this.selectedSupplier= this.suppliers[0];
this.updateList();
},
updateSupplier(supplier){
if(supplier !== this.selectedSupplier){
this.selectedSupplier= supplier;
this.updateList();
}
},
updateList(){
this.currencyOrderKey ++;
this.selectedSupplier.status = false;
this.payments = [];
},
updateOrder(payment){
this.payments.some(item => item.id === payment.id) ? this.payments = this.payments.filter(item => item.id !== payment.id) : this.payments.push(payment);
}
}
}
</script>

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