Files
CKB/resources/views/transaction/index.blade.php

1977 lines
93 KiB
PHP

@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: 400px;
overflow-y: auto;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.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);
}
.physical-stock.is-invalid {
border-color: #dc3545;
background-color: #fff5f5;
}
.physical-stock.is-invalid:focus {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
.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;
}
</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>
</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" data-toggle="tab" href="#transaksi">Transaksi</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" 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') == 'wash') @else active @endif" data-toggle="tab" href="#form-kerja">Form Kerja</a>
</li>
<li class="nav-item">
<a class="nav-link @if(old('form') == 'wash') active @endif" data-toggle="tab" href="#form-cuci">Form Cuci</a>
</li>
</ul>
<div class="tab-content mt-3">
<!-- Form Kerja -->
<div class="tab-pane @if(old('form') == 'wash') @else active @endif" id="form-kerja" role="tabpanel">
<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 }}">
<div class="form-group row">
<div class="col-6">
<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">
@if(old('form') == 'work')
@error('spk_no')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<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">
@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">
<select name="warranty" class="form-control @if(old('form') == 'work') @error('warranty') is-invalid @enderror @endif">
<option selected>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">
<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">
<select name="user_sa_id" class="form-control @if(old('form') == 'work') @error('user_sa_id') is-invalid @enderror @endif">
<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')
{{-- @php
dd($errors->all());
@endphp --}}
<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 selected 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 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 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 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 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 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="addFormField('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">
<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">
@if(old('form') == 'wash')
@error('spk_no')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
@endif
</div>
<div class="col-6">
<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">
@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">
<select name="warranty" class="form-control @if(old('form') == 'wash') @error('warranty') is-invalid @enderror @endif">
<option selected>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>
@error('warranty')
<span class="invalid-feedback" role="alert">
<strong>{!! $message !!}</strong>
</span>
@enderror
</div>
<div class="col-6">
<input type="text" id="date-wash" name="date" class="form-control @if(old('form') == 'wash') @error('date') is-invalid @enderror @endif" placeholder="Tanggal Pekerjaan">
@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">
<select name="user_sa_id" class="form-control @if(old('form') == 'wash') @error('user_sa_id') is-invalid @enderror @endif">
<option 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>
</div>
</div>
<!-- Tab Stock -->
<div class="tab-pane" id="stock" role="tabpanel">
<!-- Sub Tabs untuk Stock -->
<ul class="nav nav-tabs nav-tabs-line nav-tabs-line-warning mt-3" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#opname">Opname</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#mutasi">Mutasi</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#penerimaan">Penerimaan Mutasi</a>
</li>
</ul>
<div class="tab-content mt-3">
<!-- Form Opname -->
<div class="tab-pane active" 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 @error('opname_date') is-invalid @enderror" value="{{ old('opname_date', date('Y-m-d')) }}" placeholder="YYYY-MM-DD">
@error('opname_date')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
<div class="form-group">
<label>Keterangan</label>
<textarea name="description" class="form-control @error('description') is-invalid @enderror" rows="3" placeholder="Keterangan opname">{{ old('description') }}</textarea>
@error('description')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</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 Sistem</th>
<th class="text-center">Stock Fisik</th>
<th class="text-center">Selisih</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 class="text-center">
<span class="system-stock">{{ number_format($currentStock, 2) }}</span>
<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 }}">
</td>
<td>
<input type="number" class="form-control physical-stock @error('physical_stock.'.$loop->index) is-invalid @enderror" name="physical_stock[]" step="0.01" placeholder="0.00" data-system="{{ $currentStock }}" value="{{ old('physical_stock.'.$loop->index) }}">
@error('physical_stock.'.$loop->index)
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</td>
<td class="text-center">
<span class="difference text-bold">0.00</span>
</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>
</div>
</form>
</div>
<!-- Form Mutasi -->
<div class="tab-pane" 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 <span class="text-danger">*</span></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 class="text-danger">*</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" id="penerimaan" role="tabpanel">
<div class="mt-3">
<h6 class="mb-3">Daftar Mutasi yang Perlu Diterima</h6>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="receiveMutationsTable">
<thead class="thead-light">
<tr>
<th width="20%">No. Mutasi</th>
<th width="25%">Dealer Asal</th>
<th width="15%">Status</th>
<th width="10%">Total Item</th>
<th width="15%">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 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
<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 Mutasi
</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@section('javascripts')
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
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) {
$.each(res.data, function (i, item) {
$(`#${form}_work${id}`).append($('<option>', {
value: item.id,
text : item.name
}));
});
})
}
$("#workForm").submit(function(e) {
$(".button-save").attr("disabled");
$(".button-save").addClass("disabled");
return true;
})
$("#washForm").submit(function(e) {
$(".button-save").attr("disabled");
$(".button-save").addClass("disabled");
return true;
})
$("#opnameForm").submit(function(e) {
e.preventDefault();
// Save current tab to localStorage
localStorage.setItem('activeTab', '#opname');
// Validate form
var hasValidStock = false;
var invalidRows = [];
$('.physical-stock').each(function(index) {
var value = $(this).val();
var row = $(this).closest('tr');
var productName = row.find('td:first').text().trim();
// Check if value is valid (including 0)
if (value !== '' && value !== null && value !== undefined) {
var numValue = parseFloat(value);
if (!isNaN(numValue) && numValue >= 0) {
hasValidStock = true;
// Ensure the value is properly formatted
$(this).val(numValue.toFixed(2));
} else {
invalidRows.push(productName + ' (nilai tidak valid)');
}
}
// Don't remove elements here - let them stay for re-editing
});
// Show error if no valid stock entries
if (!hasValidStock) {
resetSubmitButton();
highlightInvalidFields();
Swal.fire({
icon: 'warning',
title: 'Peringatan',
text: 'Minimal harus ada satu produk dengan stock fisik yang diisi dengan benar!'
});
return false;
}
// Show error if there are invalid entries
if (invalidRows.length > 0) {
resetSubmitButton();
highlightInvalidFields();
Swal.fire({
icon: 'warning',
title: 'Data Tidak Valid',
text: 'Perbaiki data berikut: ' + invalidRows.join(', ')
});
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
// Clean up empty rows before submit (remove hidden inputs for truly empty fields only)
$('.physical-stock').each(function() {
var value = $(this).val();
var row = $(this).closest('tr');
// Only remove hidden inputs if physical stock is truly empty (not 0)
// Keep 0 values as they are valid input
if (value === '' || value === null || value === undefined) {
row.find('input[name="product_id[]"]').remove();
row.find('input[name="dealer_id_stock[]"]').remove();
row.find('input[name="system_stock[]"]').remove();
// But keep the physical_stock input so it can be re-edited if form fails
}
});
// Submit form
this.submit();
})
// Handle mutasi form submission
$(document).on('submit', '#mutasiForm', function(e) {
e.preventDefault();
// Save current tab to localStorage
localStorage.setItem('activeTab', '#mutasi');
// 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({
type: '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",
type: '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();
}
}
})
$("#date-work").datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
})
$("#date-wash").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 filledProducts = 0;
var totalProducts = $('.physical-stock').length;
$('.physical-stock').each(function() {
var value = $(this).val();
// Count as filled if it's a valid number (including 0)
if (value !== '' && value !== null && value !== undefined && !isNaN(parseFloat(value)) && parseFloat(value) >= 0) {
filledProducts++;
}
});
// Update button text to show progress
var buttonText = 'Simpan Opname';
if (filledProducts > 0) {
buttonText += ` (${filledProducts}/${totalProducts} produk)`;
}
if (!$('#btn-save-opname').hasClass('disabled')) {
$('#btn-save-opname').html(buttonText);
}
}
// Handle when input loses focus - don't auto-fill, let user decide
$(document).on('blur', '.physical-stock', function() {
// Trigger calculation even for empty values
$(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
}
// Function to show field error highlighting
function highlightInvalidFields() {
$('.physical-stock').each(function() {
var value = $(this).val();
var $input = $(this);
if (value !== '' && value !== null && value !== undefined) {
var numValue = parseFloat(value);
if (isNaN(numValue) || numValue < 0) {
$input.addClass('is-invalid');
} else {
$input.removeClass('is-invalid');
}
} else {
$input.removeClass('is-invalid');
}
});
}
// Remove error styling when user starts typing
$(document).on('input', '.physical-stock', function() {
$(this).removeClass('is-invalid');
});
// Handle server-side errors - scroll to first error and highlight
$(document).ready(function() {
// Set default date for opname if empty
if ($('#date-opname').val() === '') {
var today = new Date().toISOString().split('T')[0];
$('#date-opname').val(today);
}
// Initialize mutasi form
updateRemoveButtonsMutasi();
// 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"]').tab('show');
setTimeout(function() {
$('.nav-link[href="#opname"]').tab('show');
}, 100);
@elseif(session('active_tab') == 'mutasi')
// Activate stock tab and mutasi sub-tab
$('.nav-link[href="#stock"]').tab('show');
setTimeout(function() {
$('.nav-link[href="#mutasi"]').tab('show');
}, 100);
@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({
type: 'error',
title: 'Terjadi Kesalahan',
text: '{{ session("error") }}',
confirmButtonText: 'OK'
});
@endif
}
// Handle success/error messages for both opname and mutasi
@if(session('success'))
Swal.fire({
type: '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') || activeTab === 'mutasi') {
// Reset mutasi form after success
$('#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();
$("#btn-save-mutasi").attr("disabled", false);
$("#btn-save-mutasi").removeClass("disabled");
$("#btn-save-mutasi").html('Kirim Mutasi');
} else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') {
// Reset opname form after success
$('#opnameForm')[0].reset();
$('.physical-stock').val('').removeClass('is-invalid');
$('.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({
type: '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');
} 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({
type: '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);
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 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: '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
});
}
// 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;
// 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>
<hr>
<div class="row mb-3">
<div class="col-md-12">
<label for="mutationNotes"><strong>Catatan Penerimaan:</strong></label>
<textarea name="reception_notes" id="mutationNotes" class="form-control" rows="3" placeholder="Masukkan catatan jika diperlukan..."></textarea>
</div>
</div>
<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
if (mutation.mutation_details && mutation.mutation_details.length > 0) {
mutation.mutation_details.forEach(function(detail) {
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>
<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">
</td>
<td>
<textarea name="products[${detail.id}][notes]"
class="form-control"
rows="2"
placeholder="Catatan untuk produk ini..."></textarea>
</td>
</tr>
`;
});
} else {
detailHtml += `
<tr>
<td colspan="4" class="text-center">Tidak ada detail produk</td>
</tr>
`;
}
detailHtml += `
</tbody>
</table>
</div>
<div class="alert alert-info">
<i class="fa fa-info-circle"></i>
<strong>Petunjuk:</strong>
Masukkan quantity yang disetujui untuk setiap produk. Quantity tidak boleh melebihi quantity yang diminta.
</div>
`;
$('#mutationDetailContent').html(detailHtml);
// Show receive button if mutation can be received
if (mutation.can_be_received) {
$('#receiveButton').show();
}
// Add validation for quantity inputs
$('.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({
type: '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({
type: 'warning',
title: 'Peringatan',
text: 'Minimal satu produk harus memiliki quantity yang disetujui'
});
return false;
}
if (typeof Swal !== 'undefined') {
Swal.fire({
title: 'Terima Mutasi?',
text: "Mutasi akan diterima dengan quantity dan catatan yang telah Anda masukkan",
type: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Terima',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.value) {
// 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();
}
}
});
// Initialize table when tab is shown
$('a[href="#penerimaan"]').on('shown.bs.tab', function (e) {
setTimeout(function() {
initReceiveMutationsTable();
}, 100);
});
// Save active tab to localStorage
$('.nav-link').on('click', function() {
var target = $(this).attr('href');
if (target) {
localStorage.setItem('activeTab', target);
}
});
// Restore active tab from localStorage if no server-side active tab
$(document).ready(function() {
var serverActiveTab = '{{ session("active_tab") }}';
// Only restore from localStorage if no server-side active tab
if (!serverActiveTab) {
var savedTab = localStorage.getItem('activeTab');
if (savedTab) {
// Activate main tab first if it's a sub-tab
if (savedTab.includes('opname') || savedTab.includes('mutasi') || savedTab.includes('penerimaan')) {
$('.nav-link[href="#stock"]').tab('show');
setTimeout(function() {
$('.nav-link[href="' + savedTab + '"]').tab('show');
}, 100);
} else {
$('.nav-link[href="' + savedTab + '"]').tab('show');
}
}
}
});
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()
}
})
}
</script>
@endsection