« Back to History
mesr_raoll_palti.php
|
20260721_154033.php
Initial Bulk Import
Copy Code
<?php /* mesr_raoll_palti.php - Entry page for "Yarn in Palti Machine" - Saves month_end_stock_report such that report header will read "Yarn in Palti Machine" - Preserves khata (location) inside JSON meta (so location is not lost) - Module-scoped change only (no global config changes) */ error_reporting(E_ALL); ini_set('display_errors',1); require_once __DIR__ . '/modules/auth/page_acl.php'; $ctx = page_require_access('mesr_raoll_palti'); $u = $ctx['user'] ?? null; $company_id = (int)($ctx['company_id'] ?? 0); $pdo = $ctx['pdo'] ?? null; if (!$pdo) require_once __DIR__ . '/core/db.php'; /* ------------------ AJAX: cone_lookup ------------------ */ if ($_SERVER['REQUEST_METHOD']==='POST' && ($_POST['action'] ?? '')==='cone_lookup') { header('Content-Type: application/json; charset=utf-8'); $den = trim($_POST['denier'] ?? ''); $col = trim($_POST['color'] ?? ''); try { $q = $pdo->prepare("SELECT cone_weight FROM mesr_matrix WHERE company_id=:cid AND matrix_type='cone_weight' AND LOWER(TRIM(denier))=LOWER(TRIM(:d)) AND LOWER(TRIM(color)) =LOWER(TRIM(:c)) LIMIT 1"); $q->execute([':cid'=>$company_id,':d'=>$den,':c'=>$col]); $r=$q->fetch(PDO::FETCH_ASSOC); if ($r && $r['cone_weight']!==null) { echo json_encode(['success'=>true,'cone_weight'=>(float)$r['cone_weight']]); exit; } // fallback (color-only) $q2=$pdo->prepare("SELECT cone_weight FROM mesr_matrix WHERE company_id=:cid AND matrix_type='cone_weight' AND (denier IS NULL OR TRIM(denier)='') AND LOWER(TRIM(color))=LOWER(TRIM(:c)) LIMIT 1"); $q2->execute([':cid'=>$company_id,':c'=>$col]); $r2=$q2->fetch(PDO::FETCH_ASSOC); if ($r2 && $r2['cone_weight']!==null) { echo json_encode(['success'=>true,'cone_weight'=>(float)$r2['cone_weight']]); exit; } echo json_encode(['success'=>false,'msg'=>'not_found']); } catch(Exception $e) { echo json_encode(['success'=>false,'msg'=>'error','error'=>$e->getMessage()]); } exit; } /* ------------------ SAVE HANDLER ------------------ */ if ($_SERVER['REQUEST_METHOD']==='POST' && ($_POST['action'] ?? '')==='save') { $token = $_POST['csrf_token'] ?? ''; if (!hash_equals($_SESSION['csrf_token'] ?? '', (string)$token)) { echo "<div style='color:red;padding:10px;'>CSRF token mismatch.</div>"; exit; } $month = trim($_POST['month'] ?? ''); $location = trim($_POST['location'] ?? ''); $remark = trim($_POST['remark'] ?? ''); $sections_json = $_POST['sections_json'] ?? ''; $payload = json_decode($sections_json,true); if (!is_array($payload)) { echo "<div style='color:red;padding:10px;'>Invalid payload.</div>"; exit; } $open_box = $payload['sections']['open_box'] ?? []; $toF=function($v){ if ($v===''||$v===null) return 0.0; if (is_string($v)) $v=str_replace(',','',trim($v)); if (!is_numeric($v)) { if (preg_match('/([0-9]+(\.[0-9]+)?)/',$v,$m)) $v=$m[1]; else return 0.0; } return (float)$v; }; foreach ($open_box as &$r) { if (!is_array($r)) continue; $r['cones'] = $toF($r['cones'] ?? 0); $r['cone_wt_per'] = $toF($r['cone_wt_per'] ?? 0); $r['empty_cone_wt_per'] = $toF($r['empty_cone_wt_per'] ?? 0); $r['total_weight'] = $r['cones'] * $r['cone_wt_per']; $r['total_empty'] = $r['cones'] * $r['empty_cone_wt_per']; $r['net_weight'] = $r['total_weight'] - $r['total_empty']; $r['denier'] = is_string($r['denier']) ? trim($r['denier']) : ($r['denier'] ?? ''); $r['color'] = is_string($r['color']) ? trim($r['color']) : ($r['color'] ?? ''); } unset($r); if (!$month || !$location) { echo "<div style='color:orange;padding:10px;'>Month and Khata required.</div>"; exit; } // Canonical JSON stored (includes khata/location) $canon = [ 'location' => str_replace(' ','-',strtoupper(trim($location))), 'month' => $month, 'remark' => $remark, 'created_by'=> $u['id'] ?? null, 'sections' => ['open_box'=>$open_box] ]; $json_db = json_encode($canon, JSON_UNESCAPED_UNICODE); // === Module-local decision: // Save stock_type as the literal friendly string expected in reports. // This avoids changing report code and ensures report shows "Yarn in Palti Machine". $stock_type = 'Yarn in Palti Machine'; try { $ins=$pdo->prepare("INSERT INTO month_end_stock_report (company_id,month,stock_type,yarns_json,remark,created_by,created_at) VALUES (:cid,:m,:st,:yj,:r,:uid,NOW())"); $ins->execute([ ':cid'=>$company_id, ':m'=>$month, ':st'=>$stock_type, ':yj'=>$json_db, ':r'=>$remark, ':uid'=>$u['id'] ?? null ]); echo "<div style='color:green;padding:10px;'>Saved successfully.</div>"; } catch(PDOException $ex) { echo "<div style='color:red;padding:10px;'>DB error: ".htmlspecialchars($ex->getMessage())."</div>"; } exit; } /* ------------------ RENDER PAGE ------------------ */ $header_paths=[ __DIR__.'/erp/partials/header.php', __DIR__.'/partials/header.php', __DIR__.'/header.php' ]; foreach($header_paths as $p){ if(file_exists($p)){ require_once $p; break; }} /* Load denier & color lookups */ $deniers=[]; $colors=[]; try { $dm=$pdo->prepare("SELECT DISTINCT TRIM(denier) denier FROM mesr_matrix WHERE company_id=:cid AND TRIM(denier)<>'' ORDER BY denier"); $dm->execute([':cid'=>$company_id]); foreach($dm->fetchAll(PDO::FETCH_ASSOC) as $r) $deniers[]=$r['denier']; $cm=$pdo->prepare("SELECT DISTINCT TRIM(color) color FROM mesr_matrix WHERE company_id=:cid AND TRIM(color)<>'' ORDER BY color"); $cm->execute([':cid'=>$company_id]); foreach($cm->fetchAll(PDO::FETCH_ASSOC) as $r) $colors[]=$r['color']; }catch(Exception $e){ /* ignore load errors */ } $_SESSION['csrf_token'] = $_SESSION['csrf_token'] ?? bin2hex(random_bytes(16)); $csrf = $_SESSION['csrf_token']; ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MESR - Raoll Palti (Yarn in Palti Machine)</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:16px;max-width:1100px;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;width:100%; } .small-btn{padding:6px 8px;font-size:12px;margin:6px 0;background:#2d6cdf;color:#fff;border-radius:5px;border:0;cursor:pointer;} .btn{display:inline-block;padding:8px 12px;border-radius:6px;border:0;cursor:pointer;background:#2d6cdf;color:#fff;} .table{width:100%;border-collapse:collapse;margin-top:8px;} .table th,.table td{border:1px solid #eee;padding:6px 8px;font-size:13px;text-align:left;vertical-align:middle;} .section{border:1px dashed #ccc;padding:10px;margin:12px 0;border-radius:6px;background:#fbfbfb;} .total{font-weight:700;} </style> </head> <body> <div class="card"> <h3>MESR - Raoll Palti (Yarn in Palti Machine)</h3> <form id="mainForm" method="post" action=""> <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf); ?>"> <input type="hidden" name="action" value="save"> <input type="hidden" name="sections_json" id="sections_json"> <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">Khata</label> <select id="location" name="location" class="form-control" required> <option value="">-- Select --</option> <option value="MST1">MST1</option> <option value="MST2">MST2</option> </select> </div> <div class="form-group"> <label for="remark">Remark</label> <input id="remark" name="remark" class="form-control"> </div> </div> <div class="section"> <h4>Yarn in Palti Machine</h4> <button type="button" id="add_open" class="small-btn">+ Add Row</button> <table class="table" id="tbl_open"> <thead> <tr> <th>#</th> <th>Denier</th> <th>Color</th> <th>Cones</th> <th>Cone Wt (kg)</th> <th>Empty Cone Wt (kg)</th> <th>Net Weight (kg)</th> <th>Action</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="6" style="text-align:right;">Total Net Kg</td> <td id="total_open" class="total">0.000</td> <td></td> </tr> </tfoot> </table> </div> <div style="margin-top:12px;"> <button type="submit" class="btn">SAVE</button> </div> </form> </div> <script type="text/javascript"> var PRELOADED_DENIERS = <?php echo json_encode($deniers, JSON_UNESCAPED_UNICODE); ?>; var PRELOADED_COLORS = <?php echo json_encode($colors, JSON_UNESCAPED_UNICODE); ?>; function escapeHtml(s) { if (s === null || s === undefined) return ''; return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } function denierSelectHtml() { var s = '<select class="form-control item_denier"><option value=""></option>'; for (var i=0;i<PRELOADED_DENIERS.length;i++) s += '<option value="'+escapeHtml(PRELOADED_DENIERS[i])+'">'+escapeHtml(PRELOADED_DENIERS[i])+'</option>'; s += '</select>'; return s; } function colorSelectHtml() { var s = '<select class="form-control item_color"><option value=""></option>'; for (var i=0;i<PRELOADED_COLORS.length;i++) s += '<option value="'+escapeHtml(PRELOADED_COLORS[i])+'">'+escapeHtml(PRELOADED_COLORS[i])+'</option>'; s += '</select>'; return s; } function renumber(tbody) { var rows = tbody.getElementsByTagName('tr'); for (var i=0;i<rows.length;i++) if (rows[i].children.length>0) rows[i].children[0].textContent = (i+1); } function addRowToOpen() { var table = document.getElementById('tbl_open'); var tbody = table.getElementsByTagName('tbody')[0]; var tr = document.createElement('tr'); tr.innerHTML = '<td></td>' + '<td>'+ denierSelectHtml() +'</td>' + '<td>'+ colorSelectHtml() +'</td>' + '<td><input type="number" step="1" min="0" class="form-control item_cones" value="0"></td>' + '<td><input type="number" step="0.0001" min="0" class="form-control item_cone_wt" value="0"></td>' + '<td><input type="number" step="0.0001" min="0" class="form-control item_empty_cone_wt" value="0"></td>' + '<td class="item_net">0.000</td>' + '<td><button type="button" class="remove-row small-btn">X</button></td>'; tbody.appendChild(tr); renumber(tbody); var inputs = tr.querySelectorAll('input,select'); for (var i=0;i<inputs.length;i++) { inputs[i].addEventListener('input', function(){ computeRow(tr); }, false); inputs[i].addEventListener('change', function(){ computeRow(tr); }, false); } var removeBtn = tr.querySelector('.remove-row'); if (removeBtn) removeBtn.addEventListener('click', function(){ tr.remove(); renumber(tbody); recalcTotals(); }, false); computeRow(tr); } function computeRow(tr) { if (!tr) return; var cones = tr.querySelector('.item_cones'); var cw = tr.querySelector('.item_cone_wt'); var ew = tr.querySelector('.item_empty_cone_wt'); var netCell = tr.querySelector('.item_net'); var c = parseFloat(cones.value || 0), cwt = parseFloat(cw.value || 0), ewt = parseFloat(ew.value || 0); if (isNaN(c)) c=0; if (isNaN(cwt)) cwt=0; if (isNaN(ewt)) ewt=0; var weight = c * cwt; var total_empty = c * ewt; var net = weight - total_empty; netCell.textContent = (isNaN(net) ? 0 : net).toFixed(3); recalcTotals(); } function sumNetWeight(selector) { var els = document.querySelectorAll(selector); var s=0; for (var i=0;i<els.length;i++){ var v=parseFloat(els[i].textContent||'0'); if(!isNaN(v)) s+=v; } return s.toFixed(3); } function recalcTotals(){ var elOpen=document.getElementById('total_open'); if(elOpen) elOpen.textContent = sumNetWeight('#tbl_open .item_net'); } document.getElementById('add_open').addEventListener('click', addRowToOpen, false); document.getElementById('mainForm').addEventListener('submit', function(e){ e.preventDefault(); function collect(){ var out=[]; var tbody=document.querySelector('#tbl_open tbody'); if(!tbody) return out; var rows=tbody.getElementsByTagName('tr'); for(var i=0;i<rows.length;i++){ var tr=rows[i]; out.push({ denier: (tr.querySelector('.item_denier')||{}).value || '', color: (tr.querySelector('.item_color')||{}).value || '', cones: parseFloat((tr.querySelector('.item_cones')||{}).value) || 0, cone_wt_per: parseFloat((tr.querySelector('.item_cone_wt')||{}).value) || 0, empty_cone_wt_per: parseFloat((tr.querySelector('.item_empty_cone_wt')||{}).value) || 0 }); } return out; } var payload = { sections: { open_box: collect() } }; var hidden = document.getElementById('sections_json'); if (hidden) hidden.value = JSON.stringify(payload); var msgDiv = document.getElementById('mesr_message'); if (!msgDiv) { msgDiv = document.createElement('div'); msgDiv.id='mesr_message'; msgDiv.style.margin='8px 0 12px 0'; var card = document.querySelector('.card'); card.insertBefore(msgDiv, card.firstChild ? card.firstChild.nextSibling : card.firstChild); } msgDiv.innerHTML = '<div style="color:#666;padding:8px;">Saving…</div>'; var fd = new FormData(this); fetch('', { method:'POST', body:fd, credentials:'same-origin' }) .then(function(resp){ return resp.text(); }) .then(function(text){ msgDiv.innerHTML = text; if (/Saved successfully/i.test(text)) { var monthEl=document.getElementById('month'); var monthVal = monthEl ? monthEl.value : ''; var inputs = document.querySelectorAll('form#mainForm input, form#mainForm select, form#mainForm textarea'); inputs.forEach(function(inp){ if (inp === monthEl) return; if (inp.name==='csrf_token') return; if (inp.type==='hidden' && inp.id==='sections_json') return; if (inp.tagName.toLowerCase()==='select') { try { inp.selectedIndex = 0;} catch(e){ inp.value=''; } return; } if (inp.type==='checkbox' || inp.type==='radio') { inp.checked=false; return; } inp.value=''; }); document.querySelector('#tbl_open tbody').innerHTML=''; addRowToOpen(); recalcTotals(); if (monthEl) monthEl.value=monthVal; try { document.querySelector('.card form input, .card form select').focus(); } catch(e){} } else { try { msgDiv.scrollIntoView({behavior:'smooth'}); } catch(e){} } }) .catch(function(err){ msgDiv.innerHTML = '<div style="color:red;padding:10px;">Network or server error. See console for details.</div>'; console.error('submit error', err); }); }, false); addRowToOpen(); recalcTotals(); </script> </body> </html>