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); // } } }