Merge branch 'staging' of https://git.putrakuningan.com/daengdeni/lpj into tender

This commit is contained in:
2025-05-05 15:15:29 +07:00
13 changed files with 842 additions and 562 deletions

View File

@@ -134,7 +134,7 @@
if ($penawaran) {
$isNum = substr($maxCode, 2); // memastikan string ke 3 s/d 8 adalan numiric
$isNP = substr($maxCode, 0, 2);
if ((8 == strlen($maxCode)) && ("NP" == $isNP) && (isNumeric($isNum))) {
if ((8 == strlen($maxCode)) && ("NP" == $isNP) && (ctype_digit($isNum))) {
$code_penawaran_last = substr($maxCode, -4);
$year_penawaran_last = Carbon::parse($penawaran->created_at)->year;
$year_now = Carbon::now()->year;
@@ -149,11 +149,6 @@
return 'NP' . Carbon::now()->format('y') . $noUrutAkhirString;
}
function isNumeric($str)
{
return ctype_digit($str);
}
// generate last penawaran.no_spk
function onLastnumberCodePenawaranSPK($jenis_laporan_code)
: string
@@ -188,46 +183,7 @@
function onRomawi(int $bln)
: string
{
switch ($bln) {
case 1:
return "I";
break;
case 2:
return "II";
break;
case 3:
return "III";
break;
case 4:
return "IV";
break;
case 5:
return "V";
break;
case 6:
return "VI";
break;
case 7:
return "VII";
break;
case 8:
return "VIII";
break;
case 9:
return "IX";
break;
case 10:
return "X";
break;
case 11:
return "XI";
break;
case 12:
return "XII";
break;
}
return convertToRoman($bln);
}
function penyebut($nilai)
@@ -304,15 +260,6 @@
return $hariKerja;
}
function holidays()
{
return HolidayCalendar::pluck('date')->map(
function ($item) {
return Carbon::parse($item)->format('Y-m-d');
},
)->toArray();
}
function countPermohonanForUser($userId)
{
$validStatuses = [

View File

@@ -6,6 +6,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Modules\Lpj\Http\Requests\NocRequest;
use Modules\Lpj\Models\Noc;
use Modules\Lpj\Models\PenawaranTender;
use Modules\Lpj\Models\Permohonan;
use Modules\Lpj\Models\PersetujuanPenawaran;
@@ -43,26 +44,34 @@
$status = "persetujuan-penawaran";
}
$persetujuanPenawaran = PersetujuanPenawaran::updateOrCreate(
['penawaran_id' => $validated['penawaran_id']],
$validated,
$dataNoc = [
'nominal_bayar' => $validated['nominal_bayar'],
'tanggal_pembayaran' => date('Y-m-d'),
'status_bayar' => $validated['nominal_bayar'] < $validated['total_harus_bayar'] ? false : true,
'catatan_noc' => $validated['catatan_noc'],
];
$noc = Noc::updateOrCreate(
[
'permohonan_id' => $validated['permohonan_id'],
'persetujuan_penawaran_id' => $validated['persetujuan_penawaran_id']
],$dataNoc
);
$folderPath = 'noc/' . $validated['penawaran_id'];
$folderPath = 'noc/' . request()->get('penawaran_id');
if ($request->hasFile('bukti_ksl')) {
$persetujuanPenawaran->bukti_ksl = $request->file('bukti_ksl')->store(
$noc->bukti_ksl = $request->file('bukti_ksl')->store(
$folderPath,
'public',
);
}
$persetujuanPenawaran->save();
$noc->save();
// Update the status of the related permohonan to 'spk'
$permohonan = Permohonan::find(request()->get('permohonan_id'));
if ($permohonan) {
$permohonan->status_bayar = request()->get('status_bayar');
$permohonan->status_bayar = request()->get('status_pembayar');
if ($permohonan->jenis_penilaian_id == 2) {
$permohonan->status = $status;
}
@@ -116,9 +125,7 @@
*/
public function edit($id)
{
$persetujuanPenawaran = PersetujuanPenawaran::where('id', $id)->with(
['penawaran.detail', 'penawaran.permohonan.debiture', 'permohonan'],
)->first();
$persetujuanPenawaran = PersetujuanPenawaran::where('id', $id)->first();
return view('lpj::noc.form', compact('persetujuanPenawaran'));
}
@@ -181,10 +188,23 @@
'nomor_registrasi' => $persetujuanPenawaran->permohonan->nomor_registrasi ?? $persetujuanPenawaran->penawaran->nomor_registrasi,
'nama_debitur' => $persetujuanPenawaran->permohonan->debiture->name ?? $persetujuanPenawaran->penawaran->permohonan->debiture->name,
'cabang' => $persetujuanPenawaran->permohonan->branch->name ?? $persetujuanPenawaran->penawaran->permohonan->branch->name,
'tanggal_setor' => formatTanggalIndonesia($persetujuanPenawaran->created_at, true),
'nominal_bayar' => format_currency($persetujuanPenawaran->nominal_bayar ?? 0),
'bukti_ksl' => $persetujuanPenawaran->bukti_ksl ?? null,
'tanggal_penyelesaian' => formatTanggalIndonesia($persetujuanPenawaran->updated_at, true),
'tanggal_setor' => dateFormat(
$persetujuanPenawaran->moc->created_at ?? $persetujuanPenawaran->created_at,
true,
),
'nominal_bayar' => currencyFormat(
$persetujuanPenawaran->noc->nominal_bayar ?? $persetujuanPenawaran->nominal_bayar ?? 0,
),
'bukti_ksl' => $persetujuanPenawaran->noc->bukti_ksl ?? $persetujuanPenawaran->bukti_ksl ?? null,
'memo_penyelesaian' => $persetujuanPenawaran->noc->memo_penyelesaian ?? $persetujuanPenawaran->memo_penyelesaian ?? null,
'nominal_penyelesaian' => currencyFormat(
$persetujuanPenawaran->noc->nominal_penyelesaian ?? $persetujuanPenawaran->nominal_penyelesaian ?? 0,
),
'bukti_penyelesaian' => $persetujuanPenawaran->noc->bukti_penyelesaian ?? $persetujuanPenawaran->bukti_penyelesaian ?? null,
'tanggal_penyelesaian' => dateFormat(
$persetujuanPenawaran->noc->tanggal_penyelesaian ?? $persetujuanPenawaran->updated_at,
true,
),
];
});

View File

@@ -3,15 +3,16 @@
namespace Modules\Lpj\Http\Controllers;
use App\Http\Controllers\Controller;
use Barryvdh\DomPDF\Facade\Pdf;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
use Modules\Location\Models\City;
use Modules\Location\Models\District;
use Modules\Location\Models\Province;
use Modules\Location\Models\Village;
use Modules\Lpj\Models\PermohonanPembatalan;
use Modules\Lpj\Exports\PermohonanExport;
use Modules\Lpj\Http\Requests\PermohonanRequest;
use Modules\Lpj\Models\Branch;
@@ -19,16 +20,12 @@ use Modules\Lpj\Models\Debiture;
use Modules\Lpj\Models\DokumenJaminan;
use Modules\Lpj\Models\JenisFasilitasKredit;
use Modules\Lpj\Models\NilaiPlafond;
use Modules\Lpj\Models\Penilaian;
use Modules\Lpj\Models\Permohonan;
use Modules\Lpj\Models\PermohonanPembatalan;
use Modules\Lpj\Models\StatusPermohonan;
use Modules\Lpj\Models\TujuanPenilaian;
use Modules\Lpj\Notifications\PermohonanNotif;
use Modules\Lpj\Services\PermohonanHistoryService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Modules\Lpj\Models\Penilaian;
use Modules\Usermanagement\Models\User;
class PermohonanController extends Controller
{
@@ -77,7 +74,10 @@ class PermohonanController extends Controller
$documents = DokumenJaminan::where('permohonan_id', $permohonan->id)->get();
if (count($documents) < 1) {
return redirect()->route('debitur.jaminan.create', array_merge(['permohonan_id' => $permohonan->id], ['id' => $permohonan->debiture->id]))->with('success', 'Permohonan created successfully, Lengkapi data jaminan terlebih dahulu');
return redirect()->route(
'debitur.jaminan.create',
array_merge(['permohonan_id' => $permohonan->id], ['id' => $permohonan->debiture->id]),
)->with('success', 'Permohonan created successfully, Lengkapi data jaminan terlebih dahulu');
}
return redirect()
->route('permohonan.index')->with('success', 'Permohonan created successfully');
@@ -146,35 +146,6 @@ class PermohonanController extends Controller
);
}
public function update(PermohonanRequest $request, $id)
{
$permohonan = Permohonan::findOrFail($id);
$beforeRequest = $permohonan->toArray();
$validate = $request->validated();
if ($validate) {
try {
// Update in database
if ($permohonan->status == 'revisi') {
$validate['status'] = 'order';
}
$permohonan->update($validate);
$documents = DokumenJaminan::where('permohonan_id', $permohonan->id)->get();
if (count($documents) < 1) {
return redirect()->route('debitur.jaminan.create', array_merge(['permohonan_id' => $permohonan->id], ['id' => $permohonan->debiture->id]))->with('success', 'Permohonan created successfully, Lengkapi data jaminan terlebih dahulu');
}
return redirect()
->route('permohonan.index')->with('success', 'Permohonan updated successfully');
} catch (Exception $e) {
return redirect()
->route('permohonan.edit', $id)->with('error', 'Failed to update permohonan');
}
}
}
public function destroy($id)
{
try {
@@ -244,7 +215,37 @@ class PermohonanController extends Controller
$filteredRecords = $query->count();
// Get the data for the current page
$data = $query->with(['user', 'debiture', 'branch', 'tujuanPenilaian', 'penilaian','documents'])->get();
$data = $query->get();
$data = $data->map(function ($item) {
return [
'id' => $item->id,
'nomor_registrasi' => $item->nomor_registrasi,
'mig_mst_lpj_nomor_jaminan' => $item->mig_mst_lpj_nomor_jaminan,
'tanggal_permohonan' => $item->tanggal_permohonan ? dateFormat(
$item->tanggal_permohonan,
) : null,
'pemohon' => $item->user->name ?? 'N/A',
'branch' => $item->branch->name ?? 'N/A',
'debiture' => [
'name' => $item->debiture->name,
],
'tujuan_penilaian' => [
'code' => $item->tujuanPenilaian->code ?? null,
'name' => $item->tujuanPenilaian->name ?? null,
],
'status' => $item->status,
'documents' => count($item->documents),
'keterangan' => $item->keterangan,
'penilaian' => [
'id' => $item->penilaian->id ?? null,
'waktu_penilaian' => $item->penilaian->waktu_penilaian ?? null,
'rejected_note' => $item->penilaian->rejected_note ?? null,
'authorized_status' => $item->penilaian->authorized_status ?? null,
],
'registrasi_catatan' => $item->registrasi_catatan,
];
});
// Calculate the page count
$pageCount = ceil($totalRecords / $size);
@@ -324,8 +325,7 @@ class PermohonanController extends Controller
$filteredRecords = $query->count();
// Get the data for the current page
$data = $query->with(['user', 'debiture', 'branch', 'tujuanPenilaian'])->get(
);
$data = $query->with(['user', 'debiture', 'branch', 'tujuanPenilaian'])->get();
// Calculate the page count
$pageCount = ceil($totalRecords / $request->get('size'));
@@ -387,7 +387,6 @@ class PermohonanController extends Controller
return view('lpj::permohonan.pembatalan-form', compact('permohonan'));
}
public function pembatalan(Request $request)
{
// Validate the request
@@ -414,8 +413,8 @@ class PermohonanController extends Controller
return redirect()->route('permohonan.index')->with('success', 'Pembatalan Permohonan Menunggu Approval');
}
public function storeAproved(Request $request, $id): JsonResponse
{
public function storeAproved(Request $request, $id)
: JsonResponse {
$data = [];
if (request()->ajax()) {
try {
@@ -427,16 +426,15 @@ class PermohonanController extends Controller
$permohonan = Permohonan::findOrFail($request->permohonan_id);
$permohonan->update([
'status' => 'proses-survey'
'status' => 'proses-survey',
]);
$data['status'] = 'success';
$data['message'] = 'Jadwal ' . $request->noReg . ' berhasil di aprove';
} catch (\Exception $e) {
} catch (Exception $e) {
$data['status'] = 'error';
$data['message'] = 'Gagal membuat jadwal: ' . $e->getMessage();
}
} else {
$data['status'] = 'error';
$data['message'] = "no ajax request";
@@ -445,6 +443,37 @@ class PermohonanController extends Controller
return response()->json($data);
}
public function update(PermohonanRequest $request, $id)
{
$permohonan = Permohonan::findOrFail($id);
$beforeRequest = $permohonan->toArray();
$validate = $request->validated();
if ($validate) {
try {
// Update in database
if ($permohonan->status == 'revisi') {
$validate['status'] = 'order';
}
$permohonan->update($validate);
$documents = DokumenJaminan::where('permohonan_id', $permohonan->id)->get();
if (count($documents) < 1) {
return redirect()->route(
'debitur.jaminan.create',
array_merge(['permohonan_id' => $permohonan->id], ['id' => $permohonan->debiture->id]),
)->with('success', 'Permohonan created successfully, Lengkapi data jaminan terlebih dahulu');
}
return redirect()
->route('permohonan.index')->with('success', 'Permohonan updated successfully');
} catch (Exception $e) {
return redirect()
->route('permohonan.edit', $id)->with('error', 'Failed to update permohonan');
}
}
}
public function storeRescheduleSurvey(Request $request, $id)
{
@@ -455,14 +484,14 @@ class PermohonanController extends Controller
'nomor_registrasi' => 'required',
'reschedule_note' => 'required',
'reschedule_date' => 'required',
'keterangan' => 'required'
'keterangan' => 'required',
]);
DB::beginTransaction();
$permohonan = Permohonan::findOrFail($request->permohonan_id);
$permohonan->update([
'status' => 'request-reschedule'
'status' => 'request-reschedule',
]);
$penilaian = Penilaian::findOrFail($id);
@@ -477,7 +506,7 @@ class PermohonanController extends Controller
'status' => 'success',
'message' => 'Proses request reschedule permohonan Nomor registrasi ' . $request->nomor_registrasi . ' berhasil',
]);
} catch (\Exception $e) {
} catch (Exception $e) {
DB::rollBack();
return response()->json([
'status' => 'error',

View File

@@ -6,6 +6,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Modules\Lpj\Http\Requests\PersetujuanPenawaranRequest;
use Modules\Lpj\Models\Noc;
use Modules\Lpj\Models\PenawaranDetailTender;
use Modules\Lpj\Models\PenawaranDetailTenderLog;
use Modules\Lpj\Models\PenawaranTender;
@@ -67,6 +68,22 @@
$persetujuanPenawaran->save();
// Save NOC
try {
$noc = Noc::updateOrCreate([
'permohonan_id' => $persetujuanPenawaran->permohonan_id,
'persetujuan_penawaran_id' => $persetujuanPenawaran->id
],[
'bukti_bayar' => $persetujuanPenawaran->bukti_bayar,
]);
} catch (\Exception $e) {
\Log::error('Failed to create or update NOC: ' . $e->getMessage());
return redirect()
->route('persetujuan-penawaran.index')
->with('error', 'Persetujuan Penawaran berhasil disimpan tetapi gagal membuat NOC: ' . $e->getMessage());
}
return redirect()
->route('persetujuan-penawaran.index')->with('success', 'Persetujuan Penawaran berhasil disimpan.');
}

View File

@@ -4,20 +4,150 @@
use Illuminate\Foundation\Http\FormRequest;
/**
* Form Request untuk validasi data NOC (Notice of Completion)
*/
class NocRequest extends FormRequest
{
/**
* Konstanta untuk jenis file yang diizinkan
*/
private const ALLOWED_FILE_TYPES = 'pdf,jpg,jpeg,png';
/**
* Konstanta untuk ukuran file maksimum (dalam KB)
*/
private const MAX_FILE_SIZE = 10240;
/**
* Menentukan apakah pengguna berwenang untuk melakukan request ini
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Mengumpulkan semua aturan validasi
*
* @return array
*/
public function rules()
{
return array_merge(
$this->getBasicInfoRules(),
$this->getPaymentRules(),
$this->getSettlementRules(),
$this->getAuthorizationRules(),
);
}
/**
* Aturan validasi untuk informasi dasar
*
* @return array
*/
private function getBasicInfoRules()
{
return [
'penawaran_id' => 'nullable|exists:penawaran,id',
'nominal_bayar' => 'nullable|numeric|min:0',
'bukti_ksl' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:10240',
'permohonan_id' => 'required|exists:permohonan,id',
'persetujuan_penawaran_id' => 'required|exists:persetujuan_penawaran,id',
'status' => 'nullable|boolean',
'created_by' => 'nullable|exists:users,id',
'updated_by' => 'nullable|exists:users,id',
];
}
/**
* Aturan validasi untuk data pembayaran
*
* @return array
*/
private function getPaymentRules()
{
$fileRule = 'nullable|file|mimes:' . self::ALLOWED_FILE_TYPES . '|max:' . self::MAX_FILE_SIZE;
return [
'total_harus_bayar' => 'nullable|numeric|min:0',
'nominal_bayar' => 'nullable|numeric|min:0',
'bukti_ksl' => $fileRule,
'bukti_bayar' => $fileRule,
'status_bayar' => 'nullable|boolean',
'tanggal_pembayaran' => 'nullable|date',
];
}
/**
* Aturan validasi untuk data penyelesaian
*
* @return array
*/
private function getSettlementRules()
{
$fileRule = 'nullable|file|mimes:' . self::ALLOWED_FILE_TYPES . '|max:' . self::MAX_FILE_SIZE;
return [
'nominal_penyelesaian' => 'nullable|numeric|min:0',
'status_penyelesaian' => 'nullable|boolean',
'tanggal_penyelesaian' => 'nullable|date',
'bukti_penyelesaian' => $fileRule,
'memo_penyelesaian' => $fileRule,
'catatan_noc' => 'nullable|string',
];
}
/**
* Aturan validasi untuk otorisasi
*
* @return array
*/
private function getAuthorizationRules()
{
return [
'authorized_status' => 'nullable|boolean',
'authorized_at' => 'nullable|date',
'authorized_by' => 'nullable|exists:users,id',
];
}
/**
* Pesan khusus untuk validasi
*
* @return array
*/
public function messages()
{
return [
'permohonan_id.required' => 'ID Permohonan harus diisi',
'permohonan_id.exists' => 'ID Permohonan tidak valid',
'persetujuan_penawaran_id.required' => 'ID Persetujuan Penawaran harus diisi',
'persetujuan_penawaran_id.exists' => 'ID Persetujuan Penawaran tidak valid',
'nominal_bayar.numeric' => 'Nominal Bayar harus berupa angka',
'nominal_bayar.min' => 'Nominal Bayar minimal 0',
'bukti_ksl.file' => 'Bukti KSL harus berupa file',
'bukti_ksl.mimes' => 'Bukti KSL harus berformat pdf, jpg, jpeg, atau png',
'bukti_ksl.max' => 'Ukuran Bukti KSL maksimal 10MB',
'bukti_bayar.file' => 'Bukti Bayar harus berupa file',
'bukti_bayar.mimes' => 'Bukti Bayar harus berformat pdf, jpg, jpeg, atau png',
'bukti_bayar.max' => 'Ukuran Bukti Bayar maksimal 10MB',
'status.boolean' => 'Status harus berupa boolean',
'status_bayar.boolean' => 'Status Bayar harus berupa boolean',
'tanggal_pembayaran.date' => 'Format Tanggal Pembayaran tidak valid',
'nominal_penyelesaian.numeric' => 'Nominal Penyelesaian harus berupa angka',
'nominal_penyelesaian.min' => 'Nominal Penyelesaian minimal 0',
'status_penyelesaian.boolean' => 'Status Penyelesaian harus berupa boolean',
'tanggal_penyelesaian.date' => 'Format Tanggal Penyelesaian tidak valid',
'bukti_penyelesaian.file' => 'Bukti Penyelesaian harus berupa file',
'bukti_penyelesaian.mimes' => 'Bukti Penyelesaian harus berformat pdf, jpg, jpeg, atau png',
'bukti_penyelesaian.max' => 'Ukuran Bukti Penyelesaian maksimal 10MB',
'memo_penyelesaian.file' => 'Memo Penyelesaian harus berupa file',
'memo_penyelesaian.mimes' => 'Memo Penyelesaian harus berformat pdf, jpg, jpeg, atau png',
'memo_penyelesaian.max' => 'Ukuran Memo Penyelesaian maksimal 10MB',
'authorized_status.boolean' => 'Status Otorisasi harus berupa boolean',
'authorized_at.date' => 'Format Tanggal Otorisasi tidak valid',
'authorized_by.exists' => 'User Otorisasi tidak valid',
];
}
}

View File

@@ -23,8 +23,6 @@
'sla_final' => 'nullable|numeric|min:0',
'file_persetujuan_penawaran' => 'nullable|file|mimes:pdf,doc,docx|max:10240',
'surat_representasi' => 'nullable|file|mimes:pdf,doc,docx|max:10240',
'bukti_bayar' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:10240',
'nominal_bayar' => 'nullable|numeric|min:0',
'status' => 'nullable|boolean',
'authorized_status' => 'boolean',
'authorized_at' => 'nullable|date',
@@ -52,9 +50,6 @@
'surat_representasi.file' => 'Surat Representasi harus berupa file.',
'surat_representasi.mimes' => 'Surat Representasi harus berupa file PDF, DOC, atau DOCX.',
'surat_representasi.max' => 'Ukuran Surat Representasi tidak boleh lebih dari 10MB.',
'bukti_bayar.file' => 'Bukti Bayar harus berupa file.',
'bukti_bayar.mimes' => 'Bukti Bayar harus berupa file PDF, JPG, JPEG, atau PNG.',
'bukti_bayar.max' => 'Ukuran Bukti Bayar tidak boleh lebih dari 10MB.',
'region_id.required' => 'Region ID wajib diisi.',
'region_id.exists' => 'Region ID tidak valid.',
'status.required' => 'Status wajib diisi.',
@@ -62,8 +57,6 @@
'authorized_status.boolean' => 'Status otorisasi harus berupa nilai boolean.',
'authorized_at.date' => 'Tanggal otorisasi harus berupa tanggal yang valid.',
'authorized_by.exists' => 'ID pengguna yang mengotorisasi tidak valid.',
'status_bayar.required' => 'Status bayar wajib diisi.',
'status_bayar.in' => 'Status bayar harus berupa "sudah_bayar", "belum_bayar" atau "tidak bayar".',
];
}
}

