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; $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** * @param Booking $booking * @param String $invoiceNo * @param Illuminate\Support\Collection<\App\Models\KeyValuePair> $kvpCopies * @param array $options * @return void * @throws MalformedRequestException */ public function execute(Booking $booking, String $invoiceNo= "", $kvpCopies = null, array $options = []) { $generateEInvoice = $options['generateEInvoice'] ?? false; $generateEInvoiceWithNormalInvoiceTemplate = $options['generateEInvoiceWithNormalInvoiceTemplate'] ?? false; $generateEInvoiceRefund = $options['generateEInvoiceRefund'] ?? false; $bookingOriginalStatus = $options['bookingOriginalStatus'] ?? null; // Log::info('CreateInvoiceTransactionV2Processor generateEInvoice:' . json_encode($generateEInvoice)); // Log::info('CreateInvoiceTransactionV2Processor generateEInvoiceWithNormalInvoiceTemplate: ' . json_encode($generateEInvoiceWithNormalInvoiceTemplate)); // Log::info('CreateInvoiceTransactionV2Processor generateEInvoiceRefund: ' . json_encode($generateEInvoiceRefund)); // Log::info('CreateInvoiceTransactionV2Processor bookingOriginalStatus: ' . json_encode($bookingOriginalStatus)); if ($booking->status === ApprovalStatus::COMPLETED && !$generateEInvoiceRefund) { Log::info('CreateInvoiceTransactionV2Processor Check 1 Bypass New Business Logic Update for booking ' . $booking->id); // return; } $payable_amount = $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id, $generateEInvoiceRefund); $refund_amount = $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id); $booking_amount = $booking->fix_amount; if ((float) $booking_amount === (float) $refund_amount && !$generateEInvoiceRefund) { return; } // 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)) { Log::info('CreateInvoiceTransactionV2Processor Check 2 Bypass New Business Logic Update for booking ' . $booking->id); // return; } $purchaseOrder = $booking->transactions() ->where('type', TransactionType::PURCHASE_ORDER) ->complete() ->first(); if(!$purchaseOrder){ //was use for $generateEInvoiceRefund true $purchaseOrder = $booking->transactions() ->where('type', TransactionType::PURCHASE_ORDER) ->where('status', ApprovalStatus::PENDING_SUBMISSION) ->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) ->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); $eInvoiceRequestedDate = Carbon::parse($supplier->e_invoice_requested_at); if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $bookingCreatedDate->isAfter($eInvoiceRequestedDate) && $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'); } $invoice_transaction = null; if($booking->status === ApprovalStatus::APPROVED){ //NEW INVOICE for non-einvoice user applicable only when booking is completed $invoice_transaction = $booking->transactions() ->where('type', TransactionType::INVOICE) ->complete() ->latest() ->first(); } if(!$invoice_transaction) { $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); } //Update booking table, used on Export Sales Invoice Report $booking->invoice_status = ApprovalStatus::APPROVED; $booking->save(); if ($kvpCopies) { foreach ($kvpCopies as $kvp) { $invoice_transaction->attributesKVP()->save($kvp); } } $voucherRedemption = $transaction->voucherRedemption; if($generateEInvoiceRefund){ $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first(); if($metadata){ $generateEInvoice = true; } else{ $metadata = $transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first(); if($metadata){ $generateEInvoice = true; } } } if($purchaseOrder){ // 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(); $transactionTypeBill= null; if($paymentTransaction){ $transactionTypeBill = $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) $paymentTransactionTemp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first(); // Lets check if there is a refund case $refund = $paymentTransactionTemp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first(); if($refund){ $transactionTypeBill = $paymentTransactionTemp->transactions()->where('type', TransactionType::BILL)->first(); } else{ Log::info("CreateInvoiceTransactionV2Processor NO completed payment transaction nor refund transaction found for booking '$booking->id'."); } } if($transactionTypeBill){ $transaction_object = new TransactionObject( $billNumber, TransactionType::SUPPLIER_DELIVER, $transactionTypeBill->issuer, $transactionTypeBill->receiver, $transactionTypeBill->recipient_bank_account_id, $transactionTypeBill->payment_method, $payable_amount, $booking_amount, $transactionTypeBill->currency_id, $transactionTypeBill->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); } } // update perfex crm // if(config('perfexcrm.is_enabled') == 'true'){ // CreatePerfexCRMInvoice::dispatch($invoice_transaction, $purchaseOrder, $supplier); // } } if($bookingOriginalStatus){ $this->updatesBookingStatus->execute($booking, $bookingOriginalStatus); } } }