done -> integrasi user dan unit simrs + cara pembayaran

This commit is contained in:
JokoPrasetio 2025-08-21 12:03:41 +07:00
parent b2e4899f87
commit f15f9dee45
17 changed files with 463 additions and 47 deletions

View File

@ -6,15 +6,18 @@ use App\Mail\NotifikasiCustomer;
use App\Mail\NotifikasiPembayaran;
use App\Models\JadwalKonsul;
use App\Models\Karbohidrat;
use App\Models\Karyawan;
use App\Models\MasterMcu;
use App\Models\Order;
use App\Models\OrderDetail;
use App\Models\UnitInstalasi;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;
class CustomerController extends Controller
{
@ -288,6 +291,10 @@ class CustomerController extends Controller
'alamat' => $biodataResult['alamat'],
'entry_at' => Carbon::now()->format('Y-m-d H:i:s.u'),
];
if($jenisCustomer === "Karyawan RSAB Harapan Kita"){
$nip_pns = Karyawan::where('namalengkap',$biodataResult['nama_pemesan'])->first()->nip_pns;
$payloadOrder['nip'] = $nip_pns ?? null;
}
$order = Order::create($payloadOrder);
foreach ($dataCart as $cart) {
$payloadOrderDetail = [
@ -555,4 +562,52 @@ class CustomerController extends Controller
];
return view('guest.success_page', $payload);
}
public function karyawan(Request $request)
{
$search = trim($request->input('search'));
// 1. Validasi dulu
$validator = Validator::make(
['search' => $search],
['search' => 'required|string|min:2|max:50|regex:/^[a-zA-Z.\s]+$/']
);
if ($validator->fails()) {
return response()->json(['error' => 0, 'data' => []]);
}
// 2. Baru query kalau ada keyword
$data =Karyawan::where('statusenabled', true)
->where('namalengkap', 'ILIKE', "%{$search}%")
->limit(5)
->pluck('namalengkap') // langsung ambil string
->map(fn($nama) => ['label' => $nama]);
return response()->json(['error' => 0, 'data' => $data]);
}
public function unitInstalasi(Request $request)
{
$search = trim($request->input('search'));
// 1. Validasi dulu
$validator = Validator::make(
['search' => $search],
['search' => 'required|string|min:2|max:50|regex:/^[a-zA-Z.\s]+$/']
);
if ($validator->fails()) {
return response()->json(['error' => 0, 'data' => []]);
}
// 2. Baru query kalau ada keyword
$data = UnitInstalasi::where('statusenabled', true)
->select('name')
->where('name', 'ILIKE', "%{$search}%")
->limit(5)
->get()
->map(fn($row) => ['label' => $row->name]);
return response()->json(['error' => 0, 'data' => $data]);
}
}

16
app/Models/Karyawan.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Karyawan extends Model
{
protected $connection = 'dbKaryawan';
protected $table = 'public.pegawai_m';
public $timestamps = false;
protected $primaryKey = "id";
protected $guarded =[
'id'
];
}

View File

