mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
E-Invoice - Automapping Issues, Sales Invoice Report (Import) with batch processing for E-Invoices
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Bookings\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Models\Booking;
|
||||
use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingProcessor;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BatchBookingsGenerateEInvoiceLogic extends AbstractControllerLogic
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'Generate Bookings E-Invoices',
|
||||
'message' => 'You have successfully process bookings for E-Invoices'
|
||||
];
|
||||
}
|
||||
|
||||
/** @var RegenerateInvoiceBookingProcessor */
|
||||
private $regenerateInvoiceBookingProcessor;
|
||||
|
||||
/**
|
||||
* BatchBookingsGenerateEInvoiceLogic constructor.
|
||||
* @param RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
*/
|
||||
public function __construct(
|
||||
RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
) {
|
||||
$this->regenerateInvoiceBookingProcessor = $regenerateInvoiceBookingProcessor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws \App\Classes\Exceptions\AccessForbiddenException
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
* @throws \App\Classes\Exceptions\RequestValidationException
|
||||
*/
|
||||
public function logic(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'startDate' => 'nullable|date_format:d-m-Y',
|
||||
'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate',
|
||||
]);
|
||||
|
||||
$startDate = null;
|
||||
$endDate = null;
|
||||
|
||||
if (isset($validated['startDate']) && $validated['startDate']) {
|
||||
$startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay();
|
||||
} else {
|
||||
$startDate = Carbon::now()->subMonths(1)->startOfDay();
|
||||
}
|
||||
|
||||
if (isset($validated['endDate']) && $validated['endDate']) {
|
||||
$endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay();
|
||||
} else {
|
||||
$endDate = Carbon::now()->endOfDay();
|
||||
}
|
||||
|
||||
$startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1);
|
||||
$endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
|
||||
|
||||
$bookings = Booking::where('status', ApprovalStatus::COMPLETED)
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->whereHas('attributesKVP', function (Builder $query) {
|
||||
$query->where('key', 'AUTOCOUNT_DOCNO');
|
||||
})
|
||||
->with(['attributesKVP' => function ($query) {
|
||||
$query->where('key', 'AUTOCOUNT_DOCNO');
|
||||
}])
|
||||
->get();
|
||||
|
||||
foreach ($bookings as $booking) {
|
||||
// $autocountValue = optional($booking->attributesKVP->first())->value;
|
||||
//Log::info('Booking ID: ' . $booking->marking . ' | AUTOCOUNT_DOCNO: ' . $autocountValue);
|
||||
$this->regenerateInvoiceBookingProcessor->execute($booking);
|
||||
}
|
||||
|
||||
return $this->resourceResponse(JsonResource::collection(collect([])));
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,11 @@ namespace App\Classes\Modules\Bookings\ControllersLogic;
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Bookings\Services\FetchesBooking;
|
||||
use App\Classes\Modules\Bookings\Standards\Rules\CanFetchBooking;
|
||||
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
|
||||
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
|
||||
use App\Classes\Modules\Documents\Services\DeletesDocument;
|
||||
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingProcessor;
|
||||
use App\Http\Resources\BookingResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
{
|
||||
@@ -39,41 +31,23 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
/** @var FetchesBooking */
|
||||
private $fetchesBooking;
|
||||
|
||||
/** @var DeletesTransaction */
|
||||
private $deletesTransaction;
|
||||
|
||||
/** @var UpdatesBookingStatus */
|
||||
private $updatesBookingStatus;
|
||||
|
||||
/** @var DeletesDocument */
|
||||
private $deletesDocument;
|
||||
|
||||
/** @var CreateInvoiceTransactionProcessor */
|
||||
private $createInvoiceTransactionProcessor;
|
||||
/** @var RegenerateInvoiceBookingProcessor */
|
||||
private $regenerateInvoiceBookingProcessor;
|
||||
|
||||
/**
|
||||
* FetchBookingLogic constructor.
|
||||
* RegenerateInvoiceBookingLogic constructor.
|
||||
* @param CanFetchBooking $canFetchBooking
|
||||
* @param FetchesBooking $fetchesBooking
|
||||
* @param DeletesTransaction $deletesTransaction
|
||||
* @param UpdatesBookingStatus $updatesBookingStatus
|
||||
* @param DeletesDocument $deletesDocument
|
||||
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
|
||||
* @param RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
*/
|
||||
public function __construct(
|
||||
CanFetchBooking $canFetchBooking,
|
||||
FetchesBooking $fetchesBooking,
|
||||
DeletesTransaction $deletesTransaction,
|
||||
UpdatesBookingStatus $updatesBookingStatus,
|
||||
DeletesDocument $deletesDocument,
|
||||
CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
|
||||
RegenerateInvoiceBookingProcessor $regenerateInvoiceBookingProcessor
|
||||
) {
|
||||
$this->canFetchBooking = $canFetchBooking;
|
||||
$this->fetchesBooking = $fetchesBooking;
|
||||
$this->deletesTransaction = $deletesTransaction;
|
||||
$this->updatesBookingStatus = $updatesBookingStatus;
|
||||
$this->deletesDocument = $deletesDocument;
|
||||
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
|
||||
$this->regenerateInvoiceBookingProcessor = $regenerateInvoiceBookingProcessor;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,46 +70,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
|
||||
]
|
||||
);
|
||||
|
||||
$this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED);
|
||||
|
||||
$firstInvoice = $booking->transactions()
|
||||
->whereIn('type', [TransactionType::INVOICE])
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'asc')
|
||||
->first();
|
||||
|
||||
// get the first bill_no
|
||||
$firstBillNo = $firstInvoice->bill_no;
|
||||
if (strpos($firstBillNo, '-deleted') !== false) {
|
||||
$firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted'));
|
||||
}
|
||||
|
||||
// update currentInvoice bill_no to '-deleted-'
|
||||
$currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first();
|
||||
if($currentInvoice){
|
||||
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp);
|
||||
$currentInvoice->save();
|
||||
}
|
||||
|
||||
$transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get();
|
||||
if ($transactionWithSameBillNo) {
|
||||
foreach ($transactionWithSameBillNo as $transaction) {
|
||||
$transaction->bill_no = $transaction->bill_no . "-deleted-" . Str::random(10);
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
|
||||
$transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get();
|
||||
foreach ($transaction as $key => $row) {
|
||||
$this->deletesTransaction->execute($row);
|
||||
}
|
||||
|
||||
$document = $booking->documents()->whereIn('document_type', [DocumentType::PURCHASE_ORDER, DocumentType::INVOICE, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->get();
|
||||
foreach ($document as $key => $row) {
|
||||
$this->deletesDocument->execute($row);
|
||||
}
|
||||
|
||||
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true);
|
||||
$this->regenerateInvoiceBookingProcessor->execute($booking);
|
||||
|
||||
return $this->resourceResponse(new BookingResource($booking));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Bookings\Processors;
|
||||
|
||||
|
||||
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
|
||||
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
|
||||
use App\Classes\Modules\Documents\Services\DeletesDocument;
|
||||
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class RegenerateInvoiceBookingProcessor
|
||||
{
|
||||
/** @var DeletesTransaction */
|
||||
private $deletesTransaction;
|
||||
|
||||
/** @var UpdatesBookingStatus */
|
||||
private $updatesBookingStatus;
|
||||
|
||||
/** @var DeletesDocument */
|
||||
private $deletesDocument;
|
||||
|
||||
/** @var CreateInvoiceTransactionProcessor */
|
||||
private $createInvoiceTransactionProcessor;
|
||||
|
||||
/**
|
||||
* RegenerateInvoiceBookingProcessor constructor.
|
||||
* @param DeletesTransaction $deletesTransaction
|
||||
* @param UpdatesBookingStatus $updatesBookingStatus
|
||||
* @param DeletesDocument $deletesDocument
|
||||
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
|
||||
*/
|
||||
public function __construct(
|
||||
DeletesTransaction $deletesTransaction,
|
||||
UpdatesBookingStatus $updatesBookingStatus,
|
||||
DeletesDocument $deletesDocument,
|
||||
CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
|
||||
) {
|
||||
$this->deletesTransaction = $deletesTransaction;
|
||||
$this->updatesBookingStatus = $updatesBookingStatus;
|
||||
$this->deletesDocument = $deletesDocument;
|
||||
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
|
||||
}
|
||||
|
||||
public function execute(Booking $booking)
|
||||
{
|
||||
$this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED);
|
||||
|
||||
$firstInvoice = $booking->transactions()
|
||||
->whereIn('type', [TransactionType::INVOICE])
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'asc')
|
||||
->first();
|
||||
|
||||
// get the first bill_no
|
||||
if($firstInvoice){
|
||||
$firstBillNo = $firstInvoice->bill_no;
|
||||
if (strpos($firstBillNo, '-deleted') !== false) {
|
||||
$firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted'));
|
||||
}
|
||||
|
||||
// update currentInvoice bill_no to '-deleted-'
|
||||
$currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first();
|
||||
if($currentInvoice){
|
||||
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp);
|
||||
$currentInvoice->save();
|
||||
}
|
||||
|
||||
$transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get();
|
||||
if ($transactionWithSameBillNo) {
|
||||
foreach ($transactionWithSameBillNo as $transaction) {
|
||||
$transaction->bill_no = $transaction->bill_no . "-deleted-" . Str::random(10);
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
|
||||
$transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get();
|
||||
foreach ($transaction as $key => $row) {
|
||||
$this->deletesTransaction->execute($row);
|
||||
}
|
||||
|
||||
$document = $booking->documents()->whereIn('document_type', [DocumentType::PURCHASE_ORDER, DocumentType::INVOICE, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->get();
|
||||
foreach ($document as $key => $row) {
|
||||
$this->deletesDocument->execute($row);
|
||||
}
|
||||
|
||||
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true);
|
||||
}
|
||||
else {
|
||||
$this->createInvoiceTransactionProcessor->execute($booking);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace App\Http\Controllers\Bookings;
|
||||
|
||||
use App\Classes\Modules\Bookings\ControllersLogic\RegenerateInvoiceBookingLogic;
|
||||
use App\Classes\Modules\Bookings\ControllersLogic\BatchBookingsGenerateEInvoiceLogic;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
||||
class RegenerateBookingEInvoiceController
|
||||
{
|
||||
/**
|
||||
@@ -17,4 +17,13 @@ class RegenerateBookingEInvoiceController
|
||||
public function regenerate(Request $request, RegenerateInvoiceBookingLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param BatchBookingsGenerateEInvoiceLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function batchProcess(Request $request, BatchBookingsGenerateEInvoiceLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<select-component :options="options()" v-model="parameters.reportType"></select-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-12 col-md-auto p-l-3 p-r-3">
|
||||
<div class="col-12 col-md-auto">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" :class="{ disabled: isDownloading }" @click="handleExportClick">
|
||||
<span>
|
||||
Export
|
||||
@@ -30,21 +30,41 @@
|
||||
<span v-if="isDownloading" class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-auto p-l-3 p-r-3 p-md-0">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center requestModal pointer" v-if=" parameters.reportType !== ''" data-type="uploadDocumentModel">
|
||||
<span>
|
||||
Import
|
||||
</span>
|
||||
</div>
|
||||
<div class="btn btn-lg btn-secondary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" :style="'pointer-events: none; opacity: 0.65;'" v-else>
|
||||
<span>
|
||||
Import
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-12 col-md-auto pl-md-0">
|
||||
<button
|
||||
class="btn btn-lg fs-11 w-100 h-100 d-flex justify-content-center align-items-center"
|
||||
:class="parameters.reportType !== '' ? 'btn-primary requestModal pointer' : 'btn-secondary'"
|
||||
:disabled="parameters.reportType === ''"
|
||||
:data-type="parameters.reportType !== '' ? 'uploadDocumentModel' : null"
|
||||
>
|
||||
<span>Import</span>
|
||||
</button>
|
||||
<modal-component type="uploadDocumentModel">
|
||||
<upload-component :section="section" :report-type="parameters.reportType"></upload-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
<div class="col-12 col-md-auto p-md-0">
|
||||
<button
|
||||
class="btn btn-lg fs-11 w-100 h-100 d-flex justify-content-center align-items-center"
|
||||
:class="parameters.reportType === 'Sales Invoice Report' ? 'btn-primary' : 'btn-secondary'"
|
||||
:disabled="parameters.reportType !== 'Sales Invoice Report'"
|
||||
@click="() => { if (parameters.reportType === 'Sales Invoice Report') handleGenerateEInvoiceClick() }"
|
||||
>
|
||||
<span>Process E-Invoices</span>
|
||||
</button>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" id="modal-generate-einvoice">
|
||||
<general-confirmation-form-component
|
||||
contentText="Are you sure you want to batch generate E-Invoices? (Only applicable for bookings with DocNo)"
|
||||
modalType="confirm"
|
||||
class="text-center"
|
||||
:apiRoute="generateEInvoicesUrl"
|
||||
apiMethod="get"
|
||||
:section="section"
|
||||
v-if="generateEInvoicesUrl"
|
||||
>
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
<modal-component type="uploadDocumentModel">
|
||||
<upload-component :section="section" :report-type="parameters.reportType"></upload-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,6 +91,7 @@ export default {
|
||||
reportType: '',
|
||||
},
|
||||
isDownloading: false,
|
||||
generateEInvoicesUrl: null,
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
@@ -116,10 +137,28 @@ export default {
|
||||
this.submit(url, 'get', this.section, false, false);
|
||||
}
|
||||
else{
|
||||
window.open(this.url, '_blank');
|
||||
window.open(url, '_blank');
|
||||
this.isDownloading = false;
|
||||
}
|
||||
},
|
||||
handleGenerateEInvoiceClick(){
|
||||
if (!this.validate()) return;
|
||||
|
||||
const reportType = this.parameters.reportType;
|
||||
const routesMap = {
|
||||
'Sales Invoice Report': route('api.booking.batch.process'),
|
||||
};
|
||||
|
||||
const selectedRoute = routesMap[reportType];
|
||||
|
||||
if (!selectedRoute) {
|
||||
throw new Error(`No route mapping found for report type: ${reportType}`);
|
||||
}
|
||||
|
||||
this.generateEInvoicesUrl = `${selectedRoute}?startDate=${this.parameters.startDate}&endDate=${this.parameters.endDate}`;
|
||||
|
||||
$('#modal-generate-einvoice').modal('show');
|
||||
},
|
||||
successHandler(response) {
|
||||
if(window.LARAVEL_VAPOR_ENABLED){
|
||||
if (response.payload !== undefined && response.payload.src) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-8 p-l-0">
|
||||
<div class="col-12 p-l-0">
|
||||
<small class="all-caps muted fs-10">Export Report (New)</small>
|
||||
<download-upload-component section="exportDataSection"></download-upload-component>
|
||||
</div>
|
||||
|
||||
@@ -50,4 +50,7 @@ Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Booking
|
||||
Route::group(['prefix' => '{id}/einvoice', 'as' => 'einvoice.'], function () {
|
||||
Route::post('/', [RegenerateBookingEInvoiceController::class, 'regenerate'])->name('regenerate');
|
||||
});
|
||||
Route::group(['prefix' => 'batch/einvoice', 'as' => 'batch.'], function () {
|
||||
Route::get('/process', [RegenerateBookingEInvoiceController::class, 'batchProcess'])->name('process');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user