first commit
SAP-ERP Portal CI/CD / build (push) Failing after 5m20s

This commit is contained in:
John
2026-09-23 17:31:02 +05:30
commit 69b4e68baf
51657 changed files with 3864077 additions and 0 deletions
+189
View File
@@ -0,0 +1,189 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="/auth-guard.js?v=4"></script>
<script src="/company-list.js"></script>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<title>Receipts History — SAP B1</title>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Bebas+Neue&display=swap" rel="stylesheet"/>
<style>
:root{--ink:#080e18;--ink2:#0d1626;--ink3:#111f35;--purple:#9f5afd;--blue:#1a6fff;--amber:#f5a623;--green:#0dbb8a;--red:#e53e3e;--teal:#06b6d4;--border:#1c2e48;--border2:#243650;--text:#c8d6e8;--text2:#7a9ab8;--text3:#3d5470;--surface:#0f1d30;--surface2:#142338;--surface3:#0b1520;--radius:10px;--font:'Space Grotesk',sans-serif;--mono:'JetBrains Mono',monospace;--display:'Bebas Neue',sans-serif;--shadow:0 8px 32px rgba(0,0,0,.5)}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:var(--font);background:var(--ink);color:var(--text);min-height:100vh;-webkit-font-smoothing:antialiased}
nav{position:sticky;top:0;z-index:200;background:rgba(8,14,24,.92);backdrop-filter:blur(20px);border-bottom:1px solid var(--border);padding:0 12px;height:50px;display:flex;align-items:center;justify-content:space-between;gap:6px}
.nav-logo{background:var(--green);color:#fff;font-family:var(--display);font-size:15px;letter-spacing:2px;padding:3px 8px;border-radius:5px}
.nav-links{display:flex;gap:2px;overflow-x:auto;flex:1;justify-content:center}
.nav-link{padding:4px 8px;border-radius:5px;font-size:10px;font-weight:600;color:var(--text2);text-decoration:none;white-space:nowrap;font-family:var(--font)}.nav-link:hover{color:var(--text);background:rgba(255,255,255,.05)}.nav-link.active{color:var(--green);background:rgba(13,187,138,.1)}
.btn-sm{padding:4px 8px;border-radius:5px;font-size:10px;font-weight:700;border:1px solid var(--border2);color:var(--text3);background:none;cursor:pointer;font-family:var(--font)}.btn-sm:hover{border-color:var(--red);color:var(--red)}
main{padding:12px;max-width:1100px;margin:0 auto}
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:12px;overflow:hidden}
.card-hd{background:var(--surface3);padding:10px 14px;font-size:12px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--border)}
.card-hd .right{margin-left:auto;font-size:11px;color:var(--text3);font-weight:600}
.card-bd{padding:12px 14px}
.fg{margin-bottom:10px}
.fl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:var(--text3);margin-bottom:4px;display:block}
.fi{width:100%;padding:8px 10px;border:1.5px solid var(--border2);border-radius:7px;font-size:13px;font-family:var(--font);background:var(--surface2);color:var(--text);outline:none;height:36px}.fi:focus{border-color:var(--green);box-shadow:0 0 0 2px rgba(13,187,138,.15)}.fi::placeholder{color:var(--text3)}
select.fi{cursor:pointer;appearance:none;background:var(--surface2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%233d5470'/%3E%3C/svg%3E") no-repeat right 10px center;padding-right:26px}
.fi-mono{font-family:var(--mono);font-size:12px}
.btn{padding:10px 20px;border-radius:8px;border:none;font-family:var(--font);font-size:13px;font-weight:700;cursor:pointer;transition:all .18s;display:inline-flex;align-items:center;gap:6px;justify-content:center}.btn:disabled{opacity:.4;cursor:not-allowed}
.empty-msg{text-align:center;padding:24px;color:var(--text3);font-size:12px}
.sp{width:14px;height:14px;border:2px solid rgba(255,255,255,.25);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite;display:inline-block}
@keyframes spin{to{transform:rotate(360deg)}}
.toast-c{position:fixed;top:56px;right:10px;z-index:9999;display:flex;flex-direction:column;gap:6px;pointer-events:none}
.toast{padding:9px 13px;border-radius:8px;font-size:12px;font-weight:600;box-shadow:var(--shadow);max-width:280px}
.t-ok{background:var(--green);color:#fff}.t-err{background:var(--red);color:#fff}
/* Receipts table */
.rh-wrap{overflow-x:auto}
table.rh{width:100%;border-collapse:separate;border-spacing:0;font-size:11.5px;min-width:820px}
table.rh th{text-align:left;padding:8px 10px;font-size:9.5px;font-weight:700;text-transform:uppercase;color:var(--text3);border-bottom:2px solid var(--border2);white-space:nowrap}
table.rh td{padding:9px 10px;border-bottom:1px solid var(--border);vertical-align:middle}
table.rh tr:hover td{background:rgba(13,187,138,.05)}
.rh-mono{font-family:var(--mono)}
.rh-doc{font-family:var(--mono);font-weight:700;color:var(--green)}
.rh-pwo{font-family:var(--mono);color:var(--teal)}
.rh-item{font-family:var(--mono);color:var(--text)}
.rh-desc{color:var(--text2);max-width:280px;white-space:normal}
.tt-pill{font-size:9px;font-weight:700;padding:1px 6px;border-radius:3px}
.tt-c{background:rgba(13,187,138,.12);color:var(--green)}
.tt-r{background:rgba(229,62,62,.12);color:var(--red)}
</style>
<link rel="stylesheet" href="/theme.css?v=3"/>
</head>
<body>
<div class="toast-c" id="toast-c"></div>
<nav>
<span class="nav-logo">SAP</span>
<div class="nav-links">
<a href="/" class="nav-link">Home</a><a href="/production" class="nav-link">Production</a>
<a href="/issue-production" class="nav-link">Issue</a>
<a href="/receipt-production" class="nav-link">Receipt</a>
<a href="/receipts-history" class="nav-link active">Receipts History</a>
<a href="/close-production" class="nav-link">Close</a>
</div>
<button class="btn-sm" id="btn-logout">Logout</button>
</nav>
<main id="app"></main>
<script>
'use strict';
let _tok=null,_user=null;
const BE='/api';
(function(){try{_tok=sessionStorage.getItem('portal_token');const u=sessionStorage.getItem('portal_user');if(u)_user=JSON.parse(u);}catch(_e){}})();
if(!_tok)window.location.href='/';
document.getElementById('btn-logout').onclick=()=>{sessionStorage.clear();document.cookie='portal_token=;path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT';document.cookie='portal_user=;path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT';;localStorage.removeItem('token');localStorage.removeItem('portal_user');window.location.href='/';};
let _co=window.__DEFAULT_COMPANY__;
let _companies=[{value:_co,label:_co}];
function coOptions(sel){return _companies.map(c=>`<option value="${esc(c.value)}" ${sel===c.value?'selected':''}>${esc(c.label)}</option>`).join('');}
let _rows=[];
let _loading=false;
let _search='';
let _page=0,_pageSize=20,_total=null,_rawCount=0;
function esc(v){return(v||'').toString().replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
function q(s){return document.querySelector(s);}
function mk(c){const d=document.createElement('div');d.className=c;return d;}
const _MON=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
function fmtDate(iso){if(!iso)return '—';const d=new Date(iso);if(isNaN(d))return '—';return `${String(d.getUTCDate()).padStart(2,'0')} ${_MON[d.getUTCMonth()]} ${d.getUTCFullYear()}`;}
function fmtQty(n){return(Math.round((parseFloat(n)||0)*1000)/1000).toString();}
async function api(m,p,b=null){
const h={'Content-Type':'application/json'};if(_tok)h['Authorization']='Bearer '+_tok;
const o={method:m.toUpperCase(),headers:h};if(b)o.body=JSON.stringify(b);
let r,d;try{r=await fetch(BE+p,o);d=await r.json();}catch(_e){throw new Error('Cannot reach server');}
if(r.status===401){window.location.href='/';throw new Error('Session expired');}
if(!r.ok)throw new Error(d?.message||'HTTP '+r.status);return d;
}
function toast(msg,type='ok'){const tc=document.getElementById('toast-c');const el=document.createElement('div');el.className=`toast t-${type}`;el.textContent=(type==='ok'?'OK ':'ERR ')+msg;tc.appendChild(el);setTimeout(()=>el.remove(),4500);}
async function load(resetPage){
if(resetPage)_page=0;
_loading=true;render();
const searchQ=_search.trim()?`&search=${encodeURIComponent(_search.trim())}`:'';
try{
const r=await api('GET',`/sap/receipts-history?top=${_pageSize}&skip=${_page*_pageSize}&company=${encodeURIComponent(_co)}${searchQ}`);
_rows=r.data||[];_rawCount=_rows.length;_total=(typeof r.total==='number')?r.total:null;
}catch(e){toast(e.message,'err');_rows=[];_rawCount=0;_total=null;}
_loading=false;render();
}
function hasNext(){ if(_total!=null) return (_page+1)*_pageSize<_total; return _rawCount>=_pageSize; }
function render(){try{_doRender();}catch(e){console.error(e);document.getElementById('app').innerHTML=`<div style="padding:20px;color:var(--red)">Error: ${e.message}</div>`;}}
function _doRender(){
const app=document.getElementById('app');app.innerHTML='';
const c1=mk('card');
c1.innerHTML=`<div class="card-hd"><span>Receipts History</span><span class="right">Posted Receipt from Production documents</span></div>
<div class="card-bd">
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end">
<div class="fg" style="margin:0;min-width:150px"><label class="fl">Company</label><select class="fi" id="sel-co">${coOptions(_co)}</select></div>
<div class="fg" style="margin:0;flex:1;min-width:240px"><label class="fl">Search</label>
<input class="fi fi-mono" id="rh-search" value="${esc(_search)}" placeholder="PWO No, receipt doc no, item code / description or batch…"/></div>
<button class="btn" id="rh-search-btn" style="background:var(--green);color:#fff;height:36px">Search</button>
</div>
<div style="font-size:10px;color:var(--text3);margin-top:6px">Newest first. Search matches PWO No, receipt document number, item code/description, or batch number.</div>
</div>`;
app.appendChild(c1);
const c2=mk('card');
let body;
if(_loading){
body=`<div class="empty-msg"><span class="sp" style="border-color:rgba(13,187,138,.25);border-top-color:var(--green)"></span> Loading receipts…</div>`;
}else if(!_rows.length){
body=`<div class="empty-msg">No receipts found${_search.trim()?` for "${esc(_search.trim())}"`:''}.</div>`;
}else{
const trs=_rows.map(r=>`<tr>
<td class="rh-doc">${esc(r.receiptDocNum)}</td>
<td class="rh-mono" style="white-space:nowrap">${fmtDate(r.docDate)}</td>
<td class="rh-pwo">${esc(r.pwoNum||r.pwoAbsEntry||'-')}</td>
<td class="rh-item">${esc(r.itemCode)}</td>
<td class="rh-desc">${esc(r.description||'-')}</td>
<td class="rh-mono" style="text-align:right">${fmtQty(r.quantity)}</td>
<td><span class="tt-pill ${r.transType==='R'?'tt-r':'tt-c'}">${r.transType==='R'?'REJECT':'COMPLETE'}</span></td>
<td class="rh-mono">${esc(r.warehouse||'-')}</td>
<td class="rh-mono" style="color:var(--amber)">${esc(r.batch||'-')}</td>
</tr>`).join('');
body=`<div class="rh-wrap"><table class="rh">
<thead><tr>
<th>Receipt Doc No</th><th>Date</th><th>PWO No</th><th>Item</th><th>Description</th>
<th style="text-align:right">Qty</th><th>Type</th><th>Whs</th><th>Batch</th>
</tr></thead>
<tbody>${trs}</tbody>
</table></div>`;
}
const totalPages=_total!=null?Math.max(1,Math.ceil(_total/_pageSize)):null;
const pager=_loading?'':`<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px">
<button class="btn" id="rh-prev" ${_page===0?'disabled':''} style="padding:6px 14px;font-size:11px;background:var(--surface2);color:var(--text2);border:1px solid var(--border2)${_page===0?';opacity:.45;cursor:not-allowed':''}">‹ Prev</button>
<span style="font-size:11px;color:var(--text3)">${_total!=null?`Page ${_page+1} of ${totalPages} · ${_total} line${_total===1?'':'s'}`:`Page ${_page+1}`}</span>
<button class="btn" id="rh-next" ${hasNext()?'':'disabled'} style="padding:6px 14px;font-size:11px;background:var(--surface2);color:var(--text2);border:1px solid var(--border2)${hasNext()?'':';opacity:.45;cursor:not-allowed'}">Next ›</button>
</div>`;
c2.innerHTML=`<div class="card-hd"><span>Receipts</span><span class="right">${_rows.length} on this page</span></div><div class="card-bd">${body}${pager}</div>`;
app.appendChild(c2);
setTimeout(()=>{
q('#sel-co')&&(q('#sel-co').onchange=function(){_co=this.value;load(true);});
q('#rh-search')&&(q('#rh-search').oninput=function(){_search=this.value;});
q('#rh-search')&&(q('#rh-search').onkeydown=function(e){if(e.key==='Enter'){e.preventDefault();load(true);}});
q('#rh-search-btn')&&(q('#rh-search-btn').onclick=()=>load(true));
q('#rh-prev')&&(q('#rh-prev').onclick=()=>{if(_page>0){_page--;load();}});
q('#rh-next')&&(q('#rh-next').onclick=()=>{if(hasNext()){_page++;load();}});
},0);
}
async function init(){
try{
const hash=window.location.hash;
const coMatch=hash.match(/company=([^&]+)/);
if(coMatch)_co=decodeURIComponent(coMatch[1]);
try{const list=await window.fetchCompanyList();if(list.length)_companies=list;}catch(_e){}
render();
load();
}catch(e){console.error('Init error:',e);render();}
}
init();
</script>
<script src="/sidebar.js?v=25"></script>
</body>
</html>