62
app/Models/Noc.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Lpj\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
// use Modules\Lpj\Database\Factories\NocFactory;
class Noc extends Base
{
protected $table = 'noc';
protected $fillable = [
'permohonan_id',
'persetujuan_penawaran_id',
'bukti_bayar',
'nominal_bayar',
'status_bayar',
'tanggal_pembayaran',
'nominal_penyelesaian',
'status_penyelesaiaan',
'tanggal_penyelesaian',
'bukti_penyelesaian',
'bukti_ksl',
'memo_penyelesaian',
'catatan_noc',
'status',
'authorized_status',
'authorized_at',
'authorized_by',
];
protected $casts = [
'nominal_bayar' => 'decimal:2',
'status_bayar' => 'boolean',
'tanggal_pembayaran' => 'date',
'nominal_penyelesaian' => 'decimal:2',
'status_penyelesaiaan' => 'boolean',
'tanggal_penyelesaian' => 'date',
'status' => 'boolean',
'authorized_status' => 'boolean',
'authorized_at' => 'datetime',
];
// Relationship with Permohonan
public function permohonan()
{
return $this->belongsTo(Permohonan::class, 'permohonan_id');
}
// Relationship with PersetujuanPenawaran
public function persetujuanPenawaran()
{
return $this->belongsTo(PersetujuanPenawaran::class, 'persetujuan_penawaran_id');
}
// Relationship with User (for authorized_by)
public function authorizedBy()
{
return $this->belongsTo(User::class, 'authorized_by');
}
}

