Files
CKB/resources/views/transaction/index.blade.php
2025-09-19 23:01:34 +07:00

3695 lines
165 KiB
PHP
Executable File

@extends('layouts.frontapp')
@php
use App\Models\Dealer;
use Illuminate\Support\Facades\Auth;
@endphp
{{-- @section('contentHead')
<div class="kt-subheader kt-grid__item" id="kt_subheader">
<div class="kt-container kt-container--fluid ">
<div class="kt-subheader__main">
<h3 class="kt-subheader__title"> Transaksi </h3>
</div>
<div class="kt-subheader__toolbar" style="width: 1000px;">
<a href="{{ route('transaction.create') }}" id="addBtn" class="btn btn-label-success btn-bold" data-url="" data-redirect="">Tambah Transaksi</a>
</div>
</div>
</div>
@endsection --}}
@section('styles')
<style>
button.disabled {
cursor: not-allowed !important;
pointer-events: none;
}
.table-responsive {
max-height: 100%;
overflow-y: auto;
}
.text-success {
color: #28a745 !important;
}
.text-danger {
color: #dc3545 !important;
}
.text-bold {
font-weight: bold;
}
.system-stock {
font-weight: 600;
color: #007bff;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #dee2e6;
vertical-align: middle;
padding: 12px 8px;
}
.table thead th {
background-color: #f8f9fa;
color: #495057;
font-weight: 600;
font-size: 14px;
border-bottom: 2px solid #dee2e6;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(0,0,0,.02);
}
.physical-stock {
font-weight: 500;
border: 2px solid #e9ecef;
transition: border-color 0.15s ease-in-out;
}
.physical-stock:focus {
border-color: #ffc107;
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.25);
}
.difference {
font-size: 14px;
padding: 4px 8px;
border-radius: 4px;
background-color: #f8f9fa;
display: inline-block;
min-width: 60px;
}
.btn-lg {
padding: 12px 20px;
font-size: 16px;
font-weight: 600;
letter-spacing: 0.5px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.btn-lg:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
}
.quantity-input-mutasi.is-invalid {
border-color: #dc3545;
background-color: #fff5f5;
}
.quantity-input-mutasi.is-invalid:focus {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
.available-stock-mutasi {
font-weight: 600;
}
/* Styles for receive mutations table */
#receiveMutationsTable {
font-size: 14px;
}
#receiveMutationsTable th {
background-color: #f8f9fa;
font-weight: 600;
text-align: center;
vertical-align: middle;
}
#receiveMutationsTable td {
vertical-align: middle;
}
.btn-detail {
font-size: 12px;
padding: 4px 8px;
}
.status-badge {
font-size: 11px;
padding: 4px 8px;
border-radius: 12px;
font-weight: 600;
}
.mutation-detail-table {
font-size: 14px;
}
.mutation-detail-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.quantity-approved-input {
text-align: center;
font-weight: 600;
}
.quantity-approved-input.is-invalid {
border-color: #dc3545;
background-color: #fff5f5;
}
.mutation-detail-table textarea {
font-size: 12px;
resize: vertical;
}
.mutation-detail-table input {
font-size: 14px;
}
.bg-warning-light {
background-color: #fff3cd !important;
border: 1px solid #ffeaa7;
}
.form-control-plaintext.border {
background-color: #f8f9fa;
font-style: normal;
}
.alert ul {
padding-left: 1.2rem;
}
.alert ul li {
margin-bottom: 0.25rem;
}
/* Select2 styling for mutasi form */
.select2-container {
width: 100% !important;
}
.select2-container--default .select2-selection--single {
height: 38px;
border: 1px solid #e2e5ec;
border-radius: 4px;
display: flex;
align-items: center;
padding: 0;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 36px;
padding-left: 12px;
padding-right: 30px;
color: #74788d;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: calc(100% - 30px);
}
.select2-container--default .select2-selection--single .select2-selection__placeholder {
color: #74788d;
line-height: 36px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 36px;
right: 8px;
top: 1px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b {
border-color: #74788d transparent transparent transparent;
border-style: solid;
border-width: 5px 4px 0 4px;
height: 0;
left: 50%;
margin-left: -4px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 0;
}
/* Hide clear button completely */
.select2-container--default .select2-selection--single .select2-selection__clear {
display: none !important;
}
.select2-dropdown {
border: 1px solid #e2e5ec;
border-radius: 4px;
z-index: 9999 !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.select2-results__option {
padding: 8px 12px;
line-height: 1.4;
}
.select2-results__option--highlighted {
background-color: #5d78ff;
color: white;
}
.select2-container--default.select2-container--focus .select2-selection--single {
border-color: #5d78ff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(93, 120, 255, 0.25);
}
/* Select2 for table cells - adjust width */
#products-table-mutasi .select2-container {
width: 100% !important;
max-width: 100%;
}
/* Style for placeholder options */
select option[disabled] {
color: #6c757d;
font-style: italic;
background-color: #f8f9fa;
}
/* Prevent auto-selection of first option */
select:focus option:first-child {
background-color: #f8f9fa;
}
/* Required field styling */
.form-control[required]:not(:placeholder-shown):valid {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
.form-control[required]:not(:placeholder-shown):invalid {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
/* Required field indicator */
.form-control[required]::placeholder {
color: #6c757d;
}
/* Service Advisor required styling */
select[name="user_sa_id"][required] option:first-child {
color: #6c757d;
}
/* Required field labels */
.form-group label:after {
content: " *";
color: #dc3545;
font-weight: bold;
}
/* Required field focus styling */
.form-control[required]:focus {
border-color: #5d78ff;
box-shadow: 0 0 0 0.2rem rgba(93, 120, 255, 0.25);
}
/* Invalid field styling */
.form-control.is-invalid {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
/* Valid field styling */
.form-control.is-valid {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
/* Claim tab specific styling - Enhanced and Fixed */
#claimTransactionsTable {
font-size: 14px;
}
#claimTransactionsTable th {
background-color: #f8f9fa;
font-weight: 600;
text-align: center;
vertical-align: middle;
border: 1px solid #dee2e6;
}
#claimTransactionsTable td {
vertical-align: middle;
border: 1px solid #dee2e6;
}
#claimTransactionsTable .btn {
font-size: 12px;
padding: 4px 8px;
margin: 1px;
}
/* Status badge styling for claim table */
#claimTransactionsTable .badge {
font-size: 11px;
padding: 4px 8px;
border-radius: 12px;
font-weight: 600;
}
/* Fixed column widths for claim table */
#claimTransactionsTable th:nth-child(1),
#claimTransactionsTable td:nth-child(1) {
width: 12% !important;
min-width: 100px !important;
} /* Tanggal */
#claimTransactionsTable th:nth-child(2),
#claimTransactionsTable td:nth-child(2) {
width: 10% !important;
min-width: 80px !important;
} /* SPK */
#claimTransactionsTable th:nth-child(3),
#claimTransactionsTable td:nth-child(3) {
width: 12% !important;
min-width: 100px !important;
} /* No Polisi */
#claimTransactionsTable th:nth-child(4),
#claimTransactionsTable td:nth-child(4) {
width: 20% !important;
min-width: 150px !important;
} /* Pekerjaan */
#claimTransactionsTable th:nth-child(5),
#claimTransactionsTable td:nth-child(5) {
width: 8% !important;
min-width: 60px !important;
} /* Qty */
#claimTransactionsTable th:nth-child(6),
#claimTransactionsTable td:nth-child(6) {
width: 15% !important;
min-width: 120px !important;
} /* Service Advisor */
#claimTransactionsTable th:nth-child(7),
#claimTransactionsTable td:nth-child(7) {
width: 10% !important;
min-width: 80px !important;
} /* Status */
#claimTransactionsTable th:nth-child(8),
#claimTransactionsTable td:nth-child(8) {
width: 8% !important;
min-width: 80px !important;
} /* Aksi */
#claimTransactionsTable th:nth-child(9),
#claimTransactionsTable td:nth-child(9) {
width: 8% !important;
min-width: 100px !important;
} /* Pre Check */
#claimTransactionsTable th:nth-child(10),
#claimTransactionsTable td:nth-child(10) {
width: 8% !important;
min-width: 100px !important;
} /* Post Check */
/* Action column specific styling - Enhanced */
#claimTransactionsTable td:nth-child(8),
#claimTransactionsTable td:nth-child(9),
#claimTransactionsTable td:nth-child(10) {
text-align: center !important;
vertical-align: middle !important;
padding: 8px 4px !important;
}
/* Button alignment in action columns - Fixed */
#claimTransactionsTable td:nth-child(8) .btn,
#claimTransactionsTable td:nth-child(9) .btn,
#claimTransactionsTable td:nth-child(10) .btn {
margin: 1px 2px !important;
vertical-align: middle !important;
display: inline-block !important;
}
/* Specific button styling for different types */
#claimTransactionsTable .btn-success {
background-color: #28a745 !important;
border-color: #28a745 !important;
color: white !important;
}
#claimTransactionsTable .btn-warning {
background-color: #ffc107 !important;
border-color: #ffc107 !important;
color: #212529 !important;
}
#claimTransactionsTable .btn-primary {
background-color: #007bff !important;
border-color: #007bff !important;
color: white !important;
}
#claimTransactionsTable .btn-danger {
background-color: #dc3545 !important;
border-color: #dc3545 !important;
color: white !important;
}
/* Badge styling fixes */
#claimTransactionsTable .badge-warning {
background-color: #ffc107 !important;
color: #212529 !important;
}
#claimTransactionsTable .badge-success {
background-color: #28a745 !important;
color: white !important;
}
#claimTransactionsTable .badge-info {
background-color: #17a2b8 !important;
color: white !important;
}
#claimTransactionsTable .badge-danger {
background-color: #dc3545 !important;
color: white !important;
}
/* DataTable specific fixes */
#claimTransactionsTable_wrapper {
overflow-x: auto !important;
}
#claimTransactionsTable_wrapper .dataTables_scrollHead {
overflow: hidden !important;
}
#claimTransactionsTable_wrapper .dataTables_scrollBody {
overflow-x: auto !important;
}
/* Ensure responsive controls are visible */
#claimTransactionsTable_wrapper .dtr-control {
position: relative !important;
cursor: pointer !important;
background-color: #f8f9fa !important;
border: 1px solid #dee2e6 !important;
width: 30px !important;
height: 30px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-weight: bold !important;
color: #495057 !important;
}
#claimTransactionsTable_wrapper .dtr-control:before {
content: "+" !important;
font-size: 16px !important;
line-height: 1 !important;
}
#claimTransactionsTable_wrapper .dtr-control.dtr-expanded:before {
content: "-" !important;
}
/* Ensure responsive child rows are properly styled */
#claimTransactionsTable_wrapper .dtr-details {
background-color: #f8f9fa !important;
border: 1px solid #dee2e6 !important;
padding: 10px !important;
margin: 5px 0 !important;
border-radius: 4px !important;
}
#claimTransactionsTable_wrapper .dtr-details li {
border-bottom: 1px solid #e9ecef !important;
padding: 5px 0 !important;
}
#claimTransactionsTable_wrapper .dtr-details li:last-child {
border-bottom: none !important;
}
#claimTransactionsTable_wrapper .dtr-title {
font-weight: 600 !important;
color: #495057 !important;
margin-right: 10px !important;
}
#claimTransactionsTable_wrapper .dtr-data {
color: #6c757d !important;
}
/* Responsive adjustments for smaller screens */
@media (max-width: 768px) {
#claimTransactionsTable {
font-size: 12px !important;
}
#claimTransactionsTable th,
#claimTransactionsTable td {
padding: 8px 4px !important;
}
#claimTransactionsTable .btn {
font-size: 10px !important;
padding: 3px 6px !important;
min-width: 50px !important;
}
#claimTransactionsTable .badge {
font-size: 9px !important;
padding: 3px 6px !important;
}
/* Adjust column widths for mobile */
#claimTransactionsTable th:nth-child(4),
#claimTransactionsTable td:nth-child(4) {
width: 25% !important;
min-width: 120px !important;
} /* Pekerjaan - wider on mobile */
}
/* Additional fixes for DataTable rendering */
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_processing,
.dataTables_wrapper .dataTables_paginate {
color: #333 !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
padding: 0.5em 1em !important;
margin: 0 2px !important;
border-radius: 4px !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current {
background: #007bff !important;
color: white !important;
border: 1px solid #007bff !important;
}
/* Tab claim specific styling */
#form-claim {
background-color: #fff;
padding: 20px;
border: 1px solid #dee2e6;
border-top: none;
border-radius: 0 0 5px 5px;
}
#form-claim h6 {
color: #495057;
font-weight: 600;
margin-bottom: 15px;
}
/* Stock tab specific styling - simplified */
/* Ensure stock sub-tabs are visible */
#stock .nav-tabs {
display: flex;
border-bottom: 1px solid #dee2e6;
margin-top: 1rem;
}
#stock .nav-tabs .nav-link {
padding: 0.5rem 1rem;
border: 1px solid transparent;
border-radius: 0.25rem 0.25rem 0 0;
text-decoration: none;
color: #495057;
cursor: pointer;
}
#stock .nav-tabs .nav-link.active {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
/* Ensure transaksi sub-tabs have the same styling */
#transaksi .nav-tabs {
display: flex;
border-bottom: 1px solid #dee2e6;
margin-top: 1rem;
}
#transaksi .nav-tabs .nav-link {
padding: 0.5rem 1rem;
border: 1px solid transparent;
border-radius: 0.25rem 0.25rem 0 0;
text-decoration: none;
color: #495057;
cursor: pointer;
}
#transaksi .nav-tabs .nav-link.active {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
/* Prevent stock tabs from appearing in transaksi tab */
#transaksi #stock,
#transaksi #opname,
#transaksi #mutasi,
#transaksi #penerimaan {
display: none !important;
}
/* Prevent transaksi tabs from appearing in stock tab */
#stock #form-kerja,
#stock #form-cuci,
#stock #form-claim {
display: none !important;
}
/* Ensure proper tab display */
.tab-content > .tab-pane {
display: none;
}
.tab-content > .tab-pane.active {
display: block;
}
/* Ensure main tab content is properly separated */
#transaksi {
display: none;
}
#transaksi.active {
display: block;
}
#stock {
display: none;
}
#stock.active {
display: block;
}
/* Ensure sub-tab content is properly contained within their parent tabs */
#transaksi .tab-content .tab-pane {
display: none;
}
#transaksi .tab-content .tab-pane.active {
display: block;
}
#stock .tab-content .tab-pane {
display: none;
}
#stock .tab-content .tab-pane.active {
display: block;
}
/* Additional safety to prevent cross-tab content display */
#transaksi .tab-content #opname,
#transaksi .tab-content #mutasi,
#transaksi .tab-content #penerimaan {
display: none !important;
}
#stock .tab-content #form-kerja,
#stock .tab-content #form-cuci,
#stock .tab-content #form-claim {
display: none !important;
}
/* Force proper tab separation */
.tab-content > #stock {
display: none !important;
}
.tab-content > #stock.active {
display: block !important;
}
.tab-content > #transaksi {
display: none !important;
}
.tab-content > #transaksi.active {
display: block !important;
}
</style>
@endsection
@section('content')
<div class="mobile-container">
<div class="container">
<div class="row mb-4 mt-4">
<div class="col-8">
{{-- <h5 class="text-center mt-4">Cipta Kreasi Baru</h5> --}}
<a href="/"><img src="{{ asset('logo-ckb.png') }}" style="width: 100%" alt="LOGO CKB"></a>
</div>
<div class="col-4 text-right my-auto">
<a class="btn btn-sm btn-danger mt-3" style="background: red !important;" href="{{ route('logout') }}" onclick="logout(event)">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</div>
<div class="row">
<div class="col-12">
<!--begin::Portlet-->
<div class="kt-portlet">
<div class="kt-portlet__head">
<div class="kt-portlet__head-label">
<span>{{ $mechanic->name }}</span>
</div>
<div class="kt-portlet__head-toolbar">
<span class="float-right">{{ $now }}</span>
</div>
</div>
<div class="kt-portlet__body">
<div class="row">
<div class="col-8">
<b>Dealer {{ $mechanic->dealer_name }}</b><br><br>
<a href="#">Total {{ $count_transaction_dealers }} Pekerjaan terkirim pada dealer</a><br>
<a href="#">Anda telah posting {{ $count_transaction_users }} pekerjaan</a>
<!-- KPI Information -->
<div class="mt-3">
@if($kpiData['has_target'])
<div class="row">
<div class="col-6">
<small class="text-muted">Target {{ $kpiData['period'] }}</small><br>
<strong class="text-primary" id="kpi-target">{{ number_format($kpiData['target']) }} Pekerjaan</strong>
</div>
<div class="col-6">
<small class="text-muted">Pencapaian</small><br>
<strong class="text-{{ $kpiData['status_color'] }}" id="kpi-actual">{{ number_format($kpiData['actual']) }} Pekerjaan</strong>
</div>
</div>
<div class="mt-2">
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">Progress</small>
<small class="text-{{ $kpiData['status_color'] }} font-weight-bold" id="kpi-percentage">{{ $kpiData['percentage'] }}%</small>
</div>
<div class="progress" style="height: 8px;">
@php
$progressWidth = min(100, $kpiData['percentage']);
@endphp
<div class="progress-bar bg-{{ $kpiData['status_color'] }}"
role="progressbar"
style="width: {{ $progressWidth }}%"
aria-valuenow="{{ $kpiData['percentage'] }}"
aria-valuemin="0"
aria-valuemax="100">
</div>
</div>
<div class="mt-1">
@if($kpiData['status'] == 'exceeded')
<small class="text-success"><i class="fa fa-check-circle"></i> Target tercapai!</small>
@elseif($kpiData['status'] == 'good')
<small class="text-info"><i class="fa fa-arrow-up"></i> Performa baik</small>
@elseif($kpiData['status'] == 'fair')
<small class="text-warning"><i class="fa fa-exclamation-triangle"></i> Perlu peningkatan</small>
@elseif($kpiData['status'] == 'poor')
<small class="text-danger"><i class="fa fa-times-circle"></i> Perlu perbaikan</small>
@else
<small class="text-secondary"><i class="fa fa-clock"></i> Belum ada data</small>
@endif
</div>
</div>
@else
<div class="text-center py-2">
<i class="fa fa-info-circle text-muted"></i>
<small class="text-muted">Belum ada target KPI untuk {{ $kpiData['period'] }}</small>
</div>
@endif
</div>
</div>
<div class="col-4">
<div class="text-center mt-2">
<a href="{{ route('transaction.lists') }}">
<i style="font-size: 16px;" class="fa fa-eye"></i>
<p>Laporan harian</p>
</a>
</div>
<div class="text-center mt-2">
<a href="{{ route('transaction.recap') }}">
<i style="font-size: 16px;" class="fa fa-eye"></i>
<p>Rekap Laporan</p>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<!--begin::Portlet-->
<div class="kt-portlet">
<div class="kt-portlet__body">
<!-- Main Tabs -->
<ul class="nav nav-tabs nav-tabs-line nav-tabs-line-primary" role="tablist">
<li class="nav-item">
<a class="nav-link active" href="#transaksi">Transaksi</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#stock">Stock</a>
</li>
</ul>
<div class="tab-content">
<!-- Tab Transaksi -->
<div class="tab-pane active" id="transaksi" role="tabpanel">
<!-- Sub Tabs untuk Transaksi -->
<ul class="nav nav-tabs nav-tabs-line nav-tabs-line-success mt-3" role="tablist">
<li class="nav-item">
<a class="nav-link @if(old('form') == 'work') active @endif" href="#form-kerja">Form Kerja</a>
</li>
<li class="nav-item">
<a class="nav-link @if(old('form') == 'wash') active @endif" href="#form-cuci">Form Cuci</a>
</li>
<li class="nav-item">
<a class="nav-link @if(old('form') == 'claim') active @endif" href="#form-claim">Klaim</a>
</li>
</ul>
<div class="tab-content mt-3">
<div class="tab-pane @if(old('form') == 'work') active @endif" id="form-kerja" role="tabpanel">
<!-- Form Kerja -->
<form action="{{ route('transaction.store') }}" method="POST" id="workForm">
@csrf
<input type="hidden" name="form" value="work">
<input type="hidden" name="mechanic_id" value="{{ $mechanic->id }}">
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
@if($errors->has('error'))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong><i class="fa fa-times-circle"></i> Error:</strong>
{{ $errors->first('error') }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
@endif
<div class="form-group row">
<div class="col-6">
<label>No. SPK</label>
<input type="text" name="spk_no" class="form-control @if(old('form') == 'work') @error('spk_no') is-invalid @enderror @endif" value="{{ old('spk_no') }}" placeholder="No. SPK" required>
@if(old('form') == 'work')
@error('spk_no')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<label>No. Polisi</label>
<input type="text" name="police_number" class="form-control @if(old('form') == 'work') @error('police_number') is-invalid @enderror" @endif value="{{ old('police_number') }}" placeholder="No. Polisi" required>
@if(old('form') == 'work')
@error('police_number')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
</div>
<div class="form-group row">
<div class="col-6">
<label>Warranty</label>
<select name="warranty" class="form-control @if(old('form') == 'work') @error('warranty') is-invalid @enderror @endif">
<option value="" @if(old('form') == 'work') @if(old('warranty') == '' || old('warranty') == null) selected @endif @else selected @endif>Warranty</option>
<option value="1" @if(old('form') == 'work') @if(old('warranty') == 1) selected @endif @endif>Ya</option>
<option value="0" @if(old('form') == 'work') @if(old('warranty') == 0) selected @endif @endif>Tidak</option>
</select>
@if(old('form') == 'work')
@error('warranty')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<label>Tanggal Pekerjaan</label>
<input type="text" name="date" id="date-work" required class="form-control @if(old('form') == 'work') @error('date') is-invalid @enderror @endif" placeholder="Tanggal Pekerjaan">
@if(old('form') == 'work')
@error('date')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
</div>
<div class="form-group mt-4">
<label>Service Advisor</label>
<select name="user_sa_id" class="form-control @if(old('form') == 'work') @error('user_sa_id') is-invalid @enderror @endif" required>
<option value="" selected>Service Advisor</option>
@foreach ($user_sas as $user_sa)
<option @if(old('form') == 'work') @if($user_sa->id == old('user_sa_id')) selected @enderror @endif value="{{ $user_sa->id }}">{{ $user_sa->name }}</option>
@endforeach
</select>
@error('user_sa_id')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
</div>
<input type="hidden" name="category" value="work">
<div class="work_multirow">
@if (old('work_id') && old('form') == 'work')
<input type="hidden" class="work_field_counter" value="{{ count(old('work_id')) }}">
@for ($i = 0; $i < count(old('work_id')); $i++)
<div class="form-group row" id="work_field{{ $i+1 }}">
<div class="col-6">
<select name="work_id[]" id="work_work{{ $i+1 }}" class="form-control @error('work_id.'.$i) is-invalid @enderror">
<option value="" disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}" @if($work->id == old('work_id.'.$i)) selected @endif>{{ $work->name }}</option>
@endforeach
</select>
@error('work_id.'.$i)
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
</div>
<div class="col-4">
<input type="number" class="form-control @error('quantity.'.$i) is-invalid @enderror" value="{{ old('quantity.'.$i) }}" name="quantity[]" placeholder="Qty">
@error('quantity.'.$i)
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove1" onclick="removeFormField('work', 1)">X</button>
</div>
</div>
@endfor
@else
<input type="hidden" class="work_field_counter" value="5">
<div class="form-group row" id="work_field1">
<div class="col-6">
<select name="work_id[]" id="work_work1" class="form-control">
<option value="" selected disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove1" onclick="removeFormField('work', 1)">X</button>
</div>
</div>
<div class="form-group row" id="work_field2">
<div class="col-6">
<select name="work_id[]" id="work_work2" class="form-control">
<option value="" selected disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove2" onclick="removeFormField('work', 2)">X</button>
</div>
</div>
<div class="form-group row" id="work_field3">
<div class="col-6">
<select name="work_id[]" id="work_work3" class="form-control">
<option value="" selected disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove3" onclick="removeFormField('work', 3)">X</button>
</div>
</div>
<div class="form-group row" id="work_field4">
<div class="col-6">
<select name="work_id[]" id="work_work4" class="form-control">
<option value="" selected disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove4" onclick="removeFormField('work', 4)">X</button>
</div>
</div>
<div class="form-group row" id="work_field5">
<div class="col-6">
<select name="work_id[]" id="work_work5" class="form-control">
<option value="" selected disabled>Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger work-btn-remove float-right" style="width: 100%;" type="button" id="workRemove5" onclick="removeFormField('work', 5)">X</button>
</div>
</div>
@endif
<div class="row">
<div class="col-10"></div>
<div class="col-2">
<button class="btn mb-4 btn-sm btn-primary float-right btn-add-field-work" style="width: 100%;" onclick="addFormFieldWithStockCheck('work'); return false;">+</button>
</div>
</div>
</div>
<button class="btn btn-brand button-save" style="display: block; width: 100%;">Simpan</button>
</form>
</div>
<!-- Form Cuci -->
<div class="tab-pane @if(old('form') == 'wash') active @endif" id="form-cuci" role="tabpanel">
<form action="{{ route('transaction.store') }}" method="POST" id="washForm">
@csrf
<input type="hidden" name="form" value="wash">
<input type="hidden" name="mechanic_id" value="{{ $mechanic->id }}">
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
<div class="form-group row">
<div class="col-6">
<label>No. SPK</label>
<input type="text" name="spk_no" class="form-control @if(old('form') == 'wash') @error('spk_no') is-invalid @enderror @endif" value="{{ old('spk_no') }}" placeholder="No. SPK" required>
@if(old('form') == 'wash')
@error('spk_no')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<label>No. Polisi</label>
<input type="text" name="police_number" class="form-control @if(old('form') == 'wash') @error('police_number') is-invalid @enderror @endif" value="{{ old('police_number') }}" placeholder="No. Polisi" required>
@if(old('form') == 'wash')
@error('police_number')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
</div>
<div class="form-group row">
<div class="col-6">
<label>Warranty</label>
<select name="warranty" class="form-control @if(old('form') == 'wash') @error('warranty') is-invalid @enderror @endif">
<option value="" @if(old('form') == 'wash') @if(old('warranty') == '' || old('warranty') == null) selected @endif @else selected @endif>Warranty</option>
<option value="1" @if(old('form') == 'wash') @if(old('warranty') == 1) selected @endif @endif>Ya</option>
<option value="0" @if(old('form') == 'wash') @if(old('warranty') == 0) selected @endif @endif>Tidak</option>
</select>
@if(old('form') == 'wash')
@error('warranty')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<label>Tanggal Pekerjaan</label>
<input type="text" id="date-wash" name="date" class="form-control @if(old('form') == 'wash') @error('date') is-invalid @enderror @endif" placeholder="Tanggal Pekerjaan" required>
@if(old('form') == 'wash')
@error('date')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
</div>
<div class="form-group mt-4">
<label>Service Advisor</label>
<select name="user_sa_id" class="form-control @if(old('form') == 'wash') @error('user_sa_id') is-invalid @enderror @endif" required>
<option value="" selected>Service Advisor</option>
@foreach ($user_sas as $user_sa)
<option @if(old('form') == 'wash') @if($user_sa->id == old('user_sa_id')) selected @enderror @endif value="{{ $user_sa->id }}">{{ $user_sa->name }}</option>
@endforeach
</select>
@if(old('form') == 'wash')
@error('user_sa_id')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<input type="hidden" name="category" value="work">
<div class="form-group">
<label>Pekerjaan</label>
<input type="text" class="form-control" disabled value="{{ $wash_work->name }}">
<input type="hidden" class="form-control" name="work_id[]" value="{{ $wash_work->id }}">
<input type="hidden" class="form-control" name="quantity[]" value="1">
</div>
<button class="btn btn-brand button-save" style="display: block; width: 100%;">Simpan</button>
</form>
</div>
<!-- Form Klaim -->
<div class="tab-pane @if(old('form') == 'claim') active @endif" id="form-claim" role="tabpanel">
<div class="mt-3">
<h6 class="mb-3">Daftar Pekerjaan yang Dapat Diklaim</h6>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="claimTransactionsTable">
<thead>
<tr>
<th>Tanggal</th>
<th>SPK</th>
<th>No Polisi</th>
<th>Pekerjaan</th>
<th>Qty</th>
<th>Service Advisor</th>
<th>Status</th>
<th>Aksi</th>
<th>Pre Check</th>
<th>Post Check</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tab Stock (pindahkan ke sini, di luar tab transaksi) -->
<div class="tab-pane" id="stock" role="tabpanel">
<!-- Sub Tabs untuk Stock, samakan dengan Transaksi -->
<ul class="nav nav-tabs nav-tabs-line nav-tabs-line-success mt-3" role="tablist">
<li class="nav-item">
<a class="nav-link @if(old('form') == 'opname') active @endif" href="#opname">Opname</a>
</li>
<li class="nav-item">
<a class="nav-link @if(old('form') == 'mutasi') active @endif" href="#mutasi">Mutasi</a>
</li>
<li class="nav-item">
<a class="nav-link @if(old('form') == 'penerimaan') active @endif" href="#penerimaan">Penerimaan Mutasi</a>
</li>
</ul>
<div class="tab-content mt-3">
<!-- Form Opname -->
<div class="tab-pane @if(old('form') == 'opname') active @endif" id="opname" role="tabpanel">
<form action="{{ route('opnames.store') }}" method="POST" id="opnameForm">
@csrf
<input type="hidden" name="form" value="opname">
<input type="hidden" name="user_id" value="{{ $mechanic->id }}">
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
<div class="form-group">
<label>Tanggal Opname <small class="text-muted">(Default: Hari ini)</small></label>
<input type="text" name="opname_date" id="date-opname" class="form-control" value="{{ old('opname_date', date('Y-m-d')) }}" placeholder="YYYY-MM-DD">
</div>
<div class="form-group">
<label>Keterangan <small class="text-muted">(Opsional)</small></label>
<textarea name="description" class="form-control" rows="3" placeholder="Keterangan opname (opsional)">{{ old('description') }}</textarea>
</div>
<!-- List Produk dengan Stock -->
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead class="thead-light">
<tr>
<th class="text-center">Produk</th>
<th class="text-center">Dealer</th>
<th class="text-center">Stock Fisik</th>
</tr>
</thead>
<tbody>
{{-- Dealer/Mechanic - Show products for current dealer only --}}
@foreach($products as $product)
@php
$stock = $product->stocks->first();
$currentStock = $stock ? $stock->quantity : 0;
@endphp
<tr>
<td class="text-center">{{ $product->name }}</td>
<td class="text-center">{{ $mechanic->dealer_name }}</td>
<td>
<input type="hidden" name="product_id[]" value="{{ $product->id }}">
<input type="hidden" name="dealer_id_stock[]" value="{{ $mechanic->dealer_id }}">
<input type="hidden" name="system_stock[]" value="{{ $currentStock }}">
<input type="number" class="form-control physical-stock" name="physical_stock[]" step="0.01" placeholder="0.00" data-system="{{ $currentStock }}" value="{{ old('physical_stock.'.$loop->index, '0.00') }}" min="0">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="mt-4 mb-3">
<button id="btn-save-opname" class="btn btn-warning btn-lg d-block w-100 mt-2">
Simpan Opname
</button>
<small class="text-muted d-block text-center mt-2">
<i class="fa fa-info-circle"></i>
Stock fisik yang kosong akan otomatis diisi dengan 0
</small>
</div>
</form>
</div>
<!-- Form Mutasi -->
<div class="tab-pane @if(old('form') == 'mutasi') active @endif" id="mutasi" role="tabpanel">
<form action="{{ route('mutations.store') }}" method="POST" id="mutasiForm">
@csrf
<input type="hidden" name="from_dealer_id" value="{{ $mechanic->dealer_id }}">
<input type="hidden" name="from_transaction_page" value="1">
<div class="form-group">
<label>Dealer Asal</label>
<input type="text" class="form-control" value="{{ $mechanic->dealer_name }}" disabled>
<small class="text-muted">Otomatis terdeteksi dari akun Anda</small>
</div>
<div class="form-group">
<label for="to_dealer_id">Dealer Tujuan </label>
<select name="to_dealer_id" id="to_dealer_id" class="form-control" required>
<option value="">Pilih Dealer Tujuan</option>
@php
$dealers = \App\Models\Dealer::where('id', '!=', $mechanic->dealer_id)->get();
@endphp
@foreach($dealers as $dealer)
<option value="{{ $dealer->id }}">{{ $dealer->name }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<div class="d-flex justify-content-between align-items-center mb-3">
<label class="form-label mb-0">Detail Produk</span></label>
<button type="button" class="btn btn-success btn-sm" id="add-product-mutasi">
<i class="fa fa-plus"></i> Tambah Produk
</button>
</div>
<div class="table-responsive">
<table class="table table-bordered table-sm" id="products-table-mutasi">
<thead>
<tr>
<th width="40%">Produk</th>
<th width="20%">Stock Tersedia</th>
<th width="25%">Quantity</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody id="products-tbody-mutasi">
<tr class="product-row-mutasi" data-index="0">
<td>
<select name="products[0][product_id]" class="form-control product-select-mutasi" required>
<option value="">Pilih Produk</option>
@foreach($products as $product)
<option value="{{ $product->id }}">{{ $product->name }}</option>
@endforeach
</select>
</td>
<td class="text-center">
<span class="available-stock-mutasi text-muted">-</span>
</td>
<td>
<input type="number"
name="products[0][quantity_requested]"
class="form-control quantity-input-mutasi"
min="0.01"
step="0.01"
placeholder="0"
required>
</td>
<td>
<button type="button" class="btn btn-danger btn-sm remove-product-mutasi" disabled>
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="mt-4 mb-3">
<button id="btn-save-mutasi" type="submit" class="btn btn-warning btn-lg d-block w-100 mt-2">
Kirim Mutasi
</button>
</div>
</form>
</div>
<!-- Tab Penerimaan Mutasi -->
<div class="tab-pane @if(old('form') == 'penerimaan') active @endif" id="penerimaan" role="tabpanel">
<div class="mt-3">
<h6 class="mb-3">Daftar Mutasi yang Perlu Diterima & Disetujui</h6>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="receiveMutationsTable">
<thead class="thead-light">
<tr>
<th width="15%">No. Mutasi</th>
<th width="20%">Dealer Asal</th>
<th width="20%">Dealer Tujuan</th>
<th width="12%">Status</th>
<th width="8%">Total Item</th>
<th width="10%">Tanggal</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<!-- Data will be loaded via DataTables AJAX -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--end::Portlet-->
</div>
</div>
<input type="hidden" name="ajax_work_url" value="{{ route('transaction.workcategory', ':id') }}">
<input type="hidden" name="mechanic_id" value="{{ $mechanic->id }}">
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
</div>
</div>
<!-- Modal Edit Transaksi -->
<div class="modal fade" id="editTransactionModal" tabindex="-1" role="dialog" aria-labelledby="editTransactionModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editTransactionModalLabel">Edit Transaksi</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form id="editTransactionForm" action="" method="POST">
@csrf
@method('PUT')
<input type="hidden" name="transaction_id" value="">
<input type="hidden" name="from_transaction_page" value="1">
<div class="modal-body">
<div class="form-group">
<label>No. SPK</label>
<input type="text" class="form-control" name="spk" placeholder="No. SPK" required>
</div>
<div class="form-group">
<label>Tanggal</label>
<input type="text" class="form-control" name="date" id="edit-transaction-date" placeholder="YYYY-MM-DD" required>
</div>
<div class="form-group">
<label>No. Polisi</label>
<input type="text" class="form-control" name="police_number" placeholder="No. Polisi" required>
</div>
<div class="form-group">
<label>Pekerjaan</label>
<select class="form-control" name="work_id" required>
<option value="" disabled>Pilih Pekerjaan</option>
@foreach ($work_works as $work)
<option value="{{ $work->id }}">{{ $work->name }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Qty</label>
<input type="number" class="form-control" name="qty" min="1" placeholder="Qty" required>
</div>
<div class="form-group">
<label>Warranty</label>
<select class="form-control" name="warranty" required>
<option value="1">Ya</option>
<option value="0">Tidak</option>
</select>
</div>
<div class="form-group">
<label>Service Advisor</label>
<select class="form-control" name="user_sa_id" required>
<option value="">Pilih Service Advisor</option>
@foreach ($user_sas as $user_sa)
<option value="{{ $user_sa->id }}">{{ $user_sa->name }}</option>
@endforeach
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-success" id="editTransactionButton">Simpan</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modal Detail Mutasi -->
<div class="modal fade" id="mutationDetailModal" tabindex="-1" role="dialog" aria-labelledby="mutationDetailModalLabel">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mutationDetailModalLabel">Detail & Penerimaan Mutasi</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form id="receiveMutationForm" action="" method="POST">
@csrf
<input type="hidden" name="from_transaction_page" value="1">
<div class="modal-body">
<div id="mutationDetailContent">
<div class="text-center">
<i class="fa fa-spinner fa-spin fa-2x"></i>
<p class="mt-2">Memuat data...</p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-success" id="receiveButton" style="display: none;">
<i class="fa fa-check"></i> Terima
</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@section('javascripts')
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
// Global variables (stock checking removed)
let dealerId = {{ $mechanic->dealer_id }};
function logout(event){
event.preventDefault();
Swal.fire({
title: 'Logout?',
text: "Anda akan keluar dari sistem!",
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#dedede',
confirmButtonText: 'Logout'
}).then((result) => {
if (result.value) {
$('#logout-form').submit();
}
})
}
function addFormField(form) {
var id = $(`.${form}_field_counter`).val();
id = parseInt(id) + 1;
$(`
<div class="form-group row" id="${form}_field${id}">
<div class="col-6">
<select name="${form}_work_id[]" id="${form}_work${id}" class="form-control">
<option selected disabled>Pekerjaan</option>
</select>
</div>
<div class="col-4">
<input type="number" class="form-control" name="${form}_quantity[]" placeholder="Qty">
</div>
<div class="col-2">
<button class="btn btn-danger" onclick="removeFormField('${form}', ${id})" style="width: 100%; opacity: 1;" id="remove${id}">X</button>
</div>
</div>
`).insertBefore($(".btn-add-field-"+form).parent().parent());
let category_id = 1;
if(form == 'wash') {
category_id = 1;
}else if(form == 'work') {
category_id = 3;
}
let ajax_work_url = $("input[name='ajax_work_url']").val()
ajax_work_url = ajax_work_url.replace(':id', category_id);
getWork(ajax_work_url, form, id)
if(id > 1) {
$(".work-btn-remove").removeAttr('disabled')
$(".work-btn-remove").removeClass("disabled")
$(".work-btn-remove").css("opacity", "1")
}
$(`.${form}_field_counter`).val(id);
}
function removeFormField(form, id) {
var attr = $(".work-btn-remove").attr('disabled');
var id = $(`.${form}_field_counter`).val();
if (typeof attr !== 'undefined' && attr !== false) {
}else{
id = parseInt(id) - 1;
$(`.${form}_field_counter`).val(id);
$(`#${form}_field${id}`).remove();
}
if(id < 2) {
$(".work-btn-remove").attr("disabled", "disabled")
$(".work-btn-remove").addClass("disabled")
$(".work-btn-remove").css("opacity", "0.5")
}
}
function getWork(ajax_work_url, form, id) {
$.get(ajax_work_url, function(res) {
var $select = $(`#${form}_work${id}`);
// Clear existing options except the first one (placeholder)
$select.find('option:not(:first)').remove();
// Add new options
$.each(res.data, function (i, item) {
$select.append($('<option>', {
value: item.id,
text : item.name
}));
});
// Ensure placeholder is still properly set
var $placeholder = $select.find('option:first');
if ($placeholder.length) {
$placeholder.prop('disabled', true).prop('selected', true).val('');
}
})
}
// Setup form fields without stock checking
function setupFormFields() {
// Ensure transaksi tab is active by default if no tab is active
if (!$('.nav-tabs-line-primary .nav-link.active').length) {
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
}
// Ensure placeholder options are properly disabled and not selectable
$('select[name="work_id[]"]').each(function() {
var $select = $(this);
var $placeholder = $select.find('option:first');
// Make sure placeholder is disabled and has empty value
if ($placeholder.length) {
$placeholder.prop('disabled', true).prop('selected', true).val('');
}
// Prevent auto-selection of first non-disabled option
$select.on('focus', function() {
if (!$(this).val()) {
$(this).find('option:first').prop('selected', true);
}
});
});
// Handle form errors - ensure work selections are maintained
@if($errors->any() && (old('form') == 'work' || old('form') == 'wash'))
// When there are form errors, ensure the correct work selections are maintained
// The old values are already handled by the Blade template in the HTML
// We just need to ensure proper placeholder handling
$('select[name="work_id[]"]').each(function() {
var $select = $(this);
// If no value is selected, ensure placeholder is selected
if (!$select.val() || $select.val() === '') {
var $placeholder = $select.find('option:first');
if ($placeholder.length) {
$placeholder.prop('selected', true);
}
}
});
// Update field counter to match the actual number of work fields when validation fails
@if(old('form') == 'work' && old('work_id'))
var actualFieldCount = $('select[name="work_id[]"]').length;
$('.work_field_counter').val(actualFieldCount);
console.log('Validation failed - updating field counter to:', actualFieldCount);
console.log('Old work_id values:', @json(old('work_id')));
@endif
@endif
}
// Function to add form fields (stock checking removed)
function addFormFieldWithStockCheck(form) {
addFormField(form); // Call original function
// Setup placeholder for new field
setTimeout(function() {
var id = $(`.${form}_field_counter`).val();
var $newSelect = $(`#${form}_work${id}`);
// Ensure placeholder is properly set
var $placeholder = $newSelect.find('option:first');
if ($placeholder.length) {
$placeholder.prop('disabled', true).prop('selected', true).val('');
}
// Prevent auto-selection of first non-disabled option
$newSelect.on('focus', function() {
if (!$(this).val()) {
$(this).find('option:first').prop('selected', true);
}
});
}, 100);
}
$("#workForm").submit(function(e) {
// Validate required fields
var spkNo = $('input[name="spk_no"]').val().trim();
var policeNumber = $('input[name="police_number"]').val().trim();
var userSaId = $('select[name="user_sa_id"]').val();
var date = $('input[name="date"]').val().trim();
var warranty = $('select[name="warranty"]').val();
var errorMessages = [];
if (!spkNo) {
errorMessages.push('No. SPK harus diisi');
$('input[name="spk_no"]').addClass('is-invalid');
} else {
$('input[name="spk_no"]').removeClass('is-invalid');
}
if (!policeNumber) {
errorMessages.push('No. Polisi harus diisi');
$('input[name="police_number"]').addClass('is-invalid');
} else {
$('input[name="police_number"]').removeClass('is-invalid');
}
if (!userSaId || userSaId === '') {
errorMessages.push('Service Advisor harus dipilih');
$('select[name="user_sa_id"]').addClass('is-invalid');
} else {
$('select[name="user_sa_id"]').removeClass('is-invalid');
}
if (!date) {
errorMessages.push('Tanggal Pekerjaan harus diisi');
$('input[name="date"]').addClass('is-invalid');
} else {
$('input[name="date"]').removeClass('is-invalid');
}
if (!warranty || warranty === '' || warranty === 'Warranty') {
errorMessages.push('Warranty harus dipilih');
$('select[name="warranty"]').addClass('is-invalid');
} else {
$('select[name="warranty"]').removeClass('is-invalid');
}
if (errorMessages.length > 0) {
e.preventDefault();
Swal.fire({
title: 'Validasi Gagal',
html: `
<div class="text-left">
<p class="mb-3">Mohon lengkapi field berikut:</p>
<ul class="text-left">
${errorMessages.map(msg => '<li>' + msg + '</li>').join('')}
</ul>
</div>
`,
icon: 'warning',
confirmButtonText: 'OK'
});
return false;
}
// Validate that at least one work is selected with valid quantity
var hasValidWorkQuantity = false;
var validCount = 0;
var emptyWorkSelects = [];
var emptyQuantityInputs = [];
$('select[name="work_id[]"]').each(function(index) {
var workId = $(this).val();
var $quantityInput = $(this).closest('.form-group').find('input[name="quantity[]"]');
var quantity = $quantityInput.val();
// Remove previous error styling
$(this).removeClass('is-invalid');
$quantityInput.removeClass('is-invalid');
// Check if this pair is valid (both work and quantity filled)
if (workId && workId !== '' && quantity && parseInt(quantity) > 0) {
hasValidWorkQuantity = true;
validCount++;
} else if (workId && workId !== '' && (!quantity || parseInt(quantity) <= 0)) {
// Work selected but no valid quantity
emptyQuantityInputs.push($quantityInput);
} else if ((!workId || workId === '') && quantity && parseInt(quantity) > 0) {
// Quantity filled but no work selected
emptyWorkSelects.push($(this));
}
});
if (!hasValidWorkQuantity) {
e.preventDefault();
// Highlight problematic fields
emptyWorkSelects.forEach(function($select) {
$select.addClass('is-invalid');
});
emptyQuantityInputs.forEach(function($input) {
$input.addClass('is-invalid');
});
var message = 'Minimal pilih satu pekerjaan dan isi quantity-nya sebelum menyimpan!';
if (emptyWorkSelects.length > 0) {
message += '\n\n• Ada quantity yang diisi tanpa memilih pekerjaan';
}
if (emptyQuantityInputs.length > 0) {
message += '\n\n• Ada pekerjaan yang dipilih tanpa mengisi quantity';
}
Swal.fire({
title: 'Peringatan Validasi',
text: message,
icon: 'warning',
confirmButtonText: 'OK'
});
return false;
}
// Show info about how many valid pairs will be saved
console.log(`Akan menyimpan ${validCount} pekerjaan`);
$(".button-save").attr("disabled", true);
$(".button-save").addClass("disabled");
return true;
})
$("#washForm").submit(function(e) {
// Validate required fields within the wash form context
var $form = $(this);
var spkNo = $form.find('input[name="spk_no"]').val();
var policeNumber = $form.find('input[name="police_number"]').val();
var userSaId = $form.find('select[name="user_sa_id"]').val();
var date = $form.find('input[name="date"]').val();
var warranty = $form.find('select[name="warranty"]').val();
var errorMessages = [];
// Reset all field error states
$form.find('input, select').removeClass('is-invalid');
if (!spkNo || spkNo.trim() === '') {
errorMessages.push('No. SPK harus diisi');
$form.find('input[name="spk_no"]').addClass('is-invalid');
}
if (!policeNumber || policeNumber.trim() === '') {
errorMessages.push('No. Polisi harus diisi');
$form.find('input[name="police_number"]').addClass('is-invalid');
}
if (!userSaId || userSaId === '' || userSaId === null) {
errorMessages.push('Service Advisor harus dipilih');
$form.find('select[name="user_sa_id"]').addClass('is-invalid');
}
if (!date || date.trim() === '') {
errorMessages.push('Tanggal Pekerjaan harus diisi');
$form.find('input[name="date"]').addClass('is-invalid');
}
if (!warranty || warranty === 'Warranty') {
errorMessages.push('Warranty harus dipilih');
$form.find('select[name="warranty"]').addClass('is-invalid');
}
if (errorMessages.length > 0) {
e.preventDefault();
Swal.fire({
title: 'Validasi Gagal',
html: `
<div class="text-left">
<p class="mb-3">Mohon lengkapi field berikut:</p>
<ul class="text-left">
${errorMessages.map(msg => '<li>' + msg + '</li>').join('')}
</ul>
</div>
`,
icon: 'warning',
confirmButtonText: 'OK'
});
// Scroll to first invalid field
var firstInvalid = $form.find('.is-invalid:first');
if (firstInvalid.length) {
$('html, body').animate({
scrollTop: firstInvalid.offset().top - 100
}, 500);
}
return false;
}
// Disable submit button to prevent double submission
$form.find(".button-save").attr("disabled", true);
$form.find(".button-save").addClass("disabled");
$form.find(".button-save").text("Menyimpan...");
return true;
})
$("#opnameForm").submit(function(e) {
e.preventDefault();
// Set default values for empty fields and validate
var hasValidStock = false;
$('.physical-stock').each(function(index) {
var value = $(this).val();
// Set default value to 0 if empty
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
value = '0.00';
}
// Validate and format the value
var numValue = parseFloat(value);
if (!isNaN(numValue) && numValue >= 0) {
hasValidStock = true;
// Ensure the value is properly formatted
$(this).val(numValue.toFixed(2));
} else {
// If invalid, set to 0
$(this).val('0.00');
hasValidStock = true; // Still consider valid since we set default
}
});
// Always allow submission since we set defaults
if (!hasValidStock) {
// This should never happen now, but just in case
resetSubmitButton();
Swal.fire({
icon: 'warning',
title: 'Peringatan',
text: 'Terjadi kesalahan dalam validasi data. Silakan coba lagi.'
});
return false;
}
// Get opname date or use today as default
var opnameDate = $('#date-opname').val();
if (!opnameDate) {
// Set default to today if empty
var today = new Date().toISOString().split('T')[0];
$('#date-opname').val(today);
opnameDate = today;
}
// Validate date format (YYYY-MM-DD)
var datePattern = /^(\d{4})-(\d{2})-(\d{2})$/;
if (!datePattern.test(opnameDate)) {
resetSubmitButton();
Swal.fire({
icon: 'warning',
title: 'Format Tanggal Salah',
text: 'Format tanggal harus YYYY-MM-DD (contoh: 2023-12-25)'
});
return false;
}
// Validate if date is valid
var dateParts = opnameDate.match(datePattern);
var year = parseInt(dateParts[1], 10);
var month = parseInt(dateParts[2], 10);
var day = parseInt(dateParts[3], 10);
var testDate = new Date(year, month - 1, day);
if (testDate.getDate() !== day || testDate.getMonth() !== (month - 1) || testDate.getFullYear() !== year) {
resetSubmitButton();
Swal.fire({
icon: 'warning',
title: 'Tanggal Tidak Valid',
text: 'Tanggal yang dimasukkan tidak valid!'
});
return false;
}
// Check if date is not in the future
var today = new Date();
today.setHours(23, 59, 59, 999); // Set to end of today
if (testDate > today) {
resetSubmitButton();
Swal.fire({
icon: 'warning',
title: 'Tanggal Tidak Valid',
text: 'Tanggal opname tidak boleh lebih dari hari ini!'
});
return false;
}
$("#btn-save-opname").attr("disabled", true);
$("#btn-save-opname").addClass("disabled");
$("#btn-save-opname").html('<i class="fa fa-spinner fa-spin"></i> Menyimpan...');
// Date format is already YYYY-MM-DD, no conversion needed
// Submit form
this.submit();
})
// Handle mutasi form submission
$(document).on('submit', '#mutasiForm', function(e) {
e.preventDefault();
// Validate form
var isValid = true;
var errorMessages = [];
// Check if dealer tujuan is selected
var dealerTujuan = $('#to_dealer_id').val();
console.log('Dealer tujuan value:', dealerTujuan);
if (!dealerTujuan || dealerTujuan === '') {
errorMessages.push('Pilih dealer tujuan');
isValid = false;
}
// Check if at least one product is selected with quantity
var hasProducts = false;
var productCount = 0;
$('.product-select-mutasi').each(function(index) {
var productId = $(this).val();
var quantity = $(this).closest('tr').find('.quantity-input-mutasi').val();
console.log(`Product ${index}:`, 'ID =', productId, 'Qty =', quantity);
if (productId && productId !== '' && quantity && parseFloat(quantity) > 0) {
hasProducts = true;
productCount++;
}
});
if (!hasProducts) {
errorMessages.push('Minimal pilih satu produk dengan quantity yang valid');
isValid = false;
}
// Additional validation: check all required fields
var requiredFields = [
{name: 'to_dealer_id', label: 'Dealer Tujuan'},
{name: 'from_dealer_id', label: 'Dealer Asal'}
];
requiredFields.forEach(function(field) {
var value = $(`[name="${field.name}"]`).val();
console.log(`${field.name} value:`, value);
if (!value || value === '') {
errorMessages.push(`${field.label} harus diisi`);
isValid = false;
}
});
// Check products array
var hasValidProduct = false;
$('select[name^="products["][name$="][product_id]"]').each(function(index) {
var productId = $(this).val();
var quantityName = $(this).attr('name').replace('[product_id]', '[quantity_requested]');
var quantity = $(`[name="${quantityName}"]`).val();
console.log(`Product validation ${index}:`, productId, quantity);
if (productId && productId !== '' && quantity && parseFloat(quantity) > 0) {
hasValidProduct = true;
}
});
if (!hasValidProduct) {
errorMessages.push('Minimal harus ada satu produk dengan quantity yang valid');
isValid = false;
}
console.log('Final validation result:', isValid);
console.log('Error messages:', errorMessages);
// Check for invalid quantities
var hasInvalidQuantity = false;
$('.quantity-input-mutasi').each(function() {
if ($(this).hasClass('is-invalid')) {
hasInvalidQuantity = true;
return false; // break loop
}
});
if (hasInvalidQuantity) {
errorMessages.push('Perbaiki quantity yang melebihi stock tersedia');
isValid = false;
}
if (!isValid) {
// Highlight invalid fields
if (!$('#to_dealer_id').val()) {
$('#to_dealer_id').addClass('is-invalid');
} else {
$('#to_dealer_id').removeClass('is-invalid');
}
// Check products
$('select[name^="products["][name$="][product_id]"]').each(function() {
var productId = $(this).val();
var quantityInput = $(this).closest('tr').find('.quantity-input-mutasi');
var quantity = quantityInput.val();
if (!productId || productId === '') {
$(this).addClass('is-invalid');
} else {
$(this).removeClass('is-invalid');
}
if (!quantity || parseFloat(quantity) <= 0) {
quantityInput.addClass('is-invalid');
} else {
quantityInput.removeClass('is-invalid');
}
});
if (typeof Swal !== 'undefined') {
Swal.fire({
icon: 'warning',
title: 'Validasi Gagal',
text: errorMessages.join(', ')
});
} else {
alert('Validasi Gagal: ' + errorMessages.join(', '));
}
return false;
}
// Show confirmation
if (typeof Swal !== 'undefined') {
Swal.fire({
title: 'Kirim Mutasi?',
text: "Mutasi akan dikirim ke dealer tujuan",
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#ffc107',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Kirim',
cancelButtonText: 'Batal'
}).then((result) => {
console.log('SweetAlert result:', result);
if (result.value === true) { // For older SweetAlert2
console.log('Confirmed, submitting...');
submitMutasiFormDirect();
}
});
} else {
// Fallback to native confirm
if (confirm('Kirim Mutasi? Mutasi akan dikirim ke dealer tujuan')) {
submitMutasiFormDirect();
}
}
})
// Initialize datepickers
function initializeDatepickers() {
$("#date-work").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
});
$("#date-wash").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
});
$("#edit-transaction-date").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
});
$("#date-opname").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true,
startDate: '-30d',
endDate: '+0d'
});
$("#date-mutasi").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
});
}
// Calculate difference for opname
$(document).on('input change keyup', '.physical-stock', function() {
var systemStock = parseFloat($(this).data('system')) || 0;
var inputValue = $(this).val();
// Handle empty input - set to 0 for calculation
var physicalStock = 0;
if (inputValue !== '' && inputValue !== null && inputValue !== undefined) {
physicalStock = parseFloat(inputValue) || 0;
}
var difference = physicalStock - systemStock;
var differenceCell = $(this).closest('tr').find('.difference');
differenceCell.text(difference.toFixed(2));
// Add color coding for difference
if (difference > 0) {
differenceCell.removeClass('text-danger').addClass('text-success');
} else if (difference < 0) {
differenceCell.removeClass('text-success').addClass('text-danger');
} else {
differenceCell.removeClass('text-success text-danger');
}
// Update product counter
updateProductCounter();
});
// Function to update product counter
function updateProductCounter() {
var totalProducts = $('.physical-stock').length;
// Update button text to show total products
var buttonText = 'Simpan Opname';
buttonText += ` (${totalProducts} produk)`;
if (!$('#btn-save-opname').hasClass('disabled')) {
$('#btn-save-opname').html(buttonText);
}
}
// Initialize default values for physical stock inputs
function initializePhysicalStock() {
$('.physical-stock').each(function() {
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
});
}
// Handle when input loses focus - set default if empty
$(document).on('blur', '.physical-stock', function() {
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
// Trigger calculation
$(this).trigger('input');
});
// Function to reset button state if validation fails
function resetSubmitButton() {
$("#btn-save-opname").attr("disabled", false);
$("#btn-save-opname").removeClass("disabled");
updateProductCounter(); // Update with current counter
}
// Set default values when user leaves field empty
$(document).on('blur', '.physical-stock', function() {
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
});
// Remove invalid styling when user starts typing in required fields
$(document).on('input', 'input[name="spk_no"], input[name="police_number"], input[name="date"]', function() {
$(this).removeClass('is-invalid');
});
$(document).on('change', 'select[name="user_sa_id"]', function() {
$(this).removeClass('is-invalid');
});
$(document).on('change', 'select[name="warranty"]', function() {
$(this).removeClass('is-invalid');
});
// Remove invalid styling from work/quantity fields when user interacts with them
$(document).on('change', 'select[name="work_id[]"]', function() {
$(this).removeClass('is-invalid');
});
$(document).on('input', 'input[name="quantity[]"]', function() {
$(this).removeClass('is-invalid');
});
// Handle server-side errors - scroll to first error and highlight
function handleServerSideErrors() {
// Set default date for opname if empty
if ($('#date-opname').val() === '') {
var today = new Date().toISOString().split('T')[0];
$('#date-opname').val(today);
}
// Initialize opname form only if opname tab is active
if ($('#opname').hasClass('active')) {
updateProductCounter();
}
// Initialize mutasi form
updateRemoveButtonsMutasi();
// Initialize select2 for mutasi form
initMutasiSelect2();
// Initialize claim table if claim tab is active
if ($('#form-claim').hasClass('active')) {
setTimeout(function() {
initClaimTransactionsTable();
}, 100);
}
// Check if we should show specific tab (after form submission)
@if(session('success') || session('error') || $errors->any())
@if(session('active_tab') == 'opname')
// Activate stock tab and opname sub-tab
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
$('.nav-link[href="#opname"]').addClass('active');
$('#opname').addClass('active');
updateProductCounter();
@elseif(session('active_tab') == 'mutasi')
// Activate stock tab and mutasi sub-tab
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
$('.nav-link[href="#mutasi"]').addClass('active');
$('#mutasi').addClass('active');
setTimeout(function() {
initMutasiSelect2();
updateRemoveButtonsMutasi();
}, 100);
@elseif(session('active_tab') == 'penerimaan')
// Activate stock tab and penerimaan sub-tab
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
$('.nav-link[href="#penerimaan"]').addClass('active');
$('#penerimaan').addClass('active');
setTimeout(function() {
initReceiveMutationsTable();
}, 100);
@elseif($errors->any() && old('form') == 'work')
// Activate transaksi tab and form kerja sub-tab when there are work form errors
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
@elseif($errors->any() && old('form') == 'wash')
// Activate transaksi tab and form cuci sub-tab when there are wash form errors
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
$('.nav-link[href="#form-cuci"]').addClass('active');
$('#form-cuci').addClass('active');
@elseif($errors->any() && old('form') == 'claim' && Auth::user()->role_id == 3)
// Activate transaksi tab and form claim sub-tab when there are claim form errors (only for mechanics)
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
$('.nav-link[href="#form-claim"]').addClass('active');
$('#form-claim').addClass('active');
@endif
@endif
// Check if there are validation errors
if ($('.is-invalid').length > 0) {
// Scroll to first error
$('html, body').animate({
scrollTop: $('.is-invalid:first').offset().top - 100
}, 500);
// Show alert for validation errors
@if(session('error'))
Swal.fire({
icon: 'error',
title: 'Terjadi Kesalahan',
text: '{{ session("error") }}',
confirmButtonText: 'OK'
});
@endif
}
// Handle success/error messages for both opname and mutasi
@if(session('success'))
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: '{{ session("success") }}',
timer: 3000,
showConfirmButton: false
}).then(() => {
// Check if this is from mutasi form (contains "Mutasi" in message)
var successMessage = '{{ session("success") }}';
var activeTab = '{{ session("active_tab") }}';
if (successMessage.toLowerCase().includes('mutasi') && (successMessage.toLowerCase().includes('berhasil dibuat') || activeTab === 'mutasi')) {
// Reset mutasi form after success for CREATING mutations
$('#mutasiForm')[0].reset();
$('#products-tbody-mutasi').html(`
<tr class="product-row-mutasi" data-index="0">
<td>
<select name="products[0][product_id]" class="form-control product-select-mutasi" required>
<option value="">Pilih Produk</option>
@foreach($products as $product)
<option value="{{ $product->id }}">{{ $product->name }}</option>
@endforeach
</select>
</td>
<td class="text-center">
<span class="available-stock-mutasi text-muted">-</span>
</td>
<td>
<input type="number"
name="products[0][quantity_requested]"
class="form-control quantity-input-mutasi"
min="0.01"
step="0.01"
placeholder="0"
required>
</td>
<td>
<button type="button" class="btn btn-danger btn-sm remove-product-mutasi" disabled>
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
`);
productIndexMutasi = 0;
updateRemoveButtonsMutasi();
// Reinitialize select2
setTimeout(function() {
initMutasiSelect2();
}, 100);
$("#btn-save-mutasi").attr("disabled", false);
$("#btn-save-mutasi").removeClass("disabled");
$("#btn-save-mutasi").html('Kirim Mutasi');
} else if (successMessage.toLowerCase().includes('penerimaan') || (successMessage.toLowerCase().includes('mutasi') && successMessage.toLowerCase().includes('diterima')) || activeTab === 'penerimaan') {
// For penerimaan mutasi, just refresh the table without resetting form
// Activate the correct tab first
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
$('.nav-link[href="#penerimaan"]').addClass('active');
$('#penerimaan').addClass('active');
// Stay on penerimaan tab and refresh table
setTimeout(function() {
if (receiveMutationsTable && $.fn.DataTable.isDataTable('#receiveMutationsTable')) {
receiveMutationsTable.ajax.reload(null, false); // Don't reset paging
} else {
// Initialize table if not already initialized
initReceiveMutationsTable();
}
}, 100);
// Close any open modals
$('#mutationDetailModal').modal('hide');
} else if (successMessage.toLowerCase().includes('disetujui') || successMessage.toLowerCase().includes('ditolak') || activeTab === 'persetujuan') {
// For approval/rejection, refresh the table
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
$('.nav-link[href="#penerimaan"]').addClass('active');
$('#penerimaan').addClass('active');
// Refresh table to show updated status
setTimeout(function() {
if (receiveMutationsTable && $.fn.DataTable.isDataTable('#receiveMutationsTable')) {
receiveMutationsTable.ajax.reload(null, false);
} else {
initReceiveMutationsTable();
}
}, 100);
} else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') {
// Reset opname form after success
$('#opnameForm')[0].reset();
// Set default values for physical stock inputs
$('.physical-stock').each(function() {
$(this).val('0.00');
});
$('.difference').text('0.00').removeClass('text-success text-danger');
$("#btn-save-opname").attr("disabled", false);
$("#btn-save-opname").removeClass("disabled");
$("#btn-save-opname").html('Simpan Opname');
// Set default date
var today = new Date().toISOString().split('T')[0];
$('#date-opname').val(today);
// Update product counter
updateProductCounter();
}
});
@endif
@if(session('error'))
Swal.fire({
icon: 'error',
title: 'Terjadi Kesalahan',
text: '{{ session("error") }}',
confirmButtonText: 'OK'
}).then(() => {
// Check if this is from opname form error
var activeTab = '{{ session("active_tab") }}';
if (activeTab === 'opname') {
// Reset button states for opname form
$("#btn-save-opname").attr("disabled", false);
$("#btn-save-opname").removeClass("disabled");
$("#btn-save-opname").html('Simpan Opname');
// Set default values for physical stock inputs
$('.physical-stock').each(function() {
if ($(this).val() === '' || $(this).val() === null || $(this).val() === undefined) {
$(this).val('0.00');
}
});
} else if (activeTab === 'mutasi') {
// Reset button states for mutasi form
$("#btn-save-mutasi").attr("disabled", false);
$("#btn-save-mutasi").removeClass("disabled");
$("#btn-save-mutasi").html('Kirim Mutasi');
}
});
@endif
// Handle validation errors
@if($errors->any())
var errorMessages = [];
@foreach($errors->all() as $error)
errorMessages.push('{{ $error }}');
@endforeach
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
html: errorMessages.join('<br>'),
confirmButtonText: 'OK'
});
@endif
}
// Handle opname date field - set default if becomes empty
$('#date-opname').on('blur', function() {
if ($(this).val() === '') {
var today = new Date().toISOString().split('T')[0];
$(this).val(today);
}
});
// Handle mutasi form - similar to create mutation
var productIndexMutasi = 0;
// Function to submit mutasi form directly
function submitMutasiFormDirect() {
console.log('=== SUBMITTING FORM ===');
// Set loading state
$("#btn-save-mutasi").attr("disabled", true);
$("#btn-save-mutasi").addClass("disabled");
$("#btn-save-mutasi").html('<i class="fa fa-spinner fa-spin"></i> Mengirim...');
// Get form element directly
var form = document.getElementById('mutasiForm');
if (!form) {
console.error('Form not found!');
alert('Form tidak ditemukan!');
return;
}
console.log('Form found:', form);
console.log('Form action:', form.action);
console.log('Form method:', form.method);
// Check form data
var formData = new FormData(form);
console.log('Form data:');
for (var pair of formData.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
// Submit form directly - simplified approach
try {
console.log('Attempting form.submit()...');
// Temporarily remove the submit event listener to prevent recursion
$(form).off('submit');
// Submit the form
form.submit();
console.log('form.submit() called successfully');
} catch (error) {
console.error('Form submission error:', error);
// Reset button if submission fails
$("#btn-save-mutasi").attr("disabled", false);
$("#btn-save-mutasi").removeClass("disabled");
$("#btn-save-mutasi").html('Kirim Mutasi');
alert('Terjadi kesalahan saat mengirim form. Silakan coba lagi.');
}
}
// Add product row for mutasi
$('#add-product-mutasi').click(function() {
productIndexMutasi++;
var newRow = `
<tr class="product-row-mutasi" data-index="${productIndexMutasi}">
<td>
<select name="products[${productIndexMutasi}][product_id]" class="form-control product-select-mutasi" required>
<option value="">Pilih Produk</option>
@foreach($products as $product)
<option value="{{ $product->id }}">{{ $product->name }}</option>
@endforeach
</select>
</td>
<td class="text-center">
<span class="available-stock-mutasi text-muted">-</span>
</td>
<td>
<input type="number"
name="products[${productIndexMutasi}][quantity_requested]"
class="form-control quantity-input-mutasi"
min="0.01"
step="0.01"
placeholder="0"
required>
</td>
<td>
<button type="button" class="btn btn-danger btn-sm remove-product-mutasi">
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
`;
$('#products-tbody-mutasi').append(newRow);
// Initialize select2 for the new product select
var newSelect = $(`select[name="products[${productIndexMutasi}][product_id]"]`);
newSelect.select2({
placeholder: 'Pilih Produk',
width: '100%',
language: {
noResults: function() {
return "Tidak ada hasil ditemukan";
},
searching: function() {
return "Mencari...";
}
}
});
updateRemoveButtonsMutasi();
});
// Remove product row for mutasi
$(document).on('click', '.remove-product-mutasi', function() {
$(this).closest('tr').remove();
updateRemoveButtonsMutasi();
});
// Update remove buttons state for mutasi
function updateRemoveButtonsMutasi() {
var rows = $('.product-row-mutasi');
if (rows.length <= 1) {
$('.remove-product-mutasi').prop('disabled', true);
} else {
$('.remove-product-mutasi').prop('disabled', false);
}
}
// Handle product selection change for mutasi - get stock info
$(document).on('change', '.product-select-mutasi', function() {
var productId = $(this).val();
var dealerId = {{ $mechanic->dealer_id }};
var stockSpan = $(this).closest('tr').find('.available-stock-mutasi');
if (productId) {
// Get stock info via AJAX
$.ajax({
url: '{{ route("mutations.get-product-stock") }}',
method: 'GET',
data: {
product_id: productId,
dealer_id: dealerId
},
success: function(response) {
stockSpan.text(parseFloat(response.current_stock).toFixed(2));
stockSpan.removeClass('text-muted').addClass('text-info');
},
error: function() {
stockSpan.text('-');
stockSpan.removeClass('text-info').addClass('text-muted');
}
});
} else {
stockSpan.text('-');
stockSpan.removeClass('text-info').addClass('text-muted');
}
});
// Validate quantity against available stock for mutasi
$(document).on('input', '.quantity-input-mutasi', function() {
var quantity = parseFloat($(this).val()) || 0;
var stockText = $(this).closest('tr').find('.available-stock-mutasi').text();
var availableStock = parseFloat(stockText) || 0;
if (quantity > availableStock && availableStock > 0) {
$(this).addClass('is-invalid');
if (!$(this).siblings('.invalid-feedback').length) {
$(this).after('<div class="invalid-feedback">Quantity melebihi stock tersedia</div>');
}
} else {
$(this).removeClass('is-invalid');
$(this).siblings('.invalid-feedback').remove();
}
});
// Remove error styling when user starts filling fields
$(document).on('change', '#to_dealer_id', function() {
$(this).removeClass('is-invalid');
});
$(document).on('change', '.product-select-mutasi', function() {
$(this).removeClass('is-invalid');
});
$(document).on('input', '.quantity-input-mutasi', function() {
if (parseFloat($(this).val()) > 0) {
$(this).removeClass('is-invalid');
}
});
// Initialize Select2 for mutasi form
function initMutasiSelect2() {
// Initialize select2 for dealer tujuan
if ($('#to_dealer_id').length && !$('#to_dealer_id').hasClass('select2-hidden-accessible')) {
$('#to_dealer_id').select2({
placeholder: 'Pilih Dealer Tujuan',
width: '100%',
language: {
noResults: function() {
return "Tidak ada hasil ditemukan";
},
searching: function() {
return "Mencari...";
}
}
});
}
// Initialize select2 for all product selects
$('.product-select-mutasi').each(function() {
if (!$(this).hasClass('select2-hidden-accessible')) {
$(this).select2({
placeholder: 'Pilih Produk',
width: '100%',
language: {
noResults: function() {
return "Tidak ada hasil ditemukan";
},
searching: function() {
return "Mencari...";
}
}
});
}
});
}
// Initialize DataTable for receive mutations
var receiveMutationsTable;
function initReceiveMutationsTable() {
if (receiveMutationsTable) {
receiveMutationsTable.destroy();
}
receiveMutationsTable = $('#receiveMutationsTable').DataTable({
processing: true,
serverSide: true,
ajax: {
url: '{{ route("mutations.get-pending-mutations") }}',
data: {
dealer_id: {{ $mechanic->dealer_id }}
}
},
columns: [
{data: 'mutation_number', name: 'mutation_number'},
{data: 'from_dealer', name: 'from_dealer'},
{data: 'to_dealer', name: 'to_dealer'},
{data: 'status', name: 'status', orderable: false},
{data: 'total_items', name: 'total_items'},
{data: 'created_at', name: 'created_at'},
{data: 'action', name: 'action', orderable: false, searchable: false}
],
pageLength: 10,
responsive: true,
scrollX: true
});
}
// Initialize DataTable for claim transactions
var claimTransactionsTable;
function initClaimTransactionsTable() {
if (claimTransactionsTable) {
claimTransactionsTable.destroy();
}
claimTransactionsTable = $('#claimTransactionsTable').DataTable({
processing: true,
serverSide: true,
ajax: {
url: '{{ route("transaction.get-claim-transactions") }}',
data: {
dealer_id: {{ $mechanic->dealer_id }}
}
},
columns: [
{data: 'date', name: 'date', title: 'Tanggal'},
{data: 'spk', name: 'spk', title: 'SPK'},
{data: 'police_number', name: 'police_number', title: 'No Polisi'},
{data: 'work_name', name: 'work_name', title: 'Pekerjaan'},
{data: 'qty', name: 'qty', title: 'Qty'},
{data: 'sa_name', name: 'sa_name', title: 'Service Advisor'},
{data: 'status', name: 'status', title: 'Status', orderable: false},
{data: 'action', name: 'action', title: 'Aksi', orderable: false, searchable: false},
{data: 'action_precheck', name: 'action_precheck', title: 'Pre Check', orderable: false, searchable: false},
{data: 'action_postcheck', name: 'action_postcheck', title: 'Post Check', orderable: false, searchable: false},
],
pageLength: 10,
responsive: true,
scrollX: true,
});
}
// Function removed since we use single table for both receive and approval mutations
// Show mutation detail modal
function showMutationDetail(mutationId) {
$('#mutationDetailModal').modal('show');
$('#mutationDetailContent').html(`
<div class="text-center">
<i class="fa fa-spinner fa-spin fa-2x"></i>
<p class="mt-2">Memuat data...</p>
</div>
`);
$('#receiveButton').hide();
// Load mutation detail via AJAX
$.ajax({
url: '{{ route("mutations.get-detail", ":id") }}'.replace(':id', mutationId),
method: 'GET',
success: function(response) {
if (response.success) {
renderMutationDetail(response.data);
} else {
$('#mutationDetailContent').html(`
<div class="alert alert-danger">
<i class="fa fa-exclamation-triangle"></i>
${response.message || 'Gagal memuat detail mutasi'}
</div>
`);
}
},
error: function(xhr) {
$('#mutationDetailContent').html(`
<div class="alert alert-danger">
<i class="fa fa-exclamation-triangle"></i>
Terjadi kesalahan saat memuat data
</div>
`);
}
});
}
// Render mutation detail in modal
function renderMutationDetail(mutation) {
var statusColor = mutation.status_color;
var statusLabel = mutation.status_label;
var isReceived = mutation.status.value === 'received';
var canBeReceived = mutation.can_be_received;
// Set form action URL
$('#receiveMutationForm').attr('action', '{{ route("mutations.receive", ":id") }}'.replace(':id', mutation.id));
// Build detail HTML
var detailHtml = `
<div class="row mb-3">
<div class="col-md-6">
<strong>No. Mutasi:</strong><br>
${mutation.mutation_number}
</div>
<div class="col-md-6">
<strong>Status:</strong><br>
<span class="font-weight-bold text-${statusColor}">${statusLabel}</span>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<strong>Dealer Asal:</strong><br>
${mutation.from_dealer.name}
</div>
<div class="col-md-6">
<strong>Tanggal:</strong><br>
${mutation.created_at_formatted}
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<strong>Dikirim oleh:</strong><br>
${mutation.requested_by ? mutation.requested_by.name : '-'}
</div>
</div>
${mutation.shipping_notes ? `
<div class="row mb-3">
<div class="col-md-12">
<strong>Catatan dari Pengirim:</strong><br>
<div class="alert alert-info mb-0">
<i class="fa fa-info-circle mr-2"></i>
${mutation.shipping_notes}
</div>
</div>
</div>
` : ''}
<hr>
<h6 class="mb-3">Detail Produk & Penerimaan:</h6>
<div class="table-responsive">
<table class="table table-bordered mutation-detail-table">
<thead>
<tr>
<th width="30%">Produk</th>
<th width="15%" class="text-center">Qty Diminta</th>
<th width="20%" class="text-center">Qty Disetujui</th>
<th width="35%">Catatan Produk</th>
</tr>
</thead>
<tbody>
`;
// Add product details with form inputs or read-only display
if (mutation.mutation_details && mutation.mutation_details.length > 0) {
mutation.mutation_details.forEach(function(detail) {
var quantityValue = detail.quantity_approved || detail.quantity_requested;
var notesValue = detail.notes || '';
detailHtml += `
<tr>
<td>${detail.product.name}</td>
<td class="text-center">
<span class="font-weight-bold text-info">${parseFloat(detail.quantity_requested).toFixed(2)}</span>
</td>
<td>
`;
if (canBeReceived && !isReceived) {
// Editable input for mutations that can be received
detailHtml += `
<input type="number"
name="products[${detail.id}][quantity_approved]"
class="form-control quantity-approved-input"
min="0"
max="${detail.quantity_requested}"
step="0.01"
value="${detail.quantity_requested}"
data-max="${detail.quantity_requested}"
placeholder="0.00">
`;
} else {
// Read-only display for received mutations
detailHtml += `
<span class="font-weight-bold ${quantityValue == detail.quantity_requested ? 'text-success' : 'text-warning'}">
${parseFloat(quantityValue).toFixed(2)}
</span>
${quantityValue != detail.quantity_requested ?
'<small class="text-muted d-block">(Sebagian)</small>' : ''}
`;
}
detailHtml += `
</td>
<td>
`;
if (canBeReceived && !isReceived) {
// Editable textarea for mutations that can be received
detailHtml += `
<textarea name="products[${detail.id}][notes]"
class="form-control"
rows="2"
placeholder="Catatan untuk produk ini...">${notesValue}</textarea>
`;
} else {
// Read-only display for received mutations
detailHtml += `
<span class="text-muted">${notesValue || '-'}</span>
`;
}
detailHtml += `
</td>
</tr>
`;
});
} else {
detailHtml += `
<tr>
<td colspan="4" class="text-center">Tidak ada detail produk</td>
</tr>
`;
}
detailHtml += `
</tbody>
</table>
</div>
<div class="row mb-3">
<div class="col-md-12">
<label for="mutationNotes"><strong>Catatan Penerimaan:</strong></label>
`;
if (canBeReceived && !isReceived) {
// Editable textarea for mutations that can be received
detailHtml += `
<textarea name="reception_notes" id="mutationNotes" class="form-control" rows="3"
placeholder="Masukkan catatan kondisi barang saat diterima (opsional)...">${mutation.reception_notes || ''}</textarea>
`;
} else {
// Read-only display for received mutations
detailHtml += `
<div class="form-control-plaintext border rounded p-2 bg-light" style="min-height: 60px;">
${mutation.reception_notes || '<em class="text-muted">Tidak ada catatan</em>'}
</div>
`;
}
detailHtml += `
</div>
</div>
`;
// Add instructions based on status
if (canBeReceived && !isReceived) {
detailHtml += `
<div class="alert alert-info mb-0">
<div class="d-flex align-items-start">
<i class="fa fa-info-circle mt-1 mr-2"></i>
<div>
<strong>Instruksi Penerimaan:</strong>
<ul class="mb-0 mt-2">
<li>Periksa kondisi fisik produk yang diterima</li>
<li>Masukkan quantity yang benar-benar diterima untuk setiap produk</li>
<li>Quantity yang disetujui tidak boleh melebihi quantity yang diminta</li>
<li>Berikan catatan jika ada produk yang rusak atau tidak sesuai</li>
</ul>
<div class="mt-2 p-2 rounded">
<small><strong>Perhatian:</strong> Setelah diterima, catatan tidak dapat diubah lagi. Pastikan informasi sudah benar sebelum menerima mutasi.</small>
</div>
</div>
</div>
</div>
`;
} else if (isReceived) {
detailHtml += `
<div class="alert alert-success mb-0">
<div class="d-flex align-items-center">
<i class="fa fa-check-circle mr-2"></i>
<div>
<strong>Status:</strong> Mutasi telah diterima dan menunggu persetujuan admin.
<br><small>Stock akan dipindahkan setelah admin menyetujui mutasi ini.</small>
</div>
</div>
</div>
`;
}
$('#mutationDetailContent').html(detailHtml);
// Show receive button only if mutation can be received
if (canBeReceived && !isReceived) {
$('#receiveButton').show();
} else {
$('#receiveButton').hide();
}
// Add validation for quantity inputs (only for editable fields)
$('.quantity-approved-input').on('input', function() {
var value = parseFloat($(this).val()) || 0;
var max = parseFloat($(this).data('max')) || 0;
if (value > max) {
$(this).addClass('is-invalid');
if (!$(this).siblings('.invalid-feedback').length) {
$(this).after('<div class="invalid-feedback">Quantity tidak boleh melebihi quantity yang diminta</div>');
}
} else {
$(this).removeClass('is-invalid');
$(this).siblings('.invalid-feedback').remove();
}
});
}
// Handle receive form submission
$('#receiveMutationForm').on('submit', function(e) {
e.preventDefault();
// Validate form
var hasInvalidInput = $('.quantity-approved-input.is-invalid').length > 0;
if (hasInvalidInput) {
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
text: 'Perbaiki quantity yang tidak valid sebelum melanjutkan'
});
return false;
}
// Check if at least one product has quantity approved > 0
var hasApprovedQuantity = false;
$('.quantity-approved-input').each(function() {
if (parseFloat($(this).val()) > 0) {
hasApprovedQuantity = true;
return false; // break loop
}
});
if (!hasApprovedQuantity) {
Swal.fire({
icon: 'warning',
title: 'Peringatan',
text: 'Minimal satu produk harus memiliki quantity yang disetujui'
});
return false;
}
if (typeof Swal !== 'undefined') {
Swal.fire({
title: 'Konfirmasi Penerimaan Mutasi',
html: `
<div class="text-left">
<p class="mb-3">Dengan menerima mutasi ini:</p>
<ul class="text-muted mb-3" style="font-size: 14px;">
<li>Anda mengkonfirmasi telah menerima produk dari dealer pengirim</li>
<li>Data quantity dan catatan yang dimasukkan akan disimpan</li>
<li>Mutasi akan masuk ke tahap persetujuan untuk memindahkan stock</li>
<li>Catatan dan data penerimaan tidak dapat diubah setelah diterima</li>
</ul>
<div class="alert alert-info">
<i class="fa fa-info-circle mr-2"></i>
<small><strong>Info:</strong> Pastikan semua data sudah benar sebelum menerima mutasi.</small>
</div>
</div>
`,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Terima Mutasi',
cancelButtonText: 'Batal',
width: '500px'
}).then((result) => {
if (result.isConfirmed) {
// Set loading state
$('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...');
// Submit form
this.submit();
}
});
} else {
if (confirm('Terima mutasi dengan data yang telah dimasukkan?')) {
$('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...');
this.submit();
}
}
});
// Functions for claim transactions
function viewTransaction(transactionId) {
// Show transaction detail modal
Swal.fire({
title: 'Detail Transaksi',
html: '<div class="text-center"><i class="fa fa-spinner fa-spin fa-2x"></i><p class="mt-2">Memuat data...</p></div>',
showConfirmButton: false,
allowOutsideClick: false
});
// Load transaction detail via AJAX
$.ajax({
url: '{{ route("transaction.edit", ":id") }}'.replace(':id', transactionId),
method: 'GET',
success: function(response) {
if (response.status === 200) {
var transaction = response.data;
Swal.fire({
title: 'Detail Transaksi',
html: `
<div class="text-left">
<div class="row mb-2">
<div class="col-6"><strong>No. SPK:</strong></div>
<div class="col-6">${transaction.spk}</div>
</div>
<div class="row mb-2">
<div class="col-6"><strong>No. Polisi:</strong></div>
<div class="col-6">${transaction.police_number}</div>
</div>
<div class="row mb-2">
<div class="col-6"><strong>Tanggal:</strong></div>
<div class="col-6">${transaction.date}</div>
</div>
<div class="row mb-2">
<div class="col-6"><strong>Quantity:</strong></div>
<div class="col-6">${transaction.qty}</div>
</div>
<div class="row mb-2">
<div class="col-6"><strong>Warranty:</strong></div>
<div class="col-6">${transaction.warranty == 1 ? 'Ya' : 'Tidak'}</div>
</div>
</div>
`,
confirmButtonText: 'Tutup'
});
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Gagal memuat detail transaksi'
});
}
},
error: function() {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Terjadi kesalahan saat memuat data'
});
}
});
}
function editTransaction(transactionId) {
// Load transaction data and show modal with form
$('#editTransactionModal').modal('show');
const url = '{{ route("transaction.edit", ":id") }}'.replace(':id', transactionId);
const action = '{{ route("transaction.update", ":id") }}'.replace(':id', transactionId);
// Reset form
const form = document.getElementById('editTransactionForm');
form.reset();
form.action = action;
form.querySelector('input[name="transaction_id"]').value = transactionId;
// Fetch data
$.get(url, function(response) {
if (response && response.status === 200 && response.data) {
const trx = response.data;
form.querySelector('input[name="spk"]').value = trx.spk || '';
form.querySelector('input[name="date"]').value = trx.date || '';
form.querySelector('input[name="police_number"]').value = trx.police_number || '';
form.querySelector('select[name="work_id"]').value = trx.work_id || '';
form.querySelector('input[name="qty"]').value = trx.qty || 1;
form.querySelector('select[name="warranty"]').value = String(trx.warranty ?? '0');
form.querySelector('select[name="user_sa_id"]').value = trx.user_sa_id || '';
} else {
Swal.fire({ icon: 'error', title: 'Error', text: 'Gagal memuat data transaksi' });
}
}).fail(function() {
Swal.fire({ icon: 'error', title: 'Error', text: 'Terjadi kesalahan saat memuat data' });
});
}
function deleteTransaction(transactionId) {
Swal.fire({
title: 'Konfirmasi Hapus',
html: '<div class="text-left">Tindakan ini tidak dapat dibatalkan.<br>Hapus transaksi ini?</div>',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: '{{ route("transaction.destroy", ":id") }}'.replace(':id', transactionId),
method: 'POST',
data: {
_method: 'DELETE',
_token: '{{ csrf_token() }}'
},
success: function(response) {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: response && response.message ? response.message : 'Transaksi berhasil dihapus',
timer: 1800,
showConfirmButton: false
}).then(() => {
if (claimTransactionsTable) {
claimTransactionsTable.ajax.reload(null, false);
}
});
},
error: function(xhr) {
const msg = (xhr.responseJSON && xhr.responseJSON.message) ? xhr.responseJSON.message : 'Gagal menghapus transaksi';
Swal.fire({ icon: 'error', title: 'Error', text: msg });
}
});
}
});
}
function claimTransaction(transactionId) {
Swal.fire({
title: 'Konfirmasi Klaim',
text: 'Apakah Anda yakin ingin mengklaim pekerjaan ini?',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Klaim!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
// Send claim request
$.ajax({
url: '{{ route("transaction.claim", ":id") }}'.replace(':id', transactionId),
method: 'POST',
data: {
_token: '{{ csrf_token() }}'
},
success: function(response) {
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: 'Pekerjaan berhasil diklaim',
timer: 2000,
showConfirmButton: false
}).then(() => {
// Refresh the table
if (claimTransactionsTable) {
claimTransactionsTable.ajax.reload();
}
// Refresh KPI progress bar
refreshKpiProgress();
});
},
error: function() {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Gagal mengklaim pekerjaan'
});
}
});
}
});
}
// Function to refresh KPI progress bar
function refreshKpiProgress() {
$.ajax({
url: '{{ route("transaction.get-kpi-data") }}',
method: 'GET',
success: function(response) {
if (response.success) {
var kpiData = response.data;
// Update target value using ID
$('#kpi-target').text(kpiData.target + ' Pekerjaan');
// Update actual value using ID and update class for color
$('#kpi-actual').text(kpiData.actual + ' Pekerjaan').removeClass().addClass('text-' + kpiData.status_color);
// Update percentage using ID and update class for color
$('#kpi-percentage').text(kpiData.percentage + '%').removeClass().addClass('text-' + kpiData.status_color + ' font-weight-bold');
// Update progress bar
var progressWidth = Math.min(100, kpiData.percentage);
$('.progress-bar').css('width', progressWidth + '%');
$('.progress-bar').attr('aria-valuenow', kpiData.percentage);
$('.progress-bar').removeClass().addClass('progress-bar bg-' + kpiData.status_color);
// Update status message
var statusMessage = '';
if (kpiData.status === 'exceeded') {
statusMessage = '<small class="text-success"><i class="fa fa-check-circle"></i> Target tercapai!</small>';
} else if (kpiData.status === 'good') {
statusMessage = '<small class="text-info"><i class="fa fa-arrow-up"></i> Performa baik</small>';
} else if (kpiData.status === 'fair') {
statusMessage = '<small class="text-warning"><i class="fa fa-exclamation-triangle"></i> Perlu peningkatan</small>';
} else if (kpiData.status === 'poor') {
statusMessage = '<small class="text-danger"><i class="fa fa-times-circle"></i> Perlu perbaikan</small>';
} else {
statusMessage = '<small class="text-secondary"><i class="fa fa-clock"></i> Belum ada data</small>';
}
$('.mt-1').html(statusMessage);
console.log('KPI Data updated:', kpiData);
}
},
error: function(xhr, status, error) {
console.log('Failed to refresh KPI data:', error);
console.log('Response:', xhr.responseText);
}
});
}
// Note: Approve and reject buttons removed from transaction page
// These actions are now only available to admin users in the admin panel
// Handle main tab switching properly (only for main tabs)
$('.nav-tabs-line-primary .nav-link').on('click', function(e) {
e.preventDefault();
var target = $(this).attr('href');
if (target) {
// Handle main tab switching
if (target === '#transaksi' || target === '#stock') {
// Remove active from all main tabs and tab panes
$('.nav-tabs-line-primary .nav-link').removeClass('active');
$('#transaksi, #stock').removeClass('active');
// Add active to clicked main tab
$(this).addClass('active');
$(target).addClass('active');
// Handle sub-tab activation based on main tab
if (target === '#transaksi') {
// Remove active from all stock sub-tabs
$('.nav-link[href="#opname"], .nav-link[href="#mutasi"], .nav-link[href="#penerimaan"]').removeClass('active');
$('#opname, #mutasi, #penerimaan').removeClass('active');
// Always activate form-kerja by default when switching to transaksi tab
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
} else if (target === '#stock') {
// Remove active from all transaksi sub-tabs
$('.nav-link[href="#form-kerja"], .nav-link[href="#form-cuci"], .nav-link[href="#form-claim"]').removeClass('active');
$('#form-kerja, #form-cuci, #form-claim').removeClass('active');
// Always activate opname by default when switching to stock tab
$('.nav-link[href="#opname"]').addClass('active');
$('#opname').addClass('active');
setTimeout(function() {
updateProductCounter();
}, 50);
}
}
}
});
function createTransaction(form) {
let work_ids;
if(form == 'work') {
work_ids = $(`select[name='${form}_work_id[]']`).map(function (idx, elem) {
return $(elem).val();
}).get();
}
if(form == 'wash') {
work_ids = $(`input[name='${form}_work_id[]']`).map(function (idx, elem) {
return $(elem).val();
}).get();
}
let quantities = $(`input[name='${form}_quantity[]']`).map(function (idx, elem) {
return $(elem).val();
}).get();
let datas = [];
for(let i = 0; i < work_ids.length; i++) {
const data = {
user_id : $("input[name='mechanic_id']").val(),
dealer_id : $("input[name='dealer_id']").val(),
form : form,
work_id : work_ids[i],
qty : quantities[i],
spk : $(`input[name='${form}_spk_no']`).val(),
police_number : $(`input[name='${form}_police_number']`).val(),
qtys : $(`input[name='${form}_quantity']`).val(),
warranty : $(`select[name='${form}_warranty']`).val(),
user_sa_id : $(`select[name='${form}_user_sa_id']`).val(),
date : $(`input[name='${form}_date']`).val(),
}
datas.push(data)
}
$.ajax({
url: $(`#${form}Form`).attr("action"),
type: "POST",
data: {
data : datas
},
success: function(res) {
document.location.reload()
}
})
}
// Ensure transaksi tab is shown by default
function initializeTabs() {
// First, ensure all tabs are properly hidden
$('#transaksi, #stock').removeClass('active');
$('.nav-tabs-line-primary .nav-link').removeClass('active');
// Check if we have specific form values from old input
@if(old('form'))
var oldForm = '{{ old("form") }}';
if (oldForm === 'work' || oldForm === 'wash' || oldForm === 'claim') {
// Activate transaksi tab and specific sub-tab
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
// Remove any active stock sub-tabs
$('.nav-link[href="#opname"], .nav-link[href="#mutasi"], .nav-link[href="#penerimaan"]').removeClass('active');
$('#opname, #mutasi, #penerimaan').removeClass('active');
if (oldForm === 'work') {
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
} else if (oldForm === 'wash') {
$('.nav-link[href="#form-cuci"]').addClass('active');
$('#form-cuci').addClass('active');
} else if (oldForm === 'claim') {
$('.nav-link[href="#form-claim"]').addClass('active');
$('#form-claim').addClass('active');
}
} else if (oldForm === 'opname' || oldForm === 'mutasi' || oldForm === 'penerimaan') {
// Activate stock tab and specific sub-tab
$('.nav-link[href="#stock"]').addClass('active');
$('#stock').addClass('active');
// Remove any active transaksi sub-tabs
$('.nav-link[href="#form-kerja"], .nav-link[href="#form-cuci"], .nav-link[href="#form-claim"]').removeClass('active');
$('#form-kerja, #form-cuci, #form-claim').removeClass('active');
if (oldForm === 'opname') {
$('.nav-link[href="#opname"]').addClass('active');
$('#opname').addClass('active');
updateProductCounter();
} else if (oldForm === 'mutasi') {
$('.nav-link[href="#mutasi"]').addClass('active');
$('#mutasi').addClass('active');
} else if (oldForm === 'penerimaan') {
$('.nav-link[href="#penerimaan"]').addClass('active');
$('#penerimaan').addClass('active');
}
}
@else
// If no tab is active, activate transaksi tab by default
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
// Activate form-kerja by default in transaksi tab
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
@endif
// Ensure at least one main tab is active
if (!$('.nav-tabs-line-primary .nav-link.active').length) {
$('.nav-link[href="#transaksi"]').addClass('active');
$('#transaksi').addClass('active');
// Ensure at least one sub-tab is active in transaksi
if (!$('#transaksi .tab-content .tab-pane.active').length) {
$('.nav-link[href="#form-kerja"]').addClass('active');
$('#form-kerja').addClass('active');
}
}
// Initialize components based on active tabs
if ($('#opname').hasClass('active') || $('#stock').hasClass('active')) {
updateProductCounter();
}
if ($('#mutasi').hasClass('active')) {
setTimeout(function() {
initMutasiSelect2();
updateRemoveButtonsMutasi();
}, 100);
}
if ($('#penerimaan').hasClass('active')) {
setTimeout(function() {
initReceiveMutationsTable();
}, 100);
}
if ($('#form-claim').hasClass('active')) {
setTimeout(function() {
initClaimTransactionsTable();
}, 100);
}
}
// Main document ready function - consolidate all initialization
$(document).ready(function() {
// Initialize all components
setupFormFields();
initializeDatepickers();
initializePhysicalStock();
handleServerSideErrors();
initializeTabs();
// Handle edit transaction form submit via AJAX
$(document).on('submit', '#editTransactionForm', function(e) {
e.preventDefault();
const form = this;
const action = form.action;
const formData = $(form).serialize();
// Disable button to prevent double submit
const $btn = $('#editTransactionButton');
$btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Menyimpan...');
$.ajax({
url: action,
method: 'POST',
data: formData,
success: function(response) {
$('#editTransactionModal').modal('hide');
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: (response && response.message) ? response.message : 'Transaksi berhasil diperbarui',
timer: 1800,
showConfirmButton: false
}).then(() => {
if (claimTransactionsTable) {
claimTransactionsTable.ajax.reload(null, false);
}
});
},
error: function(xhr) {
let msg = 'Gagal memperbarui transaksi';
if (xhr.responseJSON && xhr.responseJSON.errors) {
const errors = xhr.responseJSON.errors;
msg = Object.values(errors).flat().join('\n');
} else if (xhr.responseJSON && xhr.responseJSON.message) {
msg = xhr.responseJSON.message;
}
Swal.fire({ icon: 'error', title: 'Error', text: msg });
},
complete: function() {
$btn.prop('disabled', false).text('Simpan');
}
});
});
});
// Handle sub-tab switching for transaksi tabs
$('#transaksi .nav-tabs-line-success .nav-link').on('click', function(e) {
e.preventDefault();
var target = $(this).attr('href');
// Remove active from all transaksi sub-tabs
$('#transaksi .nav-tabs-line-success .nav-link').removeClass('active');
$('#transaksi .tab-content .tab-pane').removeClass('active');
// Add active to clicked sub-tab
$(this).addClass('active');
$(target).addClass('active');
// Initialize components based on which sub-tab is shown
if (target === '#form-claim') {
setTimeout(function() {
initClaimTransactionsTable();
}, 100);
}
});
// Handle sub-tab switching for stock tabs
$('#stock .nav-tabs-line-success .nav-link').on('click', function(e) {
e.preventDefault();
var target = $(this).attr('href');
// Remove active from all stock sub-tabs
$('#stock .nav-tabs-line-success .nav-link').removeClass('active');
$('#stock .tab-content .tab-pane').removeClass('active');
// Add active to clicked sub-tab
$(this).addClass('active');
$(target).addClass('active');
// Initialize components based on which sub-tab is shown
if (target === '#opname') {
updateProductCounter();
} else if (target === '#mutasi') {
setTimeout(function() {
initMutasiSelect2();
updateRemoveButtonsMutasi();
}, 100);
} else if (target === '#penerimaan') {
setTimeout(function() {
initReceiveMutationsTable();
}, 100);
}
});
</script>
@endsection