diff --git a/app/Classes/General/Eloquent/Filters/CurrencyRateIsNotEqual.php b/app/Classes/General/Eloquent/Filters/CurrencyRateIsNotEqual.php
new file mode 100644
index 00000000..0372e760
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/CurrencyRateIsNotEqual.php
@@ -0,0 +1,20 @@
+where('currency_rate', '!=', $value);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/HasPendingVerifyTransaction.php b/app/Classes/General/Eloquent/Filters/HasPendingVerifyTransaction.php
new file mode 100644
index 00000000..c97af23c
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/HasPendingVerifyTransaction.php
@@ -0,0 +1,23 @@
+whereHas('transactions', function ($q) {
+ $q->where('status', ApprovalStatus::PENDING_VERIFICATION);
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/IsPartialRefund.php b/app/Classes/General/Eloquent/Filters/IsPartialRefund.php
new file mode 100644
index 00000000..1378a94c
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/IsPartialRefund.php
@@ -0,0 +1,26 @@
+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'));
+ }
+ });
+ }
+}
diff --git a/app/Classes/General/Eloquent/Filters/OwnerDoesNotHaveTransactionType.php b/app/Classes/General/Eloquent/Filters/OwnerDoesNotHaveTransactionType.php
new file mode 100644
index 00000000..4dcd401c
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/OwnerDoesNotHaveTransactionType.php
@@ -0,0 +1,24 @@
+whereDoesntHave('owner', function($query) use($value) {
+ return $query->whereHas('transactions', function($query) use($value) {
+ return $query->where('transactions.type', $value);
+ });
+ });
+ }
+}
diff --git a/app/Classes/General/Eloquent/Filters/OwnerHasTransactionType.php b/app/Classes/General/Eloquent/Filters/OwnerHasTransactionType.php
new file mode 100644
index 00000000..7f96643f
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/OwnerHasTransactionType.php
@@ -0,0 +1,24 @@
+whereHas('owner', function($query) use($value) {
+ return $query->whereHas('transactions', function($query) use($value) {
+ return $query->where('transactions.type', $value);
+ });
+ });
+ }
+}
diff --git a/app/Classes/General/Eloquent/Filters/ReceiverIn.php b/app/Classes/General/Eloquent/Filters/ReceiverIn.php
new file mode 100644
index 00000000..3ce91559
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/ReceiverIn.php
@@ -0,0 +1,20 @@
+whereIn('receiver', $value);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/WithoutBillGroup.php b/app/Classes/General/Eloquent/Filters/WithoutBillGroup.php
new file mode 100644
index 00000000..6d6794e8
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/WithoutBillGroup.php
@@ -0,0 +1,22 @@
+whereDoesntHave('billGroup');
+ }
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php
index 0648629e..171b4360 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php
@@ -14,6 +14,7 @@ use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation;
+use App\Classes\Modules\Transactions\ControllersLogic\UpdateRefundTransactionStatusLogic;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
@@ -48,6 +49,9 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
/** @var CreatesTransaction */
private $createsTransaction;
+ /** @var UpdateRefundTransactionStatusLogic */
+ private $updateRefundTransactionStatusLogic;
+
/**
* CreateBookingPaymentLogic constructor.
* @param FetchesBookingQuotation $fetchBookingQuotation
@@ -55,14 +59,16 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
+ * @param UpdateRefundTransactionStatusLogic $updateRefundTransactionStatusLogic
*/
- 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)
{
$this->fetchBookingQuotation = $fetchBookingQuotation;
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
+ $this->updateRefundTransactionStatusLogic = $updateRefundTransactionStatusLogic;
}
/**
@@ -75,12 +81,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 +100,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 +109,30 @@ 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);
+
+ }
+
+ return $this->resourceResponse(new TransactionResource($refund_transaction));
}
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php
index fabdd058..e40a947d 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php
@@ -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 .'.');
}
diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingCurrencyAverageRate.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingCurrencyAverageRate.php
index da3fe0b4..9cb7717e 100644
--- a/app/Classes/Modules/Bookings/Services/CalculatesBookingCurrencyAverageRate.php
+++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingCurrencyAverageRate.php
@@ -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) {
diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingOutstanding.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingOutstanding.php
index 5f2c7733..f3a70a6a 100644
--- a/app/Classes/Modules/Bookings/Services/CalculatesBookingOutstanding.php
+++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingOutstanding.php
@@ -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);
}
}
\ No newline at end of file
diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php
index 239545af..8792aaa6 100644
--- a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php
+++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php
@@ -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);
});
diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php
index fc355d64..099d4571 100644
--- a/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php
+++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingTransferredAmount.php
@@ -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');
}
diff --git a/app/Classes/Modules/Remarks/ControllersLogic/CreateRemarkLogic.php b/app/Classes/Modules/Remarks/ControllersLogic/CreateRemarkLogic.php
new file mode 100644
index 00000000..46d822c5
--- /dev/null
+++ b/app/Classes/Modules/Remarks/ControllersLogic/CreateRemarkLogic.php
@@ -0,0 +1,62 @@
+ '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));
+ }
+}
diff --git a/app/Classes/Modules/Remarks/ControllersLogic/DeleteRemarkLogic.php b/app/Classes/Modules/Remarks/ControllersLogic/DeleteRemarkLogic.php
new file mode 100644
index 00000000..b593d603
--- /dev/null
+++ b/app/Classes/Modules/Remarks/ControllersLogic/DeleteRemarkLogic.php
@@ -0,0 +1,66 @@
+ '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([]);
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/ControllersLogic/FetchRemarkLogic.php b/app/Classes/Modules/Remarks/ControllersLogic/FetchRemarkLogic.php
new file mode 100644
index 00000000..9c5aa5af
--- /dev/null
+++ b/app/Classes/Modules/Remarks/ControllersLogic/FetchRemarkLogic.php
@@ -0,0 +1,59 @@
+ '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));
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/ControllersLogic/ListRemarksLogic.php b/app/Classes/Modules/Remarks/ControllersLogic/ListRemarksLogic.php
new file mode 100644
index 00000000..c70ccee1
--- /dev/null
+++ b/app/Classes/Modules/Remarks/ControllersLogic/ListRemarksLogic.php
@@ -0,0 +1,59 @@
+ '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));
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/ControllersLogic/UpdateRemarkLogic.php b/app/Classes/Modules/Remarks/ControllersLogic/UpdateRemarkLogic.php
new file mode 100644
index 00000000..f120efab
--- /dev/null
+++ b/app/Classes/Modules/Remarks/ControllersLogic/UpdateRemarkLogic.php
@@ -0,0 +1,71 @@
+ '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));
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php b/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php
new file mode 100644
index 00000000..44a9507f
--- /dev/null
+++ b/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php
@@ -0,0 +1,38 @@
+commenterID = $commenterID;
+ $this->content = $content;
+ }
+
+ /**
+ * @return int
+ */
+ public function getCommenterId(): string
+ {
+ return $this->commenterID;
+ }
+
+ /**
+ * @return string
+ */
+ public function getContent(): ?string
+ {
+ return $this->content;
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/Processors/CreateRemarkProcessor.php b/app/Classes/Modules/Remarks/Processors/CreateRemarkProcessor.php
new file mode 100644
index 00000000..aadbe502
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Processors/CreateRemarkProcessor.php
@@ -0,0 +1,47 @@
+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);
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Remarks/Services/CreatesRemark.php b/app/Classes/Modules/Remarks/Services/CreatesRemark.php
new file mode 100644
index 00000000..ac0d57a3
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Services/CreatesRemark.php
@@ -0,0 +1,31 @@
+commenter_id = $object->getCommenterId();
+ $model->content = $object->getContent();
+
+ return $this->handler($remarkable->remarks(), $model);
+
+ }
+}
diff --git a/app/Classes/Modules/Remarks/Services/DeletesRemark.php b/app/Classes/Modules/Remarks/Services/DeletesRemark.php
new file mode 100644
index 00000000..4c29be9d
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Services/DeletesRemark.php
@@ -0,0 +1,19 @@
+handler($model);
+ }
+}
diff --git a/app/Classes/Modules/Remarks/Services/FetchesRemark.php b/app/Classes/Modules/Remarks/Services/FetchesRemark.php
new file mode 100644
index 00000000..a3b5c765
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Services/FetchesRemark.php
@@ -0,0 +1,33 @@
+repository = $repository;
+ }
+
+
+ /**
+ * @return Builder
+ */
+ public function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/Modules/Remarks/Services/ListsRemarks.php b/app/Classes/Modules/Remarks/Services/ListsRemarks.php
new file mode 100644
index 00000000..53479558
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Services/ListsRemarks.php
@@ -0,0 +1,33 @@
+repository = $repository;
+ }
+
+
+ /**
+ * @return Builder
+ */
+ function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/Modules/Remarks/Services/UpdatesRemark.php b/app/Classes/Modules/Remarks/Services/UpdatesRemark.php
new file mode 100644
index 00000000..4ba9501c
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Services/UpdatesRemark.php
@@ -0,0 +1,26 @@
+commenter_id = $object->getCommenterId();
+ $model->content = $object->getContent();
+
+ return $this->handler($model);
+
+ }
+}
diff --git a/app/Classes/Modules/Remarks/Standards/Rules/CanCreateRemark.php b/app/Classes/Modules/Remarks/Standards/Rules/CanCreateRemark.php
new file mode 100644
index 00000000..a7d2e5b1
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Standards/Rules/CanCreateRemark.php
@@ -0,0 +1,57 @@
+RemarkValidation = $RemarkValidation;
+ }
+
+
+ /**
+ * @return bool
+ */
+ protected function authorized($object): 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;
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/Standards/Rules/CanDeleteRemark.php b/app/Classes/Modules/Remarks/Standards/Rules/CanDeleteRemark.php
new file mode 100644
index 00000000..1c61ac9d
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Standards/Rules/CanDeleteRemark.php
@@ -0,0 +1,43 @@
+RemarkValidation = $RemarkValidation;
+ }
+
+
+ /**
+ * @return bool
+ */
+ protected function authorized($object): 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;
+ }
+
+}
diff --git a/app/Classes/Modules/Remarks/Standards/Validators/RemarkValidation.php b/app/Classes/Modules/Remarks/Standards/Validators/RemarkValidation.php
new file mode 100644
index 00000000..b35d3bde
--- /dev/null
+++ b/app/Classes/Modules/Remarks/Standards/Validators/RemarkValidation.php
@@ -0,0 +1,41 @@
+ $object->getCommenterId(),
+ 'content' => $object->getContent(),
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ protected function rules(): array {
+ return [
+ 'commenter_id' => 'required',
+ 'content' => 'required',
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ protected function messages(): array {
+ return [];
+ }
+
+}
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ApproveBillGroupPaymentVerificationLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ApproveBillGroupPaymentVerificationLogic.php
new file mode 100644
index 00000000..00117f9e
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/ApproveBillGroupPaymentVerificationLogic.php
@@ -0,0 +1,93 @@
+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([]);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentProofDocumentLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentProofDocumentLogic.php
new file mode 100644
index 00000000..2563c230
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentProofDocumentLogic.php
@@ -0,0 +1,94 @@
+ '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([]);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentTransactionLogic.php
new file mode 100644
index 00000000..75be47d4
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateBillGroupPaymentTransactionLogic.php
@@ -0,0 +1,95 @@
+ '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));
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierBillGroupLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierBillGroupLogic.php
new file mode 100644
index 00000000..6213f55f
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierBillGroupLogic.php
@@ -0,0 +1,195 @@
+ '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([]);
+ }
+}
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php
index 4c407cf5..ca0f77fd 100644
--- a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php
@@ -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-');
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/DeleteBillGroupLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/DeleteBillGroupLogic.php
new file mode 100644
index 00000000..1122c111
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/DeleteBillGroupLogic.php
@@ -0,0 +1,83 @@
+ '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));
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ListBillGroupsLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ListBillGroupsLogic.php
new file mode 100644
index 00000000..0e39585b
--- /dev/null
+++ b/app/Classes/Modules/Transactions/ControllersLogic/ListBillGroupsLogic.php
@@ -0,0 +1,42 @@
+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));
+ }
+
+}
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php
index aa432aea..f29db055 100644
--- a/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php
+++ b/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php
@@ -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);
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php
index 09e4b102..cc98847a 100644
--- a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php
+++ b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php
@@ -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;
+ $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 - $refundAmount, 2, '.', '') ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::PENDING_SUBMISSION);
+ }
+
+ $request['fix_amount'] = $booking->fix_amount - $refundAmount;
+ $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);
}
diff --git a/app/Classes/Modules/Transactions/Services/CalculatesBillGroupPaymentAmount.php b/app/Classes/Modules/Transactions/Services/CalculatesBillGroupPaymentAmount.php
new file mode 100644
index 00000000..f41de813
--- /dev/null
+++ b/app/Classes/Modules/Transactions/Services/CalculatesBillGroupPaymentAmount.php
@@ -0,0 +1,25 @@
+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,
+ ];
+ }
+}
diff --git a/app/Classes/Modules/Transactions/Services/FetchesBillGroup.php b/app/Classes/Modules/Transactions/Services/FetchesBillGroup.php
new file mode 100644
index 00000000..55e5eb11
--- /dev/null
+++ b/app/Classes/Modules/Transactions/Services/FetchesBillGroup.php
@@ -0,0 +1,31 @@
+repository = $repository;
+ }
+
+ /**
+ * @return Builder
+ */
+ public function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/Modules/Transactions/Services/ListsBillGroups.php b/app/Classes/Modules/Transactions/Services/ListsBillGroups.php
new file mode 100644
index 00000000..26379706
--- /dev/null
+++ b/app/Classes/Modules/Transactions/Services/ListsBillGroups.php
@@ -0,0 +1,31 @@
+repository = $repository;
+ }
+
+ /**
+ * @return Builder
+ */
+ public function getRepository(): Builder
+ {
+ return $this->repository->newQuery();
+ }
+}
diff --git a/app/Classes/ValueObjects/Constants/DocumentType.php b/app/Classes/ValueObjects/Constants/DocumentType.php
index 23f9a94a..42f8222b 100644
--- a/app/Classes/ValueObjects/Constants/DocumentType.php
+++ b/app/Classes/ValueObjects/Constants/DocumentType.php
@@ -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';
}
diff --git a/app/Classes/ValueObjects/Constants/RemarkTypes.php b/app/Classes/ValueObjects/Constants/RemarkTypes.php
new file mode 100644
index 00000000..9629e89a
--- /dev/null
+++ b/app/Classes/ValueObjects/Constants/RemarkTypes.php
@@ -0,0 +1,13 @@
+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}");
}
}
}
diff --git a/app/Console/Commands/UpdateGroupWithTransferFee.php b/app/Console/Commands/UpdateGroupWithTransferFee.php
new file mode 100644
index 00000000..dec74d5c
--- /dev/null
+++ b/app/Console/Commands/UpdateGroupWithTransferFee.php
@@ -0,0 +1,68 @@
+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();
+ }
+ }
+ }
+}
diff --git a/app/Http/Controllers/Remarks/CreateRemarkController.php b/app/Http/Controllers/Remarks/CreateRemarkController.php
new file mode 100644
index 00000000..a66aa8fd
--- /dev/null
+++ b/app/Http/Controllers/Remarks/CreateRemarkController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
diff --git a/app/Http/Controllers/Remarks/DeleteRemarkController.php b/app/Http/Controllers/Remarks/DeleteRemarkController.php
new file mode 100644
index 00000000..8d0163c0
--- /dev/null
+++ b/app/Http/Controllers/Remarks/DeleteRemarkController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
diff --git a/app/Http/Controllers/Remarks/FetchRemarkController.php b/app/Http/Controllers/Remarks/FetchRemarkController.php
new file mode 100644
index 00000000..ba43be07
--- /dev/null
+++ b/app/Http/Controllers/Remarks/FetchRemarkController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
diff --git a/app/Http/Controllers/Remarks/ListRemarksController.php b/app/Http/Controllers/Remarks/ListRemarksController.php
new file mode 100644
index 00000000..f76f752e
--- /dev/null
+++ b/app/Http/Controllers/Remarks/ListRemarksController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
diff --git a/app/Http/Controllers/Remarks/UpdateRemarkController.php b/app/Http/Controllers/Remarks/UpdateRemarkController.php
new file mode 100644
index 00000000..ae53f6b7
--- /dev/null
+++ b/app/Http/Controllers/Remarks/UpdateRemarkController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
diff --git a/app/Http/Controllers/Transactions/ApproveBillGroupPaymentVerificationController.php b/app/Http/Controllers/Transactions/ApproveBillGroupPaymentVerificationController.php
new file mode 100644
index 00000000..fbae0c1a
--- /dev/null
+++ b/app/Http/Controllers/Transactions/ApproveBillGroupPaymentVerificationController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Transactions/CreateBillGroupPaymentProofDocumentController.php b/app/Http/Controllers/Transactions/CreateBillGroupPaymentProofDocumentController.php
new file mode 100644
index 00000000..dab95ed8
--- /dev/null
+++ b/app/Http/Controllers/Transactions/CreateBillGroupPaymentProofDocumentController.php
@@ -0,0 +1,21 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Transactions/CreateBillGroupPaymentTransactionController.php b/app/Http/Controllers/Transactions/CreateBillGroupPaymentTransactionController.php
new file mode 100644
index 00000000..7e94c84e
--- /dev/null
+++ b/app/Http/Controllers/Transactions/CreateBillGroupPaymentTransactionController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Transactions/CreateSupplierBillGroupController.php b/app/Http/Controllers/Transactions/CreateSupplierBillGroupController.php
new file mode 100644
index 00000000..7ab2f48a
--- /dev/null
+++ b/app/Http/Controllers/Transactions/CreateSupplierBillGroupController.php
@@ -0,0 +1,21 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Transactions/DeleteBillGroupController.php b/app/Http/Controllers/Transactions/DeleteBillGroupController.php
new file mode 100644
index 00000000..2b76632b
--- /dev/null
+++ b/app/Http/Controllers/Transactions/DeleteBillGroupController.php
@@ -0,0 +1,20 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Controllers/Transactions/ListBillGroupsController.php b/app/Http/Controllers/Transactions/ListBillGroupsController.php
new file mode 100644
index 00000000..94dbd5e1
--- /dev/null
+++ b/app/Http/Controllers/Transactions/ListBillGroupsController.php
@@ -0,0 +1,21 @@
+execute($request);
+ }
+}
diff --git a/app/Http/Resources/BillGroupResource.php b/app/Http/Resources/BillGroupResource.php
new file mode 100644
index 00000000..23c8050e
--- /dev/null
+++ b/app/Http/Resources/BillGroupResource.php
@@ -0,0 +1,82 @@
+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'),
+ ];
+ }),
+ ];
+ }
+}
diff --git a/app/Http/Resources/RemarkResource.php b/app/Http/Resources/RemarkResource.php
new file mode 100644
index 00000000..24081934
--- /dev/null
+++ b/app/Http/Resources/RemarkResource.php
@@ -0,0 +1,26 @@
+ $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()
+ ];
+ }
+}
diff --git a/app/Http/Resources/TransactionResource.php b/app/Http/Resources/TransactionResource.php
index 09967f4c..b431c854 100644
--- a/app/Http/Resources/TransactionResource.php
+++ b/app/Http/Resources/TransactionResource.php
@@ -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,
diff --git a/app/Models/BillGroup.php b/app/Models/BillGroup.php
new file mode 100644
index 00000000..9270d8e8
--- /dev/null
+++ b/app/Models/BillGroup.php
@@ -0,0 +1,76 @@
+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');
+ }
+}
diff --git a/app/Models/BillGroupPayment.php b/app/Models/BillGroupPayment.php
new file mode 100644
index 00000000..e34f692c
--- /dev/null
+++ b/app/Models/BillGroupPayment.php
@@ -0,0 +1,27 @@
+BelongsTo(BillGroup::class, 'bill_group_id', 'id');
+ }
+
+ /**
+ * @return BelongsTo
+ */
+ public function group(): BelongsTo
+ {
+ return $this->BelongsTo(Group::class, 'group_id', 'id');
+ }
+}
diff --git a/app/Models/BillGroupRefund.php b/app/Models/BillGroupRefund.php
new file mode 100644
index 00000000..aa430873
--- /dev/null
+++ b/app/Models/BillGroupRefund.php
@@ -0,0 +1,27 @@
+BelongsTo(BillGroup::class, 'bill_group_id', 'id');
+ }
+
+ /**
+ * @return BelongsTo
+ */
+ public function transaction(): BelongsTo
+ {
+ return $this->BelongsTo(Transaction::class, 'transaction_id', 'id');
+ }
+}
diff --git a/app/Models/Group.php b/app/Models/Group.php
index 01dd257e..8cb6cd8a 100644
--- a/app/Models/Group.php
+++ b/app/Models/Group.php
@@ -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;
@@ -60,4 +61,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');
+ }
}
diff --git a/app/Models/Remark.php b/app/Models/Remark.php
new file mode 100644
index 00000000..f2de3a5c
--- /dev/null
+++ b/app/Models/Remark.php
@@ -0,0 +1,27 @@
+morphTo();
+ }
+
+ /**
+ * @return BelongsTo
+ */
+ public function commenter(): BelongsTo
+ {
+ return $this->BelongsTo(User::class, 'commenter_id', 'id');
+ }
+}
diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php
index 185fdb36..aba5decc 100644
--- a/app/Models/Transaction.php
+++ b/app/Models/Transaction.php
@@ -186,6 +186,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 +259,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');
+ }
+
}
diff --git a/database/migrations/2023_12_04_224416_create_bill_groups_table.php b/database/migrations/2023_12_04_224416_create_bill_groups_table.php
new file mode 100644
index 00000000..e5fd986c
--- /dev/null
+++ b/database/migrations/2023_12_04_224416_create_bill_groups_table.php
@@ -0,0 +1,44 @@
+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');
+ }
+}
diff --git a/database/migrations/2023_12_04_224509_create_bill_group_payments_table.php b/database/migrations/2023_12_04_224509_create_bill_group_payments_table.php
new file mode 100644
index 00000000..5e0d2aa2
--- /dev/null
+++ b/database/migrations/2023_12_04_224509_create_bill_group_payments_table.php
@@ -0,0 +1,34 @@
+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');
+ }
+}
diff --git a/database/migrations/2024_02_22_222130_create_bill_group_refunds_table.php b/database/migrations/2024_02_22_222130_create_bill_group_refunds_table.php
new file mode 100644
index 00000000..f7b278b1
--- /dev/null
+++ b/database/migrations/2024_02_22_222130_create_bill_group_refunds_table.php
@@ -0,0 +1,22 @@
+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');
+ }
+}
diff --git a/database/migrations/2024_04_24_180633_create_remarks_table.php b/database/migrations/2024_04_24_180633_create_remarks_table.php
new file mode 100644
index 00000000..6656fd77
--- /dev/null
+++ b/database/migrations/2024_04_24_180633_create_remarks_table.php
@@ -0,0 +1,41 @@
+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');
+ }
+}
diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php
index 87d72f71..eb94b74f 100644
--- a/database/seeds/DatabaseSeeder.php
+++ b/database/seeds/DatabaseSeeder.php
@@ -48,6 +48,6 @@ class DatabaseSeeder extends Seeder
$this->call(DummyDataSeeder::class);
}
- DB::commit();
+ // DB::commit();
}
}
diff --git a/resources/assets/vue/components/bookings/elements/BillGroupComponent.vue b/resources/assets/vue/components/bookings/elements/BillGroupComponent.vue
new file mode 100644
index 00000000..e93eb1ad
--- /dev/null
+++ b/resources/assets/vue/components/bookings/elements/BillGroupComponent.vue
@@ -0,0 +1,290 @@
+
+ {{group.complete_transactions.length}}/{{group.transactions.length}}
{{item.complete_transactions.length}}/{{item.transactions.length}}
+{{item.commenter.name}}
+{{item.content}}
+