add refund transaction under booking payment history, update on admin currency order dashboard to show the correct amount after refunded

This commit is contained in:
JiaSheng
2024-01-13 13:27:24 +08:00
parent f56ee08a53
commit e5a96e179c
5 changed files with 137 additions and 13 deletions
@@ -3,6 +3,7 @@
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;
@@ -18,6 +19,7 @@ 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\Services\FetchesTransaction;
class CreateSupplierTransactionLogic extends AbstractControllerLogic
{
@@ -48,6 +50,9 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var FetchesTransaction */
private $fetchesTransaction;
/**
* CreateSupplierTransactionLogic constructor.
@@ -56,14 +61,16 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param FetchesTransaction $fetchesTransaction
*/
public function __construct(FetchesCompany $fetchesCompany, CreateSupplierTransactionProcessor $createSupplierTransactionProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber)
public function __construct(FetchesCompany $fetchesCompany, CreateSupplierTransactionProcessor $createSupplierTransactionProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber, FetchesTransaction $fetchesTransaction)
{
$this->fetchesCompany = $fetchesCompany;
$this->createSupplierTransactionProcessor = $createSupplierTransactionProcessor;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->fetchesTransaction = $fetchesTransaction;
}
public function logic(Request $request) : JsonResponse
@@ -75,6 +82,22 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic
$payments = $request->input('payments');
foreach($payments as $payment){
$payment = $this->fetchesTransaction->execute(['id' => $payment['id']]);
$pendingRefundRequest = $payment->transactions()->refunds()->where('status', ApprovalStatus::PENDING_VERIFICATION)->first();
if ($pendingRefundRequest) {
throw new MalformedRequestException('Unable to create supplier order for pending refund request payment');
}
$totalRefund = $payment->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->sum('original_amount');
if ($payment->original_amount - $totalRefund <= 0) {
throw new MalformedRequestException('Unable to create supplier order for fully refunded payment');
}
}
$this->createSupplierTransactionProcessor->execute($supplier, $rate, $payments);
if(!count($this->createSupplierTransactionProcessor->getBills())) return $this->response([]);
@@ -81,15 +81,19 @@ class CreateSupplierTransactionProcessor
if($payment->status !== ApprovalStatus::APPROVED) continue;
$totalRefund = $payment->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->sum('original_amount');
$original_amount_after_refund = $payment->original_amount - $totalRefund;
$this->updatesTransactionStatus->execute($payment, ApprovalStatus::COMPLETED);
$billNumber = $this->generatesTransactionBillNumber->execute('SPLR-');
$constant = SegmentConstant::where('reference', SegmentConstants::SERVICE_CHARGE)->where('detail->id', $supplier->id)->first();
$serviceCharge = $this->calculatesTransactionServiceCharge->execute($payment->original_amount, $rate, $constant);
$serviceCharge = $this->calculatesTransactionServiceCharge->execute($original_amount_after_refund, $rate, $constant);
$object = new TransactionObject($billNumber, TransactionType::BILL, $supplier->id, 1,
$supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH,
$payment->original_amount * (1 / $rate), $payment->original_amount, 1, $payment->original_currency_id,
$original_amount_after_refund * (1 / $rate), $original_amount_after_refund, 1, $payment->original_currency_id,
$rate, 0, $serviceCharge, null, ApprovalStatus::PENDING_SUBMISSION);
/** @var Transaction $billTransaction */
@@ -101,7 +105,7 @@ class CreateSupplierTransactionProcessor
$transferFee = $this->calculatesTransactionTransferFee->execute($billTransaction->original_amount, $constant);
$object = new TransactionObject($transferFeeNumber, TransactionType::TRANSFER_FEE, 1, $supplier->id,
$supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH,
$payment->original_amount, $payment->original_amount, $payment->original_currency_id, $payment->original_currency_id,
$original_amount_after_refund, $original_amount_after_refund, $payment->original_currency_id, $payment->original_currency_id,
1, 0, $transferFee, null, ApprovalStatus::PENDING_VERIFICATION);
$this->pushTransferFee($this->createsTransaction->execute($billTransaction, $object));
@@ -24,7 +24,7 @@
<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.original_currency.short_code}} {{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
{{item.currency.short_code}} {{(Math.round((totalConvertRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
@@ -136,6 +136,12 @@
<div class="font-heading fs-10">{{item.original_currency.short_code}} {{(Math.round((totalRequestedRefund + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end m-b-10 bold text-danger" v-if="totalRequestedRefund != 0">
<div class="col"></div>
<div class="col-auto text-right">
<div class="font-heading fs-10">{{item.currency.short_code}} {{(Math.round((totalRequestedConvertRefund + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</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>
@@ -144,6 +150,12 @@
<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>
</div>
<div class="row align-items-end m-b-10 bold text-danger" v-if="totalRefunds != 0">
<div class="col"></div>
<div class="col-auto text-right">
<div class="font-heading fs-12">{{item.currency.short_code}} {{(Math.round((totalConvertRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end bold m-b-10 text-primary">
<div class="col">
<div class="font-heading all-caps fs-10">Rate</div>
@@ -187,6 +199,14 @@
<div class="font-heading fs-12">MYR {{(Math.round((item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end m-b-10 bold text-success" v-if="totalRefunds != 0">
<div class="col">
<div class="font-heading all-caps fs-10">Your Payment After Refund</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">MYR {{(Math.round((item.amount - totalConvertRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 m-b-5">Your Payment Proof</div>
@@ -279,6 +299,47 @@
</modal-component>
</div>
</div>
<div class="row m-t-10" v-if="totalRefunds !== 0">
<div class="col">
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border" @click="clickExpandRefundTransactions">Show Refund Transactions</button>
</div>
</div>
</div>
</div>
<div class="row" v-if="totalRefunds != 0 && expandRefundTransactions">
<div class="col bg-white padding-15">
<div v-for="(refund, index) in data.transaction_refunds">
<div class="row align-items-end m-b-10 bold">
<div class="col">
<div class="font-heading all-caps fs-10">{{ index + 1 }}. Refund updated on</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-10">{{ refund.updated_at }}</div>
</div>
</div>
<div class="row align-items-end m-b-10 bold">
<div class="col">
<div class="font-heading all-caps fs-10">&nbsp;&nbsp;&nbsp; Refund status</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-10" :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="row align-items-end m-b-10 bold text-danger">
<div class="col">
<div class="font-heading all-caps fs-10">&nbsp;&nbsp;&nbsp; Requested Refund Amount</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-10">{{refund.original_currency.short_code}} {{(Math.round((refund.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end m-b-10 bold text-danger">
<div class="col"></div>
<div class="col-auto text-right">
<div class="font-heading fs-10">{{refund.currency.short_code}} {{(Math.round((refund.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -291,6 +352,7 @@
data(){
return {
expandPaymentDetails: false,
expandRefundTransactions: false,
amount: (Math.round(1000 * 100) / 100).toFixed(2),
parameters: {
amount: (Math.round(1000 * 100) / 100).toFixed(2),
@@ -313,12 +375,12 @@
let vm = this;
var TotalRequestedRefund = 0;
this.data.transaction_refunds.forEach(function(refunds) {
TotalRequestedRefund += refunds.status === 1 ? refunds.original_amount : 0;
TotalRequestedRefund += refunds.status === 1 ? refunds.amount : 0;
});
if (vm.data.booking.fixed_currency.id != 1 && this.data.transaction_refunds[0]) {
TotalRequestedRefund = (TotalRequestedRefund * this.data.transaction_refunds[0].currency_rate);
}
return ((Math.round((TotalRequestedRefund + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
// if (vm.data.booking.fixed_currency.id != 1 && this.data.transaction_refunds[0]) {
// TotalRequestedRefund = (TotalRequestedRefund * this.data.transaction_refunds[0].currency_rate);
// }
return TotalRequestedRefund;
},
totalRefunds() {
var TotalRequestedRefund = 0;
@@ -326,11 +388,22 @@
TotalRequestedRefund += refunds.status === 2 ? refunds.original_amount : 0;
});
return TotalRequestedRefund;
},
totalConvertRefunds() {
var TotalRequestedRefund = 0;
this.data.transaction_refunds.forEach(function(refunds) {
TotalRequestedRefund += refunds.status === 2 ? refunds.amount : 0;
});
return TotalRequestedRefund;
}
},
methods: {
clickExpand(){
this.expandPaymentDetails = !this.expandPaymentDetails;
this.expandRefundTransactions = false;
},
clickExpandRefundTransactions(){
this.expandRefundTransactions = !this.expandRefundTransactions;
},
},
mixins: [componentHandler]
@@ -56,6 +56,16 @@
<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="row">
<div class="col">
<div class="font-heading fs-10 muted all-caps">Refunded Amount</div>
<div class="font-heading fs-14 text-danger bold">
{{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-auto">
@@ -95,7 +105,7 @@
<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">
{{(Math.round((item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
{{(Math.round((item.original_amount - totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
</div>
@@ -124,11 +134,20 @@
active: false,
}
},
computed: {
totalRefunds() {
var TotalRequestedRefund = 0;
this.data.transaction_refunds.forEach(function(refunds) {
TotalRequestedRefund += refunds.status === 2 ? refunds.original_amount : 0;
});
return TotalRequestedRefund;
}
},
methods: {
activate(){
this.active = !this.active;
this.$emit('input', this.item)
}
},
},
mixins: [componentHandler]
}
@@ -115,7 +115,12 @@
computed: {
total(){
return this.payments.reduce(function (total, currentValue) {
return total + currentValue.original_amount;
return total + currentValue.original_amount - currentValue.transaction_refunds.reduce(function (totalRefund, refundTransaction) {
if (refundTransaction.status === 2) {
return totalRefund + refundTransaction.original_amount;
}
return totalRefund;
}, 0);
}, 0);
},