Merge branch 'dillon/90-e-invoice-e' into vapor/staging

This commit is contained in:
Dillon Ngo
2025-08-05 00:00:00 +08:00
6 changed files with 149 additions and 10 deletions
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingProcessor;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Booking;
use Illuminate\Support\Facades\Log;
class OneTimeBatchProcessEInvoicesV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var Booking */
private $booking;
/**
* OneTimeBatchProcessEInvoicesV2CommandJob constructor.
* @param Booking $booking
*/
public function __construct(Booking $booking)
{
$this->booking = $booking;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Processing single booking for E-Invoices for July 2025.');
$start = new Carbon();
$isAllowNormalInvoice = true;
(App()->make(RegenerateInvoiceBookingProcessor::class))->execute($this->booking, $isAllowNormalInvoice);
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Processing single booking for E-Invoices for July 2025. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -14,6 +14,7 @@ use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use App\Models\Transaction;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
class RegenerateInvoiceBookingProcessor
{
@@ -48,7 +49,7 @@ class RegenerateInvoiceBookingProcessor
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
}
public function execute(Booking $booking)
public function execute(Booking $booking, bool $isAllowNormalInvoice = false)
{
$this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED);
@@ -58,6 +59,8 @@ class RegenerateInvoiceBookingProcessor
->orderBy('created_at', 'asc')
->first();
Log::info('RegenerateInvoiceBookingProcessor booking: ' . json_encode($booking->marking));
// get the first bill_no
if($firstInvoice){
$firstBillNo = $firstInvoice->bill_no;
@@ -90,10 +93,10 @@ class RegenerateInvoiceBookingProcessor
$this->deletesDocument->execute($row);
}
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true);
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true, $isAllowNormalInvoice);
}
else {
$this->createInvoiceTransactionProcessor->execute($booking);
$this->createInvoiceTransactionProcessor->execute($booking, "", false, $isAllowNormalInvoice);
}
}
}
@@ -43,7 +43,7 @@ class CreateInvoiceDocumentProcessor
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null)
public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null, $isAllowNormalInvoice = false)
{
// calculate current Paid Amount
$booking = $transaction->owner_type == Booking::class ? $transaction->owner : null;
@@ -87,6 +87,12 @@ class CreateInvoiceDocumentProcessor
$lowercaseDocumentType = strtolower($document_type);
if($document_type === DocumentType::EINVOICE){ //July 2025 workaround generate normal invoice instead of E-Invoice
if($isAllowNormalInvoice){
$lowercaseDocumentType = strtolower(DocumentType::INVOICE);
}
}
$order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType,
[
'transaction' => $transaction,
@@ -21,6 +21,7 @@ use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Booking;
use App\Models\SegmentConstant;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class CreateInvoiceTransactionProcessor
{
@@ -89,7 +90,7 @@ class CreateInvoiceTransactionProcessor
* @return void
* @throws MalformedRequestException
*/
public function execute(Booking $booking, String $invoiceNo= "", bool $isAllowEInvoice = false)
public function execute(Booking $booking, String $invoiceNo= "", bool $isAllowEInvoice = false, bool $isAllowNormalInvoice = false)
{
if ($booking->status === ApprovalStatus::COMPLETED) {
@@ -137,11 +138,18 @@ class CreateInvoiceTransactionProcessor
}
// $eInvoice = true; //cief todo: 90 - for testing
if($isAllowNormalInvoice){
$invoiceNo = ""; //July 2025 workaround generate normal invoice instead of E-Invoice
}
if($invoiceNo){
$billNumber = $invoiceNo;
}
else{
$billNUmberPrefix = $eInvoice ? 'EINV-' : 'INV-';
if($isAllowNormalInvoice){
$billNUmberPrefix = 'INV-'; //July 2025 workaround generate normal invoice instead of E-Invoice
}
$billNumber = $this->generatesTransactionBillNumber->execute($billNUmberPrefix);
}
@@ -189,7 +197,7 @@ class CreateInvoiceTransactionProcessor
if ($eInvoice)
{
if($isAllowEInvoice){
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption);
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption, $isAllowNormalInvoice);
}
}
// invoice
@@ -0,0 +1,78 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\OneTimeBatchProcessEInvoicesV2CommandJob;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Console\Command;
use App\Models\Booking;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
class OneTimeBatchProcessEInvoicesV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-time-batch-process-einvoices-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'One time batch process E-Invoices for July 2025';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$startDate = Carbon::create(2025, 7, 1)->startOfDay();
$endDate = Carbon::create(2025, 7, 31)->endOfDay();
$bookings = Booking::where('status', ApprovalStatus::COMPLETED)
->whereBetween('created_at', [$startDate, $endDate])
->get();
$count = 0;
foreach ($bookings as $booking) {
$firstInvoice = $booking->transactions()
->whereIn('type', [TransactionType::INVOICE])
->withTrashed()
->whereBetween('created_at', [$startDate, $endDate])
->orderBy('created_at', 'asc')
->first();
$normalInvoice = $booking->documents()->where('document_type', DocumentType::INVOICE)->first();
$eInvoice = $booking->documents()->where('document_type', DocumentType::EINVOICE)->first();
if($firstInvoice && !$normalInvoice && !$eInvoice){
OneTimeBatchProcessEInvoicesV2CommandJob::dispatch($booking);
$count++;
Log::info('Processed: ' . $count);
Log::info('Booking ID: ' . $booking->marking . ' | created_at: ' . $booking->created_at);
}
}
}
}
@@ -13,7 +13,7 @@ class UnfinishedPaymentOrders extends Controller
public function execute(Request $request)
{
$page = (int) $request->input('page', 1);
$perPage = 5000;
$perPage = 2500;
$offset = ($page - 1) * $perPage;
$cutOffDate = $request->cut_off_date ? Carbon::parse($request->cut_off_date) : null;
@@ -126,9 +126,9 @@ function runNextBatch() {
const row = document.createElement('tr');
row.innerHTML = `
<td><a href="\${bookingUrlTemplate.replace('__ORDER_REF__', item.order_ref)}" target="_blank">\${item.order_ref}</a></td>
<td>RM \${item.booking_amount}</td>
<td>RM \${item.paid_amount}</td>
<td>RM \${item.outstanding_amount}</td>
<td>\${item.booking_amount}</td>
<td>\${item.paid_amount}</td>
<td>\${item.outstanding_amount}</td>
<td><a href="\${customerUrlTemplate.replace('__ORDER_REF__', item.customer)}" target="_blank">\${item.customer ?? '-'}</a></td>
<td>\${item.created_at}</td>
`;