partial update close modal on all page and disable create transaction with no stock
This commit is contained in:
@@ -25,16 +25,16 @@ class CategoryController extends Controller
|
|||||||
$data = Category::all();
|
$data = Category::all();
|
||||||
return DataTables::of($data)->addIndexColumn()
|
return DataTables::of($data)->addIndexColumn()
|
||||||
->addColumn('action', function($row) use ($menu) {
|
->addColumn('action', function($row) use ($menu) {
|
||||||
$btn = '';
|
$btn = '<div class="d-flex">';
|
||||||
|
|
||||||
if(Auth::user()->can('delete', $menu)) {
|
if(Gate::allows('update', $menu)) {
|
||||||
|
$btn .= '<button class="btn btn-warning btn-sm btn-bold mr-2" id="editCategory'. $row->id .'" data-url="'. route('category.edit', $row->id) .'" data-action="'. route('category.update', $row->id) .'" onclick="editCategory('. $row->id .')"> Edit </button>';
|
||||||
|
}
|
||||||
|
if(Gate::allows('delete', $menu)) {
|
||||||
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('category.destroy', $row->id) .'" id="destroyCategory'. $row->id .'" onclick="destroyCategory('. $row->id .')"> Hapus </button>';
|
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('category.destroy', $row->id) .'" id="destroyCategory'. $row->id .'" onclick="destroyCategory('. $row->id .')"> Hapus </button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Auth::user()->can('update', $menu)) {
|
$btn .= '</div>';
|
||||||
$btn .= '<button class="btn btn-warning btn-sm btn-bold" id="editCategory'. $row->id .'" data-url="'. route('category.edit', $row->id) .'" data-action="'. route('category.update', $row->id) .'" onclick="editCategory('. $row->id .')"> Edit </button>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $btn;
|
return $btn;
|
||||||
})
|
})
|
||||||
->rawColumns(['action'])
|
->rawColumns(['action'])
|
||||||
|
|||||||
@@ -27,27 +27,28 @@ class DealerController extends Controller
|
|||||||
$data = Dealer::leftJoin('users as u', 'u.id', '=', 'pic')->select('u.name as pic_name', 'dealers.*');
|
$data = Dealer::leftJoin('users as u', 'u.id', '=', 'pic')->select('u.name as pic_name', 'dealers.*');
|
||||||
return Datatables::of($data)->addIndexColumn()
|
return Datatables::of($data)->addIndexColumn()
|
||||||
->addColumn('action', function($row) use ($menu) {
|
->addColumn('action', function($row) use ($menu) {
|
||||||
$btn = '';
|
$btn = '<div class="d-flex">';
|
||||||
if($row->pic != null) {
|
if($row->pic != null) {
|
||||||
|
|
||||||
if(Auth::user()->can('delete', $menu)) {
|
if(Gate::allows('delete', $menu)) {
|
||||||
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('dealer.destroy', $row->id) .'" id="destroyDealer'. $row->id .'" onclick="destroyDealer('. $row->id .')"> Hapus </button>';
|
$btn .= '<button class="btn btn-danger btn-sm btn-bold mr-2" data-action="'. route('dealer.destroy', $row->id) .'" id="destroyDealer'. $row->id .'" onclick="destroyDealer('. $row->id .')"> Hapus </button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Auth::user()->can('update', $menu)) {
|
if(Gate::allows('update', $menu)) {
|
||||||
$btn .= '<button class="btn btn-warning btn-sm btn-bold" id="editDealer'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" data-action="'. route('dealer.update', $row->id) .'" onclick="editDealer('. $row->id .')"> Edit </button>';
|
$btn .= '<button class="btn btn-warning btn-sm btn-bold" id="editDealer'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" data-action="'. route('dealer.update', $row->id) .'" onclick="editDealer('. $row->id .')"> Edit </button>';
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(Auth::user()->can('delete', $menu)) {
|
if(Gate::allows('delete', $menu)) {
|
||||||
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('dealer.destroy', $row->id) .'" id="destroyDealer'. $row->id .'" onclick="destroyDealer('. $row->id .')"> Hapus </button>';
|
$btn .= '<button class="btn btn-danger btn-sm btn-bold mr-2" data-action="'. route('dealer.destroy', $row->id) .'" id="destroyDealer'. $row->id .'" onclick="destroyDealer('. $row->id .')"> Hapus </button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Auth::user()->can('update', $menu)) {
|
if(Gate::allows('update', $menu)) {
|
||||||
$btn .= '<button class="btn btn-warning btn-sm btn-bold" id="editDealer'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" data-action="'. route('dealer.update', $row->id) .'" onclick="editDealer('. $row->id .')"> Edit </button>
|
$btn .= '<button class="btn btn-warning btn-sm btn-bold mr-2" id="editDealer'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" data-action="'. route('dealer.update', $row->id) .'" onclick="editDealer('. $row->id .')"> Edit </button>
|
||||||
<button class="btn btn-success btn-sm btn-bold" data-action="'. route('dealer.picstore', $row->id) .'" id="addPic'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" onclick="addPic('. $row->id .')"> Tambahkan PIC </button>';
|
<button class="btn btn-success btn-sm btn-bold" data-action="'. route('dealer.picstore', $row->id) .'" id="addPic'. $row->id .'" data-url="'. route('dealer.edit', $row->id) .'" onclick="addPic('. $row->id .')"> Tambahkan PIC </button>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$btn .= '</div>';
|
||||||
return $btn;
|
return $btn;
|
||||||
})
|
})
|
||||||
->rawColumns(['action'])
|
->rawColumns(['action'])
|
||||||
|
|||||||
@@ -670,10 +670,66 @@ class TransactionController extends Controller
|
|||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$request['quantity'] = array_filter($request['quantity'], function($value) { return !is_null($value) && $value !== ''; });
|
// Handle different form types (work vs wash)
|
||||||
|
$isWashForm = $request->form === 'wash';
|
||||||
|
$validWorkIds = [];
|
||||||
|
$validQuantities = [];
|
||||||
|
$validPairs = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($isWashForm) {
|
||||||
|
// For wash form, work_id and quantity are already fixed
|
||||||
|
$validWorkIds = $request->work_id;
|
||||||
|
$validQuantities = $request->quantity;
|
||||||
|
|
||||||
|
// Create pairs for wash form
|
||||||
|
if (is_array($request->work_id) && is_array($request->quantity)) {
|
||||||
|
for ($i = 0; $i < count($request->work_id); $i++) {
|
||||||
|
$validPairs[] = [
|
||||||
|
'work_id' => $request->work_id[$i],
|
||||||
|
'quantity' => $request->quantity[$i],
|
||||||
|
'index' => $i
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For work form, filter out empty work/quantity pairs before validation
|
||||||
|
if ($request->work_id && $request->quantity) {
|
||||||
|
for ($i = 0; $i < count($request->work_id); $i++) {
|
||||||
|
$workId = $request->work_id[$i] ?? null;
|
||||||
|
$quantity = $request->quantity[$i] ?? null;
|
||||||
|
|
||||||
|
// Only include pairs where both work_id and quantity are filled
|
||||||
|
if (!empty($workId) && !empty($quantity) && $quantity > 0) {
|
||||||
|
$validWorkIds[] = $workId;
|
||||||
|
$validQuantities[] = $quantity;
|
||||||
|
$validPairs[] = [
|
||||||
|
'work_id' => $workId,
|
||||||
|
'quantity' => $quantity,
|
||||||
|
'index' => $i
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if at least one valid pair exists (only for work form)
|
||||||
|
if (empty($validPairs)) {
|
||||||
|
return redirect()->back()
|
||||||
|
->withErrors(['error' => 'Minimal pilih satu pekerjaan dan isi quantity-nya'])
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update request with filtered data for validation
|
||||||
|
$request->merge([
|
||||||
|
'work_id' => $validWorkIds,
|
||||||
|
'quantity' => $validQuantities
|
||||||
|
]);
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'work_id.*' => ['required', 'integer'],
|
'work_id.*' => ['required', 'integer', 'exists:works,id'],
|
||||||
'quantity.*' => ['required', 'integer'],
|
'quantity.*' => ['required', 'integer', 'min:1'],
|
||||||
'spk_no' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) {
|
'spk_no' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) {
|
||||||
// Handle date format conversion safely for validation
|
// Handle date format conversion safely for validation
|
||||||
if (strpos($request->date, '/') !== false) {
|
if (strpos($request->date, '/') !== false) {
|
||||||
@@ -734,7 +790,7 @@ class TransactionController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
'warranty' => ['required'],
|
'warranty' => ['required', 'in:0,1'],
|
||||||
'date' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) {
|
'date' => ['required', 'string', 'min:1', function($attribute, $value, $fail) use($request) {
|
||||||
// Handle date format conversion safely for validation
|
// Handle date format conversion safely for validation
|
||||||
if (strpos($value, '/') !== false) {
|
if (strpos($value, '/') !== false) {
|
||||||
@@ -774,10 +830,13 @@ class TransactionController extends Controller
|
|||||||
'police_number.min' => 'No. Polisi tidak boleh kosong',
|
'police_number.min' => 'No. Polisi tidak boleh kosong',
|
||||||
'date.required' => 'Tanggal Pekerjaan harus diisi',
|
'date.required' => 'Tanggal Pekerjaan harus diisi',
|
||||||
'date.min' => 'Tanggal Pekerjaan tidak boleh kosong',
|
'date.min' => 'Tanggal Pekerjaan tidak boleh kosong',
|
||||||
|
'warranty.required' => 'Warranty harus dipilih',
|
||||||
'user_sa_id.required' => 'Service Advisor harus dipilih',
|
'user_sa_id.required' => 'Service Advisor harus dipilih',
|
||||||
'user_sa_id.exists' => 'Service Advisor yang dipilih tidak valid',
|
'user_sa_id.exists' => 'Service Advisor yang dipilih tidak valid',
|
||||||
'work_id.*.required' => 'Pekerjaan harus dipilih',
|
'work_id.*.required' => 'Pekerjaan yang dipilih harus valid',
|
||||||
'quantity.*.required' => 'Quantity harus diisi',
|
'work_id.*.exists' => 'Pekerjaan yang dipilih tidak ditemukan',
|
||||||
|
'quantity.*.required' => 'Quantity harus diisi untuk setiap pekerjaan yang dipilih',
|
||||||
|
'quantity.*.min' => 'Quantity minimal 1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Handle date format conversion safely
|
// Handle date format conversion safely
|
||||||
@@ -796,50 +855,21 @@ class TransactionController extends Controller
|
|||||||
$request['date'] = $dateValue;
|
$request['date'] = $dateValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check stock availability for all works before creating transactions
|
// Stock checking removed - allow negative stock
|
||||||
$stockErrors = [];
|
|
||||||
for($i = 0; $i < count($request->work_id); $i++) {
|
|
||||||
$stockCheck = $this->stockService->checkStockAvailability(
|
|
||||||
$request->work_id[$i],
|
|
||||||
$request->dealer_id,
|
|
||||||
$request->quantity[$i]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$stockCheck['available']) {
|
|
||||||
$work = Work::find($request->work_id[$i]);
|
|
||||||
$stockErrors[] = "Pekerjaan '{$work->name}': {$stockCheck['message']}";
|
|
||||||
|
|
||||||
// Add detailed stock information
|
|
||||||
if (!empty($stockCheck['details'])) {
|
|
||||||
foreach ($stockCheck['details'] as $detail) {
|
|
||||||
if (!$detail['is_available']) {
|
|
||||||
$stockErrors[] = "- {$detail['product_name']}: Dibutuhkan {$detail['required_quantity']}, Tersedia {$detail['available_stock']}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are stock errors, return with error messages
|
|
||||||
if (!empty($stockErrors)) {
|
|
||||||
return redirect()->back()
|
|
||||||
->withErrors(['stock' => implode('<br>', $stockErrors)])
|
|
||||||
->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
$transactions = [];
|
$transactions = [];
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
// Create transaction records
|
// Create transaction records using filtered valid pairs
|
||||||
for($i = 0; $i < count($request->work_id); $i++) {
|
foreach($validPairs as $pair) {
|
||||||
$transactionData = [
|
$transactionData = [
|
||||||
"user_id" => $request->mechanic_id,
|
"user_id" => $request->mechanic_id,
|
||||||
"dealer_id" => $request->dealer_id,
|
"dealer_id" => $request->dealer_id,
|
||||||
"form" => $request->form,
|
"form" => $request->form,
|
||||||
"work_id" => $request->work_id[$i],
|
"work_id" => $pair['work_id'],
|
||||||
"qty" => $request->quantity[$i],
|
"qty" => $pair['quantity'],
|
||||||
"spk" => $request->spk_no,
|
"spk" => $request->spk_no,
|
||||||
"police_number" => $request->police_number,
|
"police_number" => $request->police_number,
|
||||||
"warranty" => $request->warranty,
|
"warranty" => $request->warranty,
|
||||||
|
|||||||
@@ -24,16 +24,16 @@ class UserController extends Controller
|
|||||||
return DataTables::of($data)
|
return DataTables::of($data)
|
||||||
->addIndexColumn()
|
->addIndexColumn()
|
||||||
->addColumn('action', function($row) use ($menu) {
|
->addColumn('action', function($row) use ($menu) {
|
||||||
$btn = '';
|
$btn = '<div class="d-flex">';
|
||||||
|
|
||||||
if(Auth::user()->can('delete', $menu)) {
|
if(Gate::allows('update', $menu)) {
|
||||||
|
$btn .= '<button class="btn btn-warning btn-sm btn-bold mr-2" id="editUser'. $row->id .'" data-url="'. route('user.edit', $row->id) .'" data-action="'. route('user.update', $row->id) .'" onclick="editUser('. $row->id .')"> Edit </button>';
|
||||||
|
}
|
||||||
|
if(Gate::allows('delete', $menu)) {
|
||||||
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('user.destroy', $row->id) .'" id="destroyUser'. $row->id .'" onclick="destroyUser('. $row->id .')"> Hapus </button>';
|
$btn .= '<button class="btn btn-danger btn-sm btn-bold" data-action="'. route('user.destroy', $row->id) .'" id="destroyUser'. $row->id .'" onclick="destroyUser('. $row->id .')"> Hapus </button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Auth::user()->can('update', $menu)) {
|
$btn .= '</div>';
|
||||||
$btn .= '<button class="btn btn-warning btn-sm btn-bold" id="editUser'. $row->id .'" data-url="'. route('user.edit', $row->id) .'" data-action="'. route('user.update', $row->id) .'" onclick="editUser('. $row->id .')"> Edit </button>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $btn;
|
return $btn;
|
||||||
})
|
})
|
||||||
->rawColumns(['action'])
|
->rawColumns(['action'])
|
||||||
|
|||||||
@@ -100,8 +100,13 @@ class StockAuditController extends Controller
|
|||||||
$mutationNumber = $row->source ? $row->source->mutation_number : '-';
|
$mutationNumber = $row->source ? $row->source->mutation_number : '-';
|
||||||
return "Mutasi: {$mutationNumber}";
|
return "Mutasi: {$mutationNumber}";
|
||||||
} elseif ($row->source_type === 'App\\Models\\Opname') {
|
} elseif ($row->source_type === 'App\\Models\\Opname') {
|
||||||
return "Opname";
|
$opname_id = $row->source ? $row->source->id : '-';
|
||||||
} else {
|
return "Opname: #{$opname_id}";
|
||||||
|
} elseif ($row->source_type === 'App\\Models\\Transaction')
|
||||||
|
{
|
||||||
|
$transaction_id = $row->source ? $row->source->id : '-';
|
||||||
|
return "Transaksi: #{$transaction_id}";
|
||||||
|
}else {
|
||||||
return $row->source_type ?? '-';
|
return $row->source_type ?? '-';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ use App\Models\Work;
|
|||||||
use App\Models\Transaction;
|
use App\Models\Transaction;
|
||||||
use App\Models\StockLog;
|
use App\Models\StockLog;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class StockService
|
class StockService
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Check if dealer has sufficient stock for work
|
* Check if dealer has sufficient stock for work
|
||||||
|
* Modified to always return available = true (allow negative stock)
|
||||||
*
|
*
|
||||||
* @param int $workId
|
* @param int $workId
|
||||||
* @param int $dealerId
|
* @param int $dealerId
|
||||||
@@ -25,36 +27,30 @@ class StockService
|
|||||||
|
|
||||||
if (!$work) {
|
if (!$work) {
|
||||||
return [
|
return [
|
||||||
'available' => false,
|
'available' => true,
|
||||||
'message' => 'Pekerjaan tidak ditemukan',
|
'message' => 'Pekerjaan tidak ditemukan, tapi transaksi diizinkan',
|
||||||
'details' => []
|
'details' => []
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$stockDetails = [];
|
$stockDetails = [];
|
||||||
$allAvailable = true;
|
|
||||||
|
|
||||||
foreach ($work->products as $product) {
|
foreach ($work->products as $product) {
|
||||||
$requiredQuantity = $product->pivot->quantity_required * $workQuantity;
|
$requiredQuantity = $product->pivot->quantity_required * $workQuantity;
|
||||||
$availableStock = $product->getStockByDealer($dealerId);
|
$availableStock = $product->getStockByDealer($dealerId);
|
||||||
|
|
||||||
$isAvailable = $availableStock >= $requiredQuantity;
|
|
||||||
if (!$isAvailable) {
|
|
||||||
$allAvailable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stockDetails[] = [
|
$stockDetails[] = [
|
||||||
'product_id' => $product->id,
|
'product_id' => $product->id,
|
||||||
'product_name' => $product->name,
|
'product_name' => $product->name,
|
||||||
'required_quantity' => $requiredQuantity,
|
'required_quantity' => $requiredQuantity,
|
||||||
'available_stock' => $availableStock,
|
'available_stock' => $availableStock,
|
||||||
'is_available' => $isAvailable
|
'is_available' => true // Always true - allow negative stock
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'available' => $allAvailable,
|
'available' => true, // Always return true - allow negative stock
|
||||||
'message' => $allAvailable ? 'Stock tersedia' : 'Stock tidak mencukupi',
|
'message' => 'Stock tersedia (negative stock allowed)',
|
||||||
'details' => $stockDetails
|
'details' => $stockDetails
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -68,11 +64,13 @@ class StockService
|
|||||||
*/
|
*/
|
||||||
public function reduceStockForTransaction(Transaction $transaction)
|
public function reduceStockForTransaction(Transaction $transaction)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
return DB::transaction(function () use ($transaction) {
|
return DB::transaction(function () use ($transaction) {
|
||||||
$work = $transaction->work;
|
$work = $transaction->work;
|
||||||
|
|
||||||
if (!$work) {
|
if (!$work) {
|
||||||
throw new Exception('Work not found for transaction');
|
// If work not found, just return true to allow transaction to proceed
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$work->load('products');
|
$work->load('products');
|
||||||
@@ -84,30 +82,123 @@ class StockService
|
|||||||
|
|
||||||
foreach ($work->products as $product) {
|
foreach ($work->products as $product) {
|
||||||
$requiredQuantity = $product->pivot->quantity_required * $transaction->qty;
|
$requiredQuantity = $product->pivot->quantity_required * $transaction->qty;
|
||||||
|
|
||||||
|
Log::info('Processing stock reduction', [
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'product_name' => $product->name,
|
||||||
|
'dealer_id' => $transaction->dealer_id,
|
||||||
|
'required_quantity' => $requiredQuantity,
|
||||||
|
'transaction_qty' => $transaction->qty
|
||||||
|
]);
|
||||||
|
|
||||||
$stock = Stock::where('product_id', $product->id)
|
$stock = Stock::where('product_id', $product->id)
|
||||||
->where('dealer_id', $transaction->dealer_id)
|
->where('dealer_id', $transaction->dealer_id)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (!$stock) {
|
if (!$stock) {
|
||||||
throw new Exception("Stock not found for product {$product->name} at dealer");
|
Log::info('Stock not found, creating new stock record', [
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'dealer_id' => $transaction->dealer_id
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create new stock record with 0 quantity if doesn't exist
|
||||||
|
$stock = Stock::create([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'dealer_id' => $transaction->dealer_id,
|
||||||
|
'quantity' => 0
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('New stock record created', [
|
||||||
|
'stock_id' => $stock->id,
|
||||||
|
'initial_quantity' => $stock->quantity
|
||||||
|
]);
|
||||||
|
} catch (\Exception $createException) {
|
||||||
|
Log::warning('Failed to create stock, using firstOrCreate', [
|
||||||
|
'error' => $createException->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// If creating stock fails, try to use firstOrCreate instead
|
||||||
|
$stock = Stock::firstOrCreate([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'dealer_id' => $transaction->dealer_id
|
||||||
|
], [
|
||||||
|
'quantity' => 0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log::info('Existing stock found', [
|
||||||
|
'stock_id' => $stock->id,
|
||||||
|
'current_quantity' => $stock->quantity
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($stock->quantity < $requiredQuantity) {
|
// Allow negative stock - reduce regardless of current quantity
|
||||||
throw new Exception("Insufficient stock for product {$product->name}. Required: {$requiredQuantity}, Available: {$stock->quantity}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce stock
|
|
||||||
$newQuantity = $stock->quantity - $requiredQuantity;
|
$newQuantity = $stock->quantity - $requiredQuantity;
|
||||||
|
|
||||||
|
Log::info('Updating stock quantity', [
|
||||||
|
'stock_id' => $stock->id,
|
||||||
|
'previous_quantity' => $stock->quantity,
|
||||||
|
'required_quantity' => $requiredQuantity,
|
||||||
|
'new_quantity' => $newQuantity
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
$stock->updateStock(
|
$stock->updateStock(
|
||||||
$newQuantity,
|
$newQuantity,
|
||||||
$transaction,
|
$transaction,
|
||||||
"Stock reduced for work: {$work->name} (Transaction #{$transaction->id})"
|
"Stock reduced for work: {$work->name} (Transaction #{$transaction->id}) - Allow negative stock"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Log::info('Stock update successful via updateStock method');
|
||||||
|
} catch (\Exception $updateException) {
|
||||||
|
Log::warning('updateStock method failed, using fallback', [
|
||||||
|
'error' => $updateException->getMessage()
|
||||||
|
]);
|
||||||
|
// If updateStock fails, try direct update but still create stock log
|
||||||
|
$previousQuantity = $stock->quantity;
|
||||||
|
$stock->quantity = $newQuantity;
|
||||||
|
$stock->save();
|
||||||
|
|
||||||
|
// Manually create stock log since updateStock failed
|
||||||
|
try {
|
||||||
|
$stockLog = \App\Models\StockLog::create([
|
||||||
|
'stock_id' => $stock->id,
|
||||||
|
'source_type' => get_class($transaction),
|
||||||
|
'source_id' => $transaction->id,
|
||||||
|
'previous_quantity' => $previousQuantity,
|
||||||
|
'new_quantity' => $newQuantity,
|
||||||
|
'quantity_change' => $newQuantity - $previousQuantity,
|
||||||
|
'description' => "Stock reduced for work: {$work->name} (Transaction #{$transaction->id}) - Allow negative stock (manual log)",
|
||||||
|
'user_id' => auth()->id()
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('Manual stock log created successfully', [
|
||||||
|
'stock_log_id' => $stockLog->id,
|
||||||
|
'previous_quantity' => $previousQuantity,
|
||||||
|
'new_quantity' => $newQuantity
|
||||||
|
]);
|
||||||
|
} catch (\Exception $logException) {
|
||||||
|
// Log the error but don't fail the transaction
|
||||||
|
Log::warning('Failed to create stock log: ' . $logException->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Log the error but don't throw it - allow transaction to proceed
|
||||||
|
Log::error('StockService::reduceStockForTransaction error: ' . $e->getMessage(), [
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
'work_id' => $transaction->work_id,
|
||||||
|
'dealer_id' => $transaction->dealer_id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Return true to allow transaction to proceed even if stock reduction fails
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,101 +1,112 @@
|
|||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var table = $('#kt_table').DataTable({
|
var table = $("#kt_table").DataTable({
|
||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
ajax: $("input[name='ajax_url']"),
|
ajax: $("input[name='ajax_url']"),
|
||||||
columns: [
|
columns: [
|
||||||
{data: 'name', name: 'name'},
|
{ data: "name", name: "name" },
|
||||||
{data: 'form', name: 'form'},
|
{ data: "form", name: "form" },
|
||||||
{data: 'action', name: 'action', orderable: false, searchable: false},
|
{ data: "action", name: "action", orderable: false, searchable: false },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#addCategory").click(function () {
|
||||||
$("#addCategory").click(function() {
|
$("#categoryModal").modal("show");
|
||||||
$("#categoryModal").modal("show")
|
let form_action = $("input[name='store_url']").val();
|
||||||
let form_action = $("input[name='store_url']").val()
|
$("#categoryForm").attr("action", form_action);
|
||||||
$("#categoryForm").attr('action', form_action)
|
$("#categoryForm input[name='_method']").remove();
|
||||||
$("#categoryForm input[name='_method']").remove()
|
$("#categoryForm").attr("data-form", "store");
|
||||||
$("#categoryForm").attr('data-form', 'store')
|
$("#categoryForm").trigger("reset");
|
||||||
$("#categoryForm").trigger("reset")
|
});
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
function destroyCategory(id) {
|
function destroyCategory(id) {
|
||||||
let action = $("#destroyCategory"+id).attr("data-action")
|
let action = $("#destroyCategory" + id).attr("data-action");
|
||||||
console.log(action)
|
console.log(action);
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Hapus Kategori?',
|
title: "Hapus Kategori?",
|
||||||
|
icon: "question",
|
||||||
text: "Data Pekerjaan yang terkait dengan kategori ini juga akan terhapus!",
|
text: "Data Pekerjaan yang terkait dengan kategori ini juga akan terhapus!",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#d33',
|
confirmButtonColor: "#d33",
|
||||||
cancelButtonColor: '#dedede',
|
cancelButtonColor: "#dedede",
|
||||||
confirmButtonText: 'Hapus'
|
confirmButtonText: "Hapus",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.value) {
|
if (result.value) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: action,
|
url: action,
|
||||||
type: 'POST',
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
_token: $('meta[name="csrf-token"]').attr('content'),
|
_token: $('meta[name="csrf-token"]').attr("content"),
|
||||||
_method: 'DELETE'
|
_method: "DELETE",
|
||||||
},
|
},
|
||||||
success: function(res) {
|
success: function (res) {
|
||||||
Swal.fire(
|
Swal.fire("Kategori Dihapus!");
|
||||||
'Kategori Dihapus!'
|
table.ajax.reload();
|
||||||
)
|
},
|
||||||
table.ajax.reload()
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function editCategory(id) {
|
function editCategory(id) {
|
||||||
let form_action = $("#editCategory"+id).attr("data-action")
|
let form_action = $("#editCategory" + id).attr("data-action");
|
||||||
let edit_url = $("#editCategory"+id).attr("data-url")
|
let edit_url = $("#editCategory" + id).attr("data-url");
|
||||||
$("#categoryModal").modal("show")
|
$("#categoryModal").modal("show");
|
||||||
$("#categoryForm").append('<input type="hidden" name="_method" value="PUT">')
|
$("#categoryForm").append(
|
||||||
$("#categoryForm").attr('action', form_action)
|
'<input type="hidden" name="_method" value="PUT">'
|
||||||
$("#categoryForm").attr('data-form', 'update')
|
);
|
||||||
$.get(edit_url, function(res) {
|
$("#categoryForm").attr("action", form_action);
|
||||||
$("#categoryForm input[name='name']").val(res.data.name)
|
$("#categoryForm").attr("data-form", "update");
|
||||||
$("#categoryForm option[value='"+ res.data.form +"']").prop('selected', true);
|
$.get(edit_url, function (res) {
|
||||||
})
|
$("#categoryForm input[name='name']").val(res.data.name);
|
||||||
|
$("#categoryForm option[value='" + res.data.form + "']").prop(
|
||||||
|
"selected",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#categoryForm").submit(function(e) {
|
// Add event handlers for modal close buttons
|
||||||
e.preventDefault();
|
$('.close, [data-dismiss="modal"]').on("click", function () {
|
||||||
let dataForm = $("#categoryForm").attr('data-form')
|
$("#categoryModal").modal("hide");
|
||||||
if(dataForm == 'store') {
|
});
|
||||||
$.ajax({
|
|
||||||
url: $('#categoryForm').attr("action"),
|
|
||||||
type: 'POST',
|
|
||||||
data: $('#categoryForm').serialize(),
|
|
||||||
success: function(res) {
|
|
||||||
$("#categoryModal").modal("hide")
|
|
||||||
$('#categoryForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else if(dataForm == 'update') {
|
|
||||||
$.ajax({
|
|
||||||
url: $('#categoryForm').attr("action"),
|
|
||||||
type: 'POST',
|
|
||||||
data: $('#categoryForm').serialize(),
|
|
||||||
success: function(res) {
|
|
||||||
$("#categoryModal").modal("hide")
|
|
||||||
$('#categoryForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
// Also handle the "Batal" button
|
||||||
|
$('.btn-secondary[data-dismiss="modal"]').on("click", function () {
|
||||||
|
$("#categoryModal").modal("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#categoryForm").submit(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let dataForm = $("#categoryForm").attr("data-form");
|
||||||
|
if (dataForm == "store") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#categoryForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#categoryForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#categoryModal").modal("hide");
|
||||||
|
$("#categoryForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (dataForm == "update") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#categoryForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#categoryForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#categoryModal").modal("hide");
|
||||||
|
$("#categoryForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,128 +1,136 @@
|
|||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var table = $('#kt_table').DataTable({
|
var table = $("#kt_table").DataTable({
|
||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
ajax: $("input[name='ajax_url']"),
|
ajax: $("input[name='ajax_url']"),
|
||||||
columns: [
|
columns: [
|
||||||
{data: 'dealer_code', name: 'dealer_code'},
|
{ data: "dealer_code", name: "dealer_code" },
|
||||||
{data: 'name', name: 'name'},
|
{ data: "name", name: "name" },
|
||||||
{data: 'pic_name', name: 'u.name'},
|
{ data: "pic_name", name: "u.name" },
|
||||||
{data: 'address', name: 'address'},
|
{ data: "address", name: "address" },
|
||||||
{data: 'action', name: 'action', orderable: false, searchable: false},
|
{ data: "action", name: "action", orderable: false, searchable: false },
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#addDealer").click(function () {
|
||||||
$("#addDealer").click(function() {
|
$("#dealerModal").modal("show");
|
||||||
$("#dealerModal").modal("show")
|
let form_action = $("input[name='store_url']").val();
|
||||||
let form_action = $("input[name='store_url']").val()
|
$("#dealerForm").attr("action", form_action);
|
||||||
$("#dealerForm").attr('action', form_action)
|
$("#dealerForm input[name='_method']").remove();
|
||||||
$("#dealerForm input[name='_method']").remove()
|
$("#dealerForm").attr("data-form", "store");
|
||||||
$("#dealerForm").attr('data-form', 'store')
|
$("#dealerForm").trigger("reset");
|
||||||
$("#dealerForm").trigger("reset")
|
});
|
||||||
})
|
|
||||||
|
|
||||||
function destroyDealer(id) {
|
function destroyDealer(id) {
|
||||||
let action = $("#destroyDealer"+id).attr("data-action")
|
let action = $("#destroyDealer" + id).attr("data-action");
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Hapus Dealer?',
|
title: "Hapus Dealer?",
|
||||||
text: "Data pengguna yang terkait dengan dealer ini juga akan terhapus!",
|
text: "Data pengguna yang terkait dengan dealer ini juga akan terhapus!",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#d33',
|
confirmButtonColor: "#d33",
|
||||||
cancelButtonColor: '#dedede',
|
cancelButtonColor: "#dedede",
|
||||||
confirmButtonText: 'Hapus'
|
confirmButtonText: "Hapus",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.value) {
|
if (result.value) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: action,
|
url: action,
|
||||||
type: 'POST',
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
_token: $('meta[name="csrf-token"]').attr('content'),
|
_token: $('meta[name="csrf-token"]').attr("content"),
|
||||||
_method: 'DELETE'
|
_method: "DELETE",
|
||||||
},
|
},
|
||||||
success: function(res) {
|
success: function (res) {
|
||||||
Swal.fire(
|
Swal.fire("Dealer Dihapus!");
|
||||||
'Dealer Dihapus!'
|
table.ajax.reload();
|
||||||
)
|
},
|
||||||
table.ajax.reload()
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function editDealer(id) {
|
function editDealer(id) {
|
||||||
let form_action = $("#editDealer"+id).attr("data-action")
|
let form_action = $("#editDealer" + id).attr("data-action");
|
||||||
let edit_url = $("#editDealer"+id).attr("data-url")
|
let edit_url = $("#editDealer" + id).attr("data-url");
|
||||||
$("#dealerModal").modal("show")
|
$("#dealerModal").modal("show");
|
||||||
$("#dealerForm").append('<input type="hidden" name="_method" value="PUT">')
|
$("#dealerForm").append('<input type="hidden" name="_method" value="PUT">');
|
||||||
$("#dealerForm").attr('action', form_action)
|
$("#dealerForm").attr("action", form_action);
|
||||||
$("#dealerForm").attr('data-form', 'update')
|
$("#dealerForm").attr("data-form", "update");
|
||||||
$.get(edit_url, function(res) {
|
$.get(edit_url, function (res) {
|
||||||
$("#dealerForm input[name='name']").val(res.data.name)
|
$("#dealerForm input[name='name']").val(res.data.name);
|
||||||
$("#dealerForm input[name='dealer_code']").val(res.data.dealer_code)
|
$("#dealerForm input[name='dealer_code']").val(res.data.dealer_code);
|
||||||
$("#dealerForm input[name='address']").val(res.data.address)
|
$("#dealerForm input[name='address']").val(res.data.address);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPic(id) {
|
function addPic(id) {
|
||||||
let form_action = $("#addPic"+id).attr("data-action")
|
let form_action = $("#addPic" + id).attr("data-action");
|
||||||
let edit_url = $("#addPic"+id).attr("data-url")
|
let edit_url = $("#addPic" + id).attr("data-url");
|
||||||
$("#picModal").modal("show")
|
$("#picModal").modal("show");
|
||||||
$("#picForm").append('<input type="hidden" name="_method" value="PUT">')
|
$("#picForm").append('<input type="hidden" name="_method" value="PUT">');
|
||||||
$("#picForm").attr('action', form_action)
|
$("#picForm").attr("action", form_action);
|
||||||
$.get(edit_url, function(res) {
|
$.get(edit_url, function (res) {
|
||||||
$("#picForm input[name='name']").val(res.data.name)
|
$("#picForm input[name='name']").val(res.data.name);
|
||||||
$("#picForm input[name='dealer_code']").val(res.data.dealer_code)
|
$("#picForm input[name='dealer_code']").val(res.data.dealer_code);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#picForm").submit(function(e) {
|
// Add event handlers for modal close buttons
|
||||||
e.preventDefault()
|
$('.close, [data-dismiss="modal"]').on("click", function () {
|
||||||
$.ajax({
|
$("#dealerModal").modal("hide");
|
||||||
url: $('#picForm').attr("action"),
|
$("#picModal").modal("hide");
|
||||||
type: 'POST',
|
});
|
||||||
data: {pic: $('#picForm select[name="pic_id"]').val()},
|
|
||||||
success: function(res) {
|
|
||||||
$("#picModal").modal("hide")
|
|
||||||
$('#picForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
$("#dealerForm").submit(function(e) {
|
// Also handle the "Batal" button
|
||||||
|
$('.btn-secondary[data-dismiss="modal"]').on("click", function () {
|
||||||
|
$("#dealerModal").modal("hide");
|
||||||
|
$("#picModal").modal("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#picForm").submit(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let dataForm = $("#dealerForm").attr('data-form')
|
$.ajax({
|
||||||
if(dataForm == 'store') {
|
url: $("#picForm").attr("action"),
|
||||||
$.ajax({
|
type: "POST",
|
||||||
url: $('#dealerForm').attr("action"),
|
data: { pic: $('#picForm select[name="pic_id"]').val() },
|
||||||
type: 'POST',
|
success: function (res) {
|
||||||
data: $('#dealerForm').serialize(),
|
$("#picModal").modal("hide");
|
||||||
success: function(res) {
|
$("#picForm").trigger("reset");
|
||||||
$("#dealerModal").modal("hide")
|
table.ajax.reload();
|
||||||
$('#dealerForm').trigger("reset")
|
},
|
||||||
table.ajax.reload()
|
});
|
||||||
}
|
});
|
||||||
})
|
|
||||||
}else if(dataForm == 'update') {
|
|
||||||
$.ajax({
|
|
||||||
url: $('#dealerForm').attr("action"),
|
|
||||||
type: 'POST',
|
|
||||||
data: $('#dealerForm').serialize(),
|
|
||||||
success: function(res) {
|
|
||||||
$("#dealerModal").modal("hide")
|
|
||||||
$('#dealerForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
$("#dealerForm").submit(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let dataForm = $("#dealerForm").attr("data-form");
|
||||||
|
if (dataForm == "store") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#dealerForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#dealerForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#dealerModal").modal("hide");
|
||||||
|
$("#dealerForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (dataForm == "update") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#dealerForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#dealerForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#dealerModal").modal("hide");
|
||||||
|
$("#dealerForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,105 +1,125 @@
|
|||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var table = $('#kt_table').DataTable({
|
var table = $("#kt_table").DataTable({
|
||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
ajax: $("input[name='ajax_url']").val(),
|
ajax: $("input[name='ajax_url']").val(),
|
||||||
columns: [
|
columns: [
|
||||||
{data: 'DT_RowIndex', name: 'DT_RowIndex', orderable: false, searchable: false},
|
{
|
||||||
{data: 'dealer_name', name: 'd.name'},
|
data: "DT_RowIndex",
|
||||||
{data: 'role_name', name: 'r.name'},
|
name: "DT_RowIndex",
|
||||||
{data: 'name', name: 'users.name'},
|
orderable: false,
|
||||||
{data: 'email', name: 'users.email'},
|
searchable: false,
|
||||||
{data: 'action', name: 'action', orderable: false, searchable: false},
|
},
|
||||||
]
|
{ data: "dealer_name", name: "d.name" },
|
||||||
|
{ data: "role_name", name: "r.name" },
|
||||||
|
{ data: "name", name: "users.name" },
|
||||||
|
{ data: "email", name: "users.email" },
|
||||||
|
{ data: "action", name: "action", orderable: false, searchable: false },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#addUser").click(function () {
|
||||||
$("#addUser").click(function() {
|
$("#userModal").modal("show");
|
||||||
$("#userModal").modal("show")
|
let form_action = $("input[name='store_url']").val();
|
||||||
let form_action = $("input[name='store_url']").val()
|
$("#userForm").attr("action", form_action);
|
||||||
$("#userForm").attr('action', form_action)
|
$("#userForm input[name='_method']").remove();
|
||||||
$("#userForm input[name='_method']").remove()
|
$("#userForm").attr("data-form", "store");
|
||||||
$("#userForm").attr('data-form', 'store')
|
$("#userForm").trigger("reset");
|
||||||
$("#userForm").trigger("reset")
|
$("#modalHeading").html("Tambah Pengguna");
|
||||||
$("#modalHeading").html("Tambah Pengguna")
|
});
|
||||||
})
|
|
||||||
|
|
||||||
function destroyUser(id) {
|
function destroyUser(id) {
|
||||||
let action = $("#destroyUser"+id).attr("data-action")
|
let action = $("#destroyUser" + id).attr("data-action");
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Hapus User?',
|
title: "Hapus User?",
|
||||||
|
icon: "warning",
|
||||||
text: "Semua data yang terkait dengan Pengguna ini juga akan terhapus!",
|
text: "Semua data yang terkait dengan Pengguna ini juga akan terhapus!",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#d33',
|
confirmButtonColor: "#d33",
|
||||||
cancelButtonColor: '#dedede',
|
cancelButtonColor: "#dedede",
|
||||||
confirmButtonText: 'Hapus'
|
confirmButtonText: "Hapus",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.value) {
|
if (result.value) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: action,
|
url: action,
|
||||||
type: 'POST',
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
_token: $('meta[name="csrf-token"]').attr('content'),
|
_token: $('meta[name="csrf-token"]').attr("content"),
|
||||||
_method: 'DELETE'
|
_method: "DELETE",
|
||||||
},
|
},
|
||||||
success: function(res) {
|
success: function (res) {
|
||||||
Swal.fire(
|
Swal.fire("Pengguna Dihapus!");
|
||||||
'Pengguna Dihapus!'
|
table.ajax.reload();
|
||||||
)
|
},
|
||||||
table.ajax.reload()
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function editUser(id) {
|
function editUser(id) {
|
||||||
let form_action = $("#editUser"+id).attr("data-action")
|
let form_action = $("#editUser" + id).attr("data-action");
|
||||||
let edit_url = $("#editUser"+id).attr("data-url")
|
let edit_url = $("#editUser" + id).attr("data-url");
|
||||||
$("#userModal").modal("show")
|
$("#userModal").modal("show");
|
||||||
$("#userForm").append('<input type="hidden" name="_method" value="PUT">')
|
$("#userForm").append('<input type="hidden" name="_method" value="PUT">');
|
||||||
$("#userForm").attr('action', form_action)
|
$("#userForm").attr("action", form_action);
|
||||||
$("#userForm").attr('data-form', 'update')
|
$("#userForm").attr("data-form", "update");
|
||||||
$.get(edit_url, function(res) {
|
$.get(edit_url, function (res) {
|
||||||
$("#userForm input[name='name']").val(res.data.name)
|
$("#userForm input[name='name']").val(res.data.name);
|
||||||
$("#userForm input[name='email']").val(res.data.email)
|
$("#userForm input[name='email']").val(res.data.email);
|
||||||
$("#userForm select[name='dealer_id'] option[value='"+ res.data.dealer_id +"']").prop('selected', true);
|
$(
|
||||||
$("#userForm select[name='role'] option[value='"+ res.data.role_id +"']").prop('selected', true);
|
"#userForm select[name='dealer_id'] option[value='" +
|
||||||
})
|
res.data.dealer_id +
|
||||||
|
"']"
|
||||||
|
).prop("selected", true);
|
||||||
|
$(
|
||||||
|
"#userForm select[name='role'] option[value='" +
|
||||||
|
res.data.role_id +
|
||||||
|
"']"
|
||||||
|
).prop("selected", true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#userForm").submit(function(e) {
|
// Add event handlers for modal close buttons
|
||||||
e.preventDefault();
|
$('.close, [data-dismiss="modal"]').on("click", function () {
|
||||||
let dataForm = $("#userForm").attr('data-form')
|
$("#userModal").modal("hide");
|
||||||
if(dataForm == 'store') {
|
});
|
||||||
$.ajax({
|
|
||||||
url: $('#userForm').attr("action"),
|
|
||||||
type: 'POST',
|
|
||||||
data: $('#userForm').serialize(),
|
|
||||||
success: function(res) {
|
|
||||||
$("#userModal").modal("hide")
|
|
||||||
$('#userForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else if(dataForm == 'update') {
|
|
||||||
$.ajax({
|
|
||||||
url: $('#userForm').attr("action"),
|
|
||||||
type: 'POST',
|
|
||||||
data: $('#userForm').serialize(),
|
|
||||||
success: function(res) {
|
|
||||||
$("#userModal").modal("hide")
|
|
||||||
$('#userForm').trigger("reset")
|
|
||||||
table.ajax.reload()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
// Also handle the "Batal" button
|
||||||
|
$('.btn-secondary[data-dismiss="modal"]').on("click", function () {
|
||||||
|
$("#userModal").modal("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#userForm").submit(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let dataForm = $("#userForm").attr("data-form");
|
||||||
|
if (dataForm == "store") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#userForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#userForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#userModal").modal("hide");
|
||||||
|
$("#userForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (dataForm == "update") {
|
||||||
|
$.ajax({
|
||||||
|
url: $("#userForm").attr("action"),
|
||||||
|
type: "POST",
|
||||||
|
data: $("#userForm").serialize(),
|
||||||
|
success: function (res) {
|
||||||
|
$("#userModal").modal("hide");
|
||||||
|
$("#userForm").trigger("reset");
|
||||||
|
table.ajax.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalHeading"></h5>
|
<h5 class="modal-title" id="modalHeading"></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalHeading"></h5>
|
<h5 class="modal-title" id="modalHeading"></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@@ -93,6 +94,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalHeading"></h5>
|
<h5 class="modal-title" id="modalHeading"></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|||||||
@@ -119,6 +119,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalHeading"></h5>
|
<h5 class="modal-title" id="modalHeading"></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@@ -364,6 +365,16 @@ function bulkClose(url, selected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jQuery(document).ready(function () {
|
jQuery(document).ready(function () {
|
||||||
|
// Add event handlers for modal close buttons
|
||||||
|
$('.close, [data-dismiss="modal"]').on('click', function() {
|
||||||
|
$('#transactionModal').modal('hide');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also handle the "Batal" button
|
||||||
|
$('.btn-secondary[data-dismiss="modal"]').on('click', function() {
|
||||||
|
$('#transactionModal').modal('hide');
|
||||||
|
});
|
||||||
|
|
||||||
KTBootstrapDatepicker.init();
|
KTBootstrapDatepicker.init();
|
||||||
|
|
||||||
$('#kt_search').on('click', function (e) {
|
$('#kt_search').on('click', function (e) {
|
||||||
|
|||||||
@@ -48,18 +48,14 @@
|
|||||||
<td>{{ $loop->iteration }}</td>
|
<td>{{ $loop->iteration }}</td>
|
||||||
<td>{{ $role->name }}</td>
|
<td>{{ $role->name }}</td>
|
||||||
<td>
|
<td>
|
||||||
@can('update', $menus['roleprivileges.index'])
|
<div class="d-flex">
|
||||||
<button class="btn btn-sm btn-warning" onclick="editRole({{$role->id}})"><i class="fa fa-edit"></i> Edit</button>
|
@can('update', $menus['roleprivileges.index'])
|
||||||
@endcan
|
<button class="btn btn-sm btn-bold btn-warning mr-2" onclick="editRole({{$role->id}})"> Edit</button>
|
||||||
@can('delete', $menus['roleprivileges.index'])
|
@endcan
|
||||||
<br>
|
@can('delete', $menus['roleprivileges.index'])
|
||||||
<br>
|
<button class="btn btn-sm btn-bold btn-danger" onclick="deleteRole({{$role->id}}, '{{$role->name}}')">Hapus</button>
|
||||||
<form action="{{ route('roleprivileges.delete', $role->id) }}" method="post" onsubmit="return confirm('Anda akan menghapus role {{ $role->name }}?');">
|
@endcan
|
||||||
@csrf
|
</div>
|
||||||
@method('DELETE')
|
|
||||||
<button type="submit" class="btn btn-sm btn-danger"><i class="fa fa-trash"></i> Hapus</button>
|
|
||||||
</form>
|
|
||||||
@endcan
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
@@ -191,6 +187,41 @@
|
|||||||
|
|
||||||
@section('javascripts')
|
@section('javascripts')
|
||||||
<script>
|
<script>
|
||||||
|
function deleteRole(id, name) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Hapus Role?',
|
||||||
|
text: `Anda akan menghapus role ${name}?`,
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#d33',
|
||||||
|
cancelButtonColor: '#6c757d',
|
||||||
|
confirmButtonText: 'Ya, Hapus!',
|
||||||
|
cancelButtonText: 'Batal'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
// Create form and submit
|
||||||
|
let form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = '{{ route("roleprivileges.delete", ":id") }}'.replace(':id', id);
|
||||||
|
|
||||||
|
let csrfToken = document.createElement('input');
|
||||||
|
csrfToken.type = 'hidden';
|
||||||
|
csrfToken.name = '_token';
|
||||||
|
csrfToken.value = '{{ csrf_token() }}';
|
||||||
|
|
||||||
|
let methodField = document.createElement('input');
|
||||||
|
methodField.type = 'hidden';
|
||||||
|
methodField.name = '_method';
|
||||||
|
methodField.value = 'DELETE';
|
||||||
|
|
||||||
|
form.appendChild(csrfToken);
|
||||||
|
form.appendChild(methodField);
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function editRole(id) {
|
function editRole(id) {
|
||||||
let url = '{{ route("roleprivileges.edit", ":id") }}'
|
let url = '{{ route("roleprivileges.edit", ":id") }}'
|
||||||
url = url.replace(':id', id);
|
url = url.replace(':id', id);
|
||||||
@@ -265,5 +296,18 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
// Add event handlers for modal close buttons
|
||||||
|
$('.close, [data-dismiss="modal"]').on("click", function () {
|
||||||
|
$("#roleModal").modal("hide");
|
||||||
|
$("#roleEditModal").modal("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also handle the "Close" button
|
||||||
|
$('.btn-secondary[data-dismiss="modal"]').on("click", function () {
|
||||||
|
$("#roleModal").modal("hide");
|
||||||
|
$("#roleEditModal").modal("hide");
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalHeading"></h5>
|
<h5 class="modal-title" id="modalHeading"></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|||||||
@@ -87,14 +87,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
|
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 {
|
.quantity-input-mutasi.is-invalid {
|
||||||
border-color: #dc3545;
|
border-color: #dc3545;
|
||||||
background-color: #fff5f5;
|
background-color: #fff5f5;
|
||||||
@@ -424,16 +417,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
<input type="hidden" name="mechanic_id" value="{{ $mechanic->id }}">
|
<input type="hidden" name="mechanic_id" value="{{ $mechanic->id }}">
|
||||||
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
|
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
|
||||||
|
|
||||||
<!-- Stock Error Display -->
|
|
||||||
@if($errors->has('stock'))
|
|
||||||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
|
||||||
<strong><i class="fa fa-exclamation-triangle"></i> Peringatan Stock:</strong>
|
|
||||||
<br>{!! $errors->first('stock') !!}
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if($errors->has('error'))
|
@if($errors->has('error'))
|
||||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
@@ -473,7 +457,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<label>Warranty</label>
|
<label>Warranty</label>
|
||||||
<select name="warranty" class="form-control @if(old('form') == 'work') @error('warranty') is-invalid @enderror @endif">
|
<select name="warranty" class="form-control @if(old('form') == 'work') @error('warranty') is-invalid @enderror @endif">
|
||||||
<option selected>Warranty</option>
|
<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="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>
|
<option value="0" @if(old('form') == 'work') @if(old('warranty') == 0) selected @endif @endif>Tidak</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -676,15 +660,17 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<label>Warranty</label>
|
<label>Warranty</label>
|
||||||
<select name="warranty" class="form-control @if(old('form') == 'wash') @error('warranty') is-invalid @enderror @endif">
|
<select name="warranty" class="form-control @if(old('form') == 'wash') @error('warranty') is-invalid @enderror @endif">
|
||||||
<option selected>Warranty</option>
|
<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="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>
|
<option value="0" @if(old('form') == 'wash') @if(old('warranty') == 0) selected @endif @endif>Tidak</option>
|
||||||
</select>
|
</select>
|
||||||
|
@if(old('form') == 'wash')
|
||||||
@error('warranty')
|
@error('warranty')
|
||||||
<span class="invalid-feedback" role="alert">
|
<span class="invalid-feedback" role="alert">
|
||||||
<strong>{!! $message !!}</strong>
|
<strong>{!! $message !!}</strong>
|
||||||
</span>
|
</span>
|
||||||
@enderror
|
@enderror
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<label>Tanggal Pekerjaan</label>
|
<label>Tanggal Pekerjaan</label>
|
||||||
@@ -988,112 +974,8 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Global variables for stock checking
|
// Global variables (stock checking removed)
|
||||||
let dealerId = {{ $mechanic->dealer_id }};
|
let dealerId = {{ $mechanic->dealer_id }};
|
||||||
let stockWarnings = {};
|
|
||||||
|
|
||||||
// Function to check stock availability for selected work
|
|
||||||
function checkStockAvailability(workId, quantity, callback) {
|
|
||||||
if (!workId || !quantity || quantity < 1) {
|
|
||||||
if (callback) callback(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "{{ route('transaction.check-stock') }}",
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
work_id: workId,
|
|
||||||
dealer_id: dealerId,
|
|
||||||
quantity: quantity,
|
|
||||||
_token: $('meta[name="csrf-token"]').attr('content')
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
if (callback) callback(response.data);
|
|
||||||
},
|
|
||||||
error: function(xhr) {
|
|
||||||
console.error('Error checking stock:', xhr);
|
|
||||||
if (callback) callback(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to display stock warning
|
|
||||||
function displayStockWarning(fieldId, stockData) {
|
|
||||||
// Remove existing warning
|
|
||||||
$(`#stock-warning-${fieldId}`).remove();
|
|
||||||
|
|
||||||
if (!stockData || stockData.available) {
|
|
||||||
return; // No warning needed
|
|
||||||
}
|
|
||||||
|
|
||||||
let warningHtml = `
|
|
||||||
<div id="stock-warning-${fieldId}" class="alert alert-warning mt-2 mb-0" style="font-size: 12px;">
|
|
||||||
<strong><i class="fa fa-exclamation-triangle"></i> Peringatan Stock:</strong> ${stockData.message}
|
|
||||||
<ul class="mb-0 mt-1" style="font-size: 11px;">
|
|
||||||
`;
|
|
||||||
|
|
||||||
stockData.details.forEach(function(detail) {
|
|
||||||
if (!detail.is_available) {
|
|
||||||
warningHtml += `
|
|
||||||
<li>${detail.product_name}: Butuh ${detail.required_quantity}, Tersedia ${detail.available_stock}</li>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
warningHtml += `
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
$(`#work_field${fieldId.replace('work_work', '')}`).append(warningHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle work selection change
|
|
||||||
function handleWorkSelectionChange(selectElement) {
|
|
||||||
let workId = $(selectElement).val();
|
|
||||||
let fieldId = $(selectElement).attr('id');
|
|
||||||
let quantityInput = $(selectElement).closest('.form-group').find('input[name="quantity[]"]');
|
|
||||||
let quantity = parseInt(quantityInput.val()) || 1;
|
|
||||||
|
|
||||||
if (workId) {
|
|
||||||
checkStockAvailability(workId, quantity, function(stockData) {
|
|
||||||
displayStockWarning(fieldId, stockData);
|
|
||||||
|
|
||||||
// Store warning data for form submission validation
|
|
||||||
if (stockData && !stockData.available) {
|
|
||||||
stockWarnings[fieldId] = stockData;
|
|
||||||
} else {
|
|
||||||
delete stockWarnings[fieldId];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Remove warning when no work selected
|
|
||||||
$(`#stock-warning-${fieldId}`).remove();
|
|
||||||
delete stockWarnings[fieldId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle quantity change
|
|
||||||
function handleQuantityChange(quantityInput) {
|
|
||||||
let workSelect = $(quantityInput).closest('.form-group').find('select[name="work_id[]"]');
|
|
||||||
let workId = workSelect.val();
|
|
||||||
let quantity = parseInt($(quantityInput).val()) || 1;
|
|
||||||
|
|
||||||
if (workId && quantity > 0) {
|
|
||||||
let fieldId = workSelect.attr('id');
|
|
||||||
checkStockAvailability(workId, quantity, function(stockData) {
|
|
||||||
displayStockWarning(fieldId, stockData);
|
|
||||||
|
|
||||||
// Store warning data for form submission validation
|
|
||||||
if (stockData && !stockData.available) {
|
|
||||||
stockWarnings[fieldId] = stockData;
|
|
||||||
} else {
|
|
||||||
delete stockWarnings[fieldId];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logout(event){
|
function logout(event){
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -1191,24 +1073,8 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add event listeners for existing fields
|
// Setup form fields without stock checking
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Initial fields (work1, work2, etc.)
|
|
||||||
$('select[name="work_id[]"]').on('change', function() {
|
|
||||||
handleWorkSelectionChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('input[name="quantity[]"]').on('input', function() {
|
|
||||||
handleQuantityChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check stock for pre-filled fields
|
|
||||||
$('select[name="work_id[]"]').each(function() {
|
|
||||||
if ($(this).val()) {
|
|
||||||
handleWorkSelectionChange(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure placeholder options are properly disabled and not selectable
|
// Ensure placeholder options are properly disabled and not selectable
|
||||||
$('select[name="work_id[]"]').each(function() {
|
$('select[name="work_id[]"]').each(function() {
|
||||||
var $select = $(this);
|
var $select = $(this);
|
||||||
@@ -1241,19 +1107,24 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
if ($placeholder.length) {
|
if ($placeholder.length) {
|
||||||
$placeholder.prop('selected', true);
|
$placeholder.prop('selected', true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Trigger change event to update any dependent fields
|
|
||||||
$select.trigger('change');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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
|
@endif
|
||||||
});
|
});
|
||||||
|
|
||||||
// Override addFormField function to include event listeners
|
// Function to add form fields (stock checking removed)
|
||||||
function addFormFieldWithStockCheck(form) {
|
function addFormFieldWithStockCheck(form) {
|
||||||
addFormField(form); // Call original function
|
addFormField(form); // Call original function
|
||||||
|
|
||||||
// Add event listeners to new field
|
// Setup placeholder for new field
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var id = $(`.${form}_field_counter`).val();
|
var id = $(`.${form}_field_counter`).val();
|
||||||
var $newSelect = $(`#${form}_work${id}`);
|
var $newSelect = $(`#${form}_work${id}`);
|
||||||
@@ -1264,14 +1135,6 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
$placeholder.prop('disabled', true).prop('selected', true).val('');
|
$placeholder.prop('disabled', true).prop('selected', true).val('');
|
||||||
}
|
}
|
||||||
|
|
||||||
$newSelect.on('change', function() {
|
|
||||||
handleWorkSelectionChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
$newSelect.closest('.form-group').find('input[name="quantity[]"]').on('input', function() {
|
|
||||||
handleQuantityChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Prevent auto-selection of first non-disabled option
|
// Prevent auto-selection of first non-disabled option
|
||||||
$newSelect.on('focus', function() {
|
$newSelect.on('focus', function() {
|
||||||
if (!$(this).val()) {
|
if (!$(this).val()) {
|
||||||
@@ -1287,6 +1150,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
var policeNumber = $('input[name="police_number"]').val().trim();
|
var policeNumber = $('input[name="police_number"]').val().trim();
|
||||||
var userSaId = $('select[name="user_sa_id"]').val();
|
var userSaId = $('select[name="user_sa_id"]').val();
|
||||||
var date = $('input[name="date"]').val().trim();
|
var date = $('input[name="date"]').val().trim();
|
||||||
|
var warranty = $('select[name="warranty"]').val();
|
||||||
|
|
||||||
var errorMessages = [];
|
var errorMessages = [];
|
||||||
|
|
||||||
@@ -1318,6 +1182,13 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
$('input[name="date"]').removeClass('is-invalid');
|
$('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) {
|
if (errorMessages.length > 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
@@ -1336,68 +1207,66 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that at least one work is selected
|
// Validate that at least one work is selected with valid quantity
|
||||||
var hasSelectedWork = false;
|
var hasValidWorkQuantity = false;
|
||||||
$('select[name="work_id[]"]').each(function() {
|
var validCount = 0;
|
||||||
if ($(this).val() && $(this).val() !== '') {
|
var emptyWorkSelects = [];
|
||||||
hasSelectedWork = true;
|
var emptyQuantityInputs = [];
|
||||||
return false; // break loop
|
|
||||||
|
$('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 (!hasSelectedWork) {
|
if (!hasValidWorkQuantity) {
|
||||||
e.preventDefault();
|
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({
|
Swal.fire({
|
||||||
title: 'Peringatan',
|
title: 'Peringatan Validasi',
|
||||||
text: 'Minimal pilih satu pekerjaan sebelum menyimpan!',
|
text: message,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: 'OK'
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are stock warnings
|
// Show info about how many valid pairs will be saved
|
||||||
if (Object.keys(stockWarnings).length > 0) {
|
console.log(`Akan menyimpan ${validCount} pekerjaan`);
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
let warningMessages = [];
|
|
||||||
Object.values(stockWarnings).forEach(function(warning) {
|
|
||||||
warningMessages.push(warning.message);
|
|
||||||
warning.details.forEach(function(detail) {
|
|
||||||
if (!detail.is_available) {
|
|
||||||
warningMessages.push(`- ${detail.product_name}: Butuh ${detail.required_quantity}, Tersedia ${detail.available_stock}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Swal.fire({
|
|
||||||
title: 'Peringatan Stock Tidak Mencukupi',
|
|
||||||
html: `
|
|
||||||
<div class="text-left">
|
|
||||||
<p class="mb-3">Ada beberapa pekerjaan yang memerlukan produk dengan stock tidak mencukupi:</p>
|
|
||||||
<div class="alert alert-warning text-left">
|
|
||||||
${warningMessages.join('<br>')}
|
|
||||||
</div>
|
|
||||||
<p class="mb-0"><strong>Apakah Anda yakin ingin melanjutkan?</strong></p>
|
|
||||||
<small class="text-muted">Transaksi akan tetap dibuat, namun stock akan menjadi negatif.</small>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
icon: 'warning',
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: '#ffc107',
|
|
||||||
cancelButtonColor: '#6c757d',
|
|
||||||
confirmButtonText: 'Lanjutkan',
|
|
||||||
cancelButtonText: 'Batal'
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
$(".button-save").attr("disabled", true);
|
|
||||||
$(".button-save").addClass("disabled");
|
|
||||||
$("#workForm")[0].submit(); // Submit the form
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(".button-save").attr("disabled", true);
|
$(".button-save").attr("disabled", true);
|
||||||
$(".button-save").addClass("disabled");
|
$(".button-save").addClass("disabled");
|
||||||
@@ -1405,40 +1274,42 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
})
|
})
|
||||||
|
|
||||||
$("#washForm").submit(function(e) {
|
$("#washForm").submit(function(e) {
|
||||||
// Validate required fields
|
// Validate required fields within the wash form context
|
||||||
var spkNo = $('input[name="spk_no"]').val().trim();
|
var $form = $(this);
|
||||||
var policeNumber = $('input[name="police_number"]').val().trim();
|
var spkNo = $form.find('input[name="spk_no"]').val();
|
||||||
var userSaId = $('select[name="user_sa_id"]').val();
|
var policeNumber = $form.find('input[name="police_number"]').val();
|
||||||
var date = $('input[name="date"]').val().trim();
|
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 = [];
|
var errorMessages = [];
|
||||||
|
|
||||||
if (!spkNo) {
|
// Reset all field error states
|
||||||
|
$form.find('input, select').removeClass('is-invalid');
|
||||||
|
|
||||||
|
if (!spkNo || spkNo.trim() === '') {
|
||||||
errorMessages.push('No. SPK harus diisi');
|
errorMessages.push('No. SPK harus diisi');
|
||||||
$('input[name="spk_no"]').addClass('is-invalid');
|
$form.find('input[name="spk_no"]').addClass('is-invalid');
|
||||||
} else {
|
|
||||||
$('input[name="spk_no"]').removeClass('is-invalid');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!policeNumber) {
|
if (!policeNumber || policeNumber.trim() === '') {
|
||||||
errorMessages.push('No. Polisi harus diisi');
|
errorMessages.push('No. Polisi harus diisi');
|
||||||
$('input[name="police_number"]').addClass('is-invalid');
|
$form.find('input[name="police_number"]').addClass('is-invalid');
|
||||||
} else {
|
|
||||||
$('input[name="police_number"]').removeClass('is-invalid');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userSaId || userSaId === '') {
|
if (!userSaId || userSaId === '' || userSaId === null) {
|
||||||
errorMessages.push('Service Advisor harus dipilih');
|
errorMessages.push('Service Advisor harus dipilih');
|
||||||
$('select[name="user_sa_id"]').addClass('is-invalid');
|
$form.find('select[name="user_sa_id"]').addClass('is-invalid');
|
||||||
} else {
|
|
||||||
$('select[name="user_sa_id"]').removeClass('is-invalid');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!date) {
|
if (!date || date.trim() === '') {
|
||||||
errorMessages.push('Tanggal Pekerjaan harus diisi');
|
errorMessages.push('Tanggal Pekerjaan harus diisi');
|
||||||
$('input[name="date"]').addClass('is-invalid');
|
$form.find('input[name="date"]').addClass('is-invalid');
|
||||||
} else {
|
}
|
||||||
$('input[name="date"]').removeClass('is-invalid');
|
|
||||||
|
if (!warranty || warranty === 'Warranty') {
|
||||||
|
errorMessages.push('Warranty harus dipilih');
|
||||||
|
$form.find('select[name="warranty"]').addClass('is-invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorMessages.length > 0) {
|
if (errorMessages.length > 0) {
|
||||||
@@ -1456,11 +1327,23 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
confirmButtonText: 'OK'
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".button-save").attr("disabled", true);
|
// Disable submit button to prevent double submission
|
||||||
$(".button-save").addClass("disabled");
|
$form.find(".button-save").attr("disabled", true);
|
||||||
|
$form.find(".button-save").addClass("disabled");
|
||||||
|
$form.find(".button-save").text("Menyimpan...");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1714,7 +1597,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
|
|
||||||
if (typeof Swal !== 'undefined') {
|
if (typeof Swal !== 'undefined') {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'warning',
|
icon: 'warning',
|
||||||
title: 'Validasi Gagal',
|
title: 'Validasi Gagal',
|
||||||
text: errorMessages.join(', ')
|
text: errorMessages.join(', ')
|
||||||
});
|
});
|
||||||
@@ -1729,7 +1612,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Kirim Mutasi?',
|
title: 'Kirim Mutasi?',
|
||||||
text: "Mutasi akan dikirim ke dealer tujuan",
|
text: "Mutasi akan dikirim ke dealer tujuan",
|
||||||
type: 'question',
|
icon: 'question',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#ffc107',
|
confirmButtonColor: '#ffc107',
|
||||||
cancelButtonColor: '#6c757d',
|
cancelButtonColor: '#6c757d',
|
||||||
@@ -1874,6 +1757,19 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
$(document).on('change', 'select[name="user_sa_id"]', function() {
|
$(document).on('change', 'select[name="user_sa_id"]', function() {
|
||||||
$(this).removeClass('is-invalid');
|
$(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
|
// Handle server-side errors - scroll to first error and highlight
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@@ -1938,7 +1834,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
// Show alert for validation errors
|
// Show alert for validation errors
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'error',
|
icon: 'error',
|
||||||
title: 'Terjadi Kesalahan',
|
title: 'Terjadi Kesalahan',
|
||||||
text: '{{ session("error") }}',
|
text: '{{ session("error") }}',
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: 'OK'
|
||||||
@@ -1951,7 +1847,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
// Handle success/error messages for both opname and mutasi
|
// Handle success/error messages for both opname and mutasi
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'success',
|
icon: 'success',
|
||||||
title: 'Berhasil!',
|
title: 'Berhasil!',
|
||||||
text: '{{ session("success") }}',
|
text: '{{ session("success") }}',
|
||||||
timer: 3000,
|
timer: 3000,
|
||||||
@@ -2055,7 +1951,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
|
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'error',
|
icon: 'error',
|
||||||
title: 'Terjadi Kesalahan',
|
title: 'Terjadi Kesalahan',
|
||||||
text: '{{ session("error") }}',
|
text: '{{ session("error") }}',
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: 'OK'
|
||||||
@@ -2084,7 +1980,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'error',
|
icon: 'error',
|
||||||
title: 'Validasi Gagal',
|
title: 'Validasi Gagal',
|
||||||
html: errorMessages.join('<br>'),
|
html: errorMessages.join('<br>'),
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: 'OK'
|
||||||
@@ -2648,7 +2544,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
var hasInvalidInput = $('.quantity-approved-input.is-invalid').length > 0;
|
var hasInvalidInput = $('.quantity-approved-input.is-invalid').length > 0;
|
||||||
if (hasInvalidInput) {
|
if (hasInvalidInput) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'error',
|
icon: 'error',
|
||||||
title: 'Validasi Gagal',
|
title: 'Validasi Gagal',
|
||||||
text: 'Perbaiki quantity yang tidak valid sebelum melanjutkan'
|
text: 'Perbaiki quantity yang tidak valid sebelum melanjutkan'
|
||||||
});
|
});
|
||||||
@@ -2666,7 +2562,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
|
|
||||||
if (!hasApprovedQuantity) {
|
if (!hasApprovedQuantity) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
type: 'warning',
|
icon: 'warning',
|
||||||
title: 'Peringatan',
|
title: 'Peringatan',
|
||||||
text: 'Minimal satu produk harus memiliki quantity yang disetujui'
|
text: 'Minimal satu produk harus memiliki quantity yang disetujui'
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user