View File

@@ -259,4 +259,10 @@
return $this->belongsTo(Inspeksi::class, 'permohonan_id');
}
// Add this relationship
public function noc()
{
return $this->hasOne(Noc::class, 'permohonan_id');
}
}

View File

@@ -25,7 +25,6 @@
'authorized_status',
'authorized_at',
'authorized_by',
'status',
'catatan',
];
@@ -58,4 +57,10 @@
{
return $this->belongsTo(User::class, 'authorized_by');
}
// Relationship with Noc
public function noc()
{
return $this->hasOne(Noc::class, 'persetujuan_penawaran_id');
}
}

View File

@@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up()
: void
{
Schema::create('noc', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('permohonan_id');
$table->unsignedBigInteger('persetujuan_penawaran_id');
$table->string('bukti_bayar')->nullable();
$table->decimal('nominal_bayar', 15, 2)->nullable();
$table->boolean('status_bayar')->default(false);
$table->date('tanggal_pembayaran')->nullable();
$table->decimal('nominal_penyelesaian', 15, 2)->nullable();
$table->boolean('status_penyelesaiaan')->default(false);
$table->date('tanggal_penyelesaian')->nullable();
$table->string('bukti_penyelesaian')->nullable();
$table->string('bukti_ksl')->nullable();
$table->text('memo_penyelesaian')->nullable();
$table->boolean('status')->default(true);
$table->string('catatan_noc')->nullable();
$table->char('authorized_status', 1)->nullable();
$table->timestamp('authorized_at')->nullable();
$table->unsignedBigInteger('authorized_by')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->unsignedBigInteger('updated_by')->nullable();
$table->unsignedBigInteger('deleted_by')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('permohonan_id')->references('id')->on('permohonan');
$table->foreign('persetujuan_penawaran_id')->references('id')->on('persetujuan_penawaran');
});
}
/**
* Reverse the migrations.
*/
public function down()
: void
{
Schema::dropIfExists('noc');
}
};

