« Back to History
month_end_stock_entry1.php
|
20260721_154033.php
Initial Bulk Import
Copy Code
<?php /* month_end_stock_entry.php - final integrated version (replace existing file) - Prints OPTIONS to JS - Cascading dropdowns fixed - Sub Type removed; sections shown by Machine Type - Beam fetch preserved - cone_lookup, add_lookup handlers added - Save writes yarns_json into month_end_stock_report */ error_reporting(E_ALL); ini_set('display_errors',1); require_once __DIR__ . '/modules/auth/page_acl.php'; $ctx = page_require_access('month_end_stock_entry'); $u = $ctx['user'] ?? null; $company_id = (int)($ctx['company_id'] ?? 0); $pdo = $ctx['pdo'] ?? null; if (!$pdo) { require_once __DIR__ . '/core/db.php'; } /* CSRF */ $csrf = $_SESSION['csrf_token'] ?? bin2hex(random_bytes(16)); $_SESSION['csrf_token'] = $csrf; /* Server-side OPTIONS authoritative */ $OPTIONS = [ 'location' => ['MST1','MST2A','MST2B','MST2-TOP','ZARI MACHINE'], 'machine_groups' => [ 'MST1' => ['Bobin Machine','Warping Machine','Palti Machine'], 'MST2A' => ['Bobin Machine'], 'MST2B' => ['Bobin Machine'], 'MST2-TOP' => ['Warping Machine','Palti Machine','TFO'], 'ZARI MACHINE' => ['Zari Machine'] ], 'machine_types' => [ 'Bobin Machine' => ['In Bobin','Open Box','Closed Box','In Machine'], 'Warping Machine' => ['Beam Stock','Beam Quality','Yarn in Machine','Yarn in Closed Box','Yarn in Open Box'], 'Palti Machine' => ['Total Zari Roll'], 'TFO' => ['TFO Standard Section'], 'Zari Machine' => [] ] ]; /* Preload denier/color lookups if available (best-effort) */ $deniers = []; $colors = []; try { $q = $pdo->prepare("SELECT value FROM denier_lookup WHERE company_id = :cid ORDER BY value"); $q->execute([':cid'=>$company_id]); $deniers = array_column($q->fetchAll(PDO::FETCH_ASSOC), 'value'); $q2 = $pdo->prepare("SELECT value FROM color_lookup WHERE company_id = :cid ORDER BY value"); $q2->execute([':cid'=>$company_id]); $colors = array_column($q2->fetchAll(PDO::FETCH_ASSOC), 'value'); } catch (Exception $e) { // ignore if tables missing } /* -------------------- Beam fetch (unchanged) -------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'fetch') { header('Content-Type: application/json; charset=utf-8'); $bid = (int)($_POST['beam_quality_id'] ?? 0); $total_meter = (float)($_POST['total_meter'] ?? 0); $sql = "SELECT y.id, y.seq_no, y.stock_type, y.yarn_type, y.denier, y.color, y.total_tar, y.tpm, y.wastage FROM beam_quality_yarns y JOIN beam_qualities q ON q.id = y.beam_quality_id WHERE y.beam_quality_id = :bid AND q.company_id = :cid ORDER BY y.seq_no ASC, y.id ASC"; $st = $pdo->prepare($sql); $st->execute([':bid' => $bid, ':cid' => $company_id]); $rows = $st->fetchAll(PDO::FETCH_ASSOC); if (!$rows) { echo json_encode(['success' => false, 'msg' => 'No yarn rows found for selected quality.']); exit; } $st2 = $pdo->prepare("SELECT stock_type, yarn_type, denier, new_denier FROM yarn_weight_data WHERE 1"); $st2->execute(); $all_m = $st2->fetchAll(PDO::FETCH_ASSOC); $map = []; $map_short = []; foreach ($all_m as $r) { $key = strtolower(trim($r['stock_type'])) . '||' . strtolower(trim($r['yarn_type'])) . '||' . trim($r['denier']); $map[$key] = $r['new_denier']; $key2 = strtolower(trim($r['stock_type'])) . '||' . strtolower(trim($r['yarn_type'])); if (!isset($map_short[$key2])) $map_short[$key2] = $r['new_denier']; } $sum_tar = 0.0; foreach ($rows as $r) $sum_tar += (float)$r['total_tar']; $out = []; foreach ($rows as $r) { $row = $r; $k = strtolower(trim($r['stock_type'])) . '||' . strtolower(trim($r['yarn_type'])) . '||' . trim($r['denier']); $k2 = strtolower(trim($r['stock_type'])) . '||' . strtolower(trim($r['yarn_type'])); $new_denier = null; if (isset($map[$k])) $new_denier = $map[$k]; elseif (isset($map_short[$k2])) $new_denier = $map_short[$k2]; if ($new_denier === null) $new_denier = (float)$r['denier']; $meters_for_yarn = $total_meter * (float)$r['total_tar']; $weight_kg = ($meters_for_yarn * (float)$new_denier) / 9000000.0; $row['new_denier'] = (float)$new_denier; $row['meters'] = round($meters_for_yarn, 3); $row['weight_kg'] = round($weight_kg, 6); $out[] = $row; } echo json_encode(['success' => true, 'data' => $out, 'sum_tar' => $sum_tar]); exit; } /* -------------------- Cone lookup -------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'cone_lookup') { header('Content-Type: application/json; charset=utf-8'); $color = trim($_POST['color'] ?? ''); $denier = trim($_POST['denier'] ?? ''); if (!$color || !$denier) { echo json_encode(['success'=>false,'msg'=>'Missing color/denier']); exit; } $q = $pdo->prepare("SELECT cone_weight FROM cone_weight_matrix WHERE company_id = :cid AND LOWER(color)=LOWER(:color) AND LOWER(denier)=LOWER(:denier) LIMIT 1"); $q->execute([':cid'=>$company_id, ':color'=>$color, ':denier'=>$denier]); $r = $q->fetch(PDO::FETCH_ASSOC); if ($r && $r['cone_weight']) { echo json_encode(['success'=>true,'cone_weight'=> (float)$r['cone_weight'] ]); exit; } $q2 = $pdo->prepare("SELECT cone_weight FROM cone_weight_matrix WHERE company_id = :cid AND LOWER(color)=LOWER(:color) LIMIT 1"); $q2->execute([':cid'=>$company_id, ':color'=>$color]); $r2 = $q2->fetch(PDO::FETCH_ASSOC); if ($r2 && $r2['cone_weight']) { echo json_encode(['success'=>true,'cone_weight'=> (float)$r2['cone_weight'] ]); exit; } echo json_encode(['success'=>false,'msg'=>'No cone weight found']); exit; } /* -------------------- Add lookup (denier/color) -------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'add_lookup') { header('Content-Type: application/json; charset=utf-8'); $type = trim($_POST['type'] ?? ''); $value = trim($_POST['value'] ?? ''); if (!$type || !$value) { echo json_encode(['success'=>false,'msg'=>'Missing type/value']); exit; } try { if ($type === 'denier') { $ins = $pdo->prepare("INSERT INTO denier_lookup (company_id, value) VALUES (:cid, :val)"); $ins->execute([':cid'=>$company_id, ':val'=>$value]); } elseif ($type === 'color') { $ins = $pdo->prepare("INSERT INTO color_lookup (company_id, value) VALUES (:cid, :val)"); $ins->execute([':cid'=>$company_id, ':val'=>$value]); } else { echo json_encode(['success'=>false,'msg'=>'Unknown lookup type']); exit; } echo json_encode(['success'=>true,'msg'=>'Saved']); exit; } catch (Exception $e) { echo json_encode(['success'=>false,'msg'=>'DB insert failed']); exit; } } /* -------------------- Save (sections object into yarns_json) -------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save') { $token = $_POST['csrf_token'] ?? ''; if (!$token || !hash_equals($_SESSION['csrf_token'] ?? '', $token)) { echo "<div style='color:red;padding:10px;'>CSRF token mismatch.</div>"; exit; } $month = trim($_POST['month'] ?? ''); $location = trim($_POST['location'] ?? ''); $machine_group = trim($_POST['machine_group'] ?? ''); $machine_type = trim($_POST['machine_type'] ?? ''); $stock_type = trim($_POST['stock_type'] ?? ''); $remark = trim($_POST['remark'] ?? ''); $yarns_json = $_POST['yarns_json'] ?? '[]'; if (!$month || !$location || !$machine_group || !$machine_type) { echo "<div style='color:orange;padding:10px;'>Please fill month, location, machine group and machine type.</div>"; exit; } $beam_quality_id = (int)($_POST['beam_quality_id'] ?? 0); $total_meter = (float)($_POST['total_meter'] ?? 0); try { $ins = $pdo->prepare("INSERT INTO month_end_stock_report (company_id, month, location, machine_group, machine_type, stock_type, beam_quality_id, total_meter, yarns_json, remark, created_by) VALUES (:cid, :month, :location, :mg, :mt, :stock_type, :bqid, :tm, :yj, :remark, :created_by)"); $ins->execute([ ':cid' => $company_id, ':month' => $month, ':location' => $location, ':mg' => $machine_group, ':mt' => $machine_type, ':stock_type' => $stock_type, ':bqid' => $beam_quality_id ?: null, ':tm' => $total_meter ?: null, ':yj' => $yarns_json, ':remark' => $remark, ':created_by' => $u['id'] ?? null, ]); echo "<div style='color:green;padding:10px;'>Entry saved successfully.</div>"; } catch (PDOException $ex) { echo "<div style='color:red;padding:10px;'>DB error: " . htmlspecialchars($ex->getMessage()) . "</div>"; } exit; } /* -------------------- HTML (minimal styles) -------------------- */ ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Month-end Stock Entry (fixed)</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> body{font-family:Arial,Helvetica,sans-serif;background:#fff;padding:18px;} .card{border:1px solid #ddd;border-radius:6px;padding:14px;max-width:1200px;margin:8px auto;} .form-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;} .form-group{display:flex;flex-direction:column;margin-bottom:8px;} label{font-weight:600;margin-bottom:6px;} input.form-control, select.form-control, textarea.form-control{padding:8px;border:1px solid #ccc;border-radius:4px;} .section{border:1px dashed #ccc;padding:10px;margin:8px 0;border-radius:6px;background:#fafafa;} .section h4{margin:0 0 8px 0;} .actions{margin-top:10px;} .btn{display:inline-block;padding:7px 10px;border-radius:6px;border:0;cursor:pointer;} .btn-primary{background:#2d6cdf;color:#fff;} .btn-success{background:#2da54b;color:#fff;} .small-btn{padding:6px 8px;font-size:12px;margin-left:6px;} .table{width:100%;border-collapse:collapse;margin-top:8px;} .table th,.table td{border:1px solid #eee;padding:6px;font-size:13px;} </style> </head> <body> <div class="card"> <h3>Month-end Stock Entry</h3> <form id="mainForm" method="post" action=""> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>"> <div class="form-grid"> <div class="form-group"> <label for="month">Month</label> <input id="month" name="month" type="month" class="form-control" required> </div> <div class="form-group"> <label for="location">Location</label> <select id="location" name="location" class="form-control" required> <option value="">-- Select Location --</option> <?php foreach($OPTIONS['location'] as $loc): ?> <option value="<?= htmlspecialchars($loc) ?>"><?= htmlspecialchars($loc) ?></option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="machine_group">Machine Group</label> <select id="machine_group" name="machine_group" class="form-control" required> <option value="">-- Select Group --</option> </select> </div> <div class="form-group"> <label for="machine_type">Machine Type</label> <select id="machine_type" name="machine_type" class="form-control" required> <option value="">-- Select Machine Type --</option> </select> </div> <div class="form-group"> <label for="stock_type">Stock Type</label> <select id="stock_type" name="stock_type" class="form-control"> <option value="">-- Select --</option> <option>Stock in installed beam</option> <option>Stock in beam stock</option> <option>Stock in open box</option> <option>Stock in bobin</option> </select> </div> <div class="form-group"> <label for="beam_quality_id">Beam Quality (if beam)</label> <select id="beam_quality_id" name="beam_quality_id" class="form-control"> <option value="">-- Select Quality --</option> <?php foreach($pdo->query("SELECT id,name FROM beam_qualities WHERE company_id = ".(int)$company_id." ORDER BY name") as $q): ?> <option value="<?= (int)$q['id'] ?>"><?= htmlspecialchars($q['name']) ?></option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="total_meter">Total Meter (for beam)</label> <input id="total_meter" name="total_meter" type="number" step="0.001" class="form-control"> </div> <div class="form-group"> <label for="remark">Remark</label> <input id="remark" name="remark" class="form-control"> </div> </div> <div class="actions"> <button id="btnPrepare" type="button" class="btn btn-primary">Prepare Details</button> </div> <hr> <div id="detailArea" style="display:none;"> <!-- Beam --> <div id="beamWrap" style="display:none;"> <h4>Yarn Composition & Calculations (Beam)</h4> <table class="table" id="beamTable"><thead><tr> <th>#</th><th>Stock Type</th><th>Yarn Type</th><th>Color</th><th>Orig Denier</th><th>New Denier</th> <th>Total Tar</th><th>Meters</th><th>Weight (kg)</th><th>TPM</th><th>Wastage</th> </tr></thead><tbody></tbody></table> </div> <!-- Bobin sections --> <div id="bobinSections" style="display:none;"> <h4>Bobin Machine — Sections</h4> <div class="section" id="sec_in_bobin"> <h4>In Bobin</h4> <div><button id="add_in_bobin" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_in_bobin"> <thead><tr><th>#</th><th>Yarn</th><th>Denier <button class="btn small-btn denier-add" data-target="in_bobin">+ Add</button></th><th>Color <button class="btn small-btn color-add" data-target="in_bobin">+ Add</button></th><th>Bobin Count</th><th>Weight (kg)</th><th>Action</th></tr></thead> <tbody></tbody> <tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_in_bobin">0</td><td></td></tr></tfoot> </table> </div> <div class="section" id="sec_open_box"> <h4>Open Box</h4> <div><button id="add_open_box" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_open_box"> <thead><tr><th>#</th><th>Yarn</th><th>Denier <button class="btn small-btn denier-add" data-target="open_box">+ Add</button></th><th>Color <button class="btn small-btn color-add" data-target="open_box">+ Add</button></th><th>Total Cone</th><th>Cone Count (opt)</th><th>Weight (kg)</th><th>Action</th></tr></thead> <tbody></tbody> <tfoot><tr><td colspan="6" style="text-align:right;">Total Kg</td><td id="total_open_box">0</td><td></td></tr></tfoot> </table> </div> <div class="section" id="sec_closed_box"> <h4>Closed Box</h4> <div><button id="add_closed_box" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_closed_box"> <thead><tr><th>#</th><th>Yarn</th><th>Denier <button class="btn small-btn denier-add" data-target="closed_box">+ Add</button></th><th>Color <button class="btn small-btn color-add" data-target="closed_box">+ Add</button></th><th>Box/ID</th><th>Weight (kg)</th><th>Action</th></tr></thead> <tbody></tbody> <tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_closed_box">0</td><td></td></tr></tfoot> </table> </div> <div class="section" id="sec_in_machine"> <h4>In Machine</h4> <div><button id="add_in_machine" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_in_machine"> <thead><tr><th>#</th><th>Yarn</th><th>Denier <button class="btn small-btn denier-add" data-target="in_machine">+ Add</button></th><th>Color <button class="btn small-btn color-add" data-target="in_machine">+ Add</button></th><th>Total Cone</th><th>Weight (kg)</th><th>Action</th></tr></thead> <tbody></tbody> <tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_in_machine">0</td><td></td></tr></tfoot> </table> </div> </div> <!-- Warping sections --> <div id="warpingSections" style="display:none;"> <h4>Warping Machine — Sections</h4> <div class="section"> <h4>Yarn in Machine (Open Box style)</h4> <div><button id="add_warp_in_machine" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_warp_in_machine"><thead><tr><th>#</th><th>Yarn</th><th>Denier</th><th>Color</th><th>Total Cone</th><th>Weight (kg)</th><th>Action</th></tr></thead><tbody></tbody><tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_warp_in_machine">0</td><td></td></tr></tfoot></table> </div> <div class="section"> <h4>Yarn in Open Box</h4> <div><button id="add_warp_open_box" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_warp_open_box"><thead><tr><th>#</th><th>Yarn</th><th>Denier</th><th>Color</th><th>Total Cone</th><th>Weight (kg)</th><th>Action</th></tr></thead><tbody></tbody><tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_warp_open_box">0</td><td></td></tr></tfoot></table> </div> <div class="section"> <h4>Yarn in Closed Box</h4> <div><button id="add_warp_closed_box" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_warp_closed_box"><thead><tr><th>#</th><th>Yarn</th><th>Denier</th><th>Color</th><th>Box</th><th>Weight (kg)</th><th>Action</th></tr></thead><tbody></tbody><tfoot><tr><td colspan="5" style="text-align:right;">Total Kg</td><td id="total_warp_closed_box">0</td><td></td></tr></tfoot></table> </div> </div> <!-- Palti --> <div id="paltiSections" style="display:none;"> <h4>Palti Machine — Total Zari Roll</h4> <div><button id="add_palti" class="btn small-btn">Add Row</button></div> <table class="table" id="tbl_palti"><thead><tr><th>#</th><th>Denier</th><th>Color</th><th>Rolls</th><th>Action</th></tr></thead><tbody></tbody><tfoot><tr><td colspan="3" style="text-align:right;">Total Rolls</td><td id="total_palti">0</td><td></td></tr></tfoot></table> </div> <!-- TFO placeholder --> <div id="tfoSections" style="display:none;"> <h4>TFO — Placeholder (tell me fields to add)</h4> </div> <div class="mt-2"> <form id="saveForm" method="post" action=""> <input type="hidden" name="action" value="save"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>"> <input type="hidden" name="yarns_json" id="save_yarns_json"> <input type="hidden" name="month" id="save_month"> <input type="hidden" name="location_h" id="save_location"> <input type="hidden" name="machine_group_h" id="save_machine_group"> <input type="hidden" name="machine_type_h" id="save_machine_type"> <input type="hidden" name="stock_type_h" id="save_stock_type"> <input type="hidden" name="beam_quality_id_h" id="save_beam_quality_id"> <input type="hidden" name="total_meter_h" id="save_total_meter"> <input type="hidden" name="remark_h" id="save_remark"> <button id="btnSave" type="submit" class="btn btn-success">Save Entry</button> </form> </div> </div> <!-- detailArea --> </form> </div> <!-- Print OPTIONS to JS so dropdowns work --> <script>const OPTIONS = <?= json_encode($OPTIONS, JSON_UNESCAPED_UNICODE) ?>; const PRELOADED_DENIERS = <?= json_encode($deniers, JSON_UNESCAPED_UNICODE) ?>; const PRELOADED_COLORS = <?= json_encode($colors, JSON_UNESCAPED_UNICODE) ?>;</script> <script> (function(){ function $(id){ return document.getElementById(id); } function escapeHtml(s){ return (s===null||s===undefined)?'':String(s).replaceAll('&','&').replaceAll('<','<').replaceAll('>','>'); } function createOption(val){ const o = document.createElement('option'); o.value = val; o.textContent = val; return o; } document.addEventListener('DOMContentLoaded', function(){ const locationEl = $('location'), mgEl = $('machine_group'), mtEl = $('machine_type'); const prepareBtn = $('btnPrepare'), detailArea = $('detailArea'); const beamWrap = $('beamWrap'), beamTableBody = document.querySelector('#beamTable tbody'); const bobinSections = $('bobinSections'), warpingSections = $('warpingSections'), paltiSections = $('paltiSections'), tfoSections = $('tfoSections'); function clearSelect(sel, placeholder){ sel.innerHTML = ''; sel.appendChild(new Option(placeholder||'-- Select --','')); } function getKeyInsensitive(obj, key) { if (!obj) return undefined; if (Object.prototype.hasOwnProperty.call(obj, key)) return obj[key]; const keys = Object.keys(obj); const found = keys.find(k => k.toLowerCase() === String(key).toLowerCase()); return found ? obj[found] : undefined; } // populate machine groups locationEl.addEventListener('change', function(){ clearSelect(mgEl,'-- Select Group --'); clearSelect(mtEl,'-- Select Machine Type --'); const groups = getKeyInsensitive(OPTIONS.machine_groups, this.value); if (Array.isArray(groups)) groups.forEach(g => mgEl.appendChild(createOption(g))); else mgEl.appendChild(createOption('-- No groups --')); }); // populate machine types mgEl.addEventListener('change', function(){ clearSelect(mtEl,'-- Select Machine Type --'); const types = getKeyInsensitive(OPTIONS.machine_types, this.value); if (Array.isArray(types)) types.forEach(t => mtEl.appendChild(createOption(t))); else mtEl.appendChild(createOption('-- No types --')); }); // show sections by machine type mtEl.addEventListener('change', function(){ const mt = this.value || ''; detailArea.style.display = 'none'; beamWrap.style.display = 'none'; bobinSections.style.display = 'none'; warpingSections.style.display = 'none'; paltiSections.style.display = 'none'; tfoSections.style.display = 'none'; if (!mt) return; const lower = mt.toLowerCase(); if (lower.includes('bobin')) bobinSections.style.display = 'block'; else if (lower.includes('warping')) warpingSections.style.display = 'block'; else if (lower.includes('palti')) paltiSections.style.display = 'block'; else if (lower.includes('tfo')) tfoSections.style.display = 'block'; }); // helper add-row function addRowTo(tblId, cols) { const tbody = document.querySelector('#'+tblId+' tbody'); const tr = document.createElement('tr'); tr.innerHTML = cols.map(c => '<td>'+c+'</td>').join('') + '<td><button class="btn small-btn remove-row">Remove</button></td>'; tbody.appendChild(tr); tr.querySelector('.remove-row').addEventListener('click', function(e){ e.preventDefault(); tr.remove(); recalcAllTotals(); renumberTable(tbody); }); renumberTable(tbody); recalcAllTotals(); } function renumberTable(tbody){ Array.from(tbody.querySelectorAll('tr')).forEach((tr,i)=>{ const first = tr.querySelector('td'); if(first) first.textContent = i+1; }); } function sumColumn(selector){ let s=0; document.querySelectorAll(selector).forEach(el => { const v=parseFloat(el.textContent||0); if(!isNaN(v)) s+=v; }); return s; } function computeBobinWeight(count){ return (count * 30) / 1000.0; } function fetchConeWeight(color, denier, cb){ const fd=new FormData(); fd.append('action','cone_lookup'); fd.append('color',color); fd.append('denier',denier); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(j=>cb(j)).catch(()=>cb({success:false})); } // add-row handlers (bobin/open/closed/in machine) $('add_in_bobin').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />', (function(){ let s='<select class="form-control item_denier"><option></option>'; PRELOADED_DENIERS.forEach(d=> s+='<option>'+escapeHtml(d)+'</option>'); s+='</select>'; return s; })(), (function(){ let s='<select class="form-control item_color"><option></option>'; PRELOADED_COLORS.forEach(c=> s+='<option>'+escapeHtml(c)+'</option>'); s+='</select>'; return s; })(), '<input type="number" class="form-control item_count" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_in_bobin', cols); attachRowEvents(document.querySelector('#tbl_in_bobin tbody tr:last-child'),'bobin'); }); $('add_open_box').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />', (function(){ let s='<select class="form-control item_denier"><option></option>'; PRELOADED_DENIERS.forEach(d=> s+='<option>'+escapeHtml(d)+'</option>'); s+='</select>'; return s; })(), (function(){ let s='<select class="form-control item_color"><option></option>'; PRELOADED_COLORS.forEach(c=> s+='<option>'+escapeHtml(c)+'</option>'); s+='</select>'; return s; })(), '<input type="number" class="form-control item_total_cone" value="0" />','<input type="number" class="form-control item_cone_count" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_open_box', cols); attachRowEvents(document.querySelector('#tbl_open_box tbody tr:last-child'),'open_box'); }); $('add_closed_box').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />', (function(){ let s='<select class="form-control item_denier"><option></option>'; PRELOADED_DENIERS.forEach(d=> s+='<option>'+escapeHtml(d)+'</option>'); s+='</select>'; return s; })(), (function(){ let s='<select class="form-control item_color"><option></option>'; PRELOADED_COLORS.forEach(c=> s+='<option>'+escapeHtml(c)+'</option>'); s+='</select>'; return s; })(), '<input class="form-control item_box" />','<input type="number" step="0.001" class="form-control item_box_weight" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_closed_box', cols); attachRowEvents(document.querySelector('#tbl_closed_box tbody tr:last-child'),'closed_box'); }); $('add_in_machine').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />', (function(){ let s='<select class="form-control item_denier"><option></option>'; PRELOADED_DENIERS.forEach(d=> s+='<option>'+escapeHtml(d)+'</option>'); s+='</select>'; return s; })(), (function(){ let s='<select class="form-control item_color"><option></option>'; PRELOADED_COLORS.forEach(c=> s+='<option>'+escapeHtml(c)+'</option>'); s+='</select>'; return s; })(), '<input type="number" class="form-control item_total_cone" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_in_machine', cols); attachRowEvents(document.querySelector('#tbl_in_machine tbody tr:last-child'),'in_machine'); }); $('add_warp_in_machine').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />','<select class="form-control item_denier"><option></option>'+PRELOADED_DENIERS.map(d=>'<option>'+escapeHtml(d)+'</option>').join('')+'</select>','<select class="form-control item_color"><option></option>'+PRELOADED_COLORS.map(c=>'<option>'+escapeHtml(c)+'</option>').join('')+'</select>','<input type="number" class="form-control item_total_cone" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_warp_in_machine', cols); attachRowEvents(document.querySelector('#tbl_warp_in_machine tbody tr:last-child'),'warp_open'); }); $('add_warp_open_box').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />','<select class="form-control item_denier"><option></option>'+PRELOADED_DENIERS.map(d=>'<option>'+escapeHtml(d)+'</option>').join('')+'</select>','<select class="form-control item_color"><option></option>'+PRELOADED_COLORS.map(c=>'<option>'+escapeHtml(c)+'</option>').join('')+'</select>','<input type="number" class="form-control item_total_cone" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_warp_open_box', cols); attachRowEvents(document.querySelector('#tbl_warp_open_box tbody tr:last-child'),'warp_open'); }); $('add_warp_closed_box').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<input class="form-control item_yarn" />','<select class="form-control item_denier"><option></option>'+PRELOADED_DENIERS.map(d=>'<option>'+escapeHtml(d)+'</option>').join('')+'</select>','<select class="form-control item_color"><option></option>'+PRELOADED_COLORS.map(c=>'<option>'+escapeHtml(c)+'</option>').join('')+'</select>','<input class="form-control item_box" />','<input type="number" step="0.001" class="form-control item_box_weight" value="0" />','<span class="item_weight">0</span>']; addRowTo('tbl_warp_closed_box', cols); attachRowEvents(document.querySelector('#tbl_warp_closed_box tbody tr:last-child'),'warp_closed'); }); $('add_palti').addEventListener('click', function(e){ e.preventDefault(); const cols = ['', '<select class="form-control item_denier"><option></option>'+PRELOADED_DENIERS.map(d=>'<option>'+escapeHtml(d)+'</option>').join('')+'</select>','<select class="form-control item_color"><option></option>'+PRELOADED_COLORS.map(c=>'<option>'+escapeHtml(c)+'</option>').join('')+'</select>','<input type="number" class="form-control item_rolls" value="0" />']; addRowTo('tbl_palti', cols); attachRowEvents(document.querySelector('#tbl_palti tbody tr:last-child'),'palti'); }); // attach events for lookup add buttons (delegated) document.body.addEventListener('click', function(e){ if (e.target && e.target.classList.contains('denier-add')) { e.preventDefault(); const val = prompt('Enter new denier (e.g., 110 Lichi)'); if (!val) return; // Persist attempt const fd = new FormData(); fd.append('action','add_lookup'); fd.append('type','denier'); fd.append('value',val); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(j=>{ if (!j.success) console.warn('denier save failed'); }).catch(()=>{}); // add globally so new selects get it if page uses PRELOADED arrays (not persisted unless DB table exists) PRELOADED_DENIERS.push(val); } if (e.target && e.target.classList.contains('color-add')) { e.preventDefault(); const val = prompt('Enter new color (e.g., Gold)'); if (!val) return; const fd = new FormData(); fd.append('action','add_lookup'); fd.append('type','color'); fd.append('value',val); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(j=>{ if (!j.success) console.warn('color save failed'); }).catch(()=>{}); PRELOADED_COLORS.push(val); } }); function attachRowEvents(tr, type){ const denierSel = tr.querySelector('.item_denier'); const colorSel = tr.querySelector('.item_color'); const countInp = tr.querySelector('.item_count'); const coneCountInp = tr.querySelector('.item_cone_count'); const totalConeInp = tr.querySelector('.item_total_cone'); const boxWeightInp = tr.querySelector('.item_box_weight'); const rollsInp = tr.querySelector('.item_rolls'); tr.querySelectorAll('input, select').forEach(inp => inp.addEventListener('input', function(){ computeRowWeight(tr, type); })); computeRowWeight(tr, type); } function computeRowWeight(tr, type){ const denier = tr.querySelector('.item_denier') ? tr.querySelector('.item_denier').value.trim() : ''; const color = tr.querySelector('.item_color') ? tr.querySelector('.item_color').value.trim() : ''; const count = tr.querySelector('.item_count') ? parseFloat(tr.querySelector('.item_count').value||0) : 0; const coneCount = tr.querySelector('.item_cone_count') ? parseFloat(tr.querySelector('.item_cone_count').value||0) : 0; const totalCone = tr.querySelector('.item_total_cone') ? parseFloat(tr.querySelector('.item_total_cone').value||0) : 0; const boxWeight = tr.querySelector('.item_box_weight') ? parseFloat(tr.querySelector('.item_box_weight').value||0) : 0; const rolls = tr.querySelector('.item_rolls') ? parseFloat(tr.querySelector('.item_rolls').value||0) : 0; const weightCell = tr.querySelector('.item_weight'); if (type === 'bobin') { const w = computeBobinWeight(count); weightCell.textContent = w.toFixed(3); recalcAllTotals(); return; } if (['open_box','in_machine','warp_open'].includes(type)) { const cones = coneCount > 0 ? coneCount : (totalCone > 0 ? totalCone : 0); if (cones > 0 && (color || denier)) { fetchConeWeight(color, denier, function(resp){ if (resp && resp.success && resp.cone_weight) { const w = parseFloat(resp.cone_weight) * cones; weightCell.textContent = w.toFixed(3); } else weightCell.textContent = '0'; recalcAllTotals(); }); return; } weightCell.textContent = '0'; recalcAllTotals(); return; } if (type === 'closed_box') { weightCell.textContent = boxWeight > 0 ? boxWeight.toFixed(3) : '0'; recalcAllTotals(); return; } if (type === 'palti') { weightCell.textContent = rolls || 0; recalcAllTotals(); return; } weightCell.textContent = '0'; recalcAllTotals(); } function recalcAllTotals(){ $('total_in_bobin').textContent = sumColumn('#tbl_in_bobin .item_weight').toFixed(3); $('total_open_box').textContent = sumColumn('#tbl_open_box .item_weight').toFixed(3); $('total_closed_box').textContent = sumColumn('#tbl_closed_box .item_weight').toFixed(3); $('total_in_machine').textContent = sumColumn('#tbl_in_machine .item_weight').toFixed(3); $('total_warp_in_machine').textContent = sumColumn('#tbl_warp_in_machine .item_weight').toFixed(3); $('total_warp_open_box').textContent = sumColumn('#tbl_warp_open_box .item_weight').toFixed(3); $('total_warp_closed_box').textContent = sumColumn('#tbl_warp_closed_box .item_weight').toFixed(3); let totalRolls = 0; document.querySelectorAll('#tbl_palti tbody tr').forEach(tr => { const v = parseFloat(tr.querySelector('.item_rolls') ? tr.querySelector('.item_rolls').value : 0) || 0; totalRolls += v; }); $('total_palti').textContent = totalRolls; } // Prepare button logic (beam or sections) prepareBtn.addEventListener('click', function(e){ e.preventDefault(); const loc = locationEl.value, mg = mgEl.value, mt = mtEl.value; if (!loc || !mg || !mt) return alert('Select location, machine group and machine type first.'); detailArea.style.display = 'block'; if (mt.toLowerCase().includes('beam')) { const bq = $('beam_quality_id').value; const tm = parseFloat($('total_meter').value||0); if (!bq) return alert('Select beam quality'); if (!(tm>0)) return alert('Enter total meter for beam'); const fd = new FormData(); fd.append('action','fetch'); fd.append('beam_quality_id', bq); fd.append('total_meter', tm); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(resp=>{ if (!resp.success) return alert(resp.msg||'No data'); beamTableBody.innerHTML=''; resp.data.forEach((r,i)=>{ const tr=document.createElement('tr'); tr.innerHTML='<td>'+(i+1)+'</td><td>'+escapeHtml(r.stock_type)+'</td><td>'+escapeHtml(r.yarn_type)+'</td><td>'+escapeHtml(r.color)+'</td><td>'+escapeHtml(r.denier)+'</td><td>'+escapeHtml(r.new_denier)+'</td><td>'+escapeHtml(r.total_tar)+'</td><td>'+escapeHtml(r.meters)+'</td><td>'+escapeHtml(r.weight_kg)+'</td><td>'+escapeHtml(r.tpm)+'</td><td>'+escapeHtml(r.wastage)+'</td>'; beamTableBody.appendChild(tr); }); beamWrap.style.display='block'; bobinSections.style.display='none'; warpingSections.style.display='none'; paltiSections.style.display='none'; tfoSections.style.display='none'; $('save_beam_quality_id').value = $('beam_quality_id').value; $('save_total_meter').value = $('total_meter').value; $('save_month').value = $('month').value; $('save_location').value = loc; $('save_machine_group').value = mg; $('save_machine_type').value = mt; $('save_stock_type').value = $('stock_type').value; $('save_remark').value = $('remark').value; }).catch(err=>{ console.error(err); alert('Error fetching beam data.'); }); return; } beamWrap.style.display='none'; if (mt.toLowerCase().includes('bobin')) { bobinSections.style.display='block'; warpingSections.style.display='none'; paltiSections.style.display='none'; tfoSections.style.display='none'; } else if (mt.toLowerCase().includes('warping')) { warpingSections.style.display='block'; bobinSections.style.display='none'; paltiSections.style.display='none'; tfoSections.style.display='none'; } else if (mt.toLowerCase().includes('palti')) { paltiSections.style.display='block'; bobinSections.style.display='none'; warpingSections.style.display='none'; tfoSections.style.display='none'; } else if (mt.toLowerCase().includes('tfo')) { tfoSections.style.display='block'; bobinSections.style.display='none'; warpingSections.style.display='none'; paltiSections.style.display='none'; } $('save_month').value = $('month').value; $('save_location').value = loc; $('save_machine_group').value = mg; $('save_machine_type').value = mt; $('save_stock_type').value = $('stock_type').value; $('save_remark').value = $('remark').value; }); // Save compose sections -> yarns_json $('saveForm').addEventListener('submit', function(e){ const payload = { sections: {} }; payload.location = $('save_location').value; payload.machine_group = $('save_machine_group').value; payload.machine_type = $('save_machine_type').value; payload.stock_type = $('save_stock_type').value; payload.month = $('save_month').value; payload.remark = $('save_remark').value; if (beamWrap.style.display !== 'none') { payload.sections.beam = []; document.querySelectorAll('#beamTable tbody tr').forEach(tr=>{ const td=tr.querySelectorAll('td'); payload.sections.beam.push({stock_type:td[1].textContent,yarn_type:td[2].textContent,color:td[3].textContent,denier:td[4].textContent,new_denier:td[5].textContent,total_tar:td[6].textContent,meters:td[7].textContent,weight_kg:td[8].textContent}); }); } function collectTable(tblId){ const arr=[]; document.querySelectorAll('#'+tblId+' tbody tr').forEach(tr=>{ const yarn = tr.querySelector('.item_yarn') ? tr.querySelector('.item_yarn').value : ''; const denier = tr.querySelector('.item_denier') ? tr.querySelector('.item_denier').value : ''; const color = tr.querySelector('.item_color') ? tr.querySelector('.item_color').value : ''; const count = tr.querySelector('.item_count') ? tr.querySelector('.item_count').value : ''; const total_cone = tr.querySelector('.item_total_cone') ? tr.querySelector('.item_total_cone').value : ''; const cone_count = tr.querySelector('.item_cone_count') ? tr.querySelector('.item_cone_count').value : ''; const box = tr.querySelector('.item_box') ? tr.querySelector('.item_box').value : ''; const box_weight = tr.querySelector('.item_box_weight') ? tr.querySelector('.item_box_weight').value : ''; const rolls = tr.querySelector('.item_rolls') ? tr.querySelector('.item_rolls').value : ''; const weight = tr.querySelector('.item_weight') ? tr.querySelector('.item_weight').textContent : ''; const obj = { yarn: yarn, denier: denier, color: color, weight_kg: parseFloat(weight||0) }; if (tblId.indexOf('bobin')>=0) { obj.bobin_count = count; } else if (tblId.indexOf('open_box')>=0) { obj.total_cone = total_cone; obj.cone_count = cone_count; } else if (tblId.indexOf('closed_box')>=0) { obj.box = box; obj.box_weight = box_weight; } else if (tblId.indexOf('in_machine')>=0 || tblId.indexOf('warp_in_machine')>=0) { obj.total_cone = total_cone; } else if (tblId.indexOf('palti')>=0) { obj.rolls = rolls; } arr.push(obj); }); return arr; } payload.sections.in_bobin = collectTable('tbl_in_bobin'); payload.sections.open_box = collectTable('tbl_open_box'); payload.sections.closed_box = collectTable('tbl_closed_box'); payload.sections.in_machine = collectTable('tbl_in_machine'); payload.sections.warp_in_machine = collectTable('tbl_warp_in_machine'); payload.sections.warp_open_box = collectTable('tbl_warp_open_box'); payload.sections.warp_closed_box = collectTable('tbl_warp_closed_box'); payload.sections.palti = collectTable('tbl_palti'); $('save_yarns_json').value = JSON.stringify(payload); // allow submit }); }); // DOMContentLoaded })(); </script> </body> </html>