diff --git a/app/Http/Controllers/Api/AdvertisementController.php b/app/Http/Controllers/Api/AdvertisementController.php index 713d128..554213e 100644 --- a/app/Http/Controllers/Api/AdvertisementController.php +++ b/app/Http/Controllers/Api/AdvertisementController.php @@ -9,6 +9,9 @@ use Illuminate\Http\Response; use App\Http\Controllers\Controller; use App\Http\Resources\AdvertisementResource; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Validator; +use Maatwebsite\Excel\Facades\Excel; +use App\Imports\AdvertisementImport; class AdvertisementController extends Controller { @@ -18,7 +21,32 @@ class AdvertisementController extends Controller public function index(Request $request) { $perPage = $request->input('per_page', 15); // Default 15 jika tidak dikirim oleh client - $advertisements = Advertisement::paginate($perPage); + $search = $request->input('search', ''); // Ambil parameter 'search' jika ada + + // Query dasar untuk mengambil iklan + $query = Advertisement::query(); + // Jika ada pencarian, filter berdasarkan kolom yang diinginkan + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('business_name', 'like', "%$search%") + ->orWhere('npwpd', 'like', "%$search%") + ->orWhere('advertisement_content', 'like', "%$search%") + ->orWhere('business_address', 'like', "%$search%") + ->orWhere('advertisement_location', 'like', "%$search%") + ->orWhereIn('village_code', function ($subQuery) use ($search) { + $subQuery->select('village_code') + ->from('villages') + ->where('village_name', 'like', "%$search%"); + }) + ->orWhereIn('district_code', function ($subQuery) use ($search) { + $subQuery->select('district_code') + ->from('districts') + ->where('district_name', 'like', "%$search%"); + }); + }); + } + + $advertisements = $query->paginate($perPage); $advertisements->getCollection()->transform(function ($advertisement) { $village = DB::table('villages')->where('village_code', $advertisement->village_code)->first(); @@ -47,24 +75,58 @@ class AdvertisementController extends Controller { $data = $request->validated(); - // Transformasi village_name dan district_name menjadi village_code dan district_code - if (isset($data['village_name'])) { - // Ambil village_code berdasarkan village_name dari database - $data['village_code'] = DB::table('villages')->where('village_name', $data['village_name'])->value('village_code'); - unset($data['village_name']); // Hapus village_name jika sudah tidak diperlukan - } + // Cari village_code berdasarkan village_name + $village_code = DB::table('villages')->where('village_name', $data['village_name'])->value('village_code'); + // Cari district_code berdasarkan district_name + $district_code = DB::table('districts')->where('district_name', $data['district_name'])->value('district_code'); - if (isset($data['district_name'])) { - // Ambil district_code berdasarkan district_name dari database - $data['district_code'] = DB::table('districts')->where('district_name', $data['district_name'])->value('district_code'); - unset($data['district_name']); // Hapus district_name jika sudah tidak diperlukan - } + // Tambahkan village_code dan district_code ke data + $data['village_code'] = $village_code; + $data['district_code'] = $district_code; // Log data setelah transformasi info($data); return Advertisement::create($data); } + /** + * Import advertisements from Excel or CSV. + */ + public function importFromFile(Request $request) + { + // Validasi file + info($request); + $validator = Validator::make($request->all(), [ + 'file' => 'required|mimes:xlsx,xls|max:10240', // Max 10MB + ]); + + if ($validator->fails()) { + return response()->json([ + 'message' => 'File validation failed.', + 'errors' => $validator->errors() + ], 400); + } + + try { + // Ambil file dari request + $file = $request->file('file'); + + // Menggunakan Laravel Excel untuk mengimpor file + Excel::import(new AdvertisementImport, $file); + + // Jika sukses, kembalikan respons sukses + return response()->json([ + 'message' => 'File uploaded and imported successfully!' + ], 200); + } catch (\Exception $e) { + // Jika ada error, kembalikan error response + return response()->json([ + 'message' => 'Error during file import.', + 'error' => $e->getMessage() + ], 500); + } + } + /** * Display the specified resource. */ @@ -79,21 +141,19 @@ class AdvertisementController extends Controller public function update(AdvertisementRequest $request, Advertisement $advertisement): Advertisement { $data = $request->validated(); - // Transformasi village_name dan district_name menjadi village_code dan district_code - if (isset($data['village_name'])) { - // Ambil village_code berdasarkan village_name dari database - $data['village_code'] = DB::table('villages')->where('village_name', $data['village_name'])->value('village_code'); - unset($data['village_name']); // Hapus village_name jika sudah tidak diperlukan - } - if (isset($data['district_name'])) { - // Ambil district_code berdasarkan district_name dari database - $data['district_code'] = DB::table('districts')->where('district_name', $data['district_name'])->value('district_code'); - unset($data['district_name']); // Hapus district_name jika sudah tidak diperlukan - } + // Cari village_code berdasarkan village_name + $village_code = DB::table('villages')->where('village_name', $data['village_name'])->value('village_code'); + // Cari district_code berdasarkan district_name + $district_code = DB::table('districts')->where('district_name', $data['district_name'])->value('district_code'); + + // Tambahkan village_code dan district_code ke data + $data['village_code'] = $village_code; + $data['district_code'] = $district_code; // Log data setelah transformasi info($data); + $advertisement->update($data); return $advertisement; @@ -105,4 +165,35 @@ class AdvertisementController extends Controller return response()->noContent(); } + + public function searchOptionsInAdvertisements(Request $request) + { + $query = $request->input('query'); + $field = $request->input('field'); + $district = $request->input('district'); // Ambil kecamatan jika ada + + info("Query: $query, Field: $field, District: $district"); + + if ($field === 'district_name') { + $results = DB::table('districts') + ->where('district_name', 'like', '%' . $query . '%') + ->limit(10) + ->get(['district_name AS name', 'district_code AS code']); + } elseif ($field === 'village_name' && $district) { + $results = DB::table('villages') + ->where('village_name', 'like', '%' . $query . '%') + ->whereExists(function ($query) use ($district) { + $query->select(DB::raw(1)) + ->from('districts') + ->whereColumn('villages.district_code', 'districts.district_code') + ->where('districts.district_name', $district); + }) + ->limit(10) + ->get(['village_name AS name', 'village_code AS code']); + } else { + $results = collect(); + } + + return response()->json($results); + } } diff --git a/app/Http/Controllers/Data/AdvertisementController.php b/app/Http/Controllers/Data/AdvertisementController.php index 603057c..83606cc 100644 --- a/app/Http/Controllers/Data/AdvertisementController.php +++ b/app/Http/Controllers/Data/AdvertisementController.php @@ -17,6 +17,15 @@ class AdvertisementController extends Controller return view('data.advertisements.index'); } + /** + * Show the form for uploading a file. + */ + public function bulkCreate() + { + // Mengembalikan view form-upload + return view('data.advertisements.form-upload'); + } + /** * Show the form for creating a new resource. */ @@ -38,7 +47,7 @@ class AdvertisementController extends Controller // $route = 'advertisements.create'; // info("AdvertisementController@edit diakses dengan ID: $title"); - return view('form-create-update.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); + return view('data.advertisements.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); } /** @@ -77,7 +86,7 @@ class AdvertisementController extends Controller // $route = 'advertisements.update'; // Menggunakan route update untuk form edit // info("AdvertisementController@edit diakses dengan route: $route"); - return view('form-create-update.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); + return view('data.advertisements.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); } private function getFields() @@ -90,8 +99,8 @@ class AdvertisementController extends Controller "advertisement_content" => "Isi Reklame", "business_address" => "Alamat Wajib Pajak", "advertisement_location" => "Lokasi Reklame", - "village_name" => "Desa", "district_name" => "Kecamatan", + "village_name" => "Desa", "length" => "Panjang", "width" => "Lebar", "viewing_angle" => "Sudut Pandang", diff --git a/app/Imports/AdvertisementImport.php b/app/Imports/AdvertisementImport.php new file mode 100644 index 0000000..1c27243 --- /dev/null +++ b/app/Imports/AdvertisementImport.php @@ -0,0 +1,92 @@ +isEmpty()) + { + return; + } + + // Ambil data districts dengan normalisasi nama + $districts = DB::table('districts') + ->get() + ->mapWithKeys(function ($item) { + return [strtolower(trim($item->district_name)) => $item->district_code]; + }) + ->toArray(); + + // Cari header secara otomatis + $header = $rows->first(); + $headerIndex = collect($header)->search(fn($value) => !empty($value)); + + // Pastikan header ditemukan + if ($headerIndex === false) { + return; + } + + $dataToInsert = []; + + foreach ($rows->skip(1) as $row) { + // Normalisasi nama kecamatan dan desa + $districtName = strtolower(trim(str_replace('Kecamatan ', '', $row[8]))); + $villageName = strtolower(trim($row[7])); + + // Cari district_code dari tabel districts + $districtCode = $districts[$districtName] ?? null; + + $listTrueVillage = DB::table('villages') + ->where('district_code', $districtCode) // Perbaikan pada where() + ->get() + ->mapWithKeys(function ($item) { + return [strtolower(trim($item->village_name)) => [ + 'village_code' => $item->village_code, + 'district_code' => $item->district_code + ]]; + }) + ->toArray(); + + // ambil village code yang village_name sama dengan $villageName + $villageCode = $listTrueVillage[$villageName]['village_code'] ?? '0000'; + + $dataToInsert[] = [ + 'no' => $row[0], + 'business_name' => $row[1], + 'npwpd' => $row[2], + 'advertisement_type' => $row[3], + 'advertisement_content' => $row[4], + 'business_address' => $row[5], + 'advertisement_location' => $row[6], + 'village_code' => $villageCode, + 'district_code' => $districtCode, + 'length' => $row[9], + 'width' => $row[10], + 'viewing_angle' => $row[11], + 'face' => $row[12], + 'area' => $row[13], + 'angle' => $row[14], + 'contact' => $row[15] ?? "-", + 'created_at' => now(), + 'updated_at' => now() + ]; + } + // Bulk insert untuk efisiensi + if (!empty($dataToInsert)) { + Advertisement::insert($dataToInsert); + } else { + return; + } + } +} + diff --git a/composer.json b/composer.json index 7b57f35..3b92ebc 100755 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "guzzlehttp/guzzle": "^7.9", "laravel/framework": "^11.31", "laravel/sanctum": "^4.0", - "laravel/tinker": "^2.9" + "laravel/tinker": "^2.9", + "maatwebsite/excel": "^3.1" }, "require-dev": { "fakerphp/faker": "^1.23", diff --git a/composer.lock b/composer.lock index 14ca53b..07f0088 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "600bc468a0c3848ac887e905a0cd06a8", + "content-hash": "37b87e09a4c98ce5b5c07fac061edb29", "packages": [ { "name": "brick/math", @@ -135,6 +135,166 @@ ], "time": "2024-02-09T16:56:22+00:00" }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -510,6 +670,67 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.18.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0" + }, + "time": "2024-11-01T03:51:45+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -1893,6 +2114,272 @@ ], "time": "2024-09-21T08:32:55+00:00" }, + { + "name": "maatwebsite/excel", + "version": "3.1.62", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "decfb9140161fcc117571e47e35ddf27983189ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/decfb9140161fcc117571e47e35ddf27983189ce", + "reference": "decfb9140161fcc117571e47e35ddf27983189ce", + "shasum": "" + }, + "require": { + "composer/semver": "^3.3", + "ext-json": "*", + "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0", + "php": "^7.0||^8.0", + "phpoffice/phpspreadsheet": "^1.29.7", + "psr/simple-cache": "^1.0||^2.0||^3.0" + }, + "require-dev": { + "laravel/scout": "^7.0||^8.0||^9.0||^10.0", + "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + }, + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.62" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2025-01-04T12:14:36+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.2" + }, + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^11.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2025-01-27T12:07:53+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, { "name": "monolog/monolog", "version": "3.8.0", @@ -2395,6 +2882,112 @@ ], "time": "2024-11-21T10:39:51+00:00" }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.29.10", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "c80041b1628c4f18030407134fe88303661d4e4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/c80041b1628c4f18030407134fe88303661d4e4e", + "reference": "c80041b1628c4f18030407134fe88303661d4e4e", + "shasum": "" + }, + "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.10" + }, + "time": "2025-02-08T02:56:14+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.3", diff --git a/config/excel.php b/config/excel.php new file mode 100644 index 0000000..c1fd34a --- /dev/null +++ b/config/excel.php @@ -0,0 +1,380 @@ + [ + + /* + |-------------------------------------------------------------------------- + | Chunk size + |-------------------------------------------------------------------------- + | + | When using FromQuery, the query is automatically chunked. + | Here you can specify how big the chunk should be. + | + */ + 'chunk_size' => 1000, + + /* + |-------------------------------------------------------------------------- + | Pre-calculate formulas during export + |-------------------------------------------------------------------------- + */ + 'pre_calculate_formulas' => false, + + /* + |-------------------------------------------------------------------------- + | Enable strict null comparison + |-------------------------------------------------------------------------- + | + | When enabling strict null comparison empty cells ('') will + | be added to the sheet. + */ + 'strict_null_comparison' => false, + + /* + |-------------------------------------------------------------------------- + | CSV Settings + |-------------------------------------------------------------------------- + | + | Configure e.g. delimiter, enclosure and line ending for CSV exports. + | + */ + 'csv' => [ + 'delimiter' => ',', + 'enclosure' => '"', + 'line_ending' => PHP_EOL, + 'use_bom' => false, + 'include_separator_line' => false, + 'excel_compatibility' => false, + 'output_encoding' => '', + 'test_auto_detect' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Worksheet properties + |-------------------------------------------------------------------------- + | + | Configure e.g. default title, creator, subject,... + | + */ + 'properties' => [ + 'creator' => '', + 'lastModifiedBy' => '', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'manager' => '', + 'company' => '', + ], + ], + + 'imports' => [ + + /* + |-------------------------------------------------------------------------- + | Read Only + |-------------------------------------------------------------------------- + | + | When dealing with imports, you might only be interested in the + | data that the sheet exists. By default we ignore all styles, + | however if you want to do some logic based on style data + | you can enable it by setting read_only to false. + | + */ + 'read_only' => true, + + /* + |-------------------------------------------------------------------------- + | Ignore Empty + |-------------------------------------------------------------------------- + | + | When dealing with imports, you might be interested in ignoring + | rows that have null values or empty strings. By default rows + | containing empty strings or empty values are not ignored but can be + | ignored by enabling the setting ignore_empty to true. + | + */ + 'ignore_empty' => false, + + /* + |-------------------------------------------------------------------------- + | Heading Row Formatter + |-------------------------------------------------------------------------- + | + | Configure the heading row formatter. + | Available options: none|slug|custom + | + */ + 'heading_row' => [ + 'formatter' => 'slug', + ], + + /* + |-------------------------------------------------------------------------- + | CSV Settings + |-------------------------------------------------------------------------- + | + | Configure e.g. delimiter, enclosure and line ending for CSV imports. + | + */ + 'csv' => [ + 'delimiter' => null, + 'enclosure' => '"', + 'escape_character' => '\\', + 'contiguous' => false, + 'input_encoding' => Csv::GUESS_ENCODING, + ], + + /* + |-------------------------------------------------------------------------- + | Worksheet properties + |-------------------------------------------------------------------------- + | + | Configure e.g. default title, creator, subject,... + | + */ + 'properties' => [ + 'creator' => '', + 'lastModifiedBy' => '', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'manager' => '', + 'company' => '', + ], + + /* + |-------------------------------------------------------------------------- + | Cell Middleware + |-------------------------------------------------------------------------- + | + | Configure middleware that is executed on getting a cell value + | + */ + 'cells' => [ + 'middleware' => [ + //\Maatwebsite\Excel\Middleware\TrimCellValue::class, + //\Maatwebsite\Excel\Middleware\ConvertEmptyCellValuesToNull::class, + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Extension detector + |-------------------------------------------------------------------------- + | + | Configure here which writer/reader type should be used when the package + | needs to guess the correct type based on the extension alone. + | + */ + 'extension_detector' => [ + 'xlsx' => Excel::XLSX, + 'xlsm' => Excel::XLSX, + 'xltx' => Excel::XLSX, + 'xltm' => Excel::XLSX, + 'xls' => Excel::XLS, + 'xlt' => Excel::XLS, + 'ods' => Excel::ODS, + 'ots' => Excel::ODS, + 'slk' => Excel::SLK, + 'xml' => Excel::XML, + 'gnumeric' => Excel::GNUMERIC, + 'htm' => Excel::HTML, + 'html' => Excel::HTML, + 'csv' => Excel::CSV, + 'tsv' => Excel::TSV, + + /* + |-------------------------------------------------------------------------- + | PDF Extension + |-------------------------------------------------------------------------- + | + | Configure here which Pdf driver should be used by default. + | Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF + | + */ + 'pdf' => Excel::DOMPDF, + ], + + /* + |-------------------------------------------------------------------------- + | Value Binder + |-------------------------------------------------------------------------- + | + | PhpSpreadsheet offers a way to hook into the process of a value being + | written to a cell. In there some assumptions are made on how the + | value should be formatted. If you want to change those defaults, + | you can implement your own default value binder. + | + | Possible value binders: + | + | [x] Maatwebsite\Excel\DefaultValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class + | + */ + 'value_binder' => [ + 'default' => Maatwebsite\Excel\DefaultValueBinder::class, + ], + + 'cache' => [ + /* + |-------------------------------------------------------------------------- + | Default cell caching driver + |-------------------------------------------------------------------------- + | + | By default PhpSpreadsheet keeps all cell values in memory, however when + | dealing with large files, this might result into memory issues. If you + | want to mitigate that, you can configure a cell caching driver here. + | When using the illuminate driver, it will store each value in the + | cache store. This can slow down the process, because it needs to + | store each value. You can use the "batch" store if you want to + | only persist to the store when the memory limit is reached. + | + | Drivers: memory|illuminate|batch + | + */ + 'driver' => 'memory', + + /* + |-------------------------------------------------------------------------- + | Batch memory caching + |-------------------------------------------------------------------------- + | + | When dealing with the "batch" caching driver, it will only + | persist to the store when the memory limit is reached. + | Here you can tweak the memory limit to your liking. + | + */ + 'batch' => [ + 'memory_limit' => 60000, + ], + + /* + |-------------------------------------------------------------------------- + | Illuminate cache + |-------------------------------------------------------------------------- + | + | When using the "illuminate" caching driver, it will automatically use + | your default cache store. However if you prefer to have the cell + | cache on a separate store, you can configure the store name here. + | You can use any store defined in your cache config. When leaving + | at "null" it will use the default store. + | + */ + 'illuminate' => [ + 'store' => null, + ], + + /* + |-------------------------------------------------------------------------- + | Cache Time-to-live (TTL) + |-------------------------------------------------------------------------- + | + | The TTL of items written to cache. If you want to keep the items cached + | indefinitely, set this to null. Otherwise, set a number of seconds, + | a \DateInterval, or a callable. + | + | Allowable types: callable|\DateInterval|int|null + | + */ + 'default_ttl' => 10800, + ], + + /* + |-------------------------------------------------------------------------- + | Transaction Handler + |-------------------------------------------------------------------------- + | + | By default the import is wrapped in a transaction. This is useful + | for when an import may fail and you want to retry it. With the + | transactions, the previous import gets rolled-back. + | + | You can disable the transaction handler by setting this to null. + | Or you can choose a custom made transaction handler here. + | + | Supported handlers: null|db + | + */ + 'transactions' => [ + 'handler' => 'db', + 'db' => [ + 'connection' => null, + ], + ], + + 'temporary_files' => [ + + /* + |-------------------------------------------------------------------------- + | Local Temporary Path + |-------------------------------------------------------------------------- + | + | When exporting and importing files, we use a temporary file, before + | storing reading or downloading. Here you can customize that path. + | permissions is an array with the permission flags for the directory (dir) + | and the create file (file). + | + */ + 'local_path' => storage_path('framework/cache/laravel-excel'), + + /* + |-------------------------------------------------------------------------- + | Local Temporary Path Permissions + |-------------------------------------------------------------------------- + | + | Permissions is an array with the permission flags for the directory (dir) + | and the create file (file). + | If omitted the default permissions of the filesystem will be used. + | + */ + 'local_permissions' => [ + // 'dir' => 0755, + // 'file' => 0644, + ], + + /* + |-------------------------------------------------------------------------- + | Remote Temporary Disk + |-------------------------------------------------------------------------- + | + | When dealing with a multi server setup with queues in which you + | cannot rely on having a shared local temporary path, you might + | want to store the temporary file on a shared disk. During the + | queue executing, we'll retrieve the temporary file from that + | location instead. When left to null, it will always use + | the local path. This setting only has effect when using + | in conjunction with queued imports and exports. + | + */ + 'remote_disk' => null, + 'remote_prefix' => null, + + /* + |-------------------------------------------------------------------------- + | Force Resync + |-------------------------------------------------------------------------- + | + | When dealing with a multi server setup as above, it's possible + | for the clean up that occurs after entire queue has been run to only + | cleanup the server that the last AfterImportJob runs on. The rest of the server + | would still have the local temporary file stored on it. In this case your + | local storage limits can be exceeded and future imports won't be processed. + | To mitigate this you can set this config value to be true, so that after every + | queued chunk is processed the local temporary file is deleted on the server that + | processed it. + | + */ + 'force_resync_remote' => null, + ], +]; diff --git a/resources/js/data/advertisements/data-advertisements.js b/resources/js/data/advertisements/data-advertisements.js index 8b9401c..bade5e5 100644 --- a/resources/js/data/advertisements/data-advertisements.js +++ b/resources/js/data/advertisements/data-advertisements.js @@ -14,26 +14,22 @@ const dataAdvertisementsColumns = [ "Lokasi Reklame", "Desa", "Kecamatan", - "Panjang", - "Lebar", - "Sudut Pandang", - "Muka", - "Luas", - "Sudut", "Kontak", { name: "Actions", widht: "120px", formatter: function(cell, row) { - const id = row.cells[16].data; + const id = row.cells[10].data; const model = "data/advertisements"; return gridjs.html(`
+ Please upload a file with the extension .xls or .xlsx with a maximum size of 10 MB.
+
+ For .xls and .xlsx files, ensure that the data is contained within a single sheet with the following columns:
+ No, Nama Wajib Pajak, NPWPD, Jenis Reklame, Isi Reklame, Alamat Wajib Pajak, Lokasi Reklame, Desa,
+ Kecamatan, Panajang, Lebar, Sudut Pandang, Muka, Luas, Sudut, Kontak.
+