View File

@@ -19,6 +19,7 @@
<form action="{{ route('noc.store') }}" method="POST" class="grid gap-5" enctype="multipart/form-data">
@csrf
<input type="hidden" name="penawaran_id" value="{{ $persetujuanPenawaran->penawaran_id ?? old('penawaran_id') }}">
<input type="hidden" name="persetujuan_penawaran_id" value="{{ $persetujuanPenawaran->id ?? old('persetujuan_penawaran_id') }}">
<input type="hidden" name="permohonan_id" value="{{ $persetujuanPenawaran->penawaran->permohonan->id ?? $persetujuanPenawaran->permohonan->id }}">
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
@@ -26,10 +27,10 @@
Status Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<select class="input tomselect w-full @error('status_bayar') border-danger bg-danger-light @enderror" name="status_bayar" id="status_bayar">
<select class="input tomselect w-full @error('status_pembayar') border-danger bg-danger-light @enderror" name="status_pembayar" id="status_pembayar">
<option value="">Pilih Status Bayar</option>
<option value="sudah_bayar" {{ (old('status_bayar') == 'sudah_bayar') || (isset($persetujuanPenawaran->penawaran->permohonan) && $persetujuanPenawaran->penawaran->permohonan->status_bayar == 'sudah_bayar') ? 'selected' : '' }}>Sudah Bayar</option>
<option value="belum_bayar" {{ (old('status_bayar') == 'belum_bayar') || (isset($persetujuanPenawaran->penawaran->permohonan) && $persetujuanPenawaran->penawaran->permohonan->status_bayar == 'belum_bayar') ? 'selected' : '' }}>Belum Bayar</option>
<option value="sudah_bayar" {{ (old('status_pembayar') == 'sudah_bayar') || ($persetujuanPenawaran?->penawaran?->permohonan?->status_bayar == 'sudah_bayar') ? 'selected' : '' }}>Sudah Bayar</option>
<option value="belum_bayar" {{ (old('status_pembayar') == 'belum_bayar') || ($persetujuanPenawaran?->penawaran?->permohonan?->status_bayar == 'belum_bayar') ? 'selected' : '' }}>Belum Bayar</option>
</select>
@error('status_bayar')
<em class="alert text-danger text-sm">{{ $message }}</em>
@@ -39,11 +40,11 @@
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">
Bukti KSL
Total Harus Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<input type="file" name="bukti_ksl" id="bukti_ksl" class="file-input w-full @error('bukti_ksl') border-danger bg-danger-light @enderror" accept=".pdf,.doc,.docx">
@error('bukti_ksl')
<input type="number" name="total_harus_bayar" id="total_harus_bayar" class="input w-full @error('total_harus_bayar') border-danger bg-danger-light @enderror" value="{{ old('total_harus_bayar', $persetujuanPenawaran->nominal_bayar ?? '') }}" readonly>
@error('total_harus_bayar')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror
</div>
@@ -54,19 +55,47 @@
Nominal Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<input type="number" name="nominal_bayar" id="nominal_bayar" class="input w-full @error('nominal_bayar') border-danger bg-danger-light @enderror" value="{{ old('nominal_bayar', $persetujuanPenawaran->nominal_bayar ?? '') }}" placeholder="Masukkan nominal bayar">
<input type="number" name="nominal_bayar" id="nominal_bayar" class="input w-full @error('nominal_bayar') border-danger bg-danger-light @enderror" value="{{ old('nominal_bayar', $persetujuanPenawaran->noc->nominal_bayar ?? '') }}" placeholder="Masukkan nominal bayar">
@error('nominal_bayar')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">
Bukti KSL
</label>
<div class="flex flex-wrap items-baseline w-full">
<input type="file" name="bukti_ksl" id="bukti_ksl" class="file-input w-full @error('bukti_ksl') border-danger bg-danger-light @enderror" accept=".pdf,.jpg,.jpeg,.png">
@error('bukti_ksl')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror
@if(isset($persetujuanPenawaran->noc->bukti_ksl) && !empty($persetujuanPenawaran->noc->bukti_ksl))
<div class="mt-2 flex items-center">
<span class="text-sm text-gray-600 mr-2">File yang sudah diupload:</span>
<a href="{{ asset('storage/' . $persetujuanPenawaran->noc->bukti_ksl) }}"
target="_blank" class="text-blue-600 hover:text-blue-800 underline flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
Lihat File
</a>
</div>
@endif
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">
Catatan
</label>
<div class="flex flex-wrap items-baseline w-full">
<textarea name="catatan" id="catatan" rows="4" class="textarea w-full @error('catatan') border-danger bg-danger-light @enderror" placeholder="Masukkan catatan">{{ old('catatan', $persetujuanPenawaran->catatan ?? '') }}</textarea>
<textarea name="catatan" id="catatan" rows="4" class="textarea w-full @error('catatan') border-danger bg-danger-light @enderror" readonly placeholder="Masukkan catatan">{{ old('catatan', $persetujuanPenawaran->catatan ?? '') }}</textarea>
@error('catatan')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror
@@ -78,7 +107,7 @@
Catatan NOC
</label>
<div class="flex flex-wrap items-baseline w-full">
<textarea name="catatan_noc" id="catatan_noc" rows="4" class="textarea w-full @error('catatan_noc') border-danger bg-danger-light @enderror" placeholder="Masukkan catatan noc">{{ old('catatan_noc', $persetujuanPenawaran->catatan_noc ?? '') }}</textarea>
<textarea name="catatan_noc" id="catatan_noc" rows="4" class="textarea w-full @error('catatan_noc') border-danger bg-danger-light @enderror" placeholder="Masukkan catatan noc">{{ old('catatan_noc', $persetujuanPenawaran->noc->catatan_noc ?? '') }}</textarea>
@error('catatan_noc')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror

