mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-22 14:04:01 +00:00
Merge branch 'vapor/production' of https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0 into vapor/development
This commit is contained in:
@@ -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 . '.');
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,9 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
'with_transactions' => true
|
||||
]
|
||||
);
|
||||
$normalInvoice = $request->input('normal_invoice', false);
|
||||
|
||||
$this->regenerateInvoiceBookingProcessor->execute($booking);
|
||||
$this->regenerateInvoiceBookingProcessor->execute($booking, $normalInvoice);
|
||||
|
||||
return $this->resourceResponse(new BookingResource($booking));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit
|
||||
*/
|
||||
public function map($company): array
|
||||
{
|
||||
$employee = $company->employees()->orderBy('id', 'DESC')->first();
|
||||
|
||||
return [
|
||||
'<<New>>', // Code
|
||||
'300-0000', // DebtorControlAcc
|
||||
@@ -89,7 +91,7 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit
|
||||
'', // DeliverAddr2
|
||||
'', // DeliverAddr3
|
||||
'', // DeliverPostCode
|
||||
'', // EmailAddress
|
||||
$employee->email, // EmailAddress
|
||||
'', // Attention
|
||||
'', // Phone1
|
||||
'', // Phone2
|
||||
|
||||
@@ -44,7 +44,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;
|
||||
@@ -63,9 +63,9 @@ class CreateInvoiceDocumentProcessor
|
||||
if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) {
|
||||
$lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first();
|
||||
$documentDate = $lastPaymentTransaction->created_at;
|
||||
if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){
|
||||
$documentDate = $booking->updated_at;
|
||||
}
|
||||
// if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){ //cief todo: 90 - Batch generate E-Invoice date incorrect
|
||||
// $documentDate = $booking->updated_at;
|
||||
// }
|
||||
}
|
||||
|
||||
if($document_type === DocumentType::EINVOICE){
|
||||
@@ -88,6 +88,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,80 @@
|
||||
<?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()
|
||||
{
|
||||
return;
|
||||
|
||||
$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>
|
||||
`;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
export default {
|
||||
methods: {
|
||||
submitForm() {
|
||||
this.parameters.normal_invoice = false;
|
||||
this.submit(this.route('api.booking.einvoice.regenerate', this.data.id), 'post', this.section, true, true);
|
||||
},
|
||||
successHandler(){
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<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 normal invoice instead of 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 = 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>
|
||||
+11
-3
@@ -334,7 +334,7 @@
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
<div class="row m-t-15" v-if="booking.status === 3 && ($store.getters.isSuperAdmin || ($store.getters.isCustomer && $store.getters.getCompanyId === 199)) && booking.einvoice">
|
||||
<div class="row m-t-15" v-if="booking.status === 3 && ($store.getters.isSuperAdmin || ($store.getters.isCustomer && $store.getters.getCompanyId === 199)) && booking.einvoice">
|
||||
<div class="col-sm col-md-auto">
|
||||
<div class="btn btn-sm btn block all-caps b-rad-none btn-danger pointer requestModal equal-width-button" data-type="regenerateEInvoice">Regenerate E-Invoice</div>
|
||||
</div>
|
||||
@@ -342,6 +342,14 @@
|
||||
<regenerate-e-invoice-component :data="booking" :section="section" class="text-center"></regenerate-e-invoice-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
<div class="row m-t-15" v-if="booking.status === 3 && ($store.getters.isSuperAdmin || ($store.getters.isCustomer && $store.getters.getCompanyId === 199)) && booking.einvoice">
|
||||
<div class="col-sm col-md-auto">
|
||||
<div class="btn btn-sm btn block all-caps b-rad-none btn-danger pointer requestModal equal-width-button" data-type="regenerateNormalInvoiceEInvoice">Regenerate Normal Inv</div>
|
||||
</div>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="regenerateNormalInvoiceEInvoice">
|
||||
<regenerate-normal-invoice-e-invoice-component :data="booking" :section="section" class="text-center"></regenerate-normal-invoice-e-invoice-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-5 mt-3 mt-sm-0">
|
||||
<!-- <booking-payment-quotation-component :data="booking" :section="section"></booking-payment-quotation-component> -->
|
||||
@@ -497,7 +505,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5" v-if="$store.getters.isAdmin">
|
||||
<div class="row m-t-15" v-if="$store.getters.isAdmin">
|
||||
<div class="col">
|
||||
<div class="btn btn-xs all-caps b-rad-none btn-warning pointer requestModal equal-width-button" data-type="changeBookingOwner">Change Booking Owner</div>
|
||||
<modal-component type="changeBookingOwner">
|
||||
@@ -614,7 +622,7 @@
|
||||
</script>
|
||||
<style scoped>
|
||||
.equal-width-button {
|
||||
min-width: 180px;
|
||||
min-width: 200px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user