136 Commits
Author SHA1 Message Date
Syaharani cb36682d9e Update Koperasi 2026-11-06 22:38:45 +07:00
afriadirahman 6232b28e11 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-11-06 14:21:50 +07:00
afriadirahman f78b74519a Update Lihat Jumlah Kunjungan 2026-11-06 14:21:26 +07:00
Syaharani 12aa655ba4 Update BUMDes 2026-11-05 21:42:00 +07:00
Syaharani ddd07b1397 Update BUMDes 2026-11-05 21:33:10 +07:00
Syaharani 291ebf919c Update Kelompok Tani 2026-11-05 21:30:38 +07:00
Syaharani c55ff109a0 Update BUMDes 2026-11-05 19:20:05 +07:00
afriadirahman 9cdd178297 Update Spatie versi 4 2026-11-05 17:06:11 +07:00
afriadirahman b76fa9e59b Update composer json untuk spatie 2026-11-05 16:39:08 +07:00
afriadirahman 7a279ad5d2 Update Log aktivitas 2026-11-05 16:34:33 +07:00
afriadirahman a3ec431d49 Update Monitoring dan Verifikasi Petani 2026-11-05 11:01:12 +07:00
afriadirahman fd93e0d265 Update Dinamis header dan form input 2026-11-04 20:25:31 +07:00
afriadirahman 8ef4ae1f15 Update Status kelengkapan data 2026-11-04 17:31:22 +07:00
afriadirahman 89c5a1371a Update Alert Profil Petani 2026-11-04 16:20:33 +07:00
afriadirahman 41da3a71ee Update Role fasilitator, kordinator 2026-11-04 14:24:51 +07:00
afriadirahman b5b046ed86 Update Pendidikan dan Pelatihan 2026-11-04 13:17:36 +07:00
afriadirahman aa91c3fe3f Update Praktik Budidaya 2026-11-04 13:09:30 +07:00
Syaharani 53913bebe9 update kelompok tani 2026-11-03 17:53:53 +07:00
Althaf f455f8b878 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-11-03 14:47:04 +07:00
Althaf f1112e3b68 update controller 2026-11-03 10:51:50 +07:00
afriadirahman c1370a26ca Update Harga Internasional 2026-11-03 09:37:59 +07:00
Syaharani 013cb7b728 dashboard pasar 2026-10-21 10:14:49 +07:00
Althaf 4ab745cfe5 sumber informasi harga 2026-10-19 10:03:05 +07:00
Althaf c66eed56e2 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-10-16 15:11:49 +07:00
Syaharani 8be0906a2e Update profil petani 2026-10-16 15:48:42 +07:00
afriadirahman fcd79b7cfe Update dashboard Profil Detail Petani 2026-10-16 15:25:21 +07:00
Althaf bea9be8a39 resolve aksespasar 2026-10-16 15:11:39 +07:00
afriadirahman 5220b10de7 Update Config js 2026-10-16 10:38:30 +07:00
Syaharani 24725e3df1 update chart dashboard 2026-10-16 10:29:42 +07:00
Syaharani 60d32a88e9 update dashboard produksi 2026-10-16 10:04:56 +07:00
Althaf 4370d3c3d0 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-10-15 15:14:57 +07:00
Althaf 7699430301 new field akses pasar 2026-10-15 15:10:18 +07:00
fir2be df2b5a1312 hover and scroll on map 2026-10-15 14:12:03 +07:00
fir2be 2e8271d27a cars 2026-10-15 14:05:01 +07:00
fir2be 9b5c0a7309 perubahan query 2026-10-15 13:02:42 +07:00
fir2be 9d56b67998 sroll untuk 2026-10-15 11:31:57 +07:00
fir2be f95f43999a peta sebaran dan praktek budaya 2026-10-15 11:25:38 +07:00
Syaharani 3e172cf915 card dashboard produksi 2026-10-14 20:18:15 +07:00
Syaharani 3a9b3dbd7b dashboard produksi 2026-10-14 19:43:39 +07:00
Syaharani 80f0056efe dashboard produksi & ganti warna chart 2026-10-13 15:55:18 +07:00
afriadirahman aef27704f2 Update Karakteristik Petani 2026-10-12 10:22:01 +07:00
Syaharani f49bb0c2db dashboard produksi 2026-10-09 13:22:51 +07:00
afriadirahman 8a2c0292ac Update Header 2026-10-08 09:58:56 +07:00
afriadirahman 9ea324e553 Update Dashboard & Sidebar 2026-10-08 09:48:00 +07:00
afriadirahman 94c3288ea7 Update Dashboard Karakteristik Petani 2026-10-07 13:53:55 +07:00
Syaharani 8539bdcec4 update profil petani 2026-10-07 12:03:02 +07:00
Syaharani 77de648ded dashboard karakteristik petani 2026-10-07 10:20:20 +07:00
Syaharani 393cf0d0d1 karakteristik petani 2026-10-06 17:52:34 +07:00
Syaharani 7fdf9b400d solve jumlah lahan dan tanaman 2026-09-23 17:01:19 +07:00
Syaharani be4d46004e solve jumlah lahan dan tanaman 2026-09-23 16:36:14 +07:00
Syaharani fef5358402 solve filter jumlah lahan dan tanaman 2026-09-23 14:52:30 +07:00
Syaharani 02eed6da34 solve jumlah lahan dan tanaman 2026-09-23 14:37:08 +07:00
Syaharani 94d3f2a582 lower filter profil petani 2026-09-23 10:19:30 +07:00
Syaharani 471ca5ac0e filter profil petani 2026-09-23 10:13:13 +07:00
Althaf 8ec8f0c9d6 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-09-22 15:21:25 +07:00
Althaf 4d7d16e9f6 add migration riwayat petani 2026-09-22 15:20:45 +07:00
afriadirahman 1155b9b95b Update Header Pertanian 2026-09-22 15:12:32 +07:00
Syaharani 607533a327 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	app/Http/Controllers/Web/Produktivitas/PetaniController.php
2026-09-22 11:02:02 +07:00
Syaharani 6b25bff2c4 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-09-22 10:59:55 +07:00
Syaharani 71b4d42ea2 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-09-22 10:58:41 +07:00
Syaharani c42a2571f5 solve profil petani 2026-09-22 10:57:21 +07:00
Althaf 16903b21e3 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-09-18 16:22:57 +07:00
Althaf 1d4a44b8ac update destroy 2026-09-18 16:22:48 +07:00
Syaharani 539239b507 bumdes 2026-09-16 11:09:08 +07:00
afriadirahman a76b014056 Update Kelompok Tani & APP AGERA 2026-09-06 19:09:37 +07:00
Althaf d50c292cf7 instrumen koperasi 2026-09-03 13:17:16 +07:00
Althaf dacaec7a86 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-27 11:48:55 +07:00
Althaf 6967eafe98 add instrumen koperasi 2026-08-27 11:48:42 +07:00
Syaharani 118cda625a filter dashboard indikator pertanian 2026-08-20 17:24:31 +07:00
irwan.l.cahyono a3f7cb4669 filter segmen 2026-08-20 01:52:05 +07:00
irwan.l.cahyono ec009a2c55 indeks petani dan ajax 2026-08-20 01:10:56 +07:00
afriadirahman b63dafdaee Update Profile Petani 2026-08-20 01:01:27 +07:00
Althaf b97f682cd3 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-19 16:42:31 +07:00
Althaf 404019bab6 Added Score 2026-08-19 16:42:03 +07:00
Syaharani 609919ba30 solve dashboard survey petani 2026-08-19 16:21:42 +07:00
irwan.l.cahyono 047cb4a779 link ke profil 2026-08-19 10:37:17 +07:00
irwan.l.cahyono 530c297b53 revisi jumlahpetani 2026-08-19 01:57:52 +07:00
Syaharani 8fbf68e6ef solve keanggotaan kelompok tani 2026-08-18 14:05:46 +07:00
Syaharani ac8b370248 update dashboard indikator pertanian 2026-08-18 14:04:44 +07:00
Syaharani 88762f7afb update dashboard indikator pertanian 2026-08-13 17:00:00 +07:00
Syaharani b96de514e3 solve dashboard indikator pertanian 2026-08-13 16:31:11 +07:00
Syaharani 6830142a82 solve dashboard indikator pertanian 2026-08-13 16:07:55 +07:00
afriadirahman 4b26e82afb Optimize Demografi & Update Profil Petani 2026-08-13 15:31:04 +07:00
Syaharani b855a857b2 solve dashboard indikator pertanian 2026-08-13 13:07:03 +07:00
afriadirahman ba7520a23c Update Demografi Petani 2026-08-12 17:49:24 +07:00
afriadirahman 0b333ab4e9 Update Profil Detail Petani 2026-08-12 17:33:53 +07:00
Althaf 3b1f15d5b3 fixed aksespasar 2026-08-11 16:19:10 +07:00
Althaf 605506bba8 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-11 15:40:27 +07:00
afriadirahman c960ba14b1 Update Demografi Petani 2026-08-11 15:13:28 +07:00
Syaharani a4f38998d5 dashboard indikator pertanian 2026-08-07 16:09:24 +07:00
Syaharani 0d9f6c0b64 indikator pertanian 2026-08-07 15:56:37 +07:00
irwan.l.cahyono 81775b0c13 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-07 15:00:32 +07:00
irwan.l.cahyono ba1a318d09 soft deleted petani 2026-08-07 15:00:30 +07:00
afriadirahman 0761d64254 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-07 14:32:48 +07:00
afriadirahman 67c3c6c809 Update demografi dashboard 2026-08-07 14:32:40 +07:00
irwan.l.cahyono 04387268cd indeks petani 2026-08-07 14:31:16 +07:00
irwan.l.cahyono 946fabb9a5 lahan skor has petani 2026-08-07 14:17:06 +07:00
irwan.l.cahyono 0a0c86d648 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-07 12:59:26 +07:00
irwan.l.cahyono 8b21fab8b8 dashboard indeks petani 2026-08-07 12:59:25 +07:00
afriadirahman 16a0a3c56c Update Icon Demografi Dashboard 2026-08-07 11:33:08 +07:00
afriadirahman d4c6b64ba6 Update Sidebar Demografi Petani 2026-08-07 11:20:05 +07:00
afriadirahman b4089d72b3 Update Dashboard Demografi Petani 2026-08-07 11:17:53 +07:00
afriadirahman 01990ccec1 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-06 13:29:42 +07:00
irwan.l.cahyono 8aed88a31f dashboard indeks petani 2026-08-05 01:20:19 +07:00
irwan.l.cahyono 4aa0780802 dashboard profil petani komp 4 2026-08-03 13:08:01 +07:00
afriadirahman 4e41246382 Update Profile Petani Dashboard 2026-08-03 12:53:20 +07:00
Althaf 43fe9e5f7f Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-08-03 09:22:47 +07:00
irwan.l.cahyono c8d1994d3b dashboard profil petani 2026-07-30 15:23:34 +07:00
Althaf cf0f4b47b4 update akses pasar 2026-07-30 11:14:31 +07:00
irwan.l.cahyono 24a8016710 petani booted skor 2026-07-29 16:52:51 +07:00
irwan.l.cahyono 20e1eee6ff skor petani domain komponen hitung 2026-07-29 16:27:33 +07:00
afriadirahman c0432cd5f8 Update Sidebar Filter Fasilitator 2026-07-29 16:12:31 +07:00
irwan.l.cahyono 0ce0936a80 skor petani update 2026-07-29 16:05:43 +07:00
Syaharani 502c932f21 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-28 16:54:37 +07:00
Syaharani e60a66eeb7 bumdes: profil & add pengurus bumdes 2026-07-28 16:54:27 +07:00
afriadirahman 4475cd0098 Update Logo Sidebar 2026-07-28 16:18:41 +07:00
afriadirahman 67c111a2b3 Update Logo Agromonev & Agropro 2026-07-28 16:10:47 +07:00
Syaharani 3bcaa3ea50 solve survey produktivitas 2026-07-27 10:14:36 +07:00
Syaharani bed9a6f620 solve 2026-07-23 18:26:24 +07:00
Althaf 712b10e405 Merge branches 'main' and 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 17:06:45 +07:00
Althaf 6cfcf46ba6 use assets avatars 2026-07-22 17:06:31 +07:00
Syaharani b1b9828514 update jumlah tanaman 2026-07-22 16:54:57 +07:00
Syaharani 7af7e1bdaf update jumlah lahan 2026-07-22 16:40:24 +07:00
Syaharani bd05fc7f0f update hama dan penyakit 2026-07-22 16:23:32 +07:00
Syaharani 17b5687db8 update user profile 2026-07-22 15:55:07 +07:00
Syaharani e7f48b6500 solve lahan & tanaman 2026-07-22 15:49:25 +07:00
Syaharani a5884d0f8c solve akses pasar 2026-07-22 15:22:56 +07:00
Syaharani 9576c6295e solve sosial ekonomi 2026-07-22 14:41:05 +07:00
irwan.l.cahyono 079e300d5d Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 14:39:10 +07:00
irwan.l.cahyono 2c94316439 petani lahan hapus 2026-07-22 14:38:10 +07:00
Syaharani 690b53e5a2 Merge origin/main 2026-07-22 14:08:34 +07:00
irwan.l.cahyono 50c9adfdc7 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 13:56:56 +07:00
irwan.l.cahyono 696c7dede8 hama dan penyakit lahan 2026-07-22 13:56:55 +07:00
Syaharani 5967e7d6f3 solve pendidikan & pelatihan 2026-07-22 13:28:58 +07:00
Syaharani 4c66d72dc5 solve praktik budidaya 2026-07-22 13:27:35 +07:00
Syaharani e02a34a527 solve lahan & tanaman 2026-07-22 11:58:51 +07:00
389 changed files with 44419 additions and 1919 deletions
+6
View File
@@ -63,3 +63,9 @@ AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
# Optional CA bundle path for Yahoo Finance when PHP has no system CA configured.
YAHOO_FINANCE_CA_BUNDLE=
ALPHA_VANTAGE_API_KEY=
+715
View File
@@ -0,0 +1,715 @@
# AISTANDAR — Standar Pengembangan Aplikasi database-pertani-web
Dokumen ini adalah **aturan wajib** bagi AI (dan developer) yang bekerja di repo ini.
Baca seluruhnya sebelum membuat, mengubah, atau merefaktor kode.
## 0. Cara memakai dokumen ini
- Aturan di sini **mengalahkan** kebiasaan umum atau contoh dari luar. Jika ada konflik antara kode lama dan dokumen ini, ikuti dokumen ini **untuk kode baru**, dan ikuti Bagian 13 (Prosedur Refaktor) untuk kode lama.
- Jika sesuatu **tidak diatur** di sini: lihat dulu bagaimana modul yang sudah sesuai standar melakukannya, lalu tiru polanya. Jika tetap tidak jelas, **tanya**, jangan mengarang pola baru.
- **Jangan** menambah package/library baru, mengubah struktur database yang sudah ada, atau mengubah kontrak API tanpa izin eksplisit.
- Bahasa: teks yang tampil ke pengguna (label, pesan, validasi) memakai **Bahasa Indonesia**. Nama domain (petani, lahan, komoditas) tetap Bahasa Indonesia; kata kerja teknis Laravel (`index`, `store`, `show`) tetap bahasa Inggris.
---
## 1. Stack
| Bagian | Teknologi |
|---|---|
| Framework | Laravel 12 |
| Frontend web | Blade (tanpa Livewire/Inertia) |
| UI template | Vuexy (Bootstrap 5), ikon Tabler |
| Grafik | ApexCharts |
| Peta | Leaflet |
| Auth web | Session |
| Auth API | Laravel Sanctum (token) |
| Dokumentasi API | dedoc/scramble |
| Role | `app/Enums/Role.php`: `super_admin`, `admin` (admin program), `koordinator` (per komoditas), `enumerator` (penginput data petani), `fasilitator` (pemateri workshop), `petani`, `offtaker` |
---
## 2. Struktur folder & penamaan
### 2.1 Pengelompokan per domain
Controller, Model, Request, dan View **dikelompokkan per domain yang sama**:
```
Domain yang ada: Dashboard, Laporan, Produktivitas, Ekosistem, Program, Master,
Bumdes, Koperasi, Konfigurasi
```
| Lapisan | Lokasi |
|---|---|
| Controller web | `app/Http/Controllers/Web/{Domain}/{Model}Controller.php` |
| Controller API | `app/Http/Controllers/Api/{Domain}/{Model}Controller.php` |
| Form Request | `app/Http/Requests/{Domain}/Store{Model}Request.php`, `Update{Model}Request.php` |
| Model | `app/Models/{DomainModel}/{Model}.php` (ikuti folder model yang ada: `Pertanian/`, `Wilayah/`, `Program/`, `Master/`, dst.) |
| Enum | `app/Enums/` |
| Service / Query | `app/Services/{Domain}/` |
| View | `resources/views/{domain}/{modul}/` (huruf kecil, kebab-case) |
Controller baru **tidak boleh** ditaruh di root `app/Http/Controllers/`. Controller root yang sudah ada (`ProgramController`, `ProgramKomoditasController`, `ProgramLokasiController`) dipindahkan ke domain `Program/` saat direfaktor.
### 2.2 Konvensi nama
| Objek | Aturan | Contoh |
|---|---|---|
| Model | Singular, PascalCase | `Petani`, `JenisKomoditas` |
| Tabel | snake_case, **selalu ditulis eksplisit** di model | `protected $table = 'petani';` |
| Controller | `{Model}Controller` | `PetaniController` |
| Route name | `{modul}.{aksi}`, kebab-case | `jenis-komoditas.index` |
| URL | kebab-case | `/jenis-komoditas` |
| View | `{domain}/{modul}/{aksi}.blade.php` | `master/provinsi/index.blade.php` |
| Method tambahan | camelCase | `byProvinsi()`, `list()` |
> Karena nama domain berbahasa Indonesia, pluralisasi otomatis Laravel salah (`petanis`). **Wajib** set `$table` di setiap model, dan set parameter route bila perlu (`->parameters(['jenis-komoditas' => 'jenisKomoditas'])`).
---
## 3. Controller
> **Cakupan:** Bagian 3 berlaku untuk **modul CRUD** (pengelolaan data: tambah, ubah, hapus).
> Controller **Dashboard** dan **Laporan/Reporting** tidak terikat aturan 7 method dan mengikuti aturan yang lebih fleksibel di **Bagian 11**.
### 3.1 Tujuh method resmi
Untuk modul CRUD, gunakan **hanya** nama method resource Laravel:
| Method | HTTP | URL | Route name | Fungsi |
|---|---|---|---|---|
| `index` | GET | `/items` | `items.index` | Daftar data |
| `create` | GET | `/items/create` | `items.create` | Form tambah |
| `store` | POST | `/items` | `items.store` | Simpan baru |
| `show` | GET | `/items/{item}` | `items.show` | Detail |
| `edit` | GET | `/items/{item}/edit` | `items.edit` | Form ubah |
| `update` | PUT/PATCH | `/items/{item}` | `items.update` | Simpan perubahan |
| `destroy` | DELETE | `/items/{item}` | `items.destroy` | Hapus (soft delete) |
**Dilarang** memakai nama `add`, `view`, `save`, `delete`, `remove`, `detail`, atau sejenisnya untuk aksi CRUD. (Larangan ini tidak berlaku untuk Dashboard dan Laporan, lihat Bagian 11.)
### 3.2 Prinsip controller tipis
- Validasi **selalu** di Form Request, tidak pernah `$request->validate()` di controller.
- Controller hanya: terima request → panggil model/service → kembalikan respons.
- Logika bisnis yang lebih dari ±15 baris, dipakai di lebih dari satu tempat, atau melibatkan banyak tabel → pindahkan ke `app/Services/{Domain}/`.
- Operasi yang menulis ke lebih dari satu tabel → bungkus dengan `DB::transaction()`.
- Pakai route model binding (`Petani $petani`), bukan `find($id)`.
### 3.3 Tiga pola resmi
Pilih **satu** pola per modul berdasarkan tabel ini:
| Pola | Kapan dipakai | Contoh |
|---|---|---|
| **A. Offcanvas (AJAX)** | Data referensi/sederhana: sedikit field, tanpa halaman detail yang kaya | Provinsi, Kabupaten, Komoditas, Varietas, Adat |
| **B. Resource halaman** | Entitas utama: banyak field, ada relasi, perlu halaman detail | Lahan, Produksi, Workshop, BUMDes, Koperasi |
| **C. Detail multi-tab** | Entitas induk dengan banyak bagian data yang diisi bertahap | Petani, Survey Kelompok Tani |
---
#### Pola A — Offcanvas (AJAX)
- `index` mengembalikan **view**; `store`, `show`, `update`, `destroy` mengembalikan **JSON**.
- Tidak ada halaman `create`/`edit`; form ada di offcanvas di `index.blade.php`.
- `show` dipakai JS untuk mengisi form edit di offcanvas.
```php
// routes/web.php
// Route tambahan WAJIB didaftarkan SEBELUM Route::resource agar tidak tertangkap {provinsi}
Route::get('provinsi/list', [ProvinsiController::class, 'list'])->name('provinsi.list');
Route::resource('provinsi', ProvinsiController::class)->except(['create', 'edit']);
```
```php
namespace App\Http\Controllers\Web\Master;
class ProvinsiController extends Controller
{
public function index(Request $request)
{
$provinsi = Provinsi::query()
->when($request->search, fn ($q, $s) => $q->where('nama', 'like', "%{$s}%"))
->latest()
->paginate(15)
->withQueryString();
return view('master.provinsi.index', compact('provinsi'));
}
public function store(StoreProvinsiRequest $request)
{
$provinsi = Provinsi::create($request->validated());
return response()->json([
'success' => true,
'message' => 'Provinsi berhasil ditambahkan.',
'data' => $provinsi,
], 201);
}
public function show(Provinsi $provinsi)
{
return response()->json(['success' => true, 'data' => $provinsi]);
}
public function update(UpdateProvinsiRequest $request, Provinsi $provinsi)
{
$provinsi->update($request->validated());
return response()->json([
'success' => true,
'message' => 'Provinsi berhasil diperbarui.',
'data' => $provinsi,
]);
}
public function destroy(Provinsi $provinsi)
{
DB::transaction(fn () => $provinsi->delete());
return response()->json([
'success' => true,
'message' => 'Provinsi berhasil dihapus.',
]);
}
}
```
**Dropdown berantai** (provinsi → kabupaten → kecamatan → desa): method `by{Induk}` di controller anak, mengembalikan JSON `[{id, nama}]`.
```php
Route::get('kabupaten/by-provinsi/{provinsi}', [KabupatenController::class, 'byProvinsi'])
->name('kabupaten.by-provinsi');
```
---
#### Pola B — Resource halaman
- Semua 7 method; view `index`, `create`, `edit`, `show` + partial `_form`.
- Setelah `store`/`update`/`destroy` → **redirect** dengan flash message.
```php
Route::resource('lahan', LahanController::class);
```
```php
namespace App\Http\Controllers\Web\Produktivitas;
class LahanController extends Controller
{
public function index(Request $request)
{
$lahan = Lahan::query()
->with(['petani', 'desa'])
->when($request->search, fn ($q, $s) => $q->where('nama', 'like', "%{$s}%"))
->latest()
->paginate(15)
->withQueryString();
return view('produktivitas.lahan.index', compact('lahan'));
}
public function create()
{
return view('produktivitas.lahan.create', ['lahan' => new Lahan()]);
}
public function store(StoreLahanRequest $request)
{
$lahan = Lahan::create($request->validated());
return redirect()->route('lahan.show', $lahan)
->with('success', 'Lahan berhasil ditambahkan.');
}
public function show(Lahan $lahan)
{
$lahan->load(['petani', 'tanaman']);
return view('produktivitas.lahan.show', compact('lahan'));
}
public function edit(Lahan $lahan)
{
return view('produktivitas.lahan.edit', compact('lahan'));
}
public function update(UpdateLahanRequest $request, Lahan $lahan)
{
$lahan->update($request->validated());
return redirect()->route('lahan.show', $lahan)
->with('success', 'Lahan berhasil diperbarui.');
}
public function destroy(Lahan $lahan)
{
DB::transaction(fn () => $lahan->delete());
return redirect()->route('lahan.index')
->with('success', 'Lahan berhasil dihapus.');
}
}
```
---
#### Pola C — Detail multi-tab
- Controller induk (mis. `PetaniController`) memakai Pola B.
- Setiap tab punya **controller sendiri** (`PetaniLahanController`, `PraktikBudidayaController`, …) yang tetap memakai nama method resmi.
- Tab dirangkai sebagai **nested shallow resource** di bawah induk.
- View: `header.blade.php` berisi kartu profil + navigasi tab; setiap tab punya subfolder.
- Tab selain Profil **terkunci** sampai profil induk lengkap. Logika penguncian ditaruh di satu tempat (method di model induk, mis. `$petani->profilLengkap()`), bukan diulang di tiap view.
```
resources/views/produktivitas/petani/
├── index.blade.php
├── create.blade.php
├── edit.blade.php
├── show.blade.php ← tab Profil
├── header.blade.php ← kartu profil + navigasi tab
├── _form.blade.php
├── lahan-tanaman/
│ ├── index.blade.php
│ └── ...
├── praktik-budidaya/
└── ...
```
```php
Route::resource('petani', PetaniController::class);
Route::resource('petani.praktik-budidaya', PraktikBudidayaController::class)->shallow();
```
### 3.4 Batas resource
- Jika modul tidak butuh semua aksi, batasi dengan `->only([...])` / `->except([...])`. Jangan biarkan route yang tidak punya method terdaftar.
- Method di luar 7 aksi resmi hanya boleh untuk: dropdown/list (`list`, `by{Induk}`), aksi status yang jelas (`verify`, `approve`), dan export (`export`). Daftarkan sebelum `Route::resource`.
---
## 4. Validasi
- Setiap `store` dan `update` memakai Form Request: `Store{Model}Request`, `Update{Model}Request`.
- Pesan dan atribut dalam Bahasa Indonesia (`messages()` / `attributes()`, atau file `lang/id/validation.php`).
- Form Request yang sama boleh dipakai controller Web dan API.
- Untuk Pola A, Form Request otomatis mengembalikan JSON 422 karena request AJAX mengirim header `Accept: application/json`. **Jangan** menangkap error validasi secara manual.
- **Unique wajib mengabaikan data yang sudah di-soft delete** (lihat 5.3).
```php
public function rules(): array
{
return [
'kode' => [
'required', 'string', 'max:10',
Rule::unique('provinsi', 'kode')
->ignore($this->route('provinsi'))
->withoutTrashed(),
],
'nama' => ['required', 'string', 'max:100'],
];
}
```
---
## 5. Model, migration, dan soft delete
### 5.1 Model
```php
class Lahan extends Model
{
use SoftDeletes;
protected $table = 'lahan';
protected $fillable = ['petani_id', 'desa_id', 'nama', 'luas'];
protected function casts(): array
{
return [
'luas' => 'decimal:2',
'status_milik' => StatusKepemilikan::class, // Enum
];
}
}
```
- Pakai `$fillable`, bukan `$guarded = []`.
- Pilihan tetap (jawaban survei, status) disimpan sebagai **PHP Enum** di `app/Enums/` dan di-cast di model. Jangan menulis daftar pilihan langsung di Blade.
- **Jejak aktivitas:** setiap model memakai trait `App\Models\Concerns\CatatAktivitas` (spatie/laravel-activitylog). Tambah/ubah/hapus otomatis tercatat di `activity_log` dan tampil di menu Konfigurasi > Log Aktivitas. Kolom audit, `$hidden`, file/foto, dan polygon (`path`) tidak dicatat. Jika domain model baru belum ada, tambahkan labelnya di `LogAktivitasController::JENIS`. Aksi bisnis yang bukan sekadar simpan model (verifikasi, ganti status) dicatat manual dengan `activity('nama_log')->performedOn($model)->log('...')`. Perubahan lewat query massal (`->update()` pada query builder) **tidak** tercatat.
### 5.2 Migration
Setiap tabel baru **wajib** memiliki:
```php
$table->id();
// ... kolom
$table->foreignId('created_by')->nullable()->constrained('users'); // ikuti kolom audit yang sudah ada
$table->foreignId('updated_by')->nullable()->constrained('users');
$table->timestamps();
$table->softDeletes();
$table->foreignId('deleted_by')->nullable()->constrained('users');
```
- Jangan mengubah migration yang sudah dijalankan di production; buat migration baru.
- **Jangan** memakai unique index di database untuk kolom pada tabel ber-soft delete (data terhapus akan menghalangi input ulang). Keunikan dijaga di Form Request.
### 5.3 Soft delete (aturan utama)
1. **Semua penghapusan adalah soft delete.** `forceDelete()` dilarang di kode aplikasi.
2. **`deleted_by` wajib terisi** dengan user yang menghapus. Gunakan mekanisme yang sudah ada di project (trait/observer). Jika belum ada, gunakan trait berikut dan pasang di semua model:
```php
namespace App\Models\Concerns;
trait HasDeletedBy
{
protected static function bootHasDeletedBy(): void
{
static::deleting(function ($model) {
if (! $model->isForceDeleting()) {
$model->deleted_by = auth()->id();
$model->saveQuietly();
}
});
}
}
```
3. **Hapus berantai (cascade soft delete).** Jika induk dihapus, **semua data anaknya ikut di-soft delete**, termasuk cucu dan seterusnya. Tulis di model induk:
```php
protected static function booted(): void
{
static::deleting(function (Petani $petani) {
if ($petani->isForceDeleting()) {
return;
}
// ->each->delete() memicu event per anak, sehingga deleted_by
// terisi dan cascade berlanjut ke cucu
$petani->lahan()->each->delete();
$petani->praktikBudidaya()->each->delete();
// ... semua relasi hasMany/hasOne milik petani
});
}
```
- **Jangan** memakai `$petani->lahan()->delete()` (query massal), karena tidak memicu event, sehingga `deleted_by` kosong dan cascade terputus.
- Setiap kali menambah relasi anak baru, **tambahkan juga** ke blok `deleting` induknya.
- Pemanggilan `delete()` di controller selalu dibungkus `DB::transaction()`.
- Relasi `belongsTo` ke data master (Provinsi, Komoditas, dll.) **bukan** anak dan tidak ikut terhapus.
4. **Restore** belum disediakan di aplikasi; dilakukan langsung di database oleh admin. Jangan membuat halaman sampah/restore tanpa diminta.
### 5.4 Global scope
- `KomoditasProgramScope` otomatis membatasi data ke komoditas milik program aktif (`SystemProgram`). Jika data "tidak muncul", periksa scope ini dulu.
- Melewati scope hanya dengan `withoutGlobalScope(KomoditasProgramScope::class)` secara eksplisit, dengan komentar alasannya.
- Jangan menambah global scope baru tanpa izin.
---
## 6. Routing
### 6.1 Route CRUD wajib memakai `Route::resource`
Semua modul CRUD (Pola A, B, C) **wajib** didaftarkan dengan `Route::resource`. **Dilarang** menulis route CRUD satu per satu secara manual.
```php
// ❌ SALAH — route CRUD manual
Route::get('provinsi', [ProvinsiController::class, 'index'])->name('provinsi.index');
Route::post('provinsi/store', [ProvinsiController::class, 'store'])->name('provinsi.store');
Route::get('provinsi/view/{id}', [ProvinsiController::class, 'view'])->name('provinsi.view');
Route::post('provinsi/update/{id}', [ProvinsiController::class, 'update'])->name('provinsi.update');
Route::get('provinsi/delete/{id}', [ProvinsiController::class, 'destroy'])->name('provinsi.destroy');
// ✅ BENAR
Route::resource('provinsi', ProvinsiController::class)->except(['create', 'edit']);
```
Aturan turunannya:
| Kebutuhan | Cara |
|---|---|
| Tidak semua aksi dipakai | `->only([...])` atau `->except([...])` |
| Pola A (offcanvas) | `->except(['create', 'edit'])` |
| Pola B (resource halaman) | `Route::resource(...)` penuh |
| Pola C (multi-tab) | Induk `Route::resource`, tab `Route::resource('induk.tab', ...)->shallow()` |
| Beberapa modul sekaligus | `Route::resources([...])` boleh dipakai dalam satu grup domain |
| Nama parameter tidak sesuai model | `->parameters(['jenis-komoditas' => 'jenisKomoditas'])` |
| Method tambahan (`list`, `by{Induk}`, `verify`, `export`) | `Route::get/post/patch` biasa, **ditulis sebelum** `Route::resource` modul yang sama |
- Form hapus/ubah memakai method spoofing Blade (`@method('DELETE')`, `@method('PUT')`), dan AJAX mengirim method HTTP yang sesuai. Jangan memakai `GET` untuk menghapus.
- **Pengecualian:** Dashboard dan Laporan tidak memakai `Route::resource` (lihat Bagian 11). Halaman tunggal seperti Profil akun boleh memakai `Route::singleton('profil', ...)` atau route manual `edit`/`update`.
### 6.2 Aturan routing lainnya
- Semua route web di `routes/web.php`, API di `routes/api.php`.
- Kelompokkan per domain dengan `Route::middleware(...)->group()` dan komentar judul domain.
- Nested resource memakai `->shallow()`. Maksimal **dua tingkat** di URL (`/framework/{framework}/transformasi`). Hierarki lebih dalam (Framework → Transformasi → Aktivitas → Target) dipecah menjadi beberapa nested shallow resource berpasangan.
- **Satu route hanya didaftarkan satu kali.** Sebelum menambah route, cari dulu apakah sudah ada (`php artisan route:list --name=...`).
- Setelah login: `enumerator` → Dashboard Survei Petani; `fasilitator` → Profil akun (belum ada menu khusus); role lain → Dashboard Karakteristik Petani. Jangan mengubah logika ini tanpa izin.
---
## 7. Blade & Vuexy
### 7.1 Layout
- Semua halaman admin: `@extends('layout.main')` dan mengisi `@section('content')`.
- Halaman auth memakai `auth/layout.blade.php`.
- Jangan membuat layout baru; jangan menyalin `<head>`/sidebar ke halaman.
### 7.2 File view per pola
| File | Pola | Isi |
|---|---|---|
| `index.blade.php` | A, B, C | Tabel, pencarian, pagination (+ offcanvas form untuk Pola A) |
| `create.blade.php` | B, C | Form tambah, `@include('..._form')` |
| `edit.blade.php` | B, C | Form ubah, `@include('..._form')` |
| `show.blade.php` | B, C | Detail |
| `_form.blade.php` | A, B, C | Field form bersama untuk tambah dan ubah |
| `header.blade.php` | C | Kartu profil + navigasi tab |
- File `add.blade.php` dan `view.blade.php` **tidak boleh** dibuat lagi (ganti dengan `create` dan `show`).
- `_form.blade.php` menerima model (kosong saat tambah) dan memakai `old('field', $model->field)`.
### 7.3 Tampilan error validasi
```blade
<input type="text" name="nama"
class="form-control @error('nama') is-invalid @enderror"
value="{{ old('nama', $lahan->nama) }}">
@error('nama')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
```
Untuk Pola A, JS menampilkan error dari respons 422 dengan class yang sama (`is-invalid` + `invalid-feedback`).
### 7.4 Komponen
- Elemen yang muncul di lebih dari dua halaman dijadikan Blade component di `resources/views/components/` (contoh yang ada: `summary-card`, `wilayah-card`, `wilayah-dashboard`).
- Utamakan komponen yang sudah ada sebelum membuat yang baru.
### 7.5 JavaScript & plugin
- JS halaman ditulis di **file terpisah per modul** (ikuti lokasi JS yang sudah dipakai project), dimuat lewat section/stack script di layout. Hindari blok `<script>` panjang di Blade.
- Semua request AJAX mengirim header `X-CSRF-TOKEN` dan `Accept: application/json`.
- URL di JS diambil dari `route()` yang dicetak Blade (mis. atribut `data-url`), **bukan** di-hardcode.
- Pakai plugin yang sudah tersedia di template Vuexy. Jangan menambah library baru tanpa izin. Pembagian peran:
| Kebutuhan | Plugin |
|---|---|
| Konfirmasi hapus | SweetAlert2 (jika terpasang) |
| Notifikasi sukses/gagal | Sesuai yang dipakai modul lain |
| Select dengan pencarian / dropdown berantai | Select2 (jika terpasang) |
| Input tanggal | Flatpickr (jika terpasang) |
| Grafik | ApexCharts |
| Peta | Leaflet |
| Ikon | Tabler Icons (`ti ti-*`) |
---
## 8. Respons & pesan
### 8.1 Web (Pola B/C)
```php
return redirect()->route('lahan.index')->with('success', 'Lahan berhasil dihapus.');
return back()->withInput()->with('error', 'Data gagal disimpan.');
```
Kunci flash: `success`, `error`, `warning`, `info`.
### 8.2 JSON (Pola A dan AJAX web)
```json
{ "success": true, "message": "Provinsi berhasil ditambahkan.", "data": { } }
```
- Error validasi: format 422 bawaan Laravel (`message` + `errors`).
- Error lain: `{ "success": false, "message": "..." }` dengan kode HTTP yang sesuai.
### 8.3 Pola kalimat pesan
`{Nama data} berhasil ditambahkan.` / `diperbarui.` / `dihapus.`
---
## 9. Otorisasi
- Hak akses berdasarkan role pada `Role` yang sudah ada. Ikuti mekanisme pembatasan role yang sudah dipakai (middleware/policy/gate yang ada); jangan membuat sistem permission baru.
- Penginput data petani adalah role `enumerator` (bukan `fasilitator`). `fasilitator` khusus pemateri workshop.
- Semua route `petani/...` dibungkus middleware `akses.petani` (`BatasiAksesPetani`): hanya `super_admin`, `admin`, `koordinator`, `enumerator`; koordinator hanya boleh mengakses petani dengan komoditas utama yang ditugaskan (`koordinator_komoditas`, cek lewat `User::bolehAksesPetani()`). Route tab petani baru wajib diletakkan di dalam grup ini.
- Menu sidebar hanya menampilkan item yang boleh diakses role pengguna, dan route-nya juga dilindungi di sisi server. Menyembunyikan menu saja tidak cukup.
---
## 10. API (`app/Http/Controllers/Api/`)
- API dipakai aplikasi mobile/lapangan. **Kontrak API (URL, nama field, format respons) tidak boleh diubah** tanpa izin eksplisit, termasuk saat refaktor.
- Endpoint baru mengikuti pola dan format respons API yang sudah ada di folder `Api/`.
- Auth memakai Sanctum; login dibatasi rate limit (5/menit). Jangan longgarkan.
- Setiap endpoint baru harus terbaca rapi di dokumentasi Scramble (type-hint Form Request dan tipe return yang jelas).
---
## 11. Pengecualian
### 11.0 Prinsip umum Dashboard & Laporan
Dashboard dan laporan **bersifat baca (read-only)** dan bentuknya beragam, sehingga controller-nya **fleksibel**:
- **Nama method bebas**, asalkan deskriptif dan camelCase (`index`, `chartProduktivitas`, `petaSebaran`, `rekapPerDesa`, `exportExcel`).
- Boleh satu controller dengan banyak method, atau controller satu aksi (`__invoke`) jika halamannya sederhana.
- Route ditulis manual (`Route::get(...)`), **tidak** memakai `Route::resource`.
- Tidak ada `create/store/edit/update/destroy`. Jika sebuah dashboard butuh input data, input itu dibuat sebagai modul CRUD terpisah.
Yang **tetap berlaku** walau fleksibel:
- Lokasi folder per domain (Bagian 2), penamaan route kebab-case dengan prefix (`dashboard.*`, `laporan.*`).
- Validasi filter memakai Form Request jika filternya lebih dari 2–3 parameter.
- Query sederhana boleh di controller. Query agregat yang panjang, berat, atau dipakai di lebih dari satu tempat dipindah ke `app/Services/{Dashboard|Laporan}/`.
- Data yang ditampilkan tetap menghormati soft delete (data terhapus tidak ikut dihitung) dan global scope program.
- Pembatasan akses per role (Bagian 9).
### 11.1 Dashboard
- Controller: `app/Http/Controllers/Web/Dashboard/{Nama}Controller.php`.
- Pola yang disarankan: `index` mengembalikan halaman; data grafik/peta yang dimuat via AJAX memakai method bernama jelas yang mengembalikan JSON.
- Filter umum diterima lewat query string: program, wilayah (provinsi → desa), periode.
- Query berat di-cache (`Cache::remember`) dengan kunci yang memuat nilai filter.
- View: satu file per dashboard di `resources/views/dashboard/`. Grafik ApexCharts, peta Leaflet.
- Data eksternal (AlphaVantage di `InternationalMarketController`) wajib di-cache dan punya penanganan gagal (tampilkan pesan, jangan error 500).
```php
// routes/web.php
Route::prefix('dashboard')->name('dashboard.')->group(function () {
Route::get('produktivitas', [ProduktivitasController::class, 'index'])->name('produktivitas');
Route::get('produktivitas/chart-panen', [ProduktivitasController::class, 'chartPanen'])
->name('produktivitas.chart-panen');
});
```
### 11.2 Laporan / reporting
- Controller: `app/Http/Controllers/Web/Laporan/{Nama}Controller.php`; view di `resources/views/laporan/{nama}/`.
- Pola yang disarankan per laporan: halaman filter + pratinjau (`index`), lalu method export per format (`exportExcel`, `exportPdf`). Semua menerima **filter yang sama** dengan pratinjau.
- Export kecil yang menempel pada satu modul CRUD atau dashboard boleh berupa method `export` di controller modul tersebut.
- Laporan yang lambat (data besar) boleh diproses di queue, lalu file diunduh setelah siap.
- Gunakan package export yang sudah terpasang di project. Jika belum ada, tanyakan dulu.
```php
Route::prefix('laporan')->name('laporan.')->group(function () {
Route::get('rekap-panen', [RekapPanenController::class, 'index'])->name('rekap-panen');
Route::get('rekap-panen/excel', [RekapPanenController::class, 'exportExcel'])->name('rekap-panen.excel');
Route::get('rekap-panen/pdf', [RekapPanenController::class, 'exportPdf'])->name('rekap-panen.pdf');
});
```
### 11.3 Ekosistem (form builder dinamis)
- Modul `Ekosistem/` (Group, Tabel, Kolom, Formulir, Ringkasan, Value) memiliki struktur dinamis dan **dikecualikan** dari pola CRUD standar.
- Jangan direfaktor ke pola standar kecuali diminta secara eksplisit. Perubahan kecil tetap mengikuti aturan validasi, soft delete, dan kebersihan.
---
## 12. Kebersihan repo
- **Dilarang** menyimpan file salinan/cadangan: `* copy.php`, `*Backup*`, `*01.php`, `*_old*`, dll. Riwayat disimpan di Git.
- Tidak ada kode yang dikomentari dalam jumlah besar ("kode mati"); hapus saja.
- Tidak ada route ganda (lihat Bagian 6).
- Satu commit = satu perubahan logis (satu modul/fitur). Pesan commit Bahasa Indonesia, singkat, diawali jenis: `feat:`, `fix:`, `refactor:`, `chore:`.
Masalah kebersihan yang **sudah diketahui** (selesaikan saat menyentuh area terkait):
- File duplikat/backup: `* copy.php`, `IndikatorPertanianBackupController`, `PanenController01`, `SummaryDashboardController copy.php`, file `composerlock` yang tidak semestinya.
- Route ganda: `users` (resource + manual), `users.verify` (dua kali), `jenis-komoditas.by-komoditas`, `varietas.by-jenis-komoditas`.
---
## 13. Prosedur refaktor modul lama
Modul lama **wajib** disesuaikan dengan standar ini secara bertahap.
### 13.1 Aturan
1. **Satu modul per sesi/commit.** Jangan merefaktor beberapa modul sekaligus.
2. Jangan merefaktor modul yang sedang dikerjakan (ada perubahan belum di-commit) tanpa konfirmasi.
3. API **tidak** ikut diubah (Bagian 10).
4. Perilaku untuk pengguna harus tetap sama; refaktor bukan tempat menambah fitur.
### 13.2 Langkah
1. Simpan daftar route modul: `php artisan route:list --name={modul} > /tmp/before.txt`.
2. Tentukan pola target (A/B/C) sesuai 3.3.
3. Cari **semua** pemakaian nama route, URL, dan view lama di seluruh repo (Blade, JS, controller lain, sidebar), mis. `grep -rn "provinsi.view\|provinsi/add\|master.provinsi.add" app resources routes`.
4. Ubah:
- method `add` → `create`, `view` → `show`;
- file `add.blade.php` → `create.blade.php`, `view.blade.php` → `show.blade.php`;
- route manual → `Route::resource` (+ `only/except`, route tambahan di atasnya);
- validasi inline → Form Request (dengan `withoutTrashed()` pada unique);
- pastikan model memakai `SoftDeletes`, `deleted_by` terisi, dan cascade ke anak sudah ditulis;
- semua referensi yang ditemukan di langkah 3.
5. Bandingkan `route:list` sesudah dengan `/tmp/before.txt`; pastikan tidak ada route yang hilang tanpa sengaja.
6. Uji manual alur lengkap: index → tambah → detail → ubah → hapus (cek `deleted_at`, `deleted_by`, dan data anak).
7. Perbarui tabel status di 13.3.
### 13.3 Status migrasi modul
Status: `Belum` / `Proses` / `Selesai` / `Dikecualikan`
| Domain | Modul | Pola target | Status | Catatan |
|---|---|---|---|---|
| Master | Provinsi | A | Belum | Ada `list` + dropdown berantai |
| Master | Kabupaten/Kota | A | Belum | `by-provinsi` |
| Master | Kecamatan | A | Belum | `by-kabupaten` |
| Master | Desa/Kelurahan | A | Belum | `by-kecamatan` |
| Master | Komoditas | A | Belum | |
| Master | Jenis Komoditas | A | Belum | Route `by-komoditas` dobel |
| Master | Varietas | A | Belum | Route `by-jenis-komoditas` dobel |
| Master | Adat | A | Belum | |
| Master | Keluarga | ? | Belum | Tentukan pola saat refaktor |
| Produktivitas | Petani (+ semua tab) | C | Belum | |
| Produktivitas | Lahan | B | Belum | |
| Produktivitas | Tanaman | B | Belum | |
| Produktivitas | MapTanaman | ? | Belum | |
| Produktivitas | Produksi | B | Belum | |
| Produktivitas | Survey Kelompok Tani (+ tab) | C | Proses | Daftar: Form Request filter, service query, dan JS terpisah; ringkasan profil disiapkan service; form/tab lama belum direfaktor |
| Produktivitas | Sebaran Petani | ? | Belum | Sedang dikerjakan, konfirmasi dulu |
| Program | Program, Program Komoditas, Program Lokasi | B | Belum | Pindah dari root ke `Program/` |
| Program | Framework → Transformasi → Aktivitas → Target | B | Belum | Nested shallow |
| Program | Realisasi | B | Belum | |
| Program | Verifikasi | ? | Belum | Sedang dikerjakan, konfirmasi dulu |
| Program | Workshop (+ Sesi, Peserta) | B | Belum | Sesi/Peserta sedang dikerjakan |
| Program | Kelompok Belajar Tani | B | Belum | |
| Bumdes | Profil, Kelembagaan, Survei | B | Belum | |
| Koperasi | Profil, Operasional, Rantai Nilai, Sosial Ekonomi | C | Proses | Daftar Data Koperasi berfokus pada identitas koperasi, jenis, layanan, dokumen kelembagaan, responden dan enumerator (admin/super admin), dengan ringkasan total/jenis koperasi dan dokumen lengkap, card filter wilayah bertingkat berbasis relasi desa serta jenis/layanan/dokumen/urutan seperti profil lain, Form Request pencarian/pagination dan validasi hierarki wilayah, service query, serta JS terpisah; migration desa_kelurahan_id/created_by diterapkan 6 November 2026 (batch 16); penginput lama dipulihkan hanya dari log created, profil tanpa desa tetap tampil pada daftar kabupaten agar wilayah lama dapat dilengkapi di Profil; Card ringkasan pada seluruh tab memakai komponen Blade dan service, mengikuti tampilan BUMDes/Kelompok Tani, menampilkan identitas, jenis koperasi dan layanan utama, anggota dan pengurus di bawahnya, serta kontak; Profil dan tiap tab memakai Form Request, controller resource, model binding, dan JS terpisah; tab survei memakai enum/casts dan percabangan bersama di tampilan/server, rincian wajib bersyarat, dan pembersihan jawaban tidak aktif; Operasional memiliki box pengelolaan dan box Rantai Nilai dan Pascapanen (termasuk K3), masing-masing menyimpan data sendiri, simpan pengelolaan menuju box berikutnya; D6 dapat diisi semua koperasi setelah profil tersimpan, dengan penyimpanan terpisah per box, simpan saluran menuju box harga, dan tabel harga lengkap empat bentuk produk × tiga musim panen; Sosial Ekonomi membatasi keperluan pinjaman serta ikatan keuangan berdasarkan jenis simpan pinjam pada profil, bentuk pembayaran mengikuti ketersediaan mekanisme, harga pasar mengikuti pembayaran hasil bumi, dan alasan wajib untuk harga di luar pasar; simpan tetap di tab aktif, rupiah memakai pemisah ribuan; URL survei lama tetap didukung; soft delete belum direfaktor |
| Konfigurasi | User | B | Belum | Route `users` & `users.verify` dobel |
| Konfigurasi | Profil akun | — | Belum | Hanya `edit`/`update` |
| Ekosistem | Semua | — | Dikecualikan | Lihat 11.3 |
| Dashboard | Semua | — | Dikecualikan | Ikuti 11.1 |
---
## 14. Checklist modul baru
- [ ] Pola ditentukan (A/B/C) sesuai 3.3
- [ ] Migration: `id`, kolom audit, `timestamps`, `softDeletes`, `deleted_by`; tanpa unique index
- [ ] Model: `$table` eksplisit, `$fillable`, `SoftDeletes`, `deleted_by` terisi, casts/Enum, trait `CatatAktivitas`
- [ ] Relasi anak ditambahkan ke cascade `deleting` di model induk
- [ ] Form Request `Store`/`Update` dengan pesan Bahasa Indonesia dan unique `withoutTrashed()`
- [ ] Controller di `Web/{Domain}/` dengan nama method resmi saja
- [ ] Route: `Route::resource` (+ `only/except`, `shallow`), tidak dobel, route tambahan di atas resource
- [ ] View di `{domain}/{modul}/`: `index`, `create`, `edit`, `show`, `_form` sesuai pola
- [ ] JS di file terpisah, URL dari `route()`, CSRF terpasang
- [ ] Menu sidebar ditambahkan dan dibatasi per role; route dilindungi di server
- [ ] Respons/flash mengikuti Bagian 8
- [ ] Diuji manual: tambah, ubah, detail, hapus (cek `deleted_at`, `deleted_by`, data anak)
- [ ] Tidak ada file salinan/backup tertinggal
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\AksesPasar;
enum TingkatKepercayaanPembeli: int
{
case SANGAT_PERCAYA = 1;
case CUKUP_PERCAYA = 2;
case RAGU_RAGU = 3;
case TIDAK_PERCAYA = 4;
public static function options(): array
{
return [
['value' => self::SANGAT_PERCAYA->value, 'label' => 'Sangat percaya, berani langsung coba'],
['value' => self::CUKUP_PERCAYA->value, 'label' => 'Cukup percaya, tapi hati hati'],
['value' => self::RAGU_RAGU->value, 'label' => 'Ragu ragu'],
['value' => self::TIDAK_PERCAYA->value, 'label' => 'Tidak percaya, enggan mencoba'],
];
}
public static function values(): array
{
return array_column(self::cases(), 'value');
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum AsetProduktifBumdes: string
{
case BANGUNAN_KANTOR = 'bangunan_kantor';
case GUDANG_PENYIMPANAN = 'gudang_penyimpanan';
case KENDARAAN_OPERASIONAL_ANGKUT = 'kendaraan_operasional_angkut';
case LAHAN_USAHA = 'lahan_usaha';
case ALAT_PENGOLAHAN_KOMODITAS = 'alat_pengolahan_komoditas';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::BANGUNAN_KANTOR => 'Bangunan / kantor',
self::GUDANG_PENYIMPANAN => 'Gudang penyimpanan',
self::KENDARAAN_OPERASIONAL_ANGKUT => 'Kendaraan operasional/angkut',
self::LAHAN_USAHA => 'Lahan usaha',
self::ALAT_PENGOLAHAN_KOMODITAS => 'Alat pengolahan komoditas',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum BentukProdukBumdes: string
{
case BUAH_SEGAR = 'buah_segar';
case BIJI_BASAH = 'biji_basah';
case BIJI_KERING = 'biji_kering';
case TERFERMENTASI = 'terfermentasi';
public function label(): string
{
return match ($this) {
self::BUAH_SEGAR => 'Buah segar hasil petik',
self::BIJI_BASAH => 'Biji basah',
self::BIJI_KERING => 'Biji kering/biji kupas',
self::TERFERMENTASI => 'Terfermentasi',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum CakupanLayananBumdes: string
{
case DESA_SENDIRI = 'desa_sendiri';
case DESA_LAIN = 'desa_sendiri_dan_lain';
public function label(): string
{
return match ($this) {
self::DESA_SENDIRI => 'Hanya melayani desa sendiri',
self::DESA_LAIN => 'Melayani desa sendiri dan desa lain',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum DukunganDesaBumdes: string
{
case PENDAMPINGAN_TEKNIS = 'pendampingan_teknis';
case REGULASI_PERDES = 'regulasi_perdes';
case FASILITASI_JEJARING = 'fasilitasi_jejaring';
case TIDAK_ADA = 'tidak_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PENDAMPINGAN_TEKNIS => 'Pendampingan teknis',
self::REGULASI_PERDES => 'Regulasi/Perdes pendukung',
self::FASILITASI_JEJARING => 'Fasilitasi jejaring/kemitraan',
self::TIDAK_ADA => 'Tidak ada dukungan khusus',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum FormatPembukuanBumdes: string
{
case MANUAL = 'manual';
case DIGITAL_EXCEL = 'digital_excel';
case APLIKASI = 'aplikasi';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::MANUAL => 'Manual/buku kas',
self::DIGITAL_EXCEL => 'Digital/file Excel',
self::APLIKASI => 'Aplikasi keuangan khusus',
self::TIDAK_ADA => 'Tidak ada',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum HambatanUsahaBumdes: string
{
case MODAL = 'modal';
case SDM = 'sdm';
case INFRASTRUKTUR = 'infrastruktur';
case PASOKAN = 'pasokan';
case PERSAINGAN = 'persaingan';
case AKSES_PASAR = 'akses_pasar';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::MODAL => 'Keterbatasan modal',
self::SDM => 'Keterbatasan SDM/kapasitas pengurus',
self::INFRASTRUKTUR => 'Keterbatasan infrastruktur/alat',
self::PASOKAN => 'Kesulitan mendapat pasokan konsisten dari produsen',
self::PERSAINGAN => 'Persaingan dengan tengkulak/pedagang',
self::AKSES_PASAR => 'Belum ada akses ke offtaker/pasar premium',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum HubunganPemasokBumdes: string
{
case BEBAS = 'bebas';
case LANGGANAN = 'langganan';
case PINJAMAN = 'pinjaman';
case KONSINYASI = 'konsinyasi';
case KOMITMEN_VOLUME = 'komitmen_volume';
case SEMI_KONTRAK = 'semi_kontrak';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::BEBAS => 'Bebas/tidak terikat: petani bebas menjual ke BUMDes atau pihak lain kapan saja, tanpa ikatan apa pun',
self::LANGGANAN => 'Langganan tetap: petani rutin menjual ke BUMDes tanpa perjanjian formal',
self::PINJAMAN => 'Berbasis hutang/pinjaman: petani menjual ke BUMDes karena memiliki pinjaman kepada BUMDes',
self::KONSINYASI => 'Titip jual (konsinyasi): petani dibayar setelah hasil panen terjual',
self::KOMITMEN_VOLUME => 'Ada komitmen volume: kesepakatan volume tertentu yang dipenuhi secara berkala',
self::SEMI_KONTRAK => 'Semi-kontrak: kesepakatan tertulis/lisan mengenai harga, volume, dan waktu penyerahan',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum InfrastrukturPascapanenBumdes: string
{
case GUDANG_PENYIMPANAN_HASIL_PANEN = 'gudang_penyimpanan_hasil_panen';
case ALAT_MESIN_PENGERING = 'alat_mesin_pengering';
case MESIN_PULPER_HULLER = 'mesin_pulper_huller';
case TIMBANGAN = 'timbangan';
case ALAT_SORTASI = 'alat_sortasi';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::GUDANG_PENYIMPANAN_HASIL_PANEN => 'Gudang penyimpanan hasil panen',
self::ALAT_MESIN_PENGERING => 'Alat/mesin pengering',
self::MESIN_PULPER_HULLER => 'Mesin pulper/huller',
self::TIMBANGAN => 'Timbangan',
self::ALAT_SORTASI => 'Alat sortasi',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace App\Enums\Bumdes;
enum JabatanBumdes: string
{
case DIREKTUR = 'direktur';
case DIREKTUR_KETUA = 'direktur_ketua';
case SEKRETARIS = 'sekretaris';
case BENDAHARA = 'bendahara';
case KEPALA_UNIT_USAHA = 'kepala_unit_usaha';
case PENGAWAS = 'pengawas';
case PENASIHAT = 'penasihat';
case ANGGOTA = 'anggota';
case STAF_OPERASIONAL = 'staf_operasional';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::DIREKTUR => 'Direktur/Ketua',
self::DIREKTUR_KETUA => 'Direktur/Ketua',
self::SEKRETARIS => 'Sekretaris',
self::BENDAHARA => 'Bendahara',
self::KEPALA_UNIT_USAHA => 'Kepala Unit Usaha',
self::PENGAWAS => 'Pengawas',
self::PENASIHAT => 'Penasihat',
self::ANGGOTA => 'Anggota',
self::STAF_OPERASIONAL => 'Staf Operasional',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect([
self::DIREKTUR_KETUA,
self::SEKRETARIS,
self::BENDAHARA,
self::LAINNYA,
])->map(fn ($case) => [
'value' => $case->value,
'label' => $case->label(),
])->toArray();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum JabatanPengurusIntiBumdes: string
{
case PENASIHAT_KEPALA_DESA = 'penasihat_kepala_desa';
case KETUA_PENGAWAS = 'ketua_pengawas';
case DIREKTUR_KETUA_BUMDES = 'direktur_ketua_bumdes';
case SEKRETARIS = 'sekretaris';
case BENDAHARA = 'bendahara';
case KEPALA_UNIT_USAHA_KOMODITAS = 'kepala_unit_usaha_komoditas';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PENASIHAT_KEPALA_DESA => 'Penasihat (Kepala Desa)',
self::KETUA_PENGAWAS => 'Ketua Pengawas',
self::DIREKTUR_KETUA_BUMDES => 'Direktur/Ketua BUMDes',
self::SEKRETARIS => 'Sekretaris',
self::BENDAHARA => 'Bendahara',
self::KEPALA_UNIT_USAHA_KOMODITAS => 'Kepala Unit Usaha Komoditas',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum KemitraanEksternalBumdes: string
{
case NGO = 'ngo';
case PEMERINTAH_KABUPATEN = 'pemerintah_kabupaten';
case SWASTA_OFFTAKER = 'swasta_offtaker';
case PROGRAM_PEMERINTAH_LAIN = 'program_pemerintah_lain';
case BELUM_ADA = 'belum_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::NGO => 'NGO/lembaga pemberdayaan',
self::PEMERINTAH_KABUPATEN => 'Dinas/pemerintah kabupaten',
self::SWASTA_OFFTAKER => 'Perusahaan swasta/offtaker',
self::PROGRAM_PEMERINTAH_LAIN => 'Program pemerintah lain',
self::BELUM_ADA => 'Belum ada kemitraan eksternal',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum KeterlibatanKoordinasiBumdes: string
{
case SELALU = 'selalu';
case KADANG = 'kadang';
case TIDAK_PERNAH = 'tidak_pernah';
public function label(): string
{
return match ($this) {
self::SELALU => 'Selalu dilibatkan',
self::KADANG => 'Kadang dilibatkan',
self::TIDAK_PERNAH => 'Tidak pernah dilibatkan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiAsetProduktifBumdes: string
{
case BERFUNGSI = 'berfungsi';
case PERLU_PERBAIKAN = 'perlu_perbaikan_evaluasi';
case RUSAK = 'rusak_tidak_bisa_dipakai';
case MANGKRAK = 'mangkrak';
public function label(): string
{
return match ($this) {
self::BERFUNGSI => 'Berfungsi',
self::PERLU_PERBAIKAN => 'Perlu perbaikan/evaluasi',
self::RUSAK => 'Rusak/tidak bisa dipakai',
self::MANGKRAK => 'Mangkrak',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
public static function normalizeLegacy(mixed $value): ?string
{
if (! is_scalar($value) || trim((string) $value) === '') {
return null;
}
$value = trim((string) $value);
return match (mb_strtolower($value)) {
'baik', 'berfungsi', 'baik dan berfungsi', 'baik_berfungsi' => self::BERFUNGSI->value,
'rusak ringan', 'perlu perbaikan', 'perlu perbaikan/evaluasi' => self::PERLU_PERBAIKAN->value,
'rusak', 'rusak/tidak terpakai', 'rusak_tidak_terpakai', 'rusak/tidak bisa dipakai' => self::RUSAK->value,
'mangkrak' => self::MANGKRAK->value,
default => $value,
};
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiInfrastrukturBumdes: string
{
case BAIK_BERFUNGSI = 'baik_berfungsi';
case RUSAK_TIDAK_TERPAKAI = 'rusak_tidak_terpakai';
public function label(): string
{
return match ($this) {
self::BAIK_BERFUNGSI => 'Baik dan berfungsi',
self::RUSAK_TIDAK_TERPAKAI => 'Rusak/tidak terpakai',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum KondisiKeuanganBumdes: string
{
case UNTUNG_SURPLUS = 'untung_surplus';
case IMPAS = 'impas';
case RUGI_DEFISIT = 'rugi_defisit';
case TIDAK_MENJAWAB = 'tidak_menjawab';
public function label(): string
{
return match ($this) {
self::UNTUNG_SURPLUS => 'Untung/surplus',
self::IMPAS => 'Impas',
self::RUGI_DEFISIT => 'Rugi/defisit',
self::TIDAK_MENJAWAB => 'Tidak tahu/tidak mau menjawab',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum KontribusiPadesBumdes: string
{
case RUTIN = 'rutin';
case TIDAK_RUTIN = 'tidak_rutin';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::TIDAK_RUTIN => 'Ya, tapi tidak rutin',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace App\Enums\Bumdes;
enum LayananPetaniBumdes: string
{
case SIMPAN_PINJAM = 'simpan_pinjam';
case PENGADAAN_INPUT = 'pengadaan_input';
case PEMASARAN_PANEN = 'pemasaran_panen';
case PENYEWAAN_ALAT = 'penyewaan_alat';
case JASA_PENGOLAHAN = 'jasa_pengolahan';
case PELATIHAN = 'pelatihan';
case BELUM_ADA = 'belum_ada';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::SIMPAN_PINJAM => 'Simpan pinjam',
self::PENGADAAN_INPUT => 'Pengadaan input (pupuk, bibit, dll)',
self::PEMASARAN_PANEN => 'Pembelian/pemasaran hasil panen',
self::PENYEWAAN_ALAT => 'Penyewaan alat pengolahan',
self::JASA_PENGOLAHAN => 'Jasa pengolahan/fermentasi',
self::PELATIHAN => 'Pelatihan/pendampingan',
self::BELUM_ADA => 'Belum ada layanan terkait komoditas ini',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum MekanismePembayaranBumdes: string
{
case TUNAI = 'tunai';
case TEMPO = 'tempo';
case CAMPURAN = 'campuran';
case IJON = 'ijon';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::TUNAI => 'Tunai langsung',
self::TEMPO => 'Sistem tempo/dibayar kemudian',
self::CAMPURAN => 'Campuran, tergantung situasi',
self::IJON => 'BUMDes membayar di muka sebelum panen, sebagai bagian dari ikatan pinjaman kepada petani (ijon)',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum ModelFermentasiBumdes: string
{
case INDIVIDUAL = 'individual';
case KOLEKTIF_KELOMPOK = 'kolektif_kelompok';
case UNIT_BUMDES = 'unit_bumdes';
case CAMPURAN = 'campuran';
public function label(): string
{
return match ($this) {
self::INDIVIDUAL => 'Individual (masing-masing petani)',
self::KOLEKTIF_KELOMPOK => 'Kolektif kelompok tani',
self::UNIT_BUMDES => 'Unit pengolah BUMDes/desa',
self::CAMPURAN => 'Campuran',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PencatatanPetaniBumdes: string
{
case RAPI = 'rapi';
case TIDAK_RAPI = 'tidak_rapi';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::RAPI => 'Ada, tercatat rapi',
self::TIDAK_RAPI => 'Ada tapi tidak rapi',
self::TIDAK_ADA => 'Tidak ada pencatatan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum PenetapanHargaBeliBumdes: string
{
case PASAR_SETEMPAT = 'pasar_setempat';
case KALKULASI_BIAYA = 'kalkulasi_biaya';
case HARGA_MITRA = 'harga_mitra';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::PASAR_SETEMPAT => 'Mengikuti harga pasar/tengkulak setempat',
self::KALKULASI_BIAYA => 'Ditetapkan sendiri berdasarkan kalkulasi biaya',
self::HARGA_MITRA => 'Mengikuti harga dari offtaker/mitra',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PengalamanOfftakerBumdes: string
{
case BERJALAN = 'berjalan';
case BERHENTI = 'berhenti';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::BERJALAN => 'Sedang berjalan',
self::BERHENTI => 'Pernah, tapi sudah berhenti',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum PeranRantaiNilaiBumdes: string
{
case MEMBELI_LANGSUNG = 'membeli_langsung';
case PERANTARA = 'perantara';
case MENGOLAH_SENDIRI = 'mengolah_sendiri';
case BELUM_BERPERAN = 'belum_berperan';
public function label(): string
{
return match ($this) {
self::MEMBELI_LANGSUNG => 'Membeli langsung dari petani',
self::PERANTARA => 'Menjadi perantara/mengumpulkan untuk dijual ke pihak lain',
self::MENGOLAH_SENDIRI => 'Mengolah sendiri (sortasi/fermentasi/dll) sebelum dijual',
self::BELUM_BERPERAN => 'Belum berperan dalam rantai nilai komoditas ini',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PeriodePanenBumdes: string
{
case TERAKHIR = 'panen_terakhir';
case TAHUN_LALU = 'tahun_lalu';
case DUA_TAHUN_LALU = 'dua_tahun_lalu';
public function label(): string
{
return match ($this) {
self::TERAKHIR => 'Panen Terakhir',
self::TAHUN_LALU => 'Tahun Lalu',
self::DUA_TAHUN_LALU => 'Dua Tahun Lalu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PerjanjianPetaniBumdes: string
{
case TERTULIS = 'tertulis';
case LISAN = 'lisan';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::TERTULIS => 'Ada, tertulis',
self::LISAN => 'Ada, kesepakatan lisan saja',
self::TIDAK_ADA => 'Tidak ada perjanjian',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum PertanggungjawabanMusdesBumdes: string
{
case TAHUNAN = 'tahunan';
case TIDAK_RUTIN = 'tidak_rutin';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::TAHUNAN => 'Ya, setiap tahun',
self::TIDAK_RUTIN => 'Tidak rutin',
self::BELUM_PERNAH => 'Belum pernah',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Enums\Bumdes;
enum SaluranPenjualanBumdes: string
{
case OFFTAKER_EKSPORTIR = 'offtaker_eksportir';
case PEDAGANG_KABUPATEN = 'pedagang_kabupaten';
case KOPERASI_BUMDES = 'koperasi_bumdes';
case PASAR_LOKAL = 'pasar_lokal';
case BELUM_MENJUAL = 'belum_menjual';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::OFFTAKER_EKSPORTIR => 'Offtaker/eksportir langsung',
self::PEDAGANG_KABUPATEN => 'Pedagang besar/pengepul kabupaten',
self::KOPERASI_BUMDES => 'Koperasi atau BUMDes lain',
self::PASAR_LOKAL => 'Dijual eceran/pasar lokal',
self::BELUM_MENJUAL => 'Belum pernah menjual (masih disimpan/diproses)',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Enums\Bumdes;
enum SifatAuditBumdes: string
{
case INTERNAL = 'internal';
case EKSTERNAL = 'eksternal';
public function label(): string
{
return match ($this) {
self::INTERNAL => 'Internal (pengurus/pengawas BUMDes sendiri)',
self::EKSTERNAL => 'Eksternal (Inspektorat, Dinas PMD, akuntan publik/auditor independen)',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusAdArtBumdes: string
{
case ADA_LENGKAP = 'ada_lengkap';
case ADA_TIDAK_LENGKAP = 'ada_tidak_lengkap';
case TIDAK_ADA = 'tidak_ada';
case TIDAK_TAHU = 'tidak_tahu';
public function label(): string
{
return match ($this) {
self::ADA_LENGKAP => 'Ada, lengkap',
self::ADA_TIDAK_LENGKAP => 'Ada tapi tidak lengkap',
self::TIDAK_ADA => 'Tidak ada',
self::TIDAK_TAHU => 'Tidak tahu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusBadanHukumBumdes: string
{
case SUDAH_BERBADAN_HUKUM = 'sudah_berbadan_hukum';
case PROSES_PENDAFTARAN = 'proses_pendaftaran';
case BELUM_BERBADAN_HUKUM = 'belum_berbadan_hukum';
case TIDAK_TAHU = 'tidak_tahu';
public function label(): string
{
return match ($this) {
self::SUDAH_BERBADAN_HUKUM => 'Sudah berbadan hukum (terdaftar Kemenkumham)',
self::PROSES_PENDAFTARAN => 'Proses pendaftaran',
self::BELUM_BERBADAN_HUKUM => 'Belum berbadan hukum',
self::TIDAK_TAHU => 'Tidak tahu',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusFermentasiBumdes: string
{
case RUTIN = 'rutin';
case PERNAH_MENCOBA = 'pernah_mencoba';
case DIRENCANAKAN = 'direncanakan';
case TIDAK_DIRENCANAKAN = 'tidak_direncanakan';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::PERNAH_MENCOBA => 'Pernah mencoba',
self::DIRENCANAKAN => 'Belum pernah, direncanakan',
self::TIDAK_DIRENCANAKAN => 'Belum pernah, tidak direncanakan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\Bumdes;
enum StatusKeaktifanBumdes: string
{
case AKTIF_PENUH = 'aktif_penuh';
case AKTIF_TERBATAS = 'aktif_terbatas';
case TIDAK_AKTIF_VAKUM = 'tidak_aktif_vakum';
case BERDIRI_BELUM_BEROPERASI = 'berdiri_belum_beroperasi';
public function label(): string
{
return match ($this) {
self::AKTIF_PENUH => 'Aktif beroperasi penuh',
self::AKTIF_TERBATAS => 'Aktif tapi terbatas (sebagian unit usaha berjalan)',
self::TIDAK_AKTIF_VAKUM => 'Tidak aktif/vakum',
self::BERDIRI_BELUM_BEROPERASI => 'Sudah berdiri tapi belum pernah beroperasi',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusKepemilikanAsetBumdes: string
{
case MILIK_BUMDES_SENDIRI = 'milik_bumdes_sendiri';
case MILIK_DESA_DIPINJAMKAN_DIKELOLA = 'milik_desa_dipinjamkan_dikelola';
case SEWA_PINJAM_PIHAK_LAIN = 'sewa_pinjam_pihak_lain';
public function label(): string
{
return match ($this) {
self::MILIK_BUMDES_SENDIRI => 'Milik BUMDes sendiri',
self::MILIK_DESA_DIPINJAMKAN_DIKELOLA => 'Milik desa (dipinjamkan/dikelola)',
self::SEWA_PINJAM_PIHAK_LAIN => 'Sewa/pinjam pihak lain',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusPembukuanBumdes: string
{
case RUTIN_TERTIB = 'rutin_tertib';
case TIDAK_RUTIN = 'tidak_rutin';
case TIDAK_ADA = 'tidak_ada';
public function label(): string
{
return match ($this) {
self::RUTIN_TERTIB => 'Ya, rutin dan tertib',
self::TIDAK_RUTIN => 'Ada tapi tidak rutin/tidak rapi',
self::TIDAK_ADA => 'Tidak ada pembukuan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusPengeringanBumdes: string
{
case RUTIN = 'rutin';
case KADANG = 'kadang';
case TIDAK_PERNAH = 'tidak_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::KADANG => 'Kadang-kadang',
self::TIDAK_PERNAH => 'Tidak pernah, produk dijual dalam kondisi diterima',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusSortasiBumdes: string
{
case RUTIN_STANDAR = 'rutin_standar';
case TIDAK_KONSISTEN = 'tidak_konsisten';
case BELUM_PERNAH = 'belum_pernah';
public function label(): string
{
return match ($this) {
self::RUTIN_STANDAR => 'Ya, rutin dengan standar tertentu',
self::TIDAK_KONSISTEN => 'Ya, tapi tidak konsisten',
self::BELUM_PERNAH => 'Belum pernah dilakukan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Enums\Bumdes;
enum StatusUnitKomoditasBumdes: string
{
case YA = 'ya';
case DITANGANI_PENGURUS_INTI = 'ditangani_pengurus_inti';
case DIRENCANAKAN = 'direncanakan';
public function label(): string
{
return match ($this) {
self::YA => 'Ya, ada unit khusus',
self::DITANGANI_PENGURUS_INTI => 'Tidak ada unit khusus, ditangani langsung pengurus inti',
self::DIRENCANAKAN => 'Belum ada, masih direncanakan',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace App\Enums\Bumdes;
enum SumberPasokanBumdes: string
{
case ANGGOTA_KELOMPOK = 'anggota_kelompok';
case PETANI_NON_ANGGOTA = 'petani_non_anggota';
case PENGUMPUL_DESA = 'pengumpul_desa';
case CAMPURAN = 'campuran';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::ANGGOTA_KELOMPOK => 'Anggota kelompok tani langsung',
self::PETANI_NON_ANGGOTA => 'Petani non-anggota',
self::PENGUMPUL_DESA => 'Pengumpul/sub-agen desa',
self::CAMPURAN => 'Campuran',
self::LAINNYA => 'Lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Enums\Bumdes;
enum UnitUsahaBumdes: string
{
case SIMPAN_PINJAM = 'simpan_pinjam';
case PERDAGANGAN_TOKO_DESA = 'perdagangan_toko_desa';
case PENGELOLAAN_AIR_BERSIH = 'pengelolaan_air_bersih';
case WISATA_DESA_AGROWISATA = 'wisata_desa_agrowisata';
case PENGELOLAAN_HASIL_PERTANIAN_KOMODITAS = 'pengelolaan_hasil_pertanian_komoditas';
case PENYEWAAN_ALAT_ASET = 'penyewaan_alat_aset';
case JASA_LAINNYA = 'jasa_lainnya';
public function label(): string
{
return match ($this) {
self::SIMPAN_PINJAM => 'Simpan pinjam',
self::PERDAGANGAN_TOKO_DESA => 'Perdagangan/toko desa',
self::PENGELOLAAN_AIR_BERSIH => 'Pengelolaan air bersih',
self::WISATA_DESA_AGROWISATA => 'Wisata desa/agrowisata',
self::PENGELOLAAN_HASIL_PERTANIAN_KOMODITAS => 'Pengelolaan hasil pertanian/komoditas',
self::PENYEWAAN_ALAT_ASET => 'Penyewaan alat/aset',
self::JASA_LAINNYA => 'Jasa lainnya',
};
}
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $value) => [$value->value => $value->label()])->all();
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace App\Enums;
enum JenisKelompokTani: string
{
case POKTAN = 'Kelompok Tani (Poktan)';
case KWT = 'Kelompok Wanita Tani (KWT)';
case GAPOKTAN = 'Gabungan Kelompok Tani (Gapoktan)';
case PEMUDA_TANI = 'Kelompok Pemuda Tani';
case ASOSIASI = 'Asosiasi Petani';
case LAINNYA = 'Lainnya';
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $jenis) => [$jenis->value => $jenis->value])->all();
}
}
+3 -3
View File
@@ -11,9 +11,9 @@ enum KeparahanSerangan: string
public function label(): string
{
return match($this) {
self::RINGAN => 'Ringan',
self::SEDANG => 'Sedang',
self::BERAT => 'Berat',
self::RINGAN => 'Ringan, hanya beberapa tanaman',
self::SEDANG => 'Sedang, sebagian tanaman terdampak',
self::BERAT => 'Parah, sebagian besar tanaman terdampak',
};
}
+4 -4
View File
@@ -13,10 +13,10 @@ enum KondisiTanaman: string
public function label(): string
{
return match($this) {
self::BAIK => 'Baik',
self::SEDANG => 'Sedang',
self::BURUK => 'Buruk',
self::MATI => 'Mati',
self::BAIK => 'Baik, tumbuh lebat, banyak buah',
self::SEDANG => 'Sedang, cukup tumbuh, ada masalah',
self::BURUK => 'Buruk, banyak tanaman tua dan lemah/tidak berbuah',
self::MATI => 'Mati, tanaman telah mati, tidak dapat tumbuh maupun berbuah',
};
}
@@ -0,0 +1,27 @@
<?php
namespace App\Enums\Koperasi;
enum AlasanPinjamanKoperasi: string
{
case PRODUKSI = 'Produksi';
case PENDIDIKAN = 'Pendidikan';
case KESEHATAN = 'Kesehatan';
case ACARA_KELUARGA = 'Acara keluarga';
case RENOVASI = 'Renovasi';
case SEKUNDER = 'Sekunder';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::PRODUKSI => 'Keperluan produksi',
self::PENDIDIKAN => 'Pendidikan',
self::KESEHATAN => 'Kesehatan',
self::ACARA_KELUARGA => 'Acara keluarga/adat/hari besar',
self::RENOVASI => 'Renovasi rumah',
self::SEKUNDER => 'Kebutuhan sekunder',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum BagianOperasionalKoperasi: string
{
case PENGELOLAAN = 'pengelolaan';
case RANTAI_NILAI = 'rantai-nilai';
public function fragment(): string
{
return 'section-operasional-'.$this->value;
}
public function afterSaveFragment(): string
{
return self::RANTAI_NILAI->fragment();
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum BagianRantaiNilaiKoperasi: string
{
case SALURAN = 'saluran';
case HARGA = 'harga';
public function fragment(): string
{
return 'section-rantai-'.$this->value;
}
public function afterSaveFragment(): string
{
return self::HARGA->fragment();
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum BentukPembayaranKoperasi: string
{
case HASIL_BUMI = 'Hasil bumi';
case GANTI_JASA = 'Ganti jasa';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::HASIL_BUMI => 'Hasil bumi (hasil panen)',
self::GANTI_JASA => 'Ganti jasa/tenaga harian',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Enums\Koperasi;
enum BentukProdukKoperasi: string
{
case SEGAR = 'Buah segar hasil petik';
case BASAH = 'Biji basah';
case KERING = 'Biji kering/kupas';
case FERMENTASI = 'Produk terfermentasi';
public function label(): string
{
return match ($this) {
self::SEGAR => 'Buah segar hasil petik',
self::BASAH => 'Biji basah',
self::KERING => 'Biji kering/biji kupas',
self::FERMENTASI => 'Produk terfermentasi',
};
}
public function pricePrefix(): string
{
return match ($this) {
self::SEGAR => 'segar',
self::BASAH => 'basah',
self::KERING => 'kering',
self::FERMENTASI => 'fermentasi',
};
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Enums\Koperasi;
enum EfektivitasSanksiKoperasi: string
{
case SANGAT_EFEKTIF = 'Sangat efektif';
case EFEKTIF = 'Efektif';
case BIASA = 'Biasa Saja';
case KURANG = 'Kurang Efektif';
case TIDAK = 'Tidak Efektif';
public function label(): string
{
return match ($this) {
self::SANGAT_EFEKTIF => 'Sangat efektif',
self::EFEKTIF => 'Efektif',
self::BIASA => 'Biasa saja',
self::KURANG => 'Kurang efektif',
self::TIDAK => 'Tidak efektif',
};
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Enums\Koperasi;
enum FaktorManajemenKoperasi: string
{
case KEPERCAYAAN = 'Rasa saling percaya';
case KEPEMIMPINAN = 'Kepemimpinan koperasi';
case ANGGOTA = 'Jumlah anggota';
case PEMBUKUAN = 'Catatan/pembukuan rapi';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::KEPERCAYAAN => 'Rasa saling percaya',
self::KEPEMIMPINAN => 'Kepemimpinan koperasi',
self::ANGGOTA => 'Jumlah anggota',
self::PEMBUKUAN => 'Catatan/pembukuan rapi',
self::LAINNYA => 'Lainnya',
};
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Enums\Koperasi;
enum FasilitasKoperasi: string
{
case GUDANG = 'Gudang penyimpanan';
case PENGERING = 'Alat pengering';
case PEMECAH = 'Mesin pemecah';
case PENGGILING = 'Mesin penggiling';
case SORTASI = 'Mesin sortasi';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::GUDANG => 'Gudang penyimpanan',
self::PENGERING => 'Alat pengering',
self::PEMECAH => 'Mesin pemecah',
self::PENGGILING => 'Mesin penggiling',
self::SORTASI => 'Mesin sortasi',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,9 @@
<?php
namespace App\Enums\Koperasi;
enum FokusKomoditasKoperasi: string
{
case YA = 'Ya';
case TIDAK = 'Tidak';
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum FormatPembukuanKoperasi: string
{
case MANUAL = 'Manual/buku kas';
case DIGITAL = 'Digital/file Excel';
case APLIKASI = 'Aplikasi khusus';
case TIDAK_ADA = 'Tidak ada';
public function label(): string
{
return match ($this) {
self::MANUAL => 'Manual/buku kas',
self::DIGITAL => 'Digital/file Excel',
self::APLIKASI => 'Aplikasi keuangan khusus',
self::TIDAK_ADA => 'Tidak ada',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum FrekuensiPertemuanKoperasi: string
{
case BULANAN = 'Satu bulan sekali';
case TAHUNAN = 'Satu tahun sekali';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::BULANAN => 'Satu bulan sekali',
self::TAHUNAN => 'Satu tahun sekali',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Enums\Koperasi;
enum HubunganPemasokKoperasi: string
{
case BEBAS = 'Bebas';
case LANGGANAN = 'Langganan tetap';
case HUTANG = 'Berbasis hutang';
case KONSINYASI = 'Titip jual';
case VOLUME = 'Komitmen volume';
case SEMI_KONTRAK = 'Semi-kontrak';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::BEBAS => 'Bebas/tidak terikat',
self::LANGGANAN => 'Langganan tetap',
self::HUTANG => 'Berbasis hutang/pinjaman',
self::KONSINYASI => 'Titip jual (konsinyasi)',
self::VOLUME => 'Komitmen volume',
self::SEMI_KONTRAK => 'Semi-kontrak',
self::LAINNYA => 'Lainnya',
};
}
public function description(): string
{
return match ($this) {
self::BEBAS => 'Petani bebas menjual kepada koperasi atau pihak lain tanpa ikatan.',
self::LANGGANAN => 'Petani rutin menjual kepada koperasi tanpa perjanjian formal.',
self::HUTANG => 'Petani menjual kepada koperasi karena memiliki pinjaman.',
self::KONSINYASI => 'Petani dibayar setelah hasil panen terjual.',
self::VOLUME => 'Ada kesepakatan volume yang dipenuhi secara berkala.',
self::SEMI_KONTRAK => 'Ada kesepakatan harga, volume, dan waktu penyerahan.',
self::LAINNYA => '',
};
}
}
@@ -0,0 +1,17 @@
<?php
namespace App\Enums\Koperasi;
enum JawabanYaTidakKoperasi: string
{
case YA = 'Ya';
case TIDAK = 'Tidak';
public function label(): string
{
return match ($this) {
self::YA => 'Ya',
self::TIDAK => 'Tidak',
};
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php
namespace App\Enums\Koperasi;
enum JenisKoperasi: string
{
case PRODUKSI = 'Koperasi Produksi';
case SIMPAN_PINJAM = 'Koperasi Simpan Pinjam';
case PEMASARAN = 'Koperasi Pemasaran';
case DESA = 'Koperasi Desa';
case LAINNYA = 'Lainnya';
}
@@ -0,0 +1,17 @@
<?php
namespace App\Enums\Koperasi;
enum KetersediaanKoperasi: string
{
case ADA = 'Ada';
case TIDAK_ADA = 'Tidak ada';
public function label(): string
{
return match ($this) {
self::ADA => 'Ada',
self::TIDAK_ADA => 'Tidak ada',
};
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Enums\Koperasi;
enum KomoditasAgregasiKoperasi: string
{
case KOPI = 'Kopi';
case KAKAO = 'Kakao';
case VANILI = 'Vanili';
case KEMIRI = 'Kemiri';
case LAINNYA = 'Lainnya';
case TIDAK_TERLIBAT = 'Tidak terlibat';
public function label(): string
{
return match ($this) {
self::KOPI => 'Kopi',
self::KAKAO => 'Kakao',
self::VANILI => 'Vanili',
self::KEMIRI => 'Kemiri',
self::LAINNYA => 'Lainnya',
self::TIDAK_TERLIBAT => 'Tidak melakukan agregasi',
};
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum LayananKoperasi: string
{
case SIMPAN_PINJAM = 'Simpan pinjam';
case INPUT_PRODUKSI = 'Pengadaan input produksi';
case PEMASARAN = 'Pemasaran hasil';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::SIMPAN_PINJAM => 'Simpan pinjam',
self::INPUT_PRODUKSI => 'Pengadaan input produksi',
self::PEMASARAN => 'Pemasaran hasil',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum MekanismePembayaranKoperasi: string
{
case TUNAI = 'Tunai';
case TEMPO = 'Tempo';
case CAMPURAN = 'Campuran';
public function label(): string
{
return match ($this) {
self::TUNAI => 'Tunai langsung',
self::TEMPO => 'Tempo/dibayar kemudian',
self::CAMPURAN => 'Campuran, tergantung situasi',
};
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum ModelFermentasiKoperasi: string
{
case INDIVIDUAL = 'Individual';
case KOLEKTIF = 'Kolektif';
case UNIT_DESA = 'Unit desa';
case CAMPURAN = 'Campuran';
public function label(): string
{
return match ($this) {
self::INDIVIDUAL => 'Individual',
self::KOLEKTIF => 'Kolektif kelompok',
self::UNIT_DESA => 'Unit pengolah desa',
self::CAMPURAN => 'Campuran',
};
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum PenetapanHargaKoperasi: string
{
case PASAR = 'Ikut pasar';
case BIAYA = 'Kalkulasi biaya';
case OFFTAKER = 'Harga offtaker';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::PASAR => 'Mengikuti harga pasar/tengkulak setempat',
self::BIAYA => 'Kalkulasi biaya koperasi',
self::OFFTAKER => 'Mengikuti harga offtaker/mitra',
self::LAINNYA => 'Lainnya',
};
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Enums\Koperasi;
enum PeranRantaiNilaiKoperasi: string
{
case INPUT = 'Penyediaan input';
case AGREGASI = 'Agregasi';
case PEMASARAN_MENTAH = 'Pemasaran mentah';
case PENGOLAHAN = 'Pengolahan barang jadi';
case PEMASARAN_OLAHAN = 'Pemasaran olahan';
case PENJUALAN_LANGSUNG = 'Jual langsung konsumen';
case TIDAK_TERLIBAT = 'Tidak terlibat kegiatan di atas';
public function label(): string
{
return match ($this) {
self::INPUT => 'Penyediaan input pertanian (pupuk, bibit, dan lainnya)',
self::AGREGASI => 'Agregasi produk pertanian dan perkebunan',
self::PEMASARAN_MENTAH => 'Pemasaran produk mentah',
self::PENGOLAHAN => 'Pengolahan produk pangan setengah jadi/jadi',
self::PEMASARAN_OLAHAN => 'Pemasaran produk olahan',
self::PENJUALAN_LANGSUNG => 'Penjualan langsung ke konsumen',
self::TIDAK_TERLIBAT => 'Tidak terlibat',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum PerjanjianPetaniKoperasi: string
{
case TERTULIS = 'Tertulis';
case LISAN = 'Lisan';
case TIDAK_ADA = 'Tidak ada';
public function label(): string
{
return match ($this) {
self::TERTULIS => 'Ada, tertulis',
self::LISAN => 'Ada, kesepakatan lisan',
self::TIDAK_ADA => 'Tidak ada perjanjian',
};
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Enums\Koperasi;
enum PosisiKoperasi: string
{
case PENGURUS = 'Pengurus koperasi';
case ANGGOTA = 'Anggota koperasi';
case PENDAMPING = 'Pendamping koperasi';
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum PraktikFermentasiKoperasi: string
{
case RUTIN = 'Ya rutin';
case PERNAH = 'Pernah coba';
case DIRENCANAKAN = 'Belum, direncakan';
case TIDAK_DIRENCANAKAN = 'Belum, tidak';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::PERNAH => 'Pernah mencoba',
self::DIRENCANAKAN => 'Belum pernah, direncanakan',
self::TIDAK_DIRENCANAKAN => 'Belum pernah, tidak direncanakan',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum PraktikPengeringanKoperasi: string
{
case RUTIN = 'Ya rutin';
case KADANG = 'Kadang';
case TIDAK = 'Tidak';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin',
self::KADANG => 'Kadang-kadang',
self::TIDAK => 'Tidak pernah',
};
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Enums\Koperasi;
enum PraktikSortasiKoperasi: string
{
case RUTIN = 'Ya rutin';
case TIDAK_KONSISTEN = 'Ya tidak konsisten';
case BELUM = 'Belum pernah';
public function label(): string
{
return match ($this) {
self::RUTIN => 'Ya, rutin berstandar',
self::TIDAK_KONSISTEN => 'Ya, tidak konsisten',
self::BELUM => 'Belum pernah',
};
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Enums\Koperasi;
enum SkalaOperasiKoperasi: string
{
case LEVEL_DUSUN = 'Level Dusun';
case LINTAS_DUSUN = 'Lintas Dusun';
case LEVEL_DESA = 'Level Desa';
case LINTAS_DESA = 'Lintas Desa';
case LEVEL_KECAMATAN = 'Level Kecamatan';
case LINTAS_KECAMATAN = 'Lintas Kecamatan';
case LEVEL_KABUPATEN = 'Level Kabupaten';
case LINTAS_KABUPATEN = 'Lintas Kabupaten';
}
@@ -0,0 +1,21 @@
<?php
namespace App\Enums\Koperasi;
enum StatusAdArtKoperasi: string
{
case LENGKAP = 'Ada, lengkap';
case TIDAK_LENGKAP = 'Ada tapi tidak lengkap';
case TIDAK_ADA = 'Tidak ada';
case TIDAK_TAHU = 'Tidak tahu';
public function label(): string
{
return match ($this) {
self::LENGKAP => 'Ada dan lengkap',
self::TIDAK_LENGKAP => 'Ada, belum lengkap',
self::TIDAK_ADA => 'Tidak ada',
self::TIDAK_TAHU => 'Tidak tahu',
};
}
}
@@ -0,0 +1,17 @@
<?php
namespace App\Enums\Koperasi;
enum StatusPembukuanKoperasi: string
{
case SUDAH = 'Sudah';
case BELUM = 'Belum ada';
public function label(): string
{
return match ($this) {
self::SUDAH => 'Sudah',
self::BELUM => 'Belum ada',
};
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Enums\Koperasi;
enum SumberPasokanKoperasi: string
{
case ANGGOTA = 'Anggota';
case NON_ANGGOTA = 'Petani non-anggota';
case PENGUMPUL = 'Pengumpul/sub-agen';
case CAMPURAN = 'Campuran';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::ANGGOTA => 'Anggota kelompok tani langsung',
self::NON_ANGGOTA => 'Petani non-anggota',
self::PENGUMPUL => 'Pengumpul/sub-agen desa',
self::CAMPURAN => 'Campuran',
self::LAINNYA => 'Lainnya',
};
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Enums\Koperasi;
enum TabKoperasi: int
{
case KELEMBAGAAN = 1;
case RANTAI_NILAI = 2;
case SOSIAL_EKONOMI = 3;
public function slug(): string
{
return match ($this) {
self::KELEMBAGAAN => 'kelembagaan-aktor',
self::RANTAI_NILAI => 'rantai-nilai-akses-pasar',
self::SOSIAL_EKONOMI => 'sosial-ekonomi',
};
}
public function label(): string
{
return match ($this) {
self::KELEMBAGAAN => 'Operasional',
self::RANTAI_NILAI => 'Rantai Nilai & Akses Pasar',
self::SOSIAL_EKONOMI => 'Sosial Ekonomi',
};
}
public function icon(): string
{
return match ($this) {
self::KELEMBAGAAN => 'clipboard-list',
self::RANTAI_NILAI => 'arrows-exchange',
self::SOSIAL_EKONOMI => 'heart-handshake',
};
}
public function routePrefix(): string
{
return 'koperasi.pengurus.'.$this->slug();
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Enums\Koperasi;
enum TingkatKreditMacetKoperasi: string
{
case DI_BAWAH_SEPULUH = '<10%';
case SEPULUH_DUA_PULUH_LIMA = '10-25%';
case DUA_PULUH_LIMA_LIMA_PULUH = '25-50%';
case LIMA_PULUH_TUJUH_PULUH_LIMA = '50-75%';
case DI_ATAS_TUJUH_PULUH_LIMA = '>75%';
public function label(): string
{
return match ($this) {
self::DI_BAWAH_SEPULUH => 'Di bawah 10%',
self::SEPULUH_DUA_PULUH_LIMA => '10–25%',
self::DUA_PULUH_LIMA_LIMA_PULUH => '25–50%',
self::LIMA_PULUH_TUJUH_PULUH_LIMA => '50–75%',
self::DI_ATAS_TUJUH_PULUH_LIMA => 'Di atas 75%',
};
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Enums\Koperasi;
enum TujuanPenjualanKoperasi: string
{
case OFFTAKER = 'Offtaker/Eksportir';
case PEDAGANG = 'Pedagang besar';
case KOPERASI = 'Koperasi/BUMDes lain';
case ECERAN = 'Eceran';
case BELUM_MENJUAL = 'Belum pernah';
case LAINNYA = 'Lainnya';
public function label(): string
{
return match ($this) {
self::OFFTAKER => 'Offtaker/eksportir langsung',
self::PEDAGANG => 'Pedagang besar/pengepul kabupaten',
self::KOPERASI => 'Koperasi atau BUMDes lain',
self::ECERAN => 'Eceran/pasar lokal',
self::BELUM_MENJUAL => 'Belum pernah menjual (disimpan/diproses)',
self::LAINNYA => 'Lainnya',
};
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Enums\Koperasi;
enum UrutanKoperasi: string
{
case TERBARU = 'terbaru';
case NAMA_ASC = 'nama_asc';
case NAMA_DESC = 'nama_desc';
case ANGGOTA_DESC = 'anggota_desc';
case ANGGOTA_ASC = 'anggota_asc';
public function label(): string
{
return match ($this) {
self::TERBARU => 'Urut Terbaru',
self::NAMA_ASC => 'Nama A-Z',
self::NAMA_DESC => 'Nama Z-A',
self::ANGGOTA_DESC => 'Anggota Terbanyak',
self::ANGGOTA_ASC => 'Anggota Tersedikit',
};
}
}
@@ -4,12 +4,13 @@ namespace App\Enums\PendidikanPelatihan;
enum PelatihanGAP: string
{
case PEMANGKASAN = 'Pemangkasan atau perawatan tanaman';
case PEMUPUKAN = 'Pemupukan atau nutrisi tanah';
case PENGENDALIAN = 'Pengendalian hama dan penyakit';
case PEMANGKASAN = 'Pemangkasan/perawatan tanaman';
case PEMUPUKAN = 'Pemupukan/nutrisi';
case PENGENDALIAN = 'Pengendalian hama & penyakit';
case PRAKTIK = 'Praktik Berkebun yang Baik (GAP)';
case PENGOLAHAN = 'Pengolahan/pascapanen';
case PENYERBUKAN = 'Penyerbukan manual (Vanili)';
case PENYERBUKAN = 'Penyerbukan Manual (Vanili)';
case LAINNYA = 'Lainnya';
public function label(): string
{
@@ -8,7 +8,7 @@ enum FrekuensiPemangkasanPendamping: string
case TIDAK_RUTIN = 'Memangkas, tapi tidak rutin dan tidak tahu tekniknya';
case SATU_KALI_TAHUN = 'Memangkas 1 kali/tahun, tahu jenis tekniknya';
case DUA_KALI_TAHUN = 'Memangkas 2 kali/tahun, tahu jenis tekniknya';
case LEBIH_DUA_KALI_TAHUN = 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat dan pohon penaung juga dipangkas rutin';
case LEBIH_DUA_KALI_TAHUN = 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat, dan pohon penaung juga dipangkas rutin';
public function label(): string
{
@@ -17,7 +17,7 @@ enum FrekuensiPemangkasanPendamping: string
self::TIDAK_RUTIN => 'Memangkas, tapi tidak rutin dan tidak tahu tekniknya',
self::SATU_KALI_TAHUN => 'Memangkas 1 kali/tahun, tahu jenis tekniknya',
self::DUA_KALI_TAHUN => 'Memangkas 2 kali/tahun, tahu jenis tekniknya',
self::LEBIH_DUA_KALI_TAHUN => 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat dan pohon penaung juga dipangkas rutin',
self::LEBIH_DUA_KALI_TAHUN => 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat, dan pohon penaung juga dipangkas rutin',
};
}
@@ -17,7 +17,7 @@ enum FrekuensiPemangkasanUtama: int
self::TIDAK_RUTIN => 'Memangkas, tapi tidak rutin dan tidak tahu tekniknya',
self::SATU_KALI_TAHUN => 'Memangkas 1 kali/tahun, tahu jenis tekniknya',
self::DUA_KALI_TAHUN => 'Memangkas 2 kali/tahun, tahu jenis tekniknya',
self::LEBIH_DUA_KALI_TAHUN => 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat dan pohon penaung juga dipangkas rutin',
self::LEBIH_DUA_KALI_TAHUN => 'Memangkas lebih dari 2 kali/tahun dengan teknik yang tepat, dan pohon penaung juga dipangkas rutin',
};
}
@@ -16,8 +16,8 @@ enum MetodePenangananHamaPenyakit: int
self::TIDAK_ADA => 'Tidak ada penanganan',
self::CARA_TRADISIONAL => 'Cara tradisional (doa/ritual)',
self::PESTISIDA_SANITASI => 'Pestisida atau sanitasi',
self::KOMBINASI => 'Kombinasi pestisada dan sanitasi',
self::PHT => 'Pengendalian hama terpadu(PHT)',
self::KOMBINASI => 'Kombinasi pestisida dan sanitasi',
self::PHT => 'Pengendalian hama terpadu (PHT)',
};
}
+16 -1
View File
@@ -6,7 +6,22 @@ enum Role: string
{
case SUPER_ADMIN = 'super_admin';
case ADMIN = 'admin'; // admin program
case FASILITATOR = 'fasilitator';
case KOORDINATOR = 'koordinator'; // koordinator per komoditas
case ENUMERATOR = 'enumerator'; // penginput data petani di lapangan
case FASILITATOR = 'fasilitator'; // pemateri workshop
case PETANI = 'petani';
case OFFTAKER = 'offtaker';
public function label(): string
{
return match ($this) {
self::SUPER_ADMIN => 'Super Admin',
self::ADMIN => 'Admin',
self::KOORDINATOR => 'Koordinator',
self::ENUMERATOR => 'Enumerator',
self::FASILITATOR => 'Fasilitator',
self::PETANI => 'Petani',
self::OFFTAKER => 'Offtaker',
};
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Enums;
// Status kelengkapan data profil petani.
// Draf → Lengkap (ditandai enumerator penginput) → Terverifikasi (oleh koordinator, menu menyusul).
enum StatusDataPetani: string
{
case DRAFT = 'draft';
case LENGKAP = 'lengkap';
case TERVERIFIKASI = 'terverifikasi';
public function label(): string
{
return match ($this) {
self::DRAFT => 'Draf',
self::LENGKAP => 'Lengkap',
self::TERVERIFIKASI => 'Terverifikasi',
};
}
// Warna badge Vuexy (bg-label-{warna})
public function warna(): string
{
return match ($this) {
self::DRAFT => 'secondary',
self::LENGKAP => 'info',
self::TERVERIFIKASI => 'success',
};
}
public static function values(): array
{
return array_column(self::cases(), 'value');
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Enums;
enum StatusLegalitasKelompokTani: string
{
case BELUM_ADA = 'Belum ada SK/dokumen apa pun';
case PROSES = 'Sedang proses pengajuan';
case SK_DESA_KECAMATAN = 'Sudah ada SK dari desa/kecamatan';
case SK_DINAS_KABUPATEN = 'Sudah ada SK dan terdaftar di Dinas/Kabupaten';
case TIDAK_TAHU = 'Tidak tahu';
public static function options(): array
{
return collect(self::cases())->mapWithKeys(fn (self $status) => [$status->value => $status->value])->all();
}
}
@@ -20,7 +20,7 @@ class FormBasisDataController extends Controller
*/
public function index(Request $request, string $tabelId): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -20,7 +20,7 @@ class TabelBasisDataController extends Controller
*/
public function index(Request $request): AnonymousResourceCollection
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -50,7 +50,7 @@ class TabelBasisDataController extends Controller
*/
public function show(Request $request, string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -19,7 +19,7 @@ class ValueBasisDataController extends Controller
public function index(Request $request, string $tabelId): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -213,7 +213,7 @@ class ValueBasisDataController extends Controller
public function store(Request $request, string $tabelId): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -278,7 +278,7 @@ class ValueBasisDataController extends Controller
public function update(Request $request, string $tabelId, string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -354,7 +354,7 @@ class ValueBasisDataController extends Controller
public function destroy(Request $request, string $tabelId, string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
if (!Gate::any(['super_admin', 'admin', 'enumerator'])) {
abort(403);
}
@@ -20,7 +20,7 @@ class JenisKomoditasController extends Controller
*/
public function index(Request $request): AnonymousResourceCollection
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -63,7 +63,7 @@ class JenisKomoditasController extends Controller
*/
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -85,7 +85,7 @@ class JenisKomoditasController extends Controller
*/
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -107,7 +107,7 @@ class JenisKomoditasController extends Controller
*/
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -129,7 +129,7 @@ class JenisKomoditasController extends Controller
*/
public function destroy(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -13,7 +13,7 @@ class DistributionController extends Controller
{
public function index(): JsonResponse
{
if (!Gate::any(['super_admin', 'petani','fasilitator', 'offtaker'])) {
if (!Gate::any(['super_admin', 'petani','enumerator', 'offtaker'])) {
abort(403);
}
@@ -35,7 +35,7 @@ class DistributionController extends Controller
public function store(Request $request): JsonResponse
{
if (!Gate::any(['super_admin', 'petani','fasilitator', 'offtaker'])) {
if (!Gate::any(['super_admin', 'petani','enumerator', 'offtaker'])) {
abort(403);
}
@@ -60,7 +60,7 @@ class DistributionController extends Controller
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'petani','fasilitator', 'offtaker'])) {
if (!Gate::any(['super_admin', 'petani','enumerator', 'offtaker'])) {
abort(403);
}
@@ -86,7 +86,7 @@ class DistributionController extends Controller
public function batchUpsert(Request $request): JsonResponse
{
if (!Gate::any(['super_admin', 'petani','fasilitator', 'offtaker'])) {
if (!Gate::any(['super_admin', 'petani','enumerator', 'offtaker'])) {
abort(403);
}
@@ -21,7 +21,7 @@ class LahanController extends Controller
*/
public function index(Request $request): AnonymousResourceCollection
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -77,7 +77,7 @@ class LahanController extends Controller
*/
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -91,7 +91,7 @@ class LahanController extends Controller
$request->merge(['profile_id' => (int) $request->profile_id]);
}
$profileRule = $user->role === 'fasilitator' ? ['required', 'numeric', 'exists:profiles,id'] : ['nullable'];
$profileRule = $user->role === 'enumerator' ? ['required', 'numeric', 'exists:profiles,id'] : ['nullable'];
$validated = $request->validate([
'nama' => ['required', 'string', 'max:255'],
@@ -105,11 +105,11 @@ class LahanController extends Controller
'foto.*' => ['image', 'mimes:jpeg,png,jpg', 'max:5120'], // Max 5MB
]);
$targetProfileId = $user->role === 'fasilitator'
$targetProfileId = $user->role === 'enumerator'
? $validated['profile_id']
: $profile->id;
if ($user->role === 'fasilitator') {
if ($user->role === 'enumerator') {
$targetProfile = Profile::findOrFail($targetProfileId);
if ($targetProfile->desa_kelurahan_id !== $profile->desa_kelurahan_id) {
@@ -117,7 +117,7 @@ class LahanController extends Controller
}
}
$desaKelurahanId = $user->role === 'fasilitator'
$desaKelurahanId = $user->role === 'enumerator'
? $profile->desa_kelurahan_id
: ($validated['desa_kelurahan_id'] ?? $profile->desa_kelurahan_id);
@@ -149,14 +149,14 @@ class LahanController extends Controller
*/
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$lahan = Lahan::with('desaKelurahan')->findOrFail($id);
if ($lahan->profile_id !== Auth::user()->profile->id && Auth::user()->role === 'petani') {
return response()->json(['message' => 'Unauthorized'], 403);
} else if (Auth::user()->role === 'fasilitator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
} else if (Auth::user()->role === 'enumerator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
return response()->json(['message' => 'Unauthorized'], 403);
}
@@ -168,14 +168,14 @@ class LahanController extends Controller
*/
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$lahan = Lahan::findOrFail($id);
if ($lahan->profile_id !== Auth::user()->profile->id && Auth::user()->role === 'petani') {
return response()->json(['message' => 'Unauthorized'], 403);
} else if (Auth::user()->role === 'fasilitator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
} else if (Auth::user()->role === 'enumerator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
return response()->json(['message' => 'Unauthorized'], 403);
}
@@ -215,14 +215,14 @@ class LahanController extends Controller
*/
public function destroy(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$lahan = Lahan::findOrFail($id);
if ($lahan->profile_id !== Auth::user()->profile->id && Auth::user()->role === 'petani') {
return response()->json(['message' => 'Unauthorized'], 403);
} else if (Auth::user()->role === 'fasilitator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
} else if (Auth::user()->role === 'enumerator' && $lahan->desa_kelurahan_id !== Auth::user()->profile->desa_kelurahan_id) {
return response()->json(['message' => 'Unauthorized'], 403);
}
@@ -233,7 +233,7 @@ class LahanController extends Controller
public function batchUpsert(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -12,7 +12,7 @@ class OfftakerController extends Controller
{
public function index(Request $request): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
@@ -29,7 +29,7 @@ class OfftakerController extends Controller
public function store(Request $request): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
@@ -58,7 +58,7 @@ class OfftakerController extends Controller
public function show(string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
$offtaker = Offtaker::findOrFail($id);
@@ -67,7 +67,7 @@ class OfftakerController extends Controller
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
$offtaker = Offtaker::findOrFail($id);
@@ -87,7 +87,7 @@ class OfftakerController extends Controller
public function destroy(string $id): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
Offtaker::findOrFail($id)->delete();
@@ -100,7 +100,7 @@ class OfftakerController extends Controller
*/
public function batchUpsert(Request $request): JsonResponse
{
if (!Gate::any(['super_admin', 'petani', 'fasilitator', 'admin','offtaker'])) {
if (!Gate::any(['super_admin', 'petani', 'enumerator', 'admin','offtaker'])) {
abort(403, 'Unauthorized');
}
@@ -15,7 +15,7 @@ class PanenController extends Controller
{
public function index(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -30,7 +30,7 @@ class PanenController extends Controller
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -87,7 +87,7 @@ class PanenController extends Controller
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$panen = Panen::findOrFail($id);
@@ -96,7 +96,7 @@ class PanenController extends Controller
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$panen = Panen::findOrFail($id);
@@ -114,7 +114,7 @@ class PanenController extends Controller
public function destroy(string $id): JsonResponse
{
Gate::authorize(['petani', 'fasilitator']);
Gate::authorize(['petani', 'enumerator']);
Panen::findOrFail($id)->delete();
return response()->json(null, 204);
}
@@ -124,7 +124,7 @@ class PanenController extends Controller
*/
public function batchUpsert(Request $request): JsonResponse
{
if (Gate::authorize(['petani', 'fasilitator','super_admin'])) {
if (Gate::authorize(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$profileId = Auth::user()->profile->id;
@@ -14,7 +14,7 @@ class PanenController01 extends Controller
{
public function index(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -29,7 +29,7 @@ class PanenController01 extends Controller
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -58,7 +58,7 @@ class PanenController01 extends Controller
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$panen = Panen::findOrFail($id);
@@ -67,7 +67,7 @@ class PanenController01 extends Controller
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$panen = Panen::findOrFail($id);
@@ -85,7 +85,7 @@ class PanenController01 extends Controller
public function destroy(string $id): JsonResponse
{
Gate::authorize(['petani', 'fasilitator']);
Gate::authorize(['petani', 'enumerator']);
Panen::findOrFail($id)->delete();
return response()->json(null, 204);
}
@@ -95,7 +95,7 @@ class PanenController01 extends Controller
*/
public function batchUpsert(Request $request): JsonResponse
{
if (Gate::authorize(['petani', 'fasilitator','super_admin'])) {
if (Gate::authorize(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$profileId = Auth::user()->profile->id;
@@ -23,7 +23,7 @@ class ProfileController extends Controller
*/
public function index(Request $request)
{
if(!Gate::any(['fasilitator', 'super_admin'])) {
if(!Gate::any(['enumerator', 'super_admin'])) {
abort(403);
}
@@ -34,7 +34,7 @@ class ProfileController extends Controller
$profileId = $user->role === 'petani' ? $profile->id : $requestID;
$desaKelurahanId = null;
if ($profile->role === 'fasilitator' || $profile->role === 'super_admin') {
if ($profile->role === 'enumerator' || $profile->role === 'super_admin') {
$desaKelurahanId = $profile->desa_kelurahan_id;
}
@@ -95,7 +95,7 @@ class ProfileController extends Controller
*/
public function store(Request $request)
{
if(!Gate::any(['fasilitator','super_admin'])){
if(!Gate::any(['enumerator','super_admin'])){
abort(403);
}
@@ -139,7 +139,7 @@ class ProfileController extends Controller
public function show(string $id): JSONResponse
{
// attempt to access profile, only for allowed roles
if (!Gate::any(['petani', 'fasilitator', 'offtaker', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'offtaker', 'super_admin'])) {
abort(403);
}
@@ -166,7 +166,7 @@ class ProfileController extends Controller
*/
public function update(Request $request, string $id): JSONResponse
{
if (!Gate::any(['petani', 'fasilitator', 'offtaker', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'offtaker', 'super_admin'])) {
abort(403);
}
@@ -177,7 +177,7 @@ class ProfileController extends Controller
$profile = Profile::findOrFail($id);
if ($user->role === 'fasilitator' && $profile->desa_kelurahan_id != $user->profile->desa_kelurahan_id) {
if ($user->role === 'enumerator' && $profile->desa_kelurahan_id != $user->profile->desa_kelurahan_id) {
abort(403, 'Unauthorized');
}
@@ -239,7 +239,7 @@ class ProfileController extends Controller
public function downloadFile(string $id, string $type): JsonResponse | BinaryFileResponse
{
if (!Gate::any(['petani', 'fasilitator', 'super_admin'])) {
if (!Gate::any(['petani', 'enumerator', 'super_admin'])) {
abort(403);
}
@@ -260,7 +260,7 @@ class ProfileController extends Controller
public function verify(Request $request, string $id): JSONResponse
{
if (!Gate::any(['fasilitator'])) {
if (!Gate::any(['enumerator'])) {
abort(403);
}
@@ -22,7 +22,7 @@ class TanamanController extends Controller
*/
public function index(Request $request): AnonymousResourceCollection
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$user = Auth::user();
@@ -91,7 +91,7 @@ class TanamanController extends Controller
*/
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -135,7 +135,7 @@ class TanamanController extends Controller
*/
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -160,7 +160,7 @@ class TanamanController extends Controller
*/
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$tanaman = Tanaman::findOrFail($id);
@@ -195,7 +195,7 @@ class TanamanController extends Controller
*/
public function destroy(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$tanaman = Tanaman::findOrFail($id);
@@ -22,7 +22,7 @@ class TanamanController extends Controller
*/
public function index(Request $request): AnonymousResourceCollection
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$user = Auth::user();
@@ -91,7 +91,7 @@ class TanamanController extends Controller
*/
public function store(Request $request): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -141,7 +141,7 @@ class TanamanController extends Controller
*/
public function show(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
@@ -166,7 +166,7 @@ class TanamanController extends Controller
*/
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$tanaman = Tanaman::findOrFail($id);
@@ -201,7 +201,7 @@ class TanamanController extends Controller
*/
public function destroy(string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
if (!Gate::any(['petani', 'enumerator','super_admin'])) {
abort(403);
}
$tanaman = Tanaman::findOrFail($id);
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\StoreKelembagaanAktorBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class KelembagaanAktorBumdesController extends Controller
{
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
return view('bumdes.kelembagaan-aktor.index', $this->service->sectionData($pengurusBumdes));
}
public function store(StoreKelembagaanAktorBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
$this->service->saveSection($pengurusBumdes, $request->validated(), 'kelembagaan');
return redirect()->route('bumdes.kelembagaan-aktor.index', $pengurusBumdes)
->with('success', 'Data Kelembagaan berhasil disimpan.');
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bumdes\BumdesRequest;
use App\Http\Requests\Bumdes\StoreOperasionalBumdesRequest;
use App\Models\Bumdes\PengurusBumdes;
use App\Services\Bumdes\PengurusBumdesService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class OperasionalBumdesController extends Controller
{
public function __construct(private readonly PengurusBumdesService $service) {}
public function index(BumdesRequest $request, PengurusBumdes $pengurusBumdes): View
{
return view('bumdes.operasional.index', $this->service->sectionData($pengurusBumdes));
}
public function store(StoreOperasionalBumdesRequest $request, PengurusBumdes $pengurusBumdes): RedirectResponse
{
$this->service->saveSection($pengurusBumdes, $request->validated(), 'operasional');
return redirect()->route('bumdes.operasional.index', $pengurusBumdes)
->with('success', 'Data Operasional berhasil disimpan.');
}
}

Some files were not shown because too many files have changed in this diff Show More