mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 12:33:56 +00:00
353 lines
17 KiB
PHP
353 lines
17 KiB
PHP
<?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\Bookings\Services\CalculatesBookingRefundAmount;
|
|
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;
|
|
|
|
/** @var CalculatesBookingRefundAmount */
|
|
private $calculatesBookingRefundAmount;
|
|
|
|
|
|
/**
|
|
* 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
|
|
* @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount
|
|
*/
|
|
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, CalculatesBookingRefundAmount $calculatesBookingRefundAmount)
|
|
{
|
|
$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;
|
|
$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) || $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 60) && $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);
|
|
}
|
|
}
|
|
}
|