View File

@@ -49,11 +49,11 @@
<span class="sort"> <span class="sort-label"> Tanggal Permohonan </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[150px]" data-datatable-column="user_id">
<th class="min-w-[150px]" data-datatable-column="pemohon">
<span class="sort"> <span class="sort-label"> User Pemohon </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[150px]" data-datatable-column="branch_id">
<th class="min-w-[150px]" data-datatable-column="branch">
<span class="sort"> <span class="sort-label"> Cabang Pemohon </span>
<span class="sort-icon"> </span> </span>
</th>
@@ -150,21 +150,12 @@
},
tanggal_permohonan: {
title: 'Tanggal Permohonan',
render: (item, data) => {
return `${window.formatTanggalIndonesia(data.tanggal_permohonan)}`;
},
pemohon: {
title: 'User Pemohon'
},
user_id: {
title: 'User Pemohon',
render: (item, data) => {
return `${data.user.name}`;
},
},
branch_id: {
branch: {
title: 'Cabang Pemohon',
render: (item, data) => {
return `${data.branch.name}`;
},
},
debitur_id: {
title: 'Debitur',
@@ -201,8 +192,7 @@
status: {
title: 'Status',
render: (item, data) => {
console.log(data.documents.length);
if (data.documents.length > 0) {
if (data.documents > 0) {
return `<span class="badge badge-sm badge-default uppercase flex justify-center">${data.status}</span>`;
}
return `<span class="badge badge-sm badge-danger uppercase flex justify-center">Lengkapi Aset Jaminan</span>`;