@ -39,7 +39,8 @@ class Order extends Model
'alamat',
'medical_record',
'evidence_medical_record',
'nama_institusi'
'nama_institusi',
'nip'
];
protected $cast = [

View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UnitInstalasi extends Model
{
protected $connection = 'dbKaryawan';
protected $table = 'public.unitkerjapegawai_m';
public $timestamps = false;
protected $primaryKey = "id";
protected $guarded =[
'id'
];
}

View File

@ -152,6 +152,28 @@ return [
'timezone' => env('APP_TIMEZONE', 'utc' ),
],
'dbKaryawan' => [
'driver' => 'pgsql',
'url' => env('DB_URL'),
'host' => env('DB_HOST_KARYAWAN', '127.0.0.1'),
'port' => env('DB_PORT_KARYAWAN', '3306'),
'database' => env('DB_DATABASE_KARYAWAN', 'laravel'),
'username' => env('DB_USERNAME_KARYAWAN', 'root'),
'password' => env('DB_PASSWORD_KARYAWAN', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
'timezone' => env('APP_TIMEZONE', 'utc' ),
],
],
/*

View File

@ -27,12 +27,12 @@ DB_DATABASE_ORDER_GIZI = order_gizi
DB_USERNAME_ORDER_GIZI = simrs
DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@
DB_CONNECTION_ORDER_GIZI= pgsql
DB_HOST_ORDER_GIZI = 172.16.88.22
DB_PORT_ORDER_GIZI = 5432
DB_DATABASE_ORDER_GIZI = order_gizi
DB_USERNAME_ORDER_GIZI = simrs
DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@
DB_CONNECTION_AUTH_KARYAWAN = pgsql
DB_HOST_KARYAWAN = psql1.rsabhk.lan
DB_PORT_KARYAWAN = 5432
DB_DATABASE_KARYAWAN = rsab_hk_production
DB_USERNAME_KARYAWAN = postgres
DB_PASSWORD_KARYAWAN = postgres
DB_CONNECTION_AUTH_DEV = pgsql
DB_HOST_AUTH_DEV = 172.16.88.22

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

View File

@ -224,18 +224,38 @@ function showStep(index) {
// =======================
function toggleCustomerFields() {
const selected = $('input[name="jenis_customer"]:checked').val();
if (selected === 'Karyawan RSAB Harapan Kita') {
$('.karyawan').show();
$('.pasien, .umum').hide();
} else if (selected === 'Keluarga Pasien / Penunggu Pasien') {
$('.pasien').show();
$('.karyawan, .umum').hide();
} else {
$('.umum').show();
$('.karyawan, .pasien').hide();
const $nama = $('#nama_pemesan');
// Sembunyikan semua section
$('.karyawan, .pasien, .umum').hide();
// Destroy jika sudah ada selectize
if ($nama[0] && $nama[0].selectize) {
$nama[0].selectize.destroy();
}
switch (selected) {
case 'Karyawan RSAB Harapan Kita':
$('.karyawan').show();
$nama.val('')
$nama.removeClass('form-control')
$("#help_nama_pemesan").removeClass('d-none')
selectKaryawan(); // inisialisasi ulang selectize
break;
case 'Keluarga Pasien / Penunggu Pasien':
$('.pasien').show();
$nama.addClass('form-control')
$("#help_nama_pemesan").addClass('d-none')
break;
default: // Masyarakat Umum
$('.umum').show();
$nama.addClass('form-control')
$("#help_nama_pemesan").addClass('d-none')
break;
}
}
$('input[name="jenis_customer"]').on('change', toggleCustomerFields);
toggleCustomerFields();
@ -246,7 +266,9 @@ if (typeof checkout_biodata === 'object') {
if(checkout_biodata.jenis_kelamin){
$(`input[name="jenis_kelamin"][value="${checkout_biodata.jenis_kelamin}"]`).prop('checked', true);
}
$('#nama_pemesan').val(checkout_biodata.nama_pemesan);
if(checkout_biodata.jenis_customer !== 'Karyawan RSAB Harapan Kita'){
$('#nama_pemesan').val(checkout_biodata.nama_pemesan);
}
// $('#tanggal_lahir').val(checkout_biodata.tanggal_lahir);
$('#tinggi_badan').val(checkout_biodata.tinggi_badan);
$('#berat_badan').val(checkout_biodata.berat_badan);
@ -266,7 +288,7 @@ function isiKonfirmasi() {
jenis_customer: $('input[name="jenis_customer"]:checked').val(),
nama_pemesan: $('#nama_pemesan').val(),
jenis_kelamin: $('input[name="jenis_kelamin"]:checked').val(),
// tanggal_lahir: $('#tanggal_lahir').val(),
id_karyawan: $('#id_karyawan').val(),
tinggi_badan: $('#tinggi_badan').val(),
berat_badan: $('#berat_badan').val(),
no_whatsapp: $('#no_whatsapp').val(),
@ -293,6 +315,7 @@ function renderCartSummary() {
container.innerHTML = '';
let totalKeseluruhan = 0;
const carts = JSON.parse(sessionStorage.getItem('cart') || '[]');
const checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '[]');
carts.forEach((item) => {
const pesananList = Array.isArray(item.pesanan) ? item.pesanan : [];
@ -438,31 +461,58 @@ function renderCartSummary() {
<div class="flex-grow-1 position-relative">
<div class="card-body">
<h5 class="card-title">${item.nama_menu}</h5>
<div class="text-muted small mb-1">Rp ${parseInt(harga).toLocaleString('id-ID')}</div>
${item?.kalori ? `<div class="text-muted small mb-1">Kalori : ${item?.kalori} kal</div>` : ''}
<div class="card-body">
<!-- Judul menu -->
<h4 class="card-title mb-2 fw-bold text-primary">${item.nama_menu}</h4>
${item.deskripsi ? `<p class="card-text text-muted small mb-2">${item.deskripsi}</p>` : ''}
<div class="mb-2 small text-muted"><i class="fa fa-calendar-check me-1"></i>
${item.apakah_someday
? 'Tersedia setiap hari (Senin - Minggu)'
: (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia')}
</div>
<div class="mb-2 small text-muted"><i class="fa fa-utensils me-1"></i>
Menu: <strong>${item.apakah_someday ? 'Sameday' : 'Menu Normal'}</strong>
</div>
<!-- Harga -->
<div class="badge bg-success-subtle text-success fw-bold fs-6 mb-2">
${checkout_biodata?.jenis_customer === "Karyawan RSAB Harapan Kita"
? '<span class="me-1">Harga Karyawan</span>'
: '<span class="me-1">Harga</span>'
}
Rp ${parseInt(harga).toLocaleString('id-ID')}
</div>
<div class="mb-2 small text-muted"><strong>Silahkan isi tanggal pemesanan, pilih karbohidrat dan catatan pemesanan (opsional) yang diinginkan</strong></div>
${pesananHTML}
<div class="mt-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
<button class="btn btn-sm btn-outline-success"
onclick="addOrderDate(${item.id}, ${item.apakah_menu_sore})">
+ Tambah Tanggal
</button>
<!-- Kalori -->
${item?.kalori ? `<div class="text-muted small mb-1"><i class="fas fa-fire me-1"></i>Kalori: ${item.kalori} kal</div>` : ''}
<div><strong>Total:</strong> <span class="text-success">Rp ${itemTotal.toLocaleString('id-ID')}</span></div>
</div>
<!-- Deskripsi -->
${item.deskripsi ? `<p class="card-text text-muted small mb-2">${item.deskripsi}</p>` : ''}
<!-- Info tanggal & jenis menu -->
<div class="d-flex flex-column gap-1 mb-2">
<div class="small text-muted">
<i class="fas fa-calendar-check me-1"></i>
${item.apakah_someday
? 'Tersedia setiap hari (Senin Minggu)'
: (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia')
}
</div>
<div class="small text-muted">
<i class="fas fa-utensils me-1"></i>
<strong>${item.apakah_someday ? 'Sameday' : 'Menu Normal'}</strong>
</div>
</div>
<!-- Petunjuk -->
<div class="alert alert-info small p-2 mb-2">
<strong>Petunjuk:</strong> Isi tanggal pemesanan, pilih karbohidrat, dan catatan tambahan (opsional).
</div>
<!-- Form pesanan -->
${pesananHTML}
<!-- Tombol & total -->
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mt-3">
<button class="btn btn-sm btn-success" onclick="addOrderDate(${item.id}, ${item.apakah_menu_sore})">
<i class="fas fa-plus me-1"></i>Tambah Tanggal
</button>
<div class="fw-bold">
Total: <span class="text-success">Rp ${itemTotal.toLocaleString('id-ID')}</span>
</div>
</div>
</div>
</div>
</div>
@ -922,3 +972,80 @@ document.getElementById('submitNote').addEventListener('click', function(e){
})
}
});
function selectKaryawan(){
const $el = $('#nama_pemesan');
// 1. destroy jika sudah ada
if ($el[0] && $el[0].selectize) {
$el[0].selectize.destroy();
}
$el.selectize({
valueField: 'label', // sama dengan labelField
labelField: 'label',
searchField: ['label'],
create: false,
placeholder: "Cari nama karyawan...",
maxItems: 1,
load: function (query, callback) {
$.ajax({
url: '/karyawan',
data: { search: query },
success: res => callback(res.data || []),
error: () => callback([])
});
},
render: {
option: (item, escape) =>
`<div class="p-1"><div class="fw-semibold">${escape(item.label)}</div></div>`,
item: (item, escape) => `<div>${escape(item.label)}</div>`
}
});
}
selectUnitInstalasi()
function selectUnitInstalasi(){
const bagian_instalasi = $('#bagian_instalasi');
// 1. destroy jika sudah ada
if (bagian_instalasi[0] && bagian_instalasi[0].selectize) {
bagian_instalasi[0].selectize.destroy();
}
bagian_instalasi.selectize({
valueField: 'label',
labelField: 'label',
searchField: ['label'],
create: false,
sortField: [],
placeholder: "Cari unit instalasi...",
maxItems:1,
load: function (query, callback) {
$.ajax({
url: '/unit-instalasi',
data: { search: query },
success: function (response) {
if (response.error === 0 && Array.isArray(response.data)) {
callback(response.data);
} else {
callback();
}
},
error: function () {
callback();
}
});
},
render: {
option: function (item, escape) {
return `<div class="p-1">
<div class="fw-semibold" style="font-size: 0.85rem;">${escape(item.label)}</div>
</div>`;
},
item: function (item, escape) {
return `<div>${escape(item?.label)}</div>`;
}
}
});
}

View File

@ -51,6 +51,8 @@ $(document).ready(function(){
fetchMenu(filterState)
}, 300)
})
})
function changePerPage(select) {

View File

@ -3,14 +3,152 @@
if (cart.length > 0) {
$('#floatingCartButton').removeClass('d-none');
$('#menuBtn').removeClass('d-none');
}
}
});
function openImageModal(imageSrc, title) {
document.getElementById('modalImage').src = imageSrc;
document.getElementById('imageModalLabel').textContent = title;
$('#imageModal').modal('show');
}
function fetchMenu(filter = {}) {
const containerGuest = $("#order_guest_id");
$("#tanggal-filter").removeClass('d-none');
if (filter.jenis_menu === "cara_pesan") {
$("#tanggal-filter").addClass('d-none');
const cara_pesan = [
{
type: "Karyawan RSAB Harapan Kita",
gambar: "/cara_pesan/order_karyawan.png",
color: "success"
},
{
type: "Keluarga Pasien / Penunggu Pasien",
gambar: "/cara_pesan/order_keluarga_pasien.png",
color: "success"
},
{
type: "Masyarakat Umum",
gambar: "/cara_pesan/order_masyarakat_umum.png",
color: "success"
}
];
let html = `
<div class="container py-2">
<div class="text-center mb-3">
<h2 class="fw-bold text-gradient bg-gradient-primary">Cara Pemesanan</h2>
</div>
<div class="row g-4 justify-content-center">
`;
cara_pesan.forEach((cara, index) => {
html += `
<div class="col-lg-4 col-md-6">
<div class="card border-0 shadow-lg hover-lift transition-all-3">
<div class="card-body text-center">
<div class="mb-2">
<div class="avatar avatar-xxl mx-auto">
<a href="${cara.gambar}"
class="glightbox"
data-gallery="cara-pesan"
data-title="${cara.type}"
data-description="Panduan pemesanan ${cara.type}">
<img src="${cara.gambar}"
alt="${cara.type}"
class="img-fluid border rounded-3 border-3 border-${cara.color} shadow-sm image-zoom"
style="width: 120px; height: 120px; object-fit: cover; cursor: pointer;">
</a>
</div>
</div>
<h5 class="fw-bold text-${cara.color}">${cara.type}</h5>
<small class="text-muted d-block">Panduan pemesanan</small>
</div>
<div class="card-footer bg-white border-0 text-center mb-1">
<a href="${cara.gambar}"
class="btn btn-${cara.color} btn-rounded fw-semibold glightbox"
data-gallery="cara-pesan"
data-title="${cara.type}"
data-description="Panduan pemesanan ${cara.type}">
<i class="fas fa-eye me-2"></i>Lihat Panduan
</a>
</div>
</div>
</div>
`;
});
html += `
</div>
</div>
<!-- Modal Image Viewer -->
<style>
.text-gradient {
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hover-lift {
transition: all 0.3s ease;
}
.hover-lift:hover {
transform: translateY(-5px);
box-shadow: 0 1rem 3rem rgba(0,0,0,0.175) !important;
}
.transition-all-3 {
transition: all 0.3s ease;
}
.btn-rounded {
border-radius: 50px;
}
/* Image hover effect */
.image-zoom {
transition: transform 0.3s ease;
}
.image-zoom:hover {
transform: scale(1.05);
}
/* Modal backdrop styling */
.modal-backdrop {
background-color: rgba(0, 0, 0, 0.8);
}
.modal.fade .modal-dialog {
transition: transform 0.3s ease-out;
}
.modal.show .modal-dialog {
transform: none;
}
</style>
`;
containerGuest.html(html);
GLightbox({
selector: '.glightbox',
touchNavigation: true,
loop: true,
zoomable: true,
autoplayVideos: true
});
return
}
let params = new URLSearchParams({
page: filter.page || 1,
@ -45,7 +183,7 @@
$("#tanggal-filter").addClass('d-none');
let html = `
<div class="container">
<h4 class="mb-4 fw-bold text-primary">
<h4 class="mb-4 fw-bold text-gradient">
<i class="fas fa-calendar-alt me-2"></i>
Jadwal Konsultasi
</h4>
@ -147,6 +285,11 @@
--soft-gray: #f8f9fa;
--charcoal: #2d3436;
}
.text-gradient {
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.bg-gradient-primary {
background: linear-gradient(135deg, var(--mint-dark) 0%, var(--mint) 100%);
}

View File

@ -0,0 +1,13 @@
<div class="modal fade" id="imageModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl">
<div class="modal-content border-0">
<div class="modal-header border-0">
<h5 class="modal-title" id="imageModalLabel"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center p-2">
<img src="" id="modalImage" class="img-fluid rounded" style="max-height: 80vh;">
</div>
</div>
</div>
</div>

View File

@ -40,6 +40,8 @@
<div class="col-md-6">
<label class="form-label">Nama Pemesan <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="nama_pemesan" id="nama_pemesan" required>
<input type="hidden" class="form-control" name="id_karyawan" id="id_karyawan">
<div id="help_nama_pemesan" class="form-text d-none">Silakan cari dan pilih nama karyawan.</div>
</div>
<div class="col-md-6">
<label class="form-label">No. Whatsapp <span class="text-danger">*</span></label>
@ -104,7 +106,7 @@
{{-- Karyawan --}}
<div class="col-md-6 karyawan">
<label class="form-label">Bagian /Instalasi <span class="text-danger">*</span></label>
<input type="text" class="form-control karyawan-field" name="bagian_instalasi" id="bagian_instalasi">
<input type="text" class="karyawan-field" name="bagian_instalasi" id="bagian_instalasi">
</div>
<div class="col-md-6 karyawan">
<label class="form-label">Ekstensien yang bisa di Hubungi</label>

View File

@ -1,7 +1,7 @@
@extends('guest.layout.main')
@section('body_main_guests')
<section class="section py-5 bg-light">
<section class="section py-3 bg-light">
<div class="container">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 mb-2">
@ -121,6 +121,7 @@
</section>
@include('guest.checkout_order')
@include('guest.cara_bayar')
<script src="{{ ver('/js/order_guest/register.js') }}"></script>
<script src="{{ ver('/js/order_guest/functions.js') }}"></script>

View File

@ -27,11 +27,27 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
{{-- Selectize --}}
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.15.2/css/selectize.default.min.css"
integrity="sha512-pTaEn+6gF1IeWv3W1+7X7eM60TFu/agjgoHmYhAfLEU8Phuf6JKiiE8YmsNC0aCgQv4192s4Vai8YZ6VNM6vyQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
{{-- Jquery --}}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>\
<script
src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.15.2/js/selectize.min.js"
integrity="sha512-IOebNkvA/HZjMM7MxL0NYeLYEalloZ8ckak+NDtOViP7oiYzG5vn6WVXyrJDiJPhl4yRdmNAG49iuLmhkUdVsQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css" />
<script src="https://cdn.jsdelivr.net/gh/mcstudios/glightbox/dist/js/glightbox.min.js"></script>
</head>
<body class="index-page">

View File

@ -98,6 +98,8 @@ Route::get('/check-order/search', [CustomerController::class, 'searchOrder']);
Route::get('/order-mcu', [CustomerController::class, 'indexMcu']);
Route::post('/order-mcu', [CustomerController::class, 'storeMcu']);
Route::get('/success-mcu', [CustomerController::class, 'successMcu']);
Route::get('/karyawan', [CustomerController::class, 'karyawan']);
Route::get('/unit-instalasi', [CustomerController::class, 'unitInstalasi']);
// Route::get('/send-mail', function(){
// Mail::to('skyjok14@gmail.com')->queue(new NotifikasiCustomer('Test'));