diff --git a/app/Classes/General/Helper.php b/app/Classes/General/Helper.php index cb77d936..89bc70b2 100644 --- a/app/Classes/General/Helper.php +++ b/app/Classes/General/Helper.php @@ -87,4 +87,71 @@ class Helper return strtoupper('ringgit ' . $ringgitWords . ' and ' . $centsWords . ' cents only'); } + public static function getStateCodeByName($name) + { + $path = resource_path('data/lhdn/StateCodes.json'); + + if (!file_exists($path)) { + return null; + } + + $json = file_get_contents($path); + $data = json_decode($json, true); + + if (!is_array($data)) { + return null; + } + + $name = strtolower(trim($name)); + + // Step 1: Try exact match + foreach ($data as $item) { + if ( + isset($item['State']) && + strtolower(trim($item['State'])) === $name + ) { + return $item['Code'] ?? null; + } + } + + // Step 2: Try partial match + foreach ($data as $item) { + if ( + isset($item['State']) && + str_contains(strtolower($item['State']), $name) + ) { + return $item['Code'] ?? null; + } + } + + return null; + } + + public static function getMsicDescriptionByCode($code) + { + $path = resource_path('data/lhdn/MSICSubCategoryCodes.json'); + + if (!file_exists($path)) { + return null; + } + + $json = file_get_contents($path); + $data = json_decode($json, true); + + if (!is_array($data)) { + return null; + } + + foreach ($data as $item) { + if ( + isset($item['Code']) && + $item['Code'] === $code + ) { + return $item['Description'] ?? null; + } + } + + return null; + } + } diff --git a/app/Classes/Jobs/Commands/V2/ProcessBookingForEInvoiceV2CommandJob.php b/app/Classes/Jobs/Commands/V2/ProcessBookingForEInvoiceV2CommandJob.php new file mode 100644 index 00000000..e5e0a552 --- /dev/null +++ b/app/Classes/Jobs/Commands/V2/ProcessBookingForEInvoiceV2CommandJob.php @@ -0,0 +1,43 @@ +booking = $booking; + } + + public function handle() + { + Log::info(Carbon::now() . ': Start job - Processing single booking for E-Invoice.'); + $start = new Carbon(); + + (App()->make(RegenerateInvoiceBookingProcessor::class))->execute($this->booking); + + $end = new Carbon(); + $elapsedTime = $start->diff($end)->format('%H:%I:%S'); + Log::info(Carbon::now() . ': End job - Processing single booking for E-Invoice. ElapsedTime: ' . $elapsedTime . '.'); + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php new file mode 100644 index 00000000..1b467042 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php @@ -0,0 +1,103 @@ + 'Generate Bookings E-Invoices', + 'message' => sprintf( + 'You have successfully submitted %d booking%s for E-Invoices.', + $this->processedCount, + $this->processedCount === 1 ? '' : 's' + ), + ]; + } + + /** @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); + ProcessBookingForEInvoiceV2CommandJob::dispatch($booking); + } + $this->processedCount = count($bookings); + + return $this->resourceResponse(JsonResource::collection(collect([]))); + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php index 4a63eca4..39db1708 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -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)); } diff --git a/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php b/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php new file mode 100644 index 00000000..38d89f08 --- /dev/null +++ b/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php @@ -0,0 +1,99 @@ +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); + } + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsCompanies.php b/app/Classes/Modules/Exports/Services/ExportsCompanies.php new file mode 100644 index 00000000..3f97e7a0 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsCompanies.php @@ -0,0 +1,102 @@ +startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1); + $this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now(); + } + + public function headings(): array + { + return [ + 'TIN', + 'IdentityNo', + 'Name', + 'IdentityType', + 'TaxClassification', + 'MSICCode', + 'BusinessActivityDesc', + 'DebtorCode', + 'TradeName', + 'Address', + 'PostCode', + 'Phone', + 'EmailAddress', + 'City', + 'CountryCode', + 'StateCode' + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + return Company::whereBetween('e_invoice_requested_at', [$this->startDate, $this->endDate]); + } + + /** + * @param Company $company + * + * @return array + */ + public function map($company): array + { + $employee = $company->employees()->first(); + $lastBooking = $company->bookings()->orderByDesc('id')->first(); + $identityNo = $company->documents->where('document_type', DocumentType::IDENTITY_CARD)->first(); + $identityType = DocumentType::IDENTITY_CARD; + if(!$identityNo){ + $identityNo = $company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first(); + $identityType = DocumentType::SSM_REGISTRATION; + } + $identityReference = ""; + if($identityNo){ + $identityReference = preg_replace('/\s*\(.*?\)/', '', $identityNo->reference); + } + $address = $company->addresses()->where('e_invoice', '=', true)->latest()->first(); + if(!$address){ + $address = $company->addresses()->where('billing', '=', true)->first(); + } + + return [ + $company->tin, // 'TIN', + $identityReference, // 'IdentityNo', + $company->name, // 'Name', + $identityType === DocumentType::IDENTITY_CARD ? 'MyKAD' : '', // 'IdentityType', + $company->type !== null ? (string) $company->type : '0', // 'TaxClassification', + $company->msic_code, // 'MSICCode', + $company->msic_code ? Helper::getMsicDescriptionByCode($company->msic_code) : '', // 'BusinessActivityDesc', + $company->debtor, // 'DebtorCode', + $company->name, // 'TradeName', + $address ? $address->street_one . ',' . $address->street_two : '',// 'Address', + $address ? $address->postcode : '', // 'PostCode', + $company->contacts()->first() ? $company->contacts()->first()->phone : '', // 'Phone', + $employee ? $employee->email : '', // 'EmailAddress', + $address ? $address->district()->first()->name : '', // 'City', + 'MYS', // 'CountryCode', + $address ? Helper::getStateCodeByName($address->state()->first()->name) : '', // 'StateCode' + ]; + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php new file mode 100644 index 00000000..afcab016 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -0,0 +1,114 @@ +startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1); + $this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now(); + } + + public function headings(): array + { + return [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Ref', + 'ShipInfo', + 'AccNo', + 'DetailDescription', + 'FurtherDescription', + 'Classification', + 'DeptNo', + 'Qty', + 'UnitPrice', + 'submiteinvoice', + 'ConsolidatedEinvoice', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + // $query = Transaction::query(); + // $query->where('type', TransactionType::PAYMENT)->where('payment_method', '!=', PaymentMethodType::WALLET); + // $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + // $query->whereHas('booking.transactions', function ($query) { + // $query->where('type', TransactionType::PURCHASE_ORDER)->complete(); + // }); + + return Booking::where('status', ApprovalStatus::COMPLETED)->whereBetween('created_at', [$this->startDate, $this->endDate]); + } + + /** + * @param Booking $booking + * @return array + */ + public function map($booking): array + { + $records = []; + + $purchaseOrder = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); + $company = $booking->company()->first(); + + $lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first(); + if(!$lastPaymentTransaction){ + return $records; + } + $documentDate = $lastPaymentTransaction->created_at; + if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){ + $documentDate = $booking->updated_at; + } + $formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y'); + + $firstItem = true; + $transactionDetails = $purchaseOrder->transactionDetails; + foreach ($transactionDetails as $detail) { + $records[] = [ + $firstItem ? '<>' : '', + $formattedDocumentDate, + $company->debtor, + $booking->marking, + $booking->marking, + '500-0000', + 'PRODUCT NAME :', + $detail->product_name, + '022', + 'C', + $detail->quantity, + number_format($detail->price, 2), + $firstItem ? 'T' : '', + $company->e_invoice ? 'F' : 'T' + ]; + + if($firstItem) { + $firstItem = false; + } + } + return $records; + } +} diff --git a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php new file mode 100644 index 00000000..a199f75d --- /dev/null +++ b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php @@ -0,0 +1,153 @@ +createsKeyValuePair = $createsKeyValuePair; + $this->updatesKeyValuePair = $updatesKeyValuePair; + } + + /** + * @return array + */ + protected function notification():array { + return [ + 'title' => 'Import Excel', + 'message' => 'You have successfully imported and updated booking details' + ]; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $reportType = $request->input('report_type'); + + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + foreach ($object->getFiles() as $file){ + $collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true); + + $sheet = $collection->first(); + $header = $sheet->first()->toArray(); + + $normalizedHeader = array_map(fn($h) => strtolower(trim($h)), $header); + $salesInvoiceHeader = [ + 'docno', 'docdate', 'debtorcode', 'ref', 'shipinfo', 'accno', + 'detaildescription', 'furtherdescription', 'classification', + 'deptno', 'qty', 'unitprice', 'submiteinvoice', 'consolidatedeinvoice' + ]; + $customersReportHeader = [ + 'tin', 'identityno', 'name', 'identitytype', 'taxclassification', 'msiccode', + 'businessactivitydesc', 'debtorcode', 'tradename', 'address', 'postcode', + 'phone', 'emailaddress', 'city', 'countrycode', 'statecode' + ]; + + if ($reportType === 'Sales Invoice Report') { + $optionalColumn = 'einvoicevalidationlink'; + + if ( + $normalizedHeader !== $salesInvoiceHeader && + $normalizedHeader !== [...$salesInvoiceHeader, $optionalColumn] + ) { + throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.'); + } + + } elseif ($reportType === 'Customers Report' && $normalizedHeader !== $customersReportHeader) { + throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.'); + } + + $rows = $sheet->skip(1); + + foreach ($rows as $index => $details) { + $docNo = $details[0] ?? null; + $docDate = $details[1] ?? null; + $debtorCode = $details[2] ?? null; + $ref = $details[3] ?? null; + $shipInfo = $details[4] ?? null; + $accNo = $details[5] ?? null; + $detailDescription = $details[6] ?? null; + $furtherDescription = $details[7] ?? null; + $classification = $details[8] ?? null; + $deptNo = $details[9] ?? null; + $qty = $details[10] ?? null; + $unitPrice = $details[11] ?? null; + $submitEinvoice = $details[12] ?? null; + $consolidatedEinvoice = $details[13] ?? null; + $eInvoiceValidationLink = $details[14] ?? null; // Safe access for the new column + + Log::info("Row {$index} Details:", [ + 'DocNo' => $docNo, + 'DocDate' => $docDate, + 'DebtorCode' => $debtorCode, + 'Ref' => $ref, + 'ShipInfo' => $shipInfo, + 'AccNo' => $accNo, + 'DetailDescription' => $detailDescription, + 'FurtherDescription' => $furtherDescription, + 'Classification' => $classification, + 'DeptNo' => $deptNo, + 'Qty' => $qty, + 'UnitPrice' => $unitPrice, + 'SubmitEinvoice' => $submitEinvoice, + 'ConsolidatedEinvoice' => $consolidatedEinvoice, + 'EInvoiceValidationLink' => $eInvoiceValidationLink, + ]); + + $booking = Booking::where('marking', $ref)->first(); + if($docNo != "<>"){ + $this->updateOrCreateKeyValuePair($booking, "AUTOCOUNT_DOCNO", $docNo); + } + if($eInvoiceValidationLink){ + $this->updateOrCreateKeyValuePair($booking, "AUTOCOUNT_EINVOICE_VALIDATION_LINK", $eInvoiceValidationLink); + } + } + } + + return $this->response([]); + } + + private function updateOrCreateKeyValuePair($booking, $key, $value) + { + $keyValuePairObject = new KeyValuePairObject($key, $value); + $metadata = $booking->attributesKVP()->where('key', $key)->first(); + + if ($metadata) { + $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); + } else { + $this->createsKeyValuePair->execute($booking, $keyValuePairObject); + } + } +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php index d6911b37..80f963ca 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php @@ -54,6 +54,8 @@ class CreateInvoiceDocumentProcessor $brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first(); $documentDate = $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $booking->created_at; $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); + $autoCountInvoiceId = ''; + $autoCountEInvoiceValidationLink = 'CIEF'; if ($booking) { $bookingCreatedDate = Carbon::parse($booking->created_at); @@ -66,6 +68,14 @@ class CreateInvoiceDocumentProcessor } if($document_type === DocumentType::EINVOICE){ + $metadata = $booking->attributesKVP()->where('key', 'AUTOCOUNT_DOCNO')->first(); + if($metadata){ + $autoCountInvoiceId = $metadata->value; + } + $metadata = $booking->attributesKVP()->where('key', 'AUTOCOUNT_EINVOICE_VALIDATION_LINK')->first(); + if($metadata){ + $autoCountEInvoiceValidationLink = $metadata->value; + } $lastDayOfMonth = $documentDate->copy()->endOfMonth(); $documentDate = $lastDayOfMonth; } @@ -77,7 +87,19 @@ class CreateInvoiceDocumentProcessor $lowercaseDocumentType = strtolower($document_type); - $order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier, 'voucher_redemption' => $voucherRedemption, 'current_paid_amount' => $currentPaidAmount, 'document_date' => $documentDate, 'brn' => $brn, 'autocountId' => null, 'booking' => $booking]); //cief todo: 90 - autocount id to be updated + $order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, + [ + 'transaction' => $transaction, + 'po_order_transaction' => $purchaseOrder, + 'supplier' => $supplier, + 'voucher_redemption' => $voucherRedemption, + 'current_paid_amount' => $currentPaidAmount, + 'document_date' => $documentDate, + 'brn' => $brn, + 'booking' => $booking, + 'autocountId' => $autoCountInvoiceId, + 'autocountEInvoiceValidationLink' => $autoCountEInvoiceValidationLink, + ]); if($purchaseOrder && $purchaseOrder->booking->service_id === 4) { $purchaseOrderDocuments = $purchaseOrder->booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get(); diff --git a/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php b/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php index 0b07d938..baec723f 100644 --- a/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php +++ b/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php @@ -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); + } } diff --git a/app/Http/Controllers/Exports/ExportController.php b/app/Http/Controllers/Exports/ExportController.php new file mode 100644 index 00000000..ccf5ffd5 --- /dev/null +++ b/app/Http/Controllers/Exports/ExportController.php @@ -0,0 +1,86 @@ +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(); + } + + + $exportsTransactions = new ExportsSalesInvoiceReport($startDate, $endDate); + + $exportFileName = 'Exchange - Sales Invoice Report.xls'; + $filesystemDriver = Storage::getDefaultDriver(); + if($filesystemDriver === 's3'){ + return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]); + } + else{ + $response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + } + return $response; + } + + public function companies(Request $request){ + $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(); + } + + $exportsCompanies = new ExportsCompanies($startDate, $endDate); + + $exportFileName = 'Exchange - Customers Data Report.xls'; + $filesystemDriver = Storage::getDefaultDriver(); + if($filesystemDriver === 's3'){ + return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsCompanies) ]); + } + else{ + $response = $exportsCompanies->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + } + return $response; + } +} diff --git a/app/Http/Controllers/Imports/ImportController.php b/app/Http/Controllers/Imports/ImportController.php new file mode 100644 index 00000000..02f364b6 --- /dev/null +++ b/app/Http/Controllers/Imports/ImportController.php @@ -0,0 +1,17 @@ +execute($request); + } +} diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue new file mode 100644 index 00000000..ab1524e8 --- /dev/null +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -0,0 +1,205 @@ + + + + diff --git a/resources/assets/vue/components/bookings/elements/PaymentComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentComponent.vue index 1f9a606f..02f9a953 100644 --- a/resources/assets/vue/components/bookings/elements/PaymentComponent.vue +++ b/resources/assets/vue/components/bookings/elements/PaymentComponent.vue @@ -1,6 +1,12 @@