From 0ef03fe7cb28d48d24a21a8ff6164a3f9f50bf5b Mon Sep 17 00:00:00 2001 From: arifal Date: Thu, 3 Jul 2025 13:55:49 +0700 Subject: [PATCH] fix opname default value, show different opname and hide system stock opname --- .../WarehouseManagement/OpnamesController.php | 81 +++++--- .../js/warehouse_management/opnames/index.js | 2 +- .../warehouse_management/opnames/index.js.map | 2 +- .../js/warehouse_management/opnames/index.js | 17 +- resources/views/transaction/index.blade.php | 177 +++++++----------- .../mutations/print.blade.php | 4 +- .../opnames/index.blade.php | 39 ++++ .../opnames/print.blade.php | 4 +- 8 files changed, 179 insertions(+), 147 deletions(-) diff --git a/app/Http/Controllers/WarehouseManagement/OpnamesController.php b/app/Http/Controllers/WarehouseManagement/OpnamesController.php index e3ff796..c34521f 100755 --- a/app/Http/Controllers/WarehouseManagement/OpnamesController.php +++ b/app/Http/Controllers/WarehouseManagement/OpnamesController.php @@ -27,7 +27,7 @@ class OpnamesController extends Controller $dealers = Dealer::all(); if($request->ajax()){ $data = Opname::query() - ->with('user','dealer') + ->with(['user','dealer', 'details.product']) ->orderBy('created_at', 'desc'); // Filter berdasarkan dealer yang dipilih @@ -76,6 +76,46 @@ class OpnamesController extends Controller return "{$label}"; }) + ->addColumn('stock_info', function ($row) { + // Use eager loaded details + $details = $row->details; + + if ($details->isEmpty()) { + return 'Tidak ada data'; + } + + $totalProducts = $details->count(); + $matchingProducts = $details->where('difference', 0)->count(); + $differentProducts = $totalProducts - $matchingProducts; + + $info = []; + + if ($matchingProducts > 0) { + $info[] = " {$matchingProducts} sesuai"; + } + + if ($differentProducts > 0) { + // Get more details about differences + $positiveDiff = $details->where('difference', '>', 0)->count(); + $negativeDiff = $details->where('difference', '<', 0)->count(); + + $diffInfo = []; + if ($positiveDiff > 0) { + $diffInfo[] = "+{$positiveDiff}"; + } + if ($negativeDiff > 0) { + $diffInfo[] = "-{$negativeDiff}"; + } + + $diffText = implode(', ', $diffInfo); + $info[] = " {$differentProducts} selisih ({$diffText})"; + } + + // Add total products info + $info[] = "(Total: {$totalProducts} produk)"; + + return '
' . implode('
', $info) . '
'; + }) ->addColumn('action', function ($row) use ($menu) { $btn = '
'; @@ -86,7 +126,7 @@ class OpnamesController extends Controller return $btn; }) - ->rawColumns(['action', 'status']) + ->rawColumns(['action', 'status', 'stock_info']) ->make(true); } @@ -124,7 +164,7 @@ class OpnamesController extends Controller $isTransactionForm = $request->has('form') && $request->form === 'opname'; if ($isTransactionForm) { - // Custom validation for transaction form + // Simplified validation for transaction form $request->validate([ 'dealer_id' => 'required|exists:dealers,id', 'user_id' => 'required|exists:users,id', @@ -140,7 +180,7 @@ class OpnamesController extends Controller 'system_stock' => 'required|array', 'system_stock.*' => 'required|numeric|min:0', 'physical_stock' => 'required|array', - 'physical_stock.*' => 'required|numeric|min:0' + 'physical_stock.*' => 'nullable|numeric|min:0' ]); // Process transaction form data with proper date parsing @@ -199,19 +239,11 @@ class OpnamesController extends Controller $physicalStocks = $request->physical_quantity; } - // 2. Validasi minimal ada produk yang diisi (termasuk nilai 0) + // 2. Simplified validation - all products are valid, set defaults for empty physical stocks $validProductIds = array_filter($productIds); - $validSystemStocks = array_filter($systemStocks, function($value) { return $value !== null && $value !== ''; }); - $validPhysicalStocks = array_filter($physicalStocks, function($value) { - return $value !== null && $value !== '' && is_numeric($value); - }); if (empty($validProductIds) || count($validProductIds) === 0) { - throw new \Exception('Minimal harus ada satu produk yang diisi untuk opname.'); - } - - if (count($validPhysicalStocks) === 0) { - throw new \Exception('Minimal harus ada satu stock fisik yang diisi (termasuk nilai 0).'); + throw new \Exception('Minimal harus ada satu produk untuk opname.'); } // 3. Validasi duplikasi produk @@ -283,19 +315,14 @@ class OpnamesController extends Controller foreach ($productIds as $index => $productId) { if (!$productId) continue; - // Skip only if physical stock is truly not provided (empty string or null) - // Accept 0 as valid input - if (!isset($physicalStocks[$index]) || $physicalStocks[$index] === '' || $physicalStocks[$index] === null) { - continue; - } - - // Validate that physical stock is numeric (including 0) - if (!is_numeric($physicalStocks[$index])) { - continue; + // Set default value to 0 if physical stock is empty or invalid + $physicalStockValue = $physicalStocks[$index] ?? null; + if ($physicalStockValue === '' || $physicalStockValue === null || !is_numeric($physicalStockValue)) { + $physicalStockValue = 0; } $systemStock = floatval($systemStocks[$index] ?? 0); - $physicalStock = floatval($physicalStocks[$index]); + $physicalStock = floatval($physicalStockValue); $difference = $physicalStock - $systemStock; $processedCount++; @@ -337,7 +364,7 @@ class OpnamesController extends Controller // Validate we have at least one detail to insert if (empty($details)) { - throw new \Exception('Tidak ada data stock fisik yang valid untuk diproses.'); + throw new \Exception('Tidak ada data produk yang valid untuk diproses.'); } // Bulk insert untuk performa lebih baik @@ -371,13 +398,13 @@ class OpnamesController extends Controller // Redirect back to transaction page with success message and tab indicator return redirect() ->route('transaction') - ->with('success', "Opname berhasil disimpan dan disetujui. {$processedCount} produk telah diproses.") + ->with('success', "Opname berhasil disimpan. {$processedCount} produk telah diproses.") ->with('active_tab', 'opname'); } else { // Redirect to opname index for regular form return redirect() ->route('opnames.index') - ->with('success', "Opname berhasil disimpan dan disetujui. {$processedCount} produk telah diproses."); + ->with('success', "Opname berhasil disimpan. {$processedCount} produk telah diproses."); } } catch (\Illuminate\Validation\ValidationException $e) { diff --git a/public/js/warehouse_management/opnames/index.js b/public/js/warehouse_management/opnames/index.js index a8c1f6a..3101d66 100755 --- a/public/js/warehouse_management/opnames/index.js +++ b/public/js/warehouse_management/opnames/index.js @@ -1,2 +1,2 @@ -(()=>{function e(){$("#date_to").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){console.log("End date selected:",e.format())})).on("clearDate",(function(e){console.log("End date cleared")}))}function a(){$("#date_to").datepicker("remove"),$("#date_to").val(""),e(),$("#date_to").prop("disabled",!0),console.log("End date picker reset and disabled")}$(document).ready((function(){console.log("Opnames index.js loaded"),void 0!==$.fn.DataTable?(console.log("Initializing Select2..."),void 0!==$.fn.select2?$("#dealer_filter").select2({placeholder:"Pilih...",allowClear:!0,width:"100%"}):console.warn("Select2 not available, using regular select"),function(){if(console.log("Initializing datepickers..."),void 0===$.fn.datepicker)return void console.error("Bootstrap Datepicker not available!");$("#date_from").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){var a;console.log("Start date selected:",e.format()),a=e.format(),console.log("Enabling end date picker with min date:",a),$("#date_to").prop("disabled",!1),$("#date_to").datepicker("remove"),$("#date_to").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},startDate:a,endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){console.log("End date selected:",e.format())})).on("clearDate",(function(e){console.log("End date cleared")})),console.log("End date picker enabled with startDate:",a)})).on("clearDate",(function(e){console.log("Start date cleared"),a()})),e(),$("#date_to").prop("disabled",!0)}(),setTimeout((function(){!function(){console.log("Initializing DataTable..."),$.fn.DataTable.isDataTable("#opnames-table")&&$("#opnames-table").DataTable().destroy();var e=$("#opnames-table").DataTable({processing:!0,serverSide:!0,destroy:!0,ajax:{url:$("#opnames-table").data("url"),type:"GET",data:function(e){return e.dealer_filter=$("#dealer_filter").val(),e.date_from=$("#date_from").val(),e.date_to=$("#date_to").val(),console.log("AJAX data being sent:",{dealer_filter:e.dealer_filter,date_from:e.date_from,date_to:e.date_to}),e},error:function(e,a,t){console.error("DataTables AJAX error:",a,t),console.error("Response:",e.responseText)}},columnDefs:[{targets:0,width:"15%"},{targets:5,width:"15%",className:"text-center"}],columns:[{data:"created_at",name:"created_at",orderable:!0},{data:"opname_date",name:"opname_date",orderable:!0},{data:"dealer_name",name:"dealer.name",orderable:!0},{data:"user_name",name:"user.name",orderable:!0},{data:"status",name:"status",orderable:!0},{data:"action",name:"action",orderable:!1,searchable:!1}],order:[[4,"desc"]],pageLength:10,responsive:!0,ordering:!0,orderMulti:!1});(function(e){$("#kt_search").on("click",(function(){console.log("Filter button clicked");var a=$("#dealer_filter").val(),t=$("#date_from").val(),o=$("#date_to").val();console.log("Filtering with:",{dealer:a,dateFrom:t,dateTo:o}),e.ajax.reload()})),$("#kt_reset").on("click",(function(){console.log("Reset button clicked"),$("#dealer_filter").val(null).trigger("change.select2"),$("#date_from").datepicker("clearDates"),$("#date_to").datepicker("clearDates"),a(),e.ajax.reload()})),$("#date_from, #date_to").on("keypress",(function(e){13===e.which&&$("#kt_search").click()})),$("#dealer_filter").on("change",(function(){console.log("Dealer filter changed:",$(this).val())}))})(e),function(e){e.on("order.dt",(function(){console.log("Order changed:",e.order())})),e.on("processing.dt",(function(e,a,t){t?console.log("DataTable processing started"):console.log("DataTable processing finished")}))}(e)}()}),100)):console.error("DataTables not available!")}))})(); +(()=>{function e(){$("#date_to").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){console.log("End date selected:",e.format())})).on("clearDate",(function(e){console.log("End date cleared")}))}function a(){$("#date_to").datepicker("remove"),$("#date_to").val(""),e(),$("#date_to").prop("disabled",!0),console.log("End date picker reset and disabled")}$(document).ready((function(){console.log("Opnames index.js loaded"),void 0!==$.fn.DataTable?(console.log("Initializing Select2..."),void 0!==$.fn.select2?$("#dealer_filter").select2({placeholder:"Pilih...",allowClear:!0,width:"100%"}):console.warn("Select2 not available, using regular select"),function(){if(console.log("Initializing datepickers..."),void 0===$.fn.datepicker)return void console.error("Bootstrap Datepicker not available!");$("#date_from").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){var a;console.log("Start date selected:",e.format()),a=e.format(),console.log("Enabling end date picker with min date:",a),$("#date_to").prop("disabled",!1),$("#date_to").datepicker("remove"),$("#date_to").datepicker({format:"yyyy-mm-dd",autoclose:!0,todayHighlight:!0,orientation:"bottom left",templates:{leftArrow:'',rightArrow:''},startDate:a,endDate:new Date,clearBtn:!0}).on("changeDate",(function(e){console.log("End date selected:",e.format())})).on("clearDate",(function(e){console.log("End date cleared")})),console.log("End date picker enabled with startDate:",a)})).on("clearDate",(function(e){console.log("Start date cleared"),a()})),e(),$("#date_to").prop("disabled",!0)}(),setTimeout((function(){!function(){console.log("Initializing DataTable..."),$.fn.DataTable.isDataTable("#opnames-table")&&$("#opnames-table").DataTable().destroy();var e=$("#opnames-table").DataTable({processing:!0,serverSide:!0,destroy:!0,ajax:{url:$("#opnames-table").data("url"),type:"GET",data:function(e){return e.dealer_filter=$("#dealer_filter").val(),e.date_from=$("#date_from").val(),e.date_to=$("#date_to").val(),console.log("AJAX data being sent:",{dealer_filter:e.dealer_filter,date_from:e.date_from,date_to:e.date_to}),e},error:function(e,a,t){console.error("DataTables AJAX error:",a,t),console.error("Response:",e.responseText)}},columnDefs:[{targets:0,width:"15%"},{targets:1,width:"12%"},{targets:2,width:"15%"},{targets:3,width:"12%"},{targets:4,width:"10%"},{targets:5,width:"15%",className:"text-center"},{targets:6,width:"15%",className:"text-center"}],columns:[{data:"created_at",name:"created_at",orderable:!0},{data:"opname_date",name:"opname_date",orderable:!0},{data:"dealer_name",name:"dealer.name",orderable:!0},{data:"user_name",name:"user.name",orderable:!0},{data:"status",name:"status",orderable:!0},{data:"stock_info",name:"stock_info",orderable:!1,searchable:!1},{data:"action",name:"action",orderable:!1,searchable:!1}],order:[[0,"desc"]],pageLength:10,responsive:!0,ordering:!0,orderMulti:!1});(function(e){$("#kt_search").on("click",(function(){console.log("Filter button clicked");var a=$("#dealer_filter").val(),t=$("#date_from").val(),o=$("#date_to").val();console.log("Filtering with:",{dealer:a,dateFrom:t,dateTo:o}),e.ajax.reload()})),$("#kt_reset").on("click",(function(){console.log("Reset button clicked"),$("#dealer_filter").val(null).trigger("change.select2"),$("#date_from").datepicker("clearDates"),$("#date_to").datepicker("clearDates"),a(),e.ajax.reload()})),$("#date_from, #date_to").on("keypress",(function(e){13===e.which&&$("#kt_search").click()})),$("#dealer_filter").on("change",(function(){console.log("Dealer filter changed:",$(this).val())}))})(e),function(e){e.on("order.dt",(function(){console.log("Order changed:",e.order())})),e.on("processing.dt",(function(e,a,t){t?console.log("DataTable processing started"):console.log("DataTable processing finished")}))}(e)}()}),100)):console.error("DataTables not available!")}))})(); //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/public/js/warehouse_management/opnames/index.js.map b/public/js/warehouse_management/opnames/index.js.map index ec30f05..b4af9a0 100755 --- a/public/js/warehouse_management/opnames/index.js.map +++ b/public/js/warehouse_management/opnames/index.js.map @@ -1 +1 @@ -{"version":3,"file":"/js/warehouse_management/opnames/index.js","mappings":"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","sources":["webpack:///./resources/js/warehouse_management/opnames/index.js"],"sourcesContent":["$(document).ready(function () {\n console.log(\"Opnames index.js loaded\");\n\n // Check if required libraries are available\n if (typeof $.fn.DataTable === \"undefined\") {\n console.error(\"DataTables not available!\");\n return;\n }\n\n // Initialize components\n initializeSelect2();\n initializeDatepickers();\n\n // Wait for DOM to be fully ready before initializing DataTable\n setTimeout(function () {\n initializeDataTable();\n }, 100);\n});\n\n/**\n * Initialize Select2 for dealer filter - same as stock audit\n */\nfunction initializeSelect2() {\n console.log(\"Initializing Select2...\");\n\n if (typeof $.fn.select2 !== \"undefined\") {\n $(\"#dealer_filter\").select2({\n placeholder: \"Pilih...\",\n allowClear: true,\n width: \"100%\",\n });\n } else {\n console.warn(\"Select2 not available, using regular select\");\n }\n}\n\n/**\n * Initialize date pickers with bootstrap datepicker - same as transaction view\n */\nfunction initializeDatepickers() {\n console.log(\"Initializing datepickers...\");\n\n // Check if bootstrap datepicker is available\n if (typeof $.fn.datepicker === \"undefined\") {\n console.error(\"Bootstrap Datepicker not available!\");\n return;\n }\n\n // Initialize start date picker\n $(\"#date_from\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"Start date selected:\", e.format());\n enableEndDatePicker(e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"Start date cleared\");\n resetEndDatePicker();\n });\n\n // Initialize end date picker\n initializeEndDatePicker();\n\n // Initially disable end date input\n $(\"#date_to\").prop(\"disabled\", true);\n}\n\n/**\n * Enable end date picker with minimum date constraint\n */\nfunction enableEndDatePicker(startDate) {\n console.log(\"Enabling end date picker with min date:\", startDate);\n\n // Enable the input\n $(\"#date_to\").prop(\"disabled\", false);\n\n // Remove existing datepicker\n $(\"#date_to\").datepicker(\"remove\");\n\n // Re-initialize with new startDate constraint\n $(\"#date_to\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n startDate: startDate, // Set minimum date to selected start date\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"End date selected:\", e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"End date cleared\");\n });\n\n console.log(\"End date picker enabled with startDate:\", startDate);\n}\n\n/**\n * Initialize end date picker without constraints\n */\nfunction initializeEndDatePicker() {\n $(\"#date_to\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"End date selected:\", e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"End date cleared\");\n });\n}\n\n/**\n * Reset end date picker to initial state\n */\nfunction resetEndDatePicker() {\n // Remove existing datepicker\n $(\"#date_to\").datepicker(\"remove\");\n\n // Clear the input value\n $(\"#date_to\").val(\"\");\n\n // Re-initialize without startDate constraint\n initializeEndDatePicker();\n\n // Disable the input\n $(\"#date_to\").prop(\"disabled\", true);\n\n console.log(\"End date picker reset and disabled\");\n}\n\n/**\n * Initialize DataTable with server-side processing and filtering\n */\nfunction initializeDataTable() {\n console.log(\"Initializing DataTable...\");\n\n // Destroy existing table if any\n if ($.fn.DataTable.isDataTable(\"#opnames-table\")) {\n $(\"#opnames-table\").DataTable().destroy();\n }\n\n // Initialize DataTable\n const table = $(\"#opnames-table\").DataTable({\n processing: true,\n serverSide: true,\n destroy: true,\n ajax: {\n url: $(\"#opnames-table\").data(\"url\"),\n type: \"GET\",\n data: function (d) {\n // Add filter parameters\n d.dealer_filter = $(\"#dealer_filter\").val();\n d.date_from = $(\"#date_from\").val();\n d.date_to = $(\"#date_to\").val();\n\n console.log(\"AJAX data being sent:\", {\n dealer_filter: d.dealer_filter,\n date_from: d.date_from,\n date_to: d.date_to,\n });\n\n return d;\n },\n error: function (xhr, error, code) {\n console.error(\"DataTables AJAX error:\", error, code);\n console.error(\"Response:\", xhr.responseText);\n },\n },\n columnDefs: [\n { targets: 0, width: \"15%\" }, // Opname Date column\n { targets: 5, width: \"15%\", className: \"text-center\" }, // Action column\n ],\n columns: [\n {\n data: \"created_at\",\n name: \"created_at\",\n orderable: true,\n },\n {\n data: \"opname_date\",\n name: \"opname_date\",\n orderable: true,\n },\n {\n data: \"dealer_name\",\n name: \"dealer.name\",\n orderable: true,\n },\n {\n data: \"user_name\",\n name: \"user.name\",\n orderable: true,\n },\n {\n data: \"status\",\n name: \"status\",\n orderable: true,\n },\n {\n data: \"action\",\n name: \"action\",\n orderable: false,\n searchable: false,\n },\n ],\n order: [[4, \"desc\"]], // Order by created_at desc\n pageLength: 10,\n responsive: true,\n ordering: true,\n orderMulti: false,\n });\n\n // Setup filter button handlers\n setupFilterHandlers(table);\n\n // Setup other event handlers\n setupTableEventHandlers(table);\n}\n\n/**\n * Setup filter and reset button handlers\n */\nfunction setupFilterHandlers(table) {\n // Handle Filter Search Button\n $(\"#kt_search\").on(\"click\", function () {\n console.log(\"Filter button clicked\");\n\n const dealerFilter = $(\"#dealer_filter\").val();\n const dateFrom = $(\"#date_from\").val();\n const dateTo = $(\"#date_to\").val();\n\n console.log(\"Filtering with:\", {\n dealer: dealerFilter,\n dateFrom: dateFrom,\n dateTo: dateTo,\n });\n\n table.ajax.reload();\n });\n\n // Handle Filter Reset Button\n $(\"#kt_reset\").on(\"click\", function () {\n console.log(\"Reset button clicked\");\n\n // Reset select2 elements properly - same as stock audit\n $(\"#dealer_filter\").val(null).trigger(\"change.select2\");\n\n // Clear datepicker values using bootstrap datepicker method\n $(\"#date_from\").datepicker(\"clearDates\");\n $(\"#date_to\").datepicker(\"clearDates\");\n\n // Reset end date picker and disable it\n resetEndDatePicker();\n\n // Reload table\n table.ajax.reload();\n });\n\n // Handle Enter key on date inputs\n $(\"#date_from, #date_to\").on(\"keypress\", function (e) {\n if (e.which === 13) {\n // Enter key\n $(\"#kt_search\").click();\n }\n });\n\n // Optional: Auto-filter when dealer selection changes\n $(\"#dealer_filter\").on(\"change\", function () {\n console.log(\"Dealer filter changed:\", $(this).val());\n // Uncomment the line below if you want auto-filter on dealer change\n // table.ajax.reload();\n });\n}\n\n/**\n * Setup additional table event handlers\n */\nfunction setupTableEventHandlers(table) {\n // Debug ordering events\n table.on(\"order.dt\", function () {\n console.log(\"Order changed:\", table.order());\n });\n\n // Add loading indicator for processing\n table.on(\"processing.dt\", function (e, settings, processing) {\n if (processing) {\n console.log(\"DataTable processing started\");\n } else {\n console.log(\"DataTable processing finished\");\n }\n });\n\n // Handle any custom button clicks here if needed\n // Example: $(document).on('click', '.custom-btn', function() { ... });\n}\n"],"names":["initializeEndDatePicker","$","datepicker","format","autoclose","todayHighlight","orientation","templates","leftArrow","rightArrow","endDate","Date","clearBtn","on","e","console","log","resetEndDatePicker","val","prop","document","ready","fn","DataTable","select2","placeholder","allowClear","width","warn","error","startDate","initializeDatepickers","setTimeout","isDataTable","destroy","table","processing","serverSide","ajax","url","data","type","d","dealer_filter","date_from","date_to","xhr","code","responseText","columnDefs","targets","className","columns","name","orderable","searchable","order","pageLength","responsive","ordering","orderMulti","dealerFilter","dateFrom","dateTo","dealer","reload","trigger","which","click","this","setupFilterHandlers","settings","setupTableEventHandlers","initializeDataTable"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"/js/warehouse_management/opnames/index.js","mappings":"MAsHA,SAASA,IACLC,EAAE,YACGC,WAAW,CACRC,OAAQ,aACRC,WAAW,EACXC,gBAAgB,EAChBC,YAAa,cACbC,UAAW,CACPC,UAAW,mCACXC,WAAY,qCAEhBC,QAAS,IAAIC,KACbC,UAAU,IAEbC,GAAG,cAAc,SAAUC,GACxBC,QAAQC,IAAI,qBAAsBF,EAAEX,SACvC,IACAU,GAAG,aAAa,SAAUC,GACvBC,QAAQC,IAAI,mBACf,GACR,CAKD,SAASC,IAELhB,EAAE,YAAYC,WAAW,UAGzBD,EAAE,YAAYiB,IAAI,IAGlBlB,IAGAC,EAAE,YAAYkB,KAAK,YAAY,GAE/BJ,QAAQC,IAAI,qCACf,CA7JDf,EAAEmB,UAAUC,OAAM,WACdN,QAAQC,IAAI,gCAGkB,IAAnBf,EAAEqB,GAAGC,WAmBhBR,QAAQC,IAAI,gCAEgB,IAAjBf,EAAEqB,GAAGE,QACZvB,EAAE,kBAAkBuB,QAAQ,CACxBC,YAAa,WACbC,YAAY,EACZC,MAAO,SAGXZ,QAAQa,KAAK,+CAOrB,WAII,GAHAb,QAAQC,IAAI,oCAGmB,IAApBf,EAAEqB,GAAGpB,WAEZ,YADAa,QAAQc,MAAM,uCAKlB5B,EAAE,cACGC,WAAW,CACRC,OAAQ,aACRC,WAAW,EACXC,gBAAgB,EAChBC,YAAa,cACbC,UAAW,CACPC,UAAW,mCACXC,WAAY,qCAEhBC,QAAS,IAAIC,KACbC,UAAU,IAEbC,GAAG,cAAc,SAAUC,GAmBpC,IAA6BgB,EAlBjBf,QAAQC,IAAI,uBAAwBF,EAAEX,UAkBrB2B,EAjBGhB,EAAEX,SAkB9BY,QAAQC,IAAI,0CAA2Cc,GAGvD7B,EAAE,YAAYkB,KAAK,YAAY,GAG/BlB,EAAE,YAAYC,WAAW,UAGzBD,EAAE,YACGC,WAAW,CACRC,OAAQ,aACRC,WAAW,EACXC,gBAAgB,EAChBC,YAAa,cACbC,UAAW,CACPC,UAAW,mCACXC,WAAY,qCAEhBqB,UAAWA,EACXpB,QAAS,IAAIC,KACbC,UAAU,IAEbC,GAAG,cAAc,SAAUC,GACxBC,QAAQC,IAAI,qBAAsBF,EAAEX,SACvC,IACAU,GAAG,aAAa,SAAUC,GACvBC,QAAQC,IAAI,mBACf,IAELD,QAAQC,IAAI,0CAA2Cc,EA/ClD,IACAjB,GAAG,aAAa,SAAUC,GACvBC,QAAQC,IAAI,sBACZC,GACH,IAGLjB,IAGAC,EAAE,YAAYkB,KAAK,YAAY,EAClC,CAjEGY,GAGAC,YAAW,YAoJf,WACIjB,QAAQC,IAAI,6BAGRf,EAAEqB,GAAGC,UAAUU,YAAY,mBAC3BhC,EAAE,kBAAkBsB,YAAYW,UAIpC,IAAMC,EAAQlC,EAAE,kBAAkBsB,UAAU,CACxCa,YAAY,EACZC,YAAY,EACZH,SAAS,EACTI,KAAM,CACFC,IAAKtC,EAAE,kBAAkBuC,KAAK,OAC9BC,KAAM,MACND,KAAM,SAAUE,GAYZ,OAVAA,EAAEC,cAAgB1C,EAAE,kBAAkBiB,MACtCwB,EAAEE,UAAY3C,EAAE,cAAciB,MAC9BwB,EAAEG,QAAU5C,EAAE,YAAYiB,MAE1BH,QAAQC,IAAI,wBAAyB,CACjC2B,cAAeD,EAAEC,cACjBC,UAAWF,EAAEE,UACbC,QAASH,EAAEG,UAGRH,CACV,EACDb,MAAO,SAAUiB,EAAKjB,EAAOkB,GACzBhC,QAAQc,MAAM,yBAA0BA,EAAOkB,GAC/ChC,QAAQc,MAAM,YAAaiB,EAAIE,aAClC,GAELC,WAAY,CACR,CAAEC,QAAS,EAAGvB,MAAO,OACrB,CAAEuB,QAAS,EAAGvB,MAAO,OACrB,CAAEuB,QAAS,EAAGvB,MAAO,OACrB,CAAEuB,QAAS,EAAGvB,MAAO,OACrB,CAAEuB,QAAS,EAAGvB,MAAO,OACrB,CAAEuB,QAAS,EAAGvB,MAAO,MAAOwB,UAAW,eACvC,CAAED,QAAS,EAAGvB,MAAO,MAAOwB,UAAW,gBAE3CC,QAAS,CACL,CACIZ,KAAM,aACNa,KAAM,aACNC,WAAW,GAEf,CACId,KAAM,cACNa,KAAM,cACNC,WAAW,GAEf,CACId,KAAM,cACNa,KAAM,cACNC,WAAW,GAEf,CACId,KAAM,YACNa,KAAM,YACNC,WAAW,GAEf,CACId,KAAM,SACNa,KAAM,SACNC,WAAW,GAEf,CACId,KAAM,aACNa,KAAM,aACNC,WAAW,EACXC,YAAY,GAEhB,CACIf,KAAM,SACNa,KAAM,SACNC,WAAW,EACXC,YAAY,IAGpBC,MAAO,CAAC,CAAC,EAAG,SACZC,WAAY,GACZC,YAAY,EACZC,UAAU,EACVC,YAAY,KAapB,SAA6BzB,GAEzBlC,EAAE,cAAcY,GAAG,SAAS,WACxBE,QAAQC,IAAI,yBAEZ,IAAM6C,EAAe5D,EAAE,kBAAkBiB,MACnC4C,EAAW7D,EAAE,cAAciB,MAC3B6C,EAAS9D,EAAE,YAAYiB,MAE7BH,QAAQC,IAAI,kBAAmB,CAC3BgD,OAAQH,EACRC,SAAUA,EACVC,OAAQA,IAGZ5B,EAAMG,KAAK2B,QACd,IAGDhE,EAAE,aAAaY,GAAG,SAAS,WACvBE,QAAQC,IAAI,wBAGZf,EAAE,kBAAkBiB,IAAI,MAAMgD,QAAQ,kBAGtCjE,EAAE,cAAcC,WAAW,cAC3BD,EAAE,YAAYC,WAAW,cAGzBe,IAGAkB,EAAMG,KAAK2B,QACd,IAGDhE,EAAE,wBAAwBY,GAAG,YAAY,SAAUC,GAC/B,KAAZA,EAAEqD,OAEFlE,EAAE,cAAcmE,OAEvB,IAGDnE,EAAE,kBAAkBY,GAAG,UAAU,WAC7BE,QAAQC,IAAI,yBAA0Bf,EAAEoE,MAAMnD,MAGjD,GACJ,EA3DGoD,CAAoBnC,GAgExB,SAAiCA,GAE7BA,EAAMtB,GAAG,YAAY,WACjBE,QAAQC,IAAI,iBAAkBmB,EAAMqB,QACvC,IAGDrB,EAAMtB,GAAG,iBAAiB,SAAUC,EAAGyD,EAAUnC,GACzCA,EACArB,QAAQC,IAAI,gCAEZD,QAAQC,IAAI,gCAEnB,GAIJ,CA9EGwD,CAAwBrC,EAC3B,CAlPOsC,EACH,GAAE,MAXC1D,QAAQc,MAAM,4BAYrB,G","sources":["webpack:///./resources/js/warehouse_management/opnames/index.js"],"sourcesContent":["$(document).ready(function () {\n console.log(\"Opnames index.js loaded\");\n\n // Check if required libraries are available\n if (typeof $.fn.DataTable === \"undefined\") {\n console.error(\"DataTables not available!\");\n return;\n }\n\n // Initialize components\n initializeSelect2();\n initializeDatepickers();\n\n // Wait for DOM to be fully ready before initializing DataTable\n setTimeout(function () {\n initializeDataTable();\n }, 100);\n});\n\n/**\n * Initialize Select2 for dealer filter - same as stock audit\n */\nfunction initializeSelect2() {\n console.log(\"Initializing Select2...\");\n\n if (typeof $.fn.select2 !== \"undefined\") {\n $(\"#dealer_filter\").select2({\n placeholder: \"Pilih...\",\n allowClear: true,\n width: \"100%\",\n });\n } else {\n console.warn(\"Select2 not available, using regular select\");\n }\n}\n\n/**\n * Initialize date pickers with bootstrap datepicker - same as transaction view\n */\nfunction initializeDatepickers() {\n console.log(\"Initializing datepickers...\");\n\n // Check if bootstrap datepicker is available\n if (typeof $.fn.datepicker === \"undefined\") {\n console.error(\"Bootstrap Datepicker not available!\");\n return;\n }\n\n // Initialize start date picker\n $(\"#date_from\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"Start date selected:\", e.format());\n enableEndDatePicker(e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"Start date cleared\");\n resetEndDatePicker();\n });\n\n // Initialize end date picker\n initializeEndDatePicker();\n\n // Initially disable end date input\n $(\"#date_to\").prop(\"disabled\", true);\n}\n\n/**\n * Enable end date picker with minimum date constraint\n */\nfunction enableEndDatePicker(startDate) {\n console.log(\"Enabling end date picker with min date:\", startDate);\n\n // Enable the input\n $(\"#date_to\").prop(\"disabled\", false);\n\n // Remove existing datepicker\n $(\"#date_to\").datepicker(\"remove\");\n\n // Re-initialize with new startDate constraint\n $(\"#date_to\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n startDate: startDate, // Set minimum date to selected start date\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"End date selected:\", e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"End date cleared\");\n });\n\n console.log(\"End date picker enabled with startDate:\", startDate);\n}\n\n/**\n * Initialize end date picker without constraints\n */\nfunction initializeEndDatePicker() {\n $(\"#date_to\")\n .datepicker({\n format: \"yyyy-mm-dd\",\n autoclose: true,\n todayHighlight: true,\n orientation: \"bottom left\",\n templates: {\n leftArrow: '',\n rightArrow: '',\n },\n endDate: new Date(), // Don't allow future dates\n clearBtn: true,\n })\n .on(\"changeDate\", function (e) {\n console.log(\"End date selected:\", e.format());\n })\n .on(\"clearDate\", function (e) {\n console.log(\"End date cleared\");\n });\n}\n\n/**\n * Reset end date picker to initial state\n */\nfunction resetEndDatePicker() {\n // Remove existing datepicker\n $(\"#date_to\").datepicker(\"remove\");\n\n // Clear the input value\n $(\"#date_to\").val(\"\");\n\n // Re-initialize without startDate constraint\n initializeEndDatePicker();\n\n // Disable the input\n $(\"#date_to\").prop(\"disabled\", true);\n\n console.log(\"End date picker reset and disabled\");\n}\n\n/**\n * Initialize DataTable with server-side processing and filtering\n */\nfunction initializeDataTable() {\n console.log(\"Initializing DataTable...\");\n\n // Destroy existing table if any\n if ($.fn.DataTable.isDataTable(\"#opnames-table\")) {\n $(\"#opnames-table\").DataTable().destroy();\n }\n\n // Initialize DataTable\n const table = $(\"#opnames-table\").DataTable({\n processing: true,\n serverSide: true,\n destroy: true,\n ajax: {\n url: $(\"#opnames-table\").data(\"url\"),\n type: \"GET\",\n data: function (d) {\n // Add filter parameters\n d.dealer_filter = $(\"#dealer_filter\").val();\n d.date_from = $(\"#date_from\").val();\n d.date_to = $(\"#date_to\").val();\n\n console.log(\"AJAX data being sent:\", {\n dealer_filter: d.dealer_filter,\n date_from: d.date_from,\n date_to: d.date_to,\n });\n\n return d;\n },\n error: function (xhr, error, code) {\n console.error(\"DataTables AJAX error:\", error, code);\n console.error(\"Response:\", xhr.responseText);\n },\n },\n columnDefs: [\n { targets: 0, width: \"15%\" }, // Created At column\n { targets: 1, width: \"12%\" }, // Opname Date column\n { targets: 2, width: \"15%\" }, // Dealer column\n { targets: 3, width: \"12%\" }, // User column\n { targets: 4, width: \"10%\" }, // Status column\n { targets: 5, width: \"15%\", className: \"text-center\" }, // Stock Info column\n { targets: 6, width: \"15%\", className: \"text-center\" }, // Action column\n ],\n columns: [\n {\n data: \"created_at\",\n name: \"created_at\",\n orderable: true,\n },\n {\n data: \"opname_date\",\n name: \"opname_date\",\n orderable: true,\n },\n {\n data: \"dealer_name\",\n name: \"dealer.name\",\n orderable: true,\n },\n {\n data: \"user_name\",\n name: \"user.name\",\n orderable: true,\n },\n {\n data: \"status\",\n name: \"status\",\n orderable: true,\n },\n {\n data: \"stock_info\",\n name: \"stock_info\",\n orderable: false,\n searchable: false,\n },\n {\n data: \"action\",\n name: \"action\",\n orderable: false,\n searchable: false,\n },\n ],\n order: [[0, \"desc\"]], // Order by created_at desc\n pageLength: 10,\n responsive: true,\n ordering: true,\n orderMulti: false,\n });\n\n // Setup filter button handlers\n setupFilterHandlers(table);\n\n // Setup other event handlers\n setupTableEventHandlers(table);\n}\n\n/**\n * Setup filter and reset button handlers\n */\nfunction setupFilterHandlers(table) {\n // Handle Filter Search Button\n $(\"#kt_search\").on(\"click\", function () {\n console.log(\"Filter button clicked\");\n\n const dealerFilter = $(\"#dealer_filter\").val();\n const dateFrom = $(\"#date_from\").val();\n const dateTo = $(\"#date_to\").val();\n\n console.log(\"Filtering with:\", {\n dealer: dealerFilter,\n dateFrom: dateFrom,\n dateTo: dateTo,\n });\n\n table.ajax.reload();\n });\n\n // Handle Filter Reset Button\n $(\"#kt_reset\").on(\"click\", function () {\n console.log(\"Reset button clicked\");\n\n // Reset select2 elements properly - same as stock audit\n $(\"#dealer_filter\").val(null).trigger(\"change.select2\");\n\n // Clear datepicker values using bootstrap datepicker method\n $(\"#date_from\").datepicker(\"clearDates\");\n $(\"#date_to\").datepicker(\"clearDates\");\n\n // Reset end date picker and disable it\n resetEndDatePicker();\n\n // Reload table\n table.ajax.reload();\n });\n\n // Handle Enter key on date inputs\n $(\"#date_from, #date_to\").on(\"keypress\", function (e) {\n if (e.which === 13) {\n // Enter key\n $(\"#kt_search\").click();\n }\n });\n\n // Optional: Auto-filter when dealer selection changes\n $(\"#dealer_filter\").on(\"change\", function () {\n console.log(\"Dealer filter changed:\", $(this).val());\n // Uncomment the line below if you want auto-filter on dealer change\n // table.ajax.reload();\n });\n}\n\n/**\n * Setup additional table event handlers\n */\nfunction setupTableEventHandlers(table) {\n // Debug ordering events\n table.on(\"order.dt\", function () {\n console.log(\"Order changed:\", table.order());\n });\n\n // Add loading indicator for processing\n table.on(\"processing.dt\", function (e, settings, processing) {\n if (processing) {\n console.log(\"DataTable processing started\");\n } else {\n console.log(\"DataTable processing finished\");\n }\n });\n\n // Handle any custom button clicks here if needed\n // Example: $(document).on('click', '.custom-btn', function() { ... });\n}\n"],"names":["initializeEndDatePicker","$","datepicker","format","autoclose","todayHighlight","orientation","templates","leftArrow","rightArrow","endDate","Date","clearBtn","on","e","console","log","resetEndDatePicker","val","prop","document","ready","fn","DataTable","select2","placeholder","allowClear","width","warn","error","startDate","initializeDatepickers","setTimeout","isDataTable","destroy","table","processing","serverSide","ajax","url","data","type","d","dealer_filter","date_from","date_to","xhr","code","responseText","columnDefs","targets","className","columns","name","orderable","searchable","order","pageLength","responsive","ordering","orderMulti","dealerFilter","dateFrom","dateTo","dealer","reload","trigger","which","click","this","setupFilterHandlers","settings","setupTableEventHandlers","initializeDataTable"],"sourceRoot":""} \ No newline at end of file diff --git a/resources/js/warehouse_management/opnames/index.js b/resources/js/warehouse_management/opnames/index.js index 2cf7cff..038604f 100755 --- a/resources/js/warehouse_management/opnames/index.js +++ b/resources/js/warehouse_management/opnames/index.js @@ -196,8 +196,13 @@ function initializeDataTable() { }, }, columnDefs: [ - { targets: 0, width: "15%" }, // Opname Date column - { targets: 5, width: "15%", className: "text-center" }, // Action column + { targets: 0, width: "15%" }, // Created At column + { targets: 1, width: "12%" }, // Opname Date column + { targets: 2, width: "15%" }, // Dealer column + { targets: 3, width: "12%" }, // User column + { targets: 4, width: "10%" }, // Status column + { targets: 5, width: "15%", className: "text-center" }, // Stock Info column + { targets: 6, width: "15%", className: "text-center" }, // Action column ], columns: [ { @@ -225,6 +230,12 @@ function initializeDataTable() { name: "status", orderable: true, }, + { + data: "stock_info", + name: "stock_info", + orderable: false, + searchable: false, + }, { data: "action", name: "action", @@ -232,7 +243,7 @@ function initializeDataTable() { searchable: false, }, ], - order: [[4, "desc"]], // Order by created_at desc + order: [[0, "desc"]], // Order by created_at desc pageLength: 10, responsive: true, ordering: true, diff --git a/resources/views/transaction/index.blade.php b/resources/views/transaction/index.blade.php index 21aa96d..3fc6922 100755 --- a/resources/views/transaction/index.blade.php +++ b/resources/views/transaction/index.blade.php @@ -739,22 +739,12 @@ use Illuminate\Support\Facades\Auth;
- - @error('opname_date') -
- {{ $message }} -
- @enderror +
- - - @error('description') -
- {{ $message }} -
- @enderror + +
@@ -764,9 +754,7 @@ use Illuminate\Support\Facades\Auth; Produk Dealer - Stock Sistem Stock Fisik - Selisih @@ -779,22 +767,11 @@ use Illuminate\Support\Facades\Auth; {{ $product->name }} {{ $mechanic->dealer_name }} - - {{ number_format($currentStock, 2) }} + - - - - @error('physical_stock.'.$loop->index) -
- {{ $message }} -
- @enderror - - - 0.00 + @endforeach @@ -806,6 +783,10 @@ use Illuminate\Support\Facades\Auth; + + + Stock fisik yang kosong akan otomatis diisi dengan 0 +
@@ -1353,49 +1334,39 @@ use Illuminate\Support\Facades\Auth; // Save current tab to localStorage localStorage.setItem('activeTab', '#opname'); - // Validate form + // Set default values for empty fields and validate 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)'); - } + // Set default value to 0 if empty + if (value === '' || value === null || value === undefined) { + $(this).val('0.00'); + value = '0.00'; + } + + // Validate and format the value + var numValue = parseFloat(value); + if (!isNaN(numValue) && numValue >= 0) { + hasValidStock = true; + // Ensure the value is properly formatted + $(this).val(numValue.toFixed(2)); + } else { + // If invalid, set to 0 + $(this).val('0.00'); + hasValidStock = true; // Still consider valid since we set default } - // Don't remove elements here - let them stay for re-editing }); - // Show error if no valid stock entries + // Always allow submission since we set defaults if (!hasValidStock) { + // This should never happen now, but just in case 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(', ') + text: 'Terjadi kesalahan dalam validasi data. Silakan coba lagi.' }); return false; } @@ -1457,21 +1428,6 @@ use Illuminate\Support\Facades\Auth; // 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(); }) @@ -1690,31 +1646,34 @@ use Illuminate\Support\Facades\Auth; // 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 + // Update button text to show total products var buttonText = 'Simpan Opname'; - if (filledProducts > 0) { - buttonText += ` (${filledProducts}/${totalProducts} produk)`; - } + buttonText += ` (${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 + // Initialize default values for physical stock inputs + $(document).ready(function() { + $('.physical-stock').each(function() { + var value = $(this).val(); + if (value === '' || value === null || value === undefined) { + $(this).val('0.00'); + } + }); + }); + + // Handle when input loses focus - set default if empty $(document).on('blur', '.physical-stock', function() { - // Trigger calculation even for empty values + var value = $(this).val(); + if (value === '' || value === null || value === undefined) { + $(this).val('0.00'); + } + // Trigger calculation $(this).trigger('input'); }); @@ -1725,28 +1684,12 @@ use Illuminate\Support\Facades\Auth; 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'); + // Set default values when user leaves field empty + $(document).on('blur', '.physical-stock', function() { + var value = $(this).val(); + if (value === '' || value === null || value === undefined) { + $(this).val('0.00'); + } }); // Remove invalid styling when user starts typing in required fields @@ -1779,6 +1722,9 @@ use Illuminate\Support\Facades\Auth; $('#date-opname').val(today); } + // Initialize opname form + updateProductCounter(); + // Initialize mutasi form updateRemoveButtonsMutasi(); @@ -1935,7 +1881,10 @@ use Illuminate\Support\Facades\Auth; } else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') { // Reset opname form after success $('#opnameForm')[0].reset(); - $('.physical-stock').val('').removeClass('is-invalid'); + // Set default values for physical stock inputs + $('.physical-stock').each(function() { + $(this).val('0.00'); + }); $('.difference').text('0.00').removeClass('text-success text-danger'); $("#btn-save-opname").attr("disabled", false); $("#btn-save-opname").removeClass("disabled"); @@ -1963,6 +1912,12 @@ use Illuminate\Support\Facades\Auth; $("#btn-save-opname").attr("disabled", false); $("#btn-save-opname").removeClass("disabled"); $("#btn-save-opname").html('Simpan Opname'); + // Set default values for physical stock inputs + $('.physical-stock').each(function() { + if ($(this).val() === '' || $(this).val() === null || $(this).val() === undefined) { + $(this).val('0.00'); + } + }); } else if (activeTab === 'mutasi') { // Reset button states for mutasi form $("#btn-save-mutasi").attr("disabled", false); diff --git a/resources/views/warehouse_management/mutations/print.blade.php b/resources/views/warehouse_management/mutations/print.blade.php index 9d9c9c1..60c28d3 100644 --- a/resources/views/warehouse_management/mutations/print.blade.php +++ b/resources/views/warehouse_management/mutations/print.blade.php @@ -327,7 +327,7 @@
-
PT. CINTA KASIH BERSAMA
+
PT. CIPTA KREASI BARU
Warehouse Management System
Dokumen Mutasi Stock
@@ -528,7 +528,7 @@
diff --git a/resources/views/warehouse_management/opnames/index.blade.php b/resources/views/warehouse_management/opnames/index.blade.php index 1619760..152fd90 100755 --- a/resources/views/warehouse_management/opnames/index.blade.php +++ b/resources/views/warehouse_management/opnames/index.blade.php @@ -69,6 +69,7 @@ Dealer Pengguna Status + Informasi Stock Aksi @@ -114,6 +115,44 @@ letter-spacing: normal; display: block; } + + /* Stock info column styling */ + .stock-info-cell { + min-width: 120px; + max-width: 150px; + } + + .stock-info-cell .text-success { + color: #28a745 !important; + font-weight: 600; + } + + .stock-info-cell .text-danger { + color: #dc3545 !important; + font-weight: 600; + } + + .stock-info-cell .text-muted { + color: #6c757d !important; + font-size: 11px; + } + + .stock-info-cell i { + margin-right: 4px; + } + + /* Responsive adjustments for stock info column */ + @media (max-width: 768px) { + .stock-info-cell { + min-width: 100px; + max-width: 120px; + font-size: 12px; + } + + .stock-info-cell .text-muted { + font-size: 10px; + } + } @endsection diff --git a/resources/views/warehouse_management/opnames/print.blade.php b/resources/views/warehouse_management/opnames/print.blade.php index 91dcabf..14b9e47 100644 --- a/resources/views/warehouse_management/opnames/print.blade.php +++ b/resources/views/warehouse_management/opnames/print.blade.php @@ -287,7 +287,7 @@
-
PT. CINTA KASIH BERSAMA
+
PT. CIPTA KREASI BARU
Warehouse Management System
Laporan Stock Opname
@@ -420,7 +420,7 @@