mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
E-Invoice - Enhancement to allow EInvoice to be generated for cases with refund
This commit is contained in:
@@ -6,10 +6,12 @@ use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Bookings\Services\FetchesBooking;
|
||||
use App\Classes\Modules\Bookings\Standards\Rules\CanFetchBooking;
|
||||
use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingProcessor;
|
||||
use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingV2Processor;
|
||||
use App\Http\Resources\BookingResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
{
|
||||
@@ -34,20 +36,26 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
/** @var RegenerateInvoiceBookingProcessor */
|
||||
private $regenerateInvoiceBookingProcessor;
|
||||
|
||||
/** @var RegenerateInvoiceBookingV2Processor */
|
||||
private $regenerateInvoiceBookingV2Processor;
|
||||
|
||||
/**
|
||||
* RegenerateInvoiceBookingLogic constructor.
|
||||
* @param CanFetchBooking $canFetchBooking
|
||||
* @param FetchesBooking $fetchesBooking
|
||||
* @param RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
* @param RegenerateInvoiceBookingV2Processor $regenerateInvoiceBookingV2Processor
|
||||
*/
|
||||
public function __construct(
|
||||
CanFetchBooking $canFetchBooking,
|
||||
FetchesBooking $fetchesBooking,
|
||||
RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor,
|
||||
RegenerateInvoiceBookingV2Processor $regenerateInvoiceBookingV2Processor
|
||||
) {
|
||||
$this->canFetchBooking = $canFetchBooking;
|
||||
$this->fetchesBooking = $fetchesBooking;
|
||||
$this->regenerateInvoiceBookingProcessor = $regenerateInvoiceBookingProcessor;
|
||||
$this->regenerateInvoiceBookingV2Processor = $regenerateInvoiceBookingV2Processor;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,13 +73,20 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
$booking = $this->fetchesBooking->execute(
|
||||
[
|
||||
'id' => $request->route('id'),
|
||||
'status' => ApprovalStatus::COMPLETED,
|
||||
// 'status' => ApprovalStatus::COMPLETED, //cief todo: 90 - must have completed to avoid generate invoice inaccurately
|
||||
'with_transactions' => true
|
||||
]
|
||||
);
|
||||
$normalInvoice = $request->input('normal_invoice', false);
|
||||
|
||||
$this->regenerateInvoiceBookingProcessor->execute($booking, $normalInvoice);
|
||||
$eInvoiceWithNormalInvoiceTemplate = $request->input('normal_invoice', false);
|
||||
$eInvoiceRefund = $request->input('e_invoice_refund', false);
|
||||
|
||||
// if($eInvoiceRefund){
|
||||
$this->regenerateInvoiceBookingV2Processor->execute($booking, $eInvoiceWithNormalInvoiceTemplate, $eInvoiceRefund);
|
||||
// }
|
||||
// else{
|
||||
// $this->regenerateInvoiceBookingProcessor->execute($booking, $eInvoiceWithNormalInvoiceTemplate);
|
||||
// }
|
||||
|
||||
return $this->resourceResponse(new BookingResource($booking));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Bookings\Processors;
|
||||
|
||||
|
||||
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
|
||||
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
|
||||
use App\Classes\Modules\Documents\Services\DeletesDocument;
|
||||
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionV2Processor;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RegenerateInvoiceBookingV2Processor
|
||||
{
|
||||
/** @var DeletesTransaction */
|
||||
private $deletesTransaction;
|
||||
|
||||
/** @var UpdatesBookingStatus */
|
||||
private $updatesBookingStatus;
|
||||
|
||||
/** @var DeletesDocument */
|
||||
private $deletesDocument;
|
||||
|
||||
/** @var CreateInvoiceTransactionV2Processor */
|
||||
private $createInvoiceTransactionProcessor;
|
||||
|
||||
/**
|
||||
* RegenerateInvoiceBookingV2Processor constructor.
|
||||
* @param DeletesTransaction $deletesTransaction
|
||||
* @param UpdatesBookingStatus $updatesBookingStatus
|
||||
* @param DeletesDocument $deletesDocument
|
||||
* @param CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor
|
||||
*/
|
||||
public function __construct(
|
||||
DeletesTransaction $deletesTransaction,
|
||||
UpdatesBookingStatus $updatesBookingStatus,
|
||||
DeletesDocument $deletesDocument,
|
||||
CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor
|
||||
) {
|
||||
$this->deletesTransaction = $deletesTransaction;
|
||||
$this->updatesBookingStatus = $updatesBookingStatus;
|
||||
$this->deletesDocument = $deletesDocument;
|
||||
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
|
||||
}
|
||||
|
||||
public function execute(Booking $booking,
|
||||
bool $eInvoiceWithNormalInvoiceTemplate = false,
|
||||
bool $eInvoiceWithRefund = false)
|
||||
{
|
||||
$bookingOriginalStatus = $booking->status;
|
||||
|
||||
if(!$eInvoiceWithRefund){
|
||||
$this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED);
|
||||
}
|
||||
|
||||
$firstInvoice = $booking->transactions()
|
||||
->whereIn('type', [TransactionType::INVOICE])
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'asc')
|
||||
->first();
|
||||
|
||||
Log::info('RegenerateInvoiceBookingV2Processor booking: ' . json_encode($booking->marking));
|
||||
|
||||
// get the first bill_no
|
||||
if($firstInvoice){
|
||||
$firstBillNo = $firstInvoice->bill_no;
|
||||
if (strpos($firstBillNo, '-deleted') !== false) {
|
||||
$firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted'));
|
||||
}
|
||||
|
||||
// update currentInvoice bill_no to '-deleted-'
|
||||
$currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first();
|
||||
if($currentInvoice){
|
||||
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp);
|
||||
$currentInvoice->save();
|
||||
}
|
||||
|
||||
$transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get();
|
||||
if ($transactionWithSameBillNo) {
|
||||
foreach ($transactionWithSameBillNo as $transaction) {
|
||||
$transaction->bill_no = $transaction->bill_no . "-deleted-" . Str::random(10);
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
|
||||
$transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get();
|
||||
foreach ($transaction as $key => $row) {
|
||||
$this->deletesTransaction->execute($row);
|
||||
}
|
||||
|
||||
$document = $booking->documents()->whereIn('document_type', [DocumentType::PURCHASE_ORDER, DocumentType::INVOICE, DocumentType::EINVOICE, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->get();
|
||||
foreach ($document as $key => $row) {
|
||||
$this->deletesDocument->execute($row);
|
||||
}
|
||||
|
||||
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, [
|
||||
'generateEInvoice' => true,
|
||||
'generateEInvoiceWithNormalInvoiceTemplate' => $eInvoiceWithNormalInvoiceTemplate,
|
||||
'generateEInvoiceRefund' => $eInvoiceWithRefund,
|
||||
'bookingOriginalStatus' => $bookingOriginalStatus
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$this->createInvoiceTransactionProcessor->execute($booking, "", [
|
||||
'generateEInvoice' => false,
|
||||
'generateEInvoiceWithNormalInvoiceTemplate' => $eInvoiceWithNormalInvoiceTemplate,
|
||||
'generateEInvoiceRefund' => $eInvoiceWithRefund,
|
||||
'bookingOriginalStatus' => $bookingOriginalStatus
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ class CalculatesBookingCurrencyAverageRate
|
||||
}
|
||||
|
||||
|
||||
public function execute(Booking $booking, $type){
|
||||
public function execute(Booking $booking, $type, bool $generateEInvoiceRefund = false){
|
||||
|
||||
$transaction = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
@@ -37,9 +37,16 @@ class CalculatesBookingCurrencyAverageRate
|
||||
}
|
||||
|
||||
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 + $discount);
|
||||
if($generateEInvoiceRefund){
|
||||
$totalPayment = $booking->fix_currency_id === 1 ? $booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)->sum('original_amount') :
|
||||
$booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
|
||||
}
|
||||
else{
|
||||
$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, $generateEInvoiceRefund) / ($totalPayment + $discount);
|
||||
|
||||
}
|
||||
else if ($type == TransactionType::BILL) {
|
||||
@@ -47,4 +54,4 @@ class CalculatesBookingCurrencyAverageRate
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,18 @@ use Carbon\Carbon;
|
||||
class CalculatesBookingPayableAmount
|
||||
{
|
||||
|
||||
public function execute(Booking $booking, int $type){
|
||||
public function execute(Booking $booking, int $type, bool $generateEInvoiceRefund = false){
|
||||
|
||||
if($generateEInvoiceRefund){
|
||||
return $type === 1 ?
|
||||
$booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)
|
||||
->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total') :
|
||||
$booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)->sum('original_amount');
|
||||
}
|
||||
return $type === 1 ?
|
||||
$booking->transactions()->payments()->complete()
|
||||
->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total') :
|
||||
$booking->transactions()->payments()->complete()->sum('original_amount');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class CreateInvoiceDocumentProcessor
|
||||
* @return void
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null, $isAllowNormalInvoice = false)
|
||||
public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null, $generateEInvoiceWithNormalInvoiceTemplate = false, $generateEInvoiceRefund = false)
|
||||
{
|
||||
// calculate current Paid Amount
|
||||
$booking = $transaction->owner_type == Booking::class ? $transaction->owner : null;
|
||||
@@ -61,7 +61,13 @@ class CreateInvoiceDocumentProcessor
|
||||
if ($booking) {
|
||||
$bookingCreatedDate = Carbon::parse($booking->created_at);
|
||||
if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) {
|
||||
$lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first();
|
||||
if($generateEInvoiceRefund){
|
||||
$lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::REFUNDED])->latest()->first();
|
||||
}
|
||||
else{
|
||||
$lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first();
|
||||
}
|
||||
|
||||
$documentDate = $lastPaymentTransaction->created_at;
|
||||
}
|
||||
|
||||
@@ -83,7 +89,14 @@ class CreateInvoiceDocumentProcessor
|
||||
$documentDate = $lastDayOfMonth;
|
||||
}
|
||||
}
|
||||
$payment = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->first();
|
||||
|
||||
if($generateEInvoiceRefund){
|
||||
$payment = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::REFUNDED])->first();
|
||||
}
|
||||
else{
|
||||
$payment = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->first();
|
||||
}
|
||||
|
||||
$refundAmount = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->sum('amount');
|
||||
$paymentAmount = $payment->amount;
|
||||
$currentPaidAmount = $paymentAmount - $refundAmount;
|
||||
@@ -92,7 +105,7 @@ class CreateInvoiceDocumentProcessor
|
||||
$lowercaseDocumentType = strtolower($document_type);
|
||||
|
||||
if($document_type === DocumentType::EINVOICE){ //July 2025 workaround generate normal invoice instead of E-Invoice
|
||||
if($isAllowNormalInvoice){
|
||||
if($generateEInvoiceWithNormalInvoiceTemplate){
|
||||
$lowercaseDocumentType = strtolower(DocumentType::INVOICE);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +182,7 @@ class CreateInvoiceDocumentProcessor
|
||||
$document = $this->createsDocument->execute($transaction, $document_object);
|
||||
}
|
||||
else{
|
||||
$document = $this->createsDocument->execute($purchaseOrder->booking, $document_object);
|
||||
$document = $this->createsDocument->execute($purchaseOrder->booking ?? $booking, $document_object);
|
||||
}
|
||||
$this->createsFile->execute($document, $document_object);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Transactions\Processors;
|
||||
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount;
|
||||
use App\Classes\Modules\Bookings\Services\CalculatesBookingTransferredAmount;
|
||||
use App\Classes\Modules\ServiceTypes\Services\FetchesServiceConfigurations;
|
||||
use App\Classes\Modules\Transactions\Services\ListsTransactions;
|
||||
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
|
||||
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
|
||||
use App\Classes\Modules\Bookings\Services\CalculatesBookingPaidAmount;
|
||||
use App\Classes\Modules\Bookings\Services\CalculatesBookingCurrencyAverageRate;
|
||||
use App\Classes\Modules\Companies\Services\FetchesCompany;
|
||||
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
|
||||
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\SegmentConstants;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Classes\ValueObjects\Constants\KVPKey;
|
||||
use App\Models\Booking;
|
||||
use App\Models\SegmentConstant;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreateInvoiceTransactionV2Processor
|
||||
{
|
||||
|
||||
/** @var CreatesTransaction */
|
||||
private $createsTransaction;
|
||||
|
||||
/** @var GeneratesTransactionBillNumber */
|
||||
private $generatesTransactionBillNumber;
|
||||
|
||||
/** @var CalculatesBookingPaidAmount */
|
||||
private $calculatesBookingPaidAmount;
|
||||
|
||||
/** @var CalculatesBookingPayableAmount */
|
||||
private $calculatesBookingPayableAmount;
|
||||
|
||||
/** @var CalculatesBookingTransferredAmount */
|
||||
private $calculatesBookingTransferredAmount;
|
||||
|
||||
/** @var CalculatesBookingCurrencyAverageRate */
|
||||
private $calculatesBookingCurrencyAverageRate;
|
||||
|
||||
/** @var FetchesCompany */
|
||||
private $fetchesCompany;
|
||||
|
||||
/** @var UpdatesBookingStatus */
|
||||
private $updatesBookingStatus;
|
||||
|
||||
/** @var CreateInvoiceDocumentProcessor */
|
||||
private $invoiceDocumentProcessor;
|
||||
|
||||
|
||||
/**
|
||||
* CreateInvoiceTransactionV2Processor constructor.
|
||||
* @param ListsTransactions $listsTransactions
|
||||
* @param CreatesTransaction $createsTransaction
|
||||
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
|
||||
* @param CalculatesBookingPaidAmount $calculatesBookingPaidAmount
|
||||
* @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount
|
||||
* @param CalculatesBookingTransferredAmount $calculatesBookingTransferredAmount
|
||||
* @param FetchesServiceConfigurations $fetchesServiceConfigurations
|
||||
* @param CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate
|
||||
* @param FetchesCompany $fetchesCompany
|
||||
* @param UpdatesBookingStatus $updatesBookingStatus
|
||||
* @param CreateInvoiceDocumentProcessor $invoiceDocumentProcessor
|
||||
*/
|
||||
public function __construct(ListsTransactions $listsTransactions, CreatesTransaction $createsTransaction, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CalculatesBookingPaidAmount $calculatesBookingPaidAmount, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingTransferredAmount $calculatesBookingTransferredAmount, FetchesServiceConfigurations $fetchesServiceConfigurations, CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate, FetchesCompany $fetchesCompany, UpdatesBookingStatus $updatesBookingStatus, CreateInvoiceDocumentProcessor $invoiceDocumentProcessor)
|
||||
{
|
||||
$this->createsTransaction = $createsTransaction;
|
||||
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
|
||||
$this->calculatesBookingPaidAmount = $calculatesBookingPaidAmount;
|
||||
$this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount;
|
||||
$this->calculatesBookingTransferredAmount = $calculatesBookingTransferredAmount;
|
||||
$this->calculatesBookingCurrencyAverageRate = $calculatesBookingCurrencyAverageRate;
|
||||
$this->fetchesCompany = $fetchesCompany;
|
||||
$this->updatesBookingStatus = $updatesBookingStatus;
|
||||
$this->invoiceDocumentProcessor = $invoiceDocumentProcessor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Booking $booking
|
||||
* @param String $invoiceNo
|
||||
* @param array $options
|
||||
* @return void
|
||||
* @throws MalformedRequestException
|
||||
*/
|
||||
public function execute(Booking $booking, String $invoiceNo= "", array $options = [])
|
||||
{
|
||||
$generateEInvoice = $options['generateEInvoice'] ?? false;
|
||||
$generateEInvoiceWithNormalInvoiceTemplate = $options['generateEInvoiceWithNormalInvoiceTemplate'] ?? false;
|
||||
$generateEInvoiceRefund = $options['generateEInvoiceRefund'] ?? false;
|
||||
$bookingOriginalStatus = $options['bookingOriginalStatus'] ?? ApprovalStatus::COMPLETED;
|
||||
|
||||
if($generateEInvoiceRefund){
|
||||
$generateEInvoice = true; //cief todo: 90 - cannot have 2 flags doing the same thing
|
||||
}
|
||||
|
||||
if ($booking->status === ApprovalStatus::COMPLETED && !$generateEInvoiceRefund) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payable_amount = $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id, $generateEInvoiceRefund);
|
||||
$booking_amount = $booking->fix_amount;
|
||||
|
||||
// confirm that booking amount has been fully paid
|
||||
if ((float) $booking_amount > (float) $payable_amount) {
|
||||
return;
|
||||
}
|
||||
// confirm that all payments has been transferred
|
||||
if ($this->calculatesBookingTransferredAmount->execute($booking) !== $this->calculatesBookingPaidAmount->execute($booking)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($generateEInvoiceRefund){
|
||||
$purchaseOrder = $booking->transactions()
|
||||
->where('type', TransactionType::PURCHASE_ORDER)
|
||||
->where('status', ApprovalStatus::PENDING_SUBMISSION)
|
||||
->first();
|
||||
}
|
||||
else{
|
||||
$purchaseOrder = $booking->transactions()
|
||||
->where('type', TransactionType::PURCHASE_ORDER)
|
||||
->complete()
|
||||
->first();
|
||||
}
|
||||
|
||||
$constants = SegmentConstant::where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->id', $booking->service->id)->first();
|
||||
|
||||
if ($constants->detail->is_billable && !$purchaseOrder && !$generateEInvoiceRefund) {
|
||||
return;
|
||||
}
|
||||
|
||||
// $transaction = $booking->transactions()
|
||||
// ->where('type', TransactionType::PAYMENT)
|
||||
// ->first();
|
||||
|
||||
$transaction = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->latest()->get()[0];
|
||||
$supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);
|
||||
|
||||
// Check if eInvoice implementation has started and company opted in for eInvoice
|
||||
$eInvoice = false;
|
||||
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
|
||||
$bookingCreatedDate = Carbon::parse($booking->created_at);
|
||||
if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $supplier->e_invoice === 1) {
|
||||
$eInvoice = true;
|
||||
}
|
||||
$kvp = $booking->attributesKVP()->where('key', KVPKey::BOOKING_EINVOICE_ELIGIBLE)->first();
|
||||
if($kvp){
|
||||
$eInvoice = true;
|
||||
}
|
||||
|
||||
if($generateEInvoiceWithNormalInvoiceTemplate){
|
||||
$invoiceNo = ""; //July 2025 workaround generate normal invoice instead of E-Invoice
|
||||
}
|
||||
|
||||
if($invoiceNo){
|
||||
$billNumber = $invoiceNo;
|
||||
}
|
||||
else{
|
||||
$billNUmberPrefix = $eInvoice ? 'EINV-' : 'INV-';
|
||||
if($generateEInvoiceWithNormalInvoiceTemplate){
|
||||
$billNUmberPrefix = 'INV-'; //July 2025 workaround generate normal invoice instead of E-Invoice
|
||||
}
|
||||
$billNumber = $this->generatesTransactionBillNumber->execute($billNUmberPrefix);
|
||||
}
|
||||
|
||||
$booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::PAYMENT, $generateEInvoiceRefund);
|
||||
|
||||
if($generateEInvoiceRefund){
|
||||
$total_service_charge = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->whereIn('status', [ApprovalStatus::REFUNDED])
|
||||
->sum('service_charge');
|
||||
|
||||
$total_tax = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->whereIn('status', [ApprovalStatus::REFUNDED])
|
||||
->sum('tax');
|
||||
}
|
||||
else{
|
||||
$total_service_charge = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->sum('service_charge');
|
||||
|
||||
$total_tax = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->sum('tax');
|
||||
}
|
||||
|
||||
|
||||
|
||||
$transaction_object = new TransactionObject(
|
||||
$billNumber,
|
||||
TransactionType::INVOICE,
|
||||
$transaction->issuer,
|
||||
$transaction->receiver,
|
||||
$transaction->recipient_bank_account_id,
|
||||
$transaction->payment_method,
|
||||
$payable_amount,
|
||||
$booking_amount,
|
||||
$transaction->currency_id,
|
||||
$transaction->original_currency_id,
|
||||
$booking_currency_average_rate,
|
||||
$total_tax,
|
||||
$total_service_charge,
|
||||
null,
|
||||
ApprovalStatus::APPROVED
|
||||
);
|
||||
$invoice_transaction = $this->createsTransaction->execute($purchaseOrder->booking ?? $booking, $transaction_object);
|
||||
|
||||
$voucherRedemption = $transaction->voucherRedemption;
|
||||
|
||||
// purchase order
|
||||
if(!$generateEInvoiceRefund){
|
||||
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate);
|
||||
}
|
||||
|
||||
// deliver order
|
||||
if(!$generateEInvoiceRefund){
|
||||
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate);
|
||||
}
|
||||
|
||||
// e-invoice
|
||||
if ($eInvoice)
|
||||
{
|
||||
if($generateEInvoice){
|
||||
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund);
|
||||
}
|
||||
}
|
||||
// invoice
|
||||
else
|
||||
{
|
||||
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund);
|
||||
}
|
||||
|
||||
if(!$generateEInvoiceRefund){
|
||||
$billNumber = $this->generatesTransactionBillNumber->execute('SPDO-');
|
||||
|
||||
$booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::BILL, $generateEInvoiceRefund);
|
||||
|
||||
$paymentTransaction = $booking->transactions()->payments()->where('status', ApprovalStatus::COMPLETED)->first();
|
||||
|
||||
$transaction = null;
|
||||
if($paymentTransaction){
|
||||
$transaction = $paymentTransaction->transactions()->where('type', TransactionType::BILL)->first();
|
||||
}
|
||||
else{ // Special handling for refund cases (When a refund is deleted via DeleteRefundTransactionLogic, a booking payment transaction is set to ApprovalStatus::APPROVED)
|
||||
$temp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first();
|
||||
// Lets check if there is a refund case
|
||||
$refund = $temp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first();
|
||||
if($refund){
|
||||
$transaction = $temp;
|
||||
}
|
||||
else{
|
||||
throw new Exception("No payment found for booking '$booking->id'.");
|
||||
}
|
||||
}
|
||||
|
||||
$transaction_object = new TransactionObject(
|
||||
$billNumber,
|
||||
TransactionType::SUPPLIER_DELIVER,
|
||||
$transaction->issuer,
|
||||
$transaction->receiver,
|
||||
$transaction->recipient_bank_account_id,
|
||||
$transaction->payment_method,
|
||||
$payable_amount,
|
||||
$booking_amount,
|
||||
$transaction->currency_id,
|
||||
$transaction->original_currency_id,
|
||||
$booking_currency_average_rate,
|
||||
$total_tax,
|
||||
$total_service_charge,
|
||||
null,
|
||||
ApprovalStatus::APPROVED
|
||||
);
|
||||
$supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object);
|
||||
|
||||
// supply deliver order
|
||||
$this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null);
|
||||
}
|
||||
|
||||
//if(!$generateEInvoiceRefund){
|
||||
$this->updatesBookingStatus->execute($booking, $bookingOriginalStatus);
|
||||
//}
|
||||
|
||||
// update perfex crm
|
||||
// if(config('perfexcrm.is_enabled') == 'true'){
|
||||
// CreatePerfexCRMInvoice::dispatch($invoice_transaction, $purchaseOrder, $supplier);
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col bg-white padding-40 b-rad-lg">
|
||||
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="isLoading" ></loading-component>
|
||||
<div class="row justify-content-center" v-show="!isLoading">
|
||||
<div class="col">
|
||||
<div class="row m-b-20">
|
||||
<div class="col">
|
||||
<h3 class="all-caps">Are you Sure?</h3>
|
||||
<div class="fs-11">Are you sure you want to regenerate the e-invoice for this payment?</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col p-r-5">
|
||||
<div class="btn btn-sm btn-success btn-block b-rad-none" data-dismiss="modal">Cancel</div>
|
||||
</div>
|
||||
<div class="col p-l-5">
|
||||
<div class="btn btn-sm btn-danger btn-block b-rad-none" @click="submitForm()">Confirm</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
|
||||
export default {
|
||||
methods: {
|
||||
submitForm() {
|
||||
this.parameters.normal_invoice = false;
|
||||
this.parameters.e_invoice_refund = true;
|
||||
this.submit(this.route('api.booking.einvoice.regenerate', this.data.id), 'post', this.section, true, true);
|
||||
},
|
||||
successHandler(){
|
||||
this.closeModal();
|
||||
this.$store.dispatch('reloadList', {'name': "bookingDetailSection"});
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler, ModalFormHandler]
|
||||
}
|
||||
</script>
|
||||
+61
-1
File diff suppressed because one or more lines are too long
@@ -25,7 +25,7 @@
|
||||
<td class="header-details">
|
||||
<div class="title"><strong>E-Invoice</strong></div>
|
||||
<div class="number">EI#: {{ $autocountId ?? 'NONE'}}</div>
|
||||
<div class="ref">Ref# {{ $po_order_transaction->booking->marking }}</div>
|
||||
<div class="ref">Ref# {{ $booking->marking }}</div>
|
||||
<div class="date">Date: {{ $document_date->toDateString() }}</div>
|
||||
<div> </div>
|
||||
</td>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
|
||||
$booking = $po_order_transaction->owner;
|
||||
$booking = $po_order_transaction->owner ?? $booking;
|
||||
$paymentSum = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->where('status', ApprovalStatus::COMPLETED)
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
$totalPayment = 0;
|
||||
$average_currency_rate = $transaction->currency_rate;
|
||||
|
||||
$paymentSumRefund = 0;
|
||||
if ($paymentSum){
|
||||
$average_currency_rate = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
@@ -53,30 +55,41 @@
|
||||
|
||||
$totalPayment = $paymentSum - $refundedAmount - $refundedServiceCharge;
|
||||
}
|
||||
else{
|
||||
$paymentSumRefund = $booking->transactions()
|
||||
->where('type', TransactionType::PAYMENT)
|
||||
->where('status', ApprovalStatus::REFUNDED)
|
||||
->get()
|
||||
->sum(function ($transaction) {
|
||||
return round($transaction->amount, 2);
|
||||
});
|
||||
}
|
||||
?>
|
||||
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = ($currency_id) === 1 ? $transaction_detail->price : bcdiv($transaction_detail->price, $average_currency_rate, 7);
|
||||
$displayUnitPrice = round($exactUnitPrice, 2);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
$displayedItemTotal = round(bcmul($displayUnitPrice, $transaction_detail->quantity, 7), 2);
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($displayUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($displayedItemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@if (!empty($po_order_transaction) && $po_order_transaction->transactionDetails)
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = ($currency_id) === 1 ? $transaction_detail->price : bcdiv($transaction_detail->price, $average_currency_rate, 7);
|
||||
$displayUnitPrice = round($exactUnitPrice, 2);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
$displayedItemTotal = round(bcmul($displayUnitPrice, $transaction_detail->quantity, 7), 2);
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($displayUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($displayedItemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endif
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@php
|
||||
@@ -101,7 +114,7 @@
|
||||
->get()
|
||||
->sum(function ($transaction) {
|
||||
return $transaction->service_charge;
|
||||
});
|
||||
});
|
||||
}
|
||||
?>
|
||||
<td class="right">{{ number_format($serviceCharge, 2) }}</td>
|
||||
@@ -142,11 +155,11 @@
|
||||
|
||||
$displayedTotal = bcadd(
|
||||
bcadd(
|
||||
bcadd($displayedSubtotal, $serviceCharge, 5),
|
||||
$tax,
|
||||
bcadd($displayedSubtotal, $serviceCharge, 5),
|
||||
$tax,
|
||||
5
|
||||
),
|
||||
$voucherDiscount,
|
||||
),
|
||||
$voucherDiscount,
|
||||
5
|
||||
);
|
||||
|
||||
@@ -159,6 +172,10 @@
|
||||
$discrepancy = bcsub($expectedTotal, $displayedTotal, 5);
|
||||
$total = $totalPayment;
|
||||
}
|
||||
|
||||
if($paymentSumRefund){
|
||||
$total = $paymentSumRefund;
|
||||
}
|
||||
@endphp
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
@@ -173,4 +190,4 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user