تُطبَّق تلقائياً على كل فاتورة وتظهر في تقارير التاجرات
اكواد الهدايا
Claude AI - تحليل المنتجات من الصور
يستخدم Claude AI لقراءة صورة المنتج واستخراج: الاسم، اللون، نوع القماش، القياسات، الوصف.
احصل على مفتاح API مجاني من console.anthropic.com
>
بوتيك جديد
اضافة تاجرة
💼
اضافة منتج
📦
صوّر المنتج وسيملأ Claude البيانات تلقائياً (اسم، لون، قماش، مقاس...)
بيانات العميل
اختياري - اضغط تجاهل للفاتورة مباشرة
+968
✶
اضافة موظفة
اختر الموظفة
كل المبيعات ستُنسب للموظفة المختارة حتى تغييرها
تقرير التاجرة
ثيم الألوان
اختر لون النظام
ذهبي
وردي
أزرق
أخضر
بنفسجي
فاتح
خصوصية الأسعار
تنبيه المخزون
'+b.name+'';}).join('');
var ids=['t-bout','p-bout','dash-bout','pos-b'];
for(var i=0;i'+t.name+(b?' ('+b.name+')':'')+'';}).join('');
}
function switchBout(id){DB.curBout=id;save();renderDashboard();checkStockAlerts();}
function renderBoutiques(){
var tb=document.getElementById('tbl-bouts');if(!tb)return;
var rows='';
for(var i=0;i
'+b.name+'
'+(b.loc||'—')+'
'+b.comm+'%
'+tc+'
'+fmtM(ms)+'
';}
tb.innerHTML=rows||'
لا توجد بوتيكات
';
}
function openBoutForm(id){var b=id?DB.boutiques.find(function(x){return x.id===id;}):null;document.getElementById('b-title').textContent=b?'تعديل البوتيك':'بوتيك جديد';document.getElementById('b-id').value=b?b.id:'';document.getElementById('b-name').value=b?b.name:'';document.getElementById('b-loc').value=b?(b.loc||''):'';document.getElementById('b-phone').value=b?(b.phone||''):'';document.getElementById('b-comm').value=b?b.comm:'20';document.getElementById('b-notes').value=b?(b.notes||''):'';openOv('ov-boutique');}
function editBout(id){openBoutForm(id);}
function saveBout(){var id=document.getElementById('b-id').value;var name=document.getElementById('b-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'b'+Date.now(),name:name,loc:document.getElementById('b-loc').value.trim(),phone:document.getElementById('b-phone').value.trim(),comm:parseFloat(document.getElementById('b-comm').value)||0,notes:document.getElementById('b-notes').value.trim()};if(id){var i=DB.boutiques.findIndex(function(x){return x.id===id;});if(i>-1)DB.boutiques[i]=obj;}else{DB.boutiques.push(obj);if(!DB.curBout)DB.curBout=obj.id;}save();closeOv('ov-boutique');fillBouts();renderBoutiques();showToast('تم حفظ البوتيك','ok');}
function delBout(id){if(!confirm('حذف؟'))return; DB.boutiques=DB.boutiques.filter(function(b){return b.id!==id;});if(DB.curBout===id)DB.curBout=DB.boutiques[0]?DB.boutiques[0].id:null;save();fillBouts();renderBoutiques();}
function renderTraders(){
var tb=document.getElementById('tbl-traders');if(!tb)return;
var q=((document.getElementById('trader-q')||{}).value||'').toLowerCase();
var tlist=q?DB.traders.filter(function(t){return t.name.toLowerCase().indexOf(q)>-1||(t.phone&&t.phone.indexOf(q)>-1);}):DB.traders;
var rows='';
for(var i=0;i
'+tr.name[0]+'
'+tr.name+'
'+(b.name||'—')+'
'+(tr.phone||'—')+'
'+prods+'
'+fmtM(tsales)+'
'+fmtM(trem)+'
';}
tb.innerHTML=rows||'
لا توجد تاجرات
';
var tb=document.getElementById('tbl-traders');if(!tb)return;
var q=((document.getElementById('trader-q')||{}).value||'').toLowerCase();
var tlist=q?DB.traders.filter(function(t){return t.name.toLowerCase().indexOf(q)>-1||(t.phone&&t.phone.indexOf(q)>-1);}):DB.traders;
var rows='';
for(var i=0;i
'+tr.name[0]+'
'+tr.name+'
'+(b.name||'—')+'
'+(tr.phone||'—')+'
'+prods+'
'+fmtM(tsales)+'
'+fmtM(trem)+'
';}
tb.innerHTML=rows||'
لا توجد تاجرات
';
}
function openTraderForm(id){var t=id?DB.traders.find(function(x){return x.id===id;}):null;document.getElementById('t-title').textContent=t?'تعديل التاجرة':'اضافة تاجرة';document.getElementById('t-id').value=t?t.id:'';document.getElementById('t-name').value=t?t.name:'';document.getElementById('t-phone').value=t?(t.phone||''):'';document.getElementById('t-idn').value=t?(t.idn||''):'';document.getElementById('t-notes').value=t?(t.notes||''):'';fillBouts();var tb=document.getElementById('t-bout');if(tb&&t)tb.value=t.boutId;openOv('ov-trader');}
function editTrader(id){openTraderForm(id);}
function saveTrader(){var id=document.getElementById('t-id').value;var name=document.getElementById('t-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'t'+Date.now(),name:name,phone:document.getElementById('t-phone').value.trim(),idn:document.getElementById('t-idn').value.trim(),boutId:document.getElementById('t-bout').value,notes:document.getElementById('t-notes').value.trim(),address:(document.getElementById('t-addr')||{}).value||'',city:(document.getElementById('t-city')||{}).value||'',instagram:(document.getElementById('t-insta')||{}).value||'',color:(document.getElementById('t-color')||{}).value||'#c9a84c',logo:(document.getElementById('t-logo')||{}).value||''};if(id){var i=DB.traders.findIndex(function(x){return x.id===id;});if(i>-1)DB.traders[i]=obj;}else DB.traders.push(obj);save();closeOv('ov-trader');renderTraders();showToast('تم حفظ التاجرة','ok');}
function delTrader(id){if(!confirm('حذف؟'))return; DB.traders=DB.traders.filter(function(t){return t.id!==id;});save();renderTraders();}
function renderProducts(){
var tb=document.getElementById('tbl-prods');if(!tb)return;
var q=(document.getElementById('prod-q')||{}).value||'';
var list=q?DB.products.filter(function(p){return p.name.indexOf(q)>-1||p.sku.indexOf(q)>-1;}):DB.products.slice();
var rows='';
for(var i=0;i
'+p.sku+'
'+(p.img?'':'📦')+'
'+p.name+'
'+(p.cat||'')+'
'+(t?t.name:'—')+'
'+fmtM(p.price)+'
'+p.qty+'
';}
tb.innerHTML=rows||'
لا توجد منتجات
';
}
function openProdForm(id){var p=id?DB.products.find(function(x){return x.id===id;}):null;document.getElementById('p-title').textContent=p?'تعديل المنتج':'اضافة منتج';document.getElementById('p-id').value=p?p.id:'';document.getElementById('p-sku').value=p?p.sku:('SKU'+String(DB.products.length+1).padStart(3,'0'));document.getElementById('p-name').value=p?p.name:'';document.getElementById('p-cost').value=p?p.cost:'';document.getElementById('p-price').value=p?p.price:'';document.getElementById('p-qty').value=p?p.qty:'1';document.getElementById('p-cat').value=p?(p.cat||''):'';document.getElementById('p-notes').value=p?(p.notes||''):'';document.getElementById('p-img').value=p?(p.img||''):'';var prev=document.getElementById('p-img-prev');if(prev)prev.innerHTML=(p&&p.img)?'':'📦';fillTraders('p-trader');fillBouts();var pt=document.getElementById('p-trader');var pb=document.getElementById('p-bout');if(p&&pt)pt.value=p.traderId;if(p&&pb)pb.value=p.boutId;var aiWrap=document.getElementById('ai-wrap');if(aiWrap)aiWrap.style.display='none';var aiSt=document.getElementById('ai-status');if(aiSt)aiSt.textContent='';_aiResult=null;var pSizes=document.getElementById('p-sizes');if(pSizes)pSizes.value=p?(p.sizes||''):'';loadSizesIntoForm(p?p.sizes:'');openOv('ov-product');}
function editProd(id){openProdForm(id);}
function autoFillBout(){var t=DB.traders.find(function(x){return x.id===document.getElementById('p-trader').value;});var pb=document.getElementById('p-bout');if(t&&pb)pb.value=t.boutId;}
function prevImg(inp){if(!inp.files||!inp.files[0])return;var r=new FileReader();r.onload=function(e){var prev=document.getElementById('p-img-prev');var hid=document.getElementById('p-img');if(prev)prev.innerHTML='';if(hid)hid.value=e.target.result;};r.readAsDataURL(inp.files[0]);}
function clearImg(){var prev=document.getElementById('p-img-prev');var hid=document.getElementById('p-img');var fi=document.getElementById('p-img-file');if(prev)prev.innerHTML='📦';if(hid)hid.value='';if(fi)fi.value='';}
function saveProd(){var id=document.getElementById('p-id').value;var name=document.getElementById('p-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'p'+Date.now(),sku:document.getElementById('p-sku').value||('SKU'+Date.now()),name:name,traderId:document.getElementById('p-trader').value,boutId:document.getElementById('p-bout').value,cost:parseFloat(document.getElementById('p-cost').value)||0,price:parseFloat(document.getElementById('p-price').value)||0,qty:parseInt(document.getElementById('p-qty').value)||0,cat:document.getElementById('p-cat').value.trim(),img:document.getElementById('p-img').value||'',notes:document.getElementById('p-notes').value.trim(),sizes:collectSizes()};if(id){var i=DB.products.findIndex(function(x){return x.id===id;});if(i>-1)DB.products[i]=obj;}else DB.products.push(obj);save();closeOv('ov-product');renderProducts();showToast('تم حفظ المنتج','ok');}
function delProd(id){if(!confirm('حذف؟'))return; DB.products=DB.products.filter(function(p){return p.id!==id;});save();renderProducts();}
function renderPos(){fillBouts();fillTraders('pos-t');var posT=document.getElementById('pos-t');if(posT){var opt=document.createElement('option');opt.value='';opt.textContent='جميع التاجرات';posT.insertBefore(opt,posT.firstChild);posT.value='';}renderPosGrid();renderCart();if(!activeStaffId&&(DB.staff||[]).length>0)openStaffSelector();}
function renderPosGrid(){
var grid=document.getElementById('pos-grid');if(!grid)return;
var bid=(document.getElementById('pos-b')||{}).value||'';
var tid=(document.getElementById('pos-t')||{}).value||'';
var q=((document.getElementById('pos-q')||{}).value||'').toLowerCase();
var list=DB.products.filter(function(p){
if(p.qty<=0)return false;
if(bid&&p.boutId!==bid)return false;
if(tid&&p.traderId!==tid)return false;
if(q&&p.name.toLowerCase().indexOf(q)<0&&p.sku.toLowerCase().indexOf(q)<0)return false;
return true;
});
if(!list.length){grid.innerHTML='
لا توجد منتجات
';return;}
// Build trader color map
var traderColors={};
DB.traders.forEach(function(t){ traderColors[t.id]=t.color||'#c9a84c'; });
// Low stock threshold
var stockThreshold=parseInt((DB.settings||{}).stockAlert||5);
var stockNotify=(DB.settings||{}).stockNotify!==false;
var html='';
for(var i=0;i0&&p.qty<=stockThreshold;
html+='
';
// Low stock badge
if(isLow){
html+='
⚠ '+p.qty+' متبق
';
}
// Trader color strip at top
html+='';
if(p.img){
html+='';
} else {
html+='
📦
';
}
html+='
'+p.name+'
';
// Trader name with color badge
if(t.logo){
html+='
'
+''+t.name+'
';
} else {
html+='
'+t.name+'
';
}
html+='
'+fmtM(p.price)+'
';
html+='
متاح: '+p.qty+'
';
html+='
';
}
grid.innerHTML=html;
}
function posKey(e){if(e.key==='Enter'){var q=(document.getElementById('pos-q')||{}).value||'';var match=DB.products.find(function(p){return p.sku===q||p.sku===q.replace(/^0+/,'');});if(match){addToCart(match.id);document.getElementById('pos-q').value='';renderPosGrid();}}}
function addToCart(pid){var p=DB.products.find(function(x){return x.id===pid;});if(!p||p.qty<=0)return;var ex=CART.find(function(c){return c.pid===pid;});if(ex){if(ex.qtymaxQty){
showToast('الكمية المتوفرة في المخزن: '+maxQty+' فقط','er');
ci.qty=maxQty;
} else {
ci.qty=Math.max(1,newQty);
}
renderCart();calcCart();
}
function renderCart(){
var container=document.getElementById('cart-items');if(!container)return;
if(!CART.length){container.innerHTML='
السلة فارغة
';return;}
var html='';
for(var i=0;i'+(c.img?'':'
📦
')+'
'+c.name+'
'+fmt(c.price)+' x '+c.qty+'
'+c.qty+'
'+fmt(c.price*c.qty)+'
';}
container.innerHTML=html;
}
function getDisc(sub){var t=(document.getElementById('disc-t')||{}).value||'0';var v=parseFloat((document.getElementById('disc-v')||{}).value)||0;if(t==='pct')return Math.min(sub,sub*v/100);if(t==='fixed')return Math.min(sub,v);return 0;}
function calcCart(){var sub=CART.reduce(function(a,c){return a+c.price*c.qty;},0);var disc=getDisc(sub);var total=Math.max(0,sub-disc);var subEl=document.getElementById('s-sub');var dRow=document.getElementById('s-disc-row');var dEl=document.getElementById('s-disc');var totEl=document.getElementById('s-total');if(subEl)subEl.textContent=fmtM(sub);if(dRow)dRow.style.display=disc>0?'flex':'none';if(dEl)dEl.textContent='-'+fmtM(disc);if(totEl)totEl.textContent=fmtM(total);}
function discChange(){var t=(document.getElementById('disc-t')||{}).value;var cr=document.getElementById('code-row');if(cr)cr.style.display=t==='code'?'block':'none';calcCart();}
function applyCode(){var inp=document.getElementById('code-inp');var msg=document.getElementById('code-msg');if(!inp)return;var code=inp.value.trim().toUpperCase();var codes=DB.settings.codes||[];var gc=codes.find(function(c){return c.code===code&&c.active;});if(!gc){if(msg){msg.style.color='var(--er)';msg.textContent='الكود غير صالح';}return;}var dt=document.getElementById('disc-t');var dv=document.getElementById('disc-v');if(dt)dt.value=gc.type;if(dv)dv.value=gc.val;if(msg){msg.style.color='var(--ok)';msg.textContent='تم تطبيق: '+gc.label;}calcCart();}
function startSale(){if(!CART.length){showToast('أضف منتجاً للسلة أولاً','warn','السلة فارغة');return;}document.getElementById('c-name').value='';document.getElementById('c-phone').value='';openOv('ov-customer');}
function skipCust(){closeOv('ov-customer');finalizeSale('','');}
function confirmCust(){var cn=(document.getElementById('c-name')||{}).value||'';var cp=(document.getElementById('c-phone')||{}).value||'';closeOv('ov-customer');finalizeSale(cn,cp);}
function finalizeSale(cname,cphone){var sub=CART.reduce(function(a,c){return a+c.price*c.qty;},0);var disc=getDisc(sub);var total=Math.max(0,sub-disc);var method=(document.getElementById('pay-m')||{}).value||'cash';var boutId=CART[0]?CART[0].boutId:DB.curBout;var inv=nextInv();var items=CART.map(function(c){return{pid:c.pid,name:c.name,qty:c.qty,price:c.price,tid:c.tid};});var sale={id:'s'+Date.now(),boutId:boutId,inv:inv,date:nowDate(),time:nowTime(),method:method,items:items,sub:sub,disc:disc,total:total,cname:cname,cphone:cphone,status:'completed',staffId:activeStaffId||null};CART.forEach(function(c){var p=DB.products.find(function(x){return x.id===c.pid;});if(p)p.qty-=c.qty;});DB.sales.push(sale);save();LAST_SALE=sale;CART=[];renderCart();calcCart();renderPosGrid();showReceipt(sale);}
function showReceipt(sale){var b=DB.boutiques.find(function(x){return x.id===sale.boutId;})||{};var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'};document.getElementById('r-bname').textContent=b.name||'—';document.getElementById('r-bloc').textContent=b.loc||'';document.getElementById('r-dt').textContent=sale.date+' '+sale.time;document.getElementById('r-inv').textContent='فاتورة: '+sale.inv;var rc=document.getElementById('r-cust');if(rc){if(sale.cname||sale.cphone){rc.style.display='block';rc.innerHTML='العميل: '+(sale.cname||'')+''+(sale.cphone?' | +968'+sale.cphone:'');}else rc.style.display='none';}var ri=document.getElementById('r-items');if(ri){var html='';for(var i=0;i'+it.name+' x'+it.qty+''+fmtM(it.qty*it.price)+'
';}}
function recordPay(tid,bid){var el=document.getElementById('pamt-'+tid);var amt=el?parseFloat(el.value):0;if(!amt||amt<=0){showToast('أدخل مبلغ الدفعة','er','حقل مطلوب');return;}DB.settlements.push({id:'set'+Date.now(),traderId:tid,boutiqueId:bid,date:nowDate(),paid:amt,notes:'دفعة '+nowDate()});save();if(el)el.value='';renderSettlements();}
function sendSettleWA(tid,from,to){var tr=DB.traders.find(function(x){return x.id===tid;});if(!tr||!tr.phone)return;var b=DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};var comm=b.comm||0;var sales=DB.sales.filter(function(s){return s.status==='completed'&&(!from||s.date>=from)&&(!to||s.date<=to)&&s.items.some(function(it){return it.tid===tid;});});var tsales=sales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tid;}).reduce(function(x,it){return x+it.qty*it.price;},0);},0);var tcomm=tsales*comm/100;var tnet=tsales-tcomm;var tpaid=DB.settlements.filter(function(x){return x.traderId===tid&&(!from||x.date>=from)&&(!to||x.date<=to);}).reduce(function(a,x){return a+x.paid;},0);var trem=tnet-tpaid;var ph=tr.phone.replace(/\D/g,'');if(ph.indexOf('968')!==0)ph='968'+ph.replace(/^0/,'');var lines=['تسوية حساب - '+(b.name||''),'التاجرة: '+tr.name,'الفترة: '+(from||'')+' الى '+(to||''),'---','مبيعاتك: '+fmtM(tsales),'الايجار '+comm+'%: '+fmtM(tcomm),'الصافي لك: '+fmtM(tnet),(tpaid>0?'تم صرفه: '+fmtM(tpaid):''),'المتبقي: '+fmtM(trem),'---','شكرا لتعاملك معنا'].filter(function(l){return l!=='';});window.open('https://wa.me/'+ph+'?text='+encodeURIComponent(lines.join('\n')),'_blank');}
function setStaffPeriod(p){
var t=nowDate(),f='';
if(p==='month') f=t.slice(0,8)+'01';
var fe=document.getElementById('st-from');
var te=document.getElementById('st-to');
if(fe)fe.value=f; if(te)te.value=t;
renderStaffStats();
}
function calcStaffComm(staff,sales){
if(!staff.ct||staff.ct==='none') return 0;
var total=0;
sales.forEach(function(s){
if(staff.ct==='pct'||staff.ct==='both') total+=s.total*(staff.cp||0)/100;
if(staff.ct==='fixed'||staff.ct==='both') total+=(staff.cf||0)*s.items.length;
});
return total;
}
function renderStaff(){
var tb=document.getElementById("tbl-staff");
if(!tb)return;
var list=DB.staff||[];
var rows="";
for(var i=0;i";
rows+='
'+s.name[0]+'
'+s.name+"
";
rows+="
"+s.email+"
";
rows+="
"+(s.join||"—")+(s.end?'
انتهت: '+s.end+"
":"")+"
";
rows+="
"+fmtM(s.salary||0)+"
";
rows+="
"+cl+"
";
rows+='
'+((s.perms||[]).length)+" صلاحية
";
rows+="
";
rows+=' ';
rows+='';
rows+="
";
}
tb.innerHTML=rows||'
لا توجد موظفات
';
renderStaffStats();
}
function openStaffForm(id){var s=id?((DB.staff||[]).find(function(x){return x.id===id;})):null;document.getElementById('st-title').textContent=s?'تعديل الموظفة':'اضافة موظفة';document.getElementById('st-id').value=s?s.id:'';document.getElementById('st-name').value=s?s.name:'';document.getElementById('st-email').value=s?(s.email||''):'';document.getElementById('st-pass').value='';document.getElementById('st-salary').value=s?(s.salary||0):0;document.getElementById('st-join').value=s?(s.join||nowDate()):nowDate();document.getElementById('st-end').value=s?(s.end||''):'';document.getElementById('st-ct').value=s?(s.ct||'none'):'none';document.getElementById('st-cp').value=s?(s.cp||0):0;document.getElementById('st-cf').value=s?(s.cf||0):0;commTypeChg();var pg=document.getElementById('perms-grid');if(pg){var ph='';for(var i=0;i-1))?'checked':'';ph+='';}pg.innerHTML=ph;}openOv('ov-staff');}
function editStaff(id){openStaffForm(id);}
function commTypeChg(){var t=(document.getElementById('st-ct')||{}).value;var cp=document.getElementById('st-cp');var cf=document.getElementById('st-cf');if(cp)cp.style.display=(t==='pct'||t==='both')?'block':'none';if(cf)cf.style.display=(t==='fixed'||t==='both')?'block':'none';}
function saveStaff(){var id=document.getElementById('st-id').value;var name=document.getElementById('st-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var pass=document.getElementById('st-pass').value;var existing=id?((DB.staff||[]).find(function(x){return x.id===id;})):null;var perms=[];var chks=document.querySelectorAll('#perms-grid input:checked');for(var i=0;i-1)DB.staff[i]=obj;else DB.staff.push(obj);save();closeOv('ov-staff');renderStaff();showToast('تم حفظ الموظفة','ok');}
function delStaff(id){if(!confirm('حذف؟'))return; DB.staff=DB.staff.filter(function(x){return x.id!==id;});save();renderStaff();}
function setRepPeriod(p) {
var t = nowDate();
var f = '';
if (p === 'today') { f = t; }
else if (p === 'week') {
var d = new Date(); d.setDate(d.getDate()-6);
f = d.toISOString().slice(0,10);
} else if (p === 'month') { f = t.slice(0,8)+'01'; }
else { f = ''; }
var fe = document.getElementById('rep-from');
var te = document.getElementById('rep-to');
if (fe) fe.value = f;
if (te) te.value = t;
renderReports();
}
function renderReports() {
var from = (document.getElementById('rep-from')||{}).value||'';
var to = (document.getElementById('rep-to')||{}).value||'';
// Filter sales by period
var sales = DB.sales.filter(function(s) {
if (s.status !== 'completed') return false;
if (from && s.date < from) return false;
if (to && s.date > to) return false;
return true;
});
var totalRev = sales.reduce(function(a,s){return a+s.total;},0);
var totalComm = sales.reduce(function(a,s){
var b = DB.boutiques.find(function(x){return x.id===s.boutId;})||{};
return a + s.total*(b.comm||0)/100;
},0);
var totalPaid = DB.settlements.reduce(function(a,x){return a+x.paid;},0);
var totalDue = DB.traders.reduce(function(a,tr){
var b = DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var ts= sales.filter(function(s){return s.items.some(function(it){return it.tid===tr.id;});})
.reduce(function(x,s){return x+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(y,it){return y+it.qty*it.price;},0);},0);
var net=ts-ts*(b.comm||0)/100;
var paid=DB.settlements.filter(function(x){return x.traderId===tr.id;}).reduce(function(x,y){return x+y.paid;},0);
return a+Math.max(0,net-paid);
},0);
// KPI Cards
var rs = document.getElementById('rep-stats');
if (rs) rs.innerHTML =
'
اجمالي الإيرادات
'+fmtM(totalRev)+'
'
+'
عمولة البوتيك
'+fmtM(totalComm)+'
'
+'
المستحقات المتبقية
'+fmtM(totalDue)+'
'
+'
عدد الفواتير
'+sales.length+'
';
// Daily sales chart
renderDailyChart(sales, from, to);
// Payment methods
renderPaymentMethods(sales);
// Traders detailed
renderTraderReport(sales, from, to);
// Top products
renderTopProducts(sales);
// Slow movers
renderSlowMovers(sales);
// Inventory
renderInventory();
}
function renderDailyChart(sales, from, to) {
var chartEl = document.getElementById('rep-chart-days');
var labelsEl = document.getElementById('rep-chart-labels');
if (!chartEl) return;
// Build last 14 days or period
var days = [];
var end = to || nowDate();
var start = from;
if (!start) {
var d = new Date(end); d.setDate(d.getDate()-13);
start = d.toISOString().slice(0,10);
}
var cur = new Date(start);
var endD = new Date(end);
while (cur <= endD && days.length < 30) {
days.push(cur.toISOString().slice(0,10));
cur.setDate(cur.getDate()+1);
}
var dayTotals = {};
days.forEach(function(d){ dayTotals[d]=0; });
sales.forEach(function(s){ if(dayTotals[s.date]!==undefined) dayTotals[s.date]+=s.total; });
var maxVal = Math.max.apply(null, days.map(function(d){return dayTotals[d];})) || 1;
var html = '';
var labelHtml = '';
days.forEach(function(d) {
var h = Math.max(4, Math.round((dayTotals[d]/maxVal)*100));
var hasVal = dayTotals[d] > 0;
html += '
'
+(hasVal?'
'+Math.round(dayTotals[d])+'
':'')
+''
+'
';
labelHtml += '
'+d.slice(8)+'
';
});
chartEl.innerHTML = html;
if (labelsEl) labelsEl.innerHTML = labelHtml;
}
function renderPaymentMethods(sales) {
var el = document.getElementById('rep-payment-methods');
if (!el) return;
var methods = { cash:'نقدا', card:'بطاقة', transfer:'تحويل' };
var totals = { cash:0, card:0, transfer:0 };
var counts = { cash:0, card:0, transfer:0 };
sales.forEach(function(s) {
if (totals[s.method] !== undefined) { totals[s.method]+=s.total; counts[s.method]++; }
});
var grandTotal = sales.reduce(function(a,s){return a+s.total;},0) || 1;
var colors = { cash:'var(--ok)', card:'var(--in)', transfer:'var(--gold)' };
var html = '';
['cash','card','transfer'].forEach(function(m) {
if (!totals[m]) return;
var pct = Math.round(totals[m]/grandTotal*100);
html += '
'
+'
'
+''+methods[m]+''+fmtM(totals[m])+' ('+pct+'%)
'
+'
'
+'
'+counts[m]+' فاتورة
'
+'
';
});
el.innerHTML = html || '
لا توجد مبيعات
';
}
function renderTraderReport(sales, from, to) {
var tb = document.getElementById('rep-traders');
if (!tb) return;
var rows = '';
var traderData = DB.traders.map(function(tr) {
var b = DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var comm = b.comm||0;
var trSales = sales.filter(function(s){return s.items.some(function(it){return it.tid===tr.id;});});
var items = trSales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(x,it){return x+it.qty;},0);},0);
var revenue = trSales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(x,it){return x+it.qty*it.price;},0);},0);
var boutComm = revenue*comm/100;
var net = revenue-boutComm;
var paid = DB.settlements.filter(function(x){return x.traderId===tr.id;}).reduce(function(a,x){return a+x.paid;},0);
return {tr:tr, items:items, revenue:revenue, boutComm:boutComm, net:net, paid:paid, rem:net-paid};
}).filter(function(x){return x.revenue>0;}).sort(function(a,b){return b.revenue-a.revenue;});
traderData.forEach(function(x) {
rows += '
'
+'
'+x.tr.name[0]+'
'+x.tr.name+'
'
+'
'+x.items+'
'
+'
'+fmtM(x.revenue)+'
'
+'
'+fmtM(x.boutComm)+'
'
+'
'+fmtM(x.net)+'
'
+'
'+fmtM(x.paid)+'
'
+'
'+fmtM(x.rem)+'
'
+'
';
});
tb.innerHTML = rows || '
لا توجد بيانات
';
}
function renderTopProducts(sales) {
var tb = document.getElementById('rep-top-prods');
if (!tb) return;
var prodMap = {};
sales.forEach(function(s) {
s.items.forEach(function(it) {
if (!prodMap[it.pid]) prodMap[it.pid] = {name:it.name, tid:it.tid, qty:0, rev:0};
prodMap[it.pid].qty += it.qty;
prodMap[it.pid].rev += it.qty*it.price;
});
});
var sorted = Object.keys(prodMap).map(function(k){return prodMap[k];}).sort(function(a,b){return b.qty-a.qty;}).slice(0,10);
var rows = '';
sorted.forEach(function(p, i) {
var tr = DB.traders.find(function(x){return x.id===p.tid;})||{};
rows += '
'
+'
'+(i+1)+''+p.name+'
'
+'
'+(tr.name||'—')+'
'
+'
'+p.qty+'
'
+'
'+fmtM(p.rev)+'
'
+'
';
});
tb.innerHTML = rows || '
لا توجد بيانات
';
}
function renderSlowMovers(sales) {
var tb = document.getElementById('rep-slow-prods');
var cnt = document.getElementById('rep-slow-count');
if (!tb) return;
// Products with qty > 0 that had zero sales in the period
var soldPids = {};
sales.forEach(function(s){s.items.forEach(function(it){soldPids[it.pid]=true;});});
var slow = DB.products.filter(function(p){return p.qty>0 && !soldPids[p.id];});
if (cnt) cnt.textContent = slow.length + ' منتج';
var rows = '';
slow.sort(function(a,b){return b.qty*b.price - a.qty*a.price;}).slice(0,15).forEach(function(p) {
var tr = DB.traders.find(function(x){return x.id===p.traderId;})||{};
rows += '
'
+'
'+p.name+'
'
+'
'+(tr.name||'—')+'
'
+'
'+p.qty+'
'
+'
'+fmtM(p.price)+'
'
+'
'+fmtM(p.qty*p.price)+'
'
+'
';
});
tb.innerHTML = rows || '
جميع المنتجات تتحرك
';
}
function renderInventory() {
var invEl = document.getElementById('rep-inventory');
var tb = document.getElementById('rep-stock');
var active = DB.products.filter(function(p){return p.qty>0;});
var totalVal = active.reduce(function(a,p){return a+p.qty*p.price;},0);
var totalCost= active.reduce(function(a,p){return a+p.qty*p.cost;},0);
var totalQty = active.reduce(function(a,p){return a+p.qty;},0);
if (invEl) invEl.innerHTML =
'
إجمالي القطع'+totalQty+' قطعة
'
+'
قيمة التكلفة'+fmtM(totalCost)+'
'
+'
قيمة البيع'+fmtM(totalVal)+'
'
+'
هامش الربح المتوقع'+fmtM(totalVal-totalCost)+'
';
if (!tb) return;
var rows = '';
active.sort(function(a,b){return b.qty*b.price-a.qty*a.price;}).slice(0,15).forEach(function(p) {
rows += '
';}el.innerHTML=html;}
function addCode(){var code=prompt('كود الخصم:');if(!code||!code.trim())return;var type=prompt('النوع: pct او fixed','pct');if(type!=='pct'&&type!=='fixed'){alert('نوع غير صالح');return;}var val=parseFloat(prompt(type==='pct'?'النسبة %:':'المبلغ:','10'));if(!val)return;var label=prompt('وصف:',code)||code;var maxU=parseInt(prompt('اقصى استخدامات (0 = لا محدود):','0')||'0');if(!DB.settings)DB.settings={};if(!DB.settings.codes)DB.settings.codes=[];DB.settings.codes.push({code:code.trim().toUpperCase(),type:type,val:val,label:label,uses:0,maxUses:maxU,active:true});save();renderCodes();}
function delCode(i){if(!confirm('حذف؟'))return; if(DB.settings&&DB.settings.codes){DB.settings.codes.splice(i,1);save();renderCodes();}}
function renderDashboard(){
fillBouts();
var today=nowDate();
var cur=DB.boutiques.find(function(b){return b.id===DB.curBout;})||DB.boutiques[0];
if(!cur)return;
var bsales=DB.sales.filter(function(s){return s.boutId===cur.id&&s.status==='completed';});
var t_today=bsales.filter(function(s){return s.date===today;}).reduce(function(a,s){return a+s.total;},0);
var t_all=bsales.reduce(function(a,s){return a+s.total;},0);
var tc=DB.traders.filter(function(t){return t.boutId===cur.id;}).length;
var due=DB.traders.filter(function(t){return t.boutId===cur.id;}).reduce(function(a,tr){var comm=cur.comm||0;var ts=DB.sales.filter(function(s){return s.status==='completed'&&s.boutId===cur.id&&s.items.some(function(it){return it.tid===tr.id;});}).reduce(function(x,s){return x+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(y,it){return y+it.qty*it.price;},0);},0);var net=ts-ts*comm/100;var paid=DB.settlements.filter(function(x){return x.traderId===tr.id;}).reduce(function(x,y){return x+y.paid;},0);return a+Math.max(0,net-paid);},0);
var el;
el=document.getElementById('d-today');if(el)el.textContent=fmtM(t_today);
el=document.getElementById('d-total');if(el)el.textContent=fmtM(t_all);
el=document.getElementById('d-tcount');if(el)el.textContent=tc;
el=document.getElementById('d-due');if(el)el.textContent=fmtM(due);
var ds=document.getElementById('d-sales-tbl');
if(ds){var recent=bsales.slice().reverse().slice(0,6);var rows='';for(var i=0;i
';}
}
// ═══════════════════════════════════════════
// AUTH — LOGIN / LOGOUT
// ═══════════════════════════════════════════
var currentUser = null;
function doLogin() {
var user = (document.getElementById('login-user')||{}).value||'';
var pass = (document.getElementById('login-pass')||{}).value||'';
var errEl = document.getElementById('login-error');
if (!user.trim()) {
if(errEl){errEl.style.display='block';errEl.textContent='ادخل اسم المستخدم';}
return;
}
// Find staff member
var staff = (DB.staff||[]).find(function(s){
return s.email === user.trim() && s.pass === pass;
});
if (!staff) {
if(errEl){errEl.style.display='block';errEl.textContent='اسم المستخدم أو كلمة المرور غير صحيحة';}
// Shake animation
var btn = document.querySelector('#login-screen .btn-gold');
if(btn){btn.style.transform='translateX(8px)';setTimeout(function(){btn.style.transform='translateX(-8px)';setTimeout(function(){btn.style.transform='';},100);},100);}
return;
}
// Success
currentUser = staff;
activeStaffId = staff.id;
// Hide login screen
var ls = document.getElementById('login-screen');
if(ls) ls.style.display='none';
// Update sidebar user info
updateUserBar();
// Apply permissions — hide nav items not in perms
applyPermissions(staff.perms||[]);
// Navigate to POS or dashboard
var startPage = (staff.perms||[]).indexOf('نقطة البيع') > -1 ? 'pos' : 'dashboard';
var navEl = document.getElementById('nav-'+startPage);
goPage(startPage, navEl);
// Clear password field
var passEl = document.getElementById('login-pass');
if(passEl) passEl.value='';
}
function resetToDemo() {
if (!confirm('سيتم حذف كل البيانات وإعادة ضبط النظام. متأكد؟')) return;
localStorage.removeItem('bpro3');
location.re
function showToast(msg, type, title) {
var t = document.getElementById('toast');
if (!t) return;
// Clear existing timer
if (window._toastTimer) clearTimeout(window._toastTimer);
if (window._toastBarTimer) clearInterval(window._toastBarTimer);
var icons = {ok:'✔', er:'✖', warn:'⚠', info:'ℹ'};
var titles = {ok:'تم بنجاح', er:'خطأ', warn:'تنبيه', info:'معلومة'};
var tp = type || 'ok';
var iconEl = document.getElementById('toast-icon');
var titleEl = document.getElementById('toast-title');
var msgEl = document.getElementById('toast-msg');
var barEl = document.getElementById('toast-bar');
t.className = 'toast toast-' + tp;
if (iconEl) iconEl.innerHTML = icons[tp] || icons.ok;
if (titleEl) titleEl.textContent = title || titles[tp] || '';
if (msgEl) msgEl.textContent = msg || '';
if (barEl) {
barEl.style.width = '100%';
barEl.style.transitionDuration = '3s';
setTimeout(function(){ barEl.style.width = '0%'; }, 50);
}
t.classList.add('show');
window._toastTimer = setTimeout(function(){
t.classList.remove('show');
}, 3200);
}
function showConfirm(msg, onOk, onCancel) {
var existing = document.getElementById('confirm-dialog');
if (existing) existing.remove();
window._confirmOk = onOk;
window._confirmCancel = onCancel;
var el = document.createElement('div');
el.id = 'confirm-dialog';
el.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:99998;display:flex;align-items:center;justify-content:center;padding:16px;backdrop-filter:blur(4px)';
var box = document.createElement('div');
box.style.cssText = 'background:var(--s1);border:1px solid var(--br);border-radius:16px;padding:28px;width:320px;text-align:center;box-shadow:0 16px 48px rgba(0,0,0,.5)';
var icon = document.createElement('div');
icon.style.cssText = 'font-size:36px;margin-bottom:12px';
icon.innerHTML = '⚠️';
var txt = document.createElement('div');
txt.style.cssText = 'font-size:15px;font-weight:700;margin-bottom:8px;line-height:1.5';
txt.textContent = msg;
var btns = document.createElement('div');
btns.style.cssText = 'display:flex;gap:10px;margin-top:20px';
var cancelBtn = document.createElement('button');
cancelBtn.textContent = 'إلغاء';
cancelBtn.style.cssText = 'flex:1;padding:11px;background:var(--s2);border:1px solid var(--br);border-radius:9px;color:var(--tx);cursor:pointer;font-family:Tajawal;font-size:14px';
cancelBtn.onclick = function(){
document.getElementById('confirm-dialog').remove();
if(window._confirmCancel) window._confirmCancel();
};
var okBtn = document.createElement('button');
okBtn.textContent = 'تأكيد';
okBtn.style.cssText = 'flex:1;padding:11px;background:linear-gradient(135deg,var(--er),#c03030);border:none;border-radius:9px;color:#fff;cursor:pointer;font-family:Tajawal;font-size:14px;font-weight:700';
okBtn.onclick = function(){
document.getElementById('confirm-dialog').remove();
if(window._confirmOk) window._confirmOk();
};
btns.appendChild(cancelBtn);
btns.appendChild(okBtn);
box.appendChild(icon);
box.appendChild(txt);
box.appendChild(btns);
el.appendChild(box);
document.body.appendChild(el);
}
function saveCostSetting(){
if(!DB.settings) DB.settings={};
var el=document.getElementById('cfg-hide-cost');
DB.settings.hideCost = el ? el.checked : false;
save();
applyCostVisibility();
showToast(DB.settings.hideCost?'تم إخفاء سعر التكلفة':'ظهر سعر التكلفة مجدداً','ok');
}
function applyCostVisibility(){
var hide=(DB.settings&&DB.settings.hideCost);
var costRows=document.querySelectorAll('.cost-field');
for(var i=0;i -1) ? '' : 'none';
});
}
// Allow Enter key on login form
document.addEventListener('keydown', function(e){
var ls = document.getElementById('login-screen');
if(ls && ls.style.display !== 'none' && e.key === 'Enter') doLogin();
});
// Active staff tracking
var activeStaffId = null;
function selectStaff(id) {
activeStaffId = id;
var nameEl = document.getElementById('pos-staff-name');
var avatarEl = document.getElementById('pos-staff-avatar');
if (id) {
var s = (DB.staff||[]).find(function(x){return x.id===id;});
if (s) {
if (nameEl) nameEl.textContent = s.name;
if (avatarEl) { avatarEl.textContent = s.name[0]; avatarEl.style.background = 'linear-gradient(135deg,var(--gold2),var(--rose))'; }
}
} else {
if (nameEl) nameEl.textContent = 'لم تُحدد بعد';
if (avatarEl) { avatarEl.textContent = '؟'; avatarEl.style.background = 'var(--s3)'; }
}
closeOv('ov-select-staff');
}
function openStaffSelector() {
var list = document.getElementById('staff-select-list');
if (!list) return;
var staff = DB.staff||[];
if (!staff.length) {
list.innerHTML = '
لا توجد موظفات
';
openOv('ov-select-staff');
return;
}
var html = '';
for (var i=0; i';
html += '
' + s.name[0] + '
';
html += '
';
html += '
' + s.name + '
';
html += '
' + s.email + '
';
html += '
';
if (isActive) html += '✓';
html += '
';
}
list.innerHTML = html;
openOv('ov-select-staff');
}
function getVAT(){ return parseFloat((DB.settings&&DB.settings.vat)||0)||0; }
function getCardFee(){ return parseFloat((DB.settings&&DB.settings.cardFee)||0)||0; }
// TRADER REPORT
var _traderReportId = null;
function setTrRepPeriod(p){
var t=nowDate(),f='',d=new Date();
if(p==='month'){f=t.slice(0,8)+'01';}
else if(p==='last'){
d.setDate(0);
var y=d.getFullYear(),m=String(d.getMonth()+1).padStart(2,'0');
f=y+'-'+m+'-01';
t=y+'-'+m+'-'+String(d.getDate()).padStart(2,'0');
}
var fe=document.getElementById('tr-rep-from');
var te=document.getElementById('tr-rep-to');
if(fe)fe.value=f; if(te)te.value=t;
buildTraderReport();
}
function openTraderReport(tid){
_traderReportId=tid;
var t=nowDate(),f=t.slice(0,8)+'01';
var fe=document.getElementById('tr-rep-from');
var te=document.getElementById('tr-rep-to');
if(fe)fe.value=f; if(te)te.value=t;
buildTraderReport();
openOv('ov-trader-report');
}
function buildTraderReport(){
var tid=_traderReportId; if(!tid)return;
var tr=DB.traders.find(function(x){return x.id===tid;}); if(!tr)return;
var b=DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var comm=b.comm||0, vat=getVAT(), cFee=getCardFee();
var from=(document.getElementById('tr-rep-from')||{}).value||'';
var to=(document.getElementById('tr-rep-to')||{}).value||'';
var title=document.getElementById('tr-rep-title');
if(title)title.textContent='تقرير: '+tr.name;
var sales=DB.sales.filter(function(s){
if(s.status!=='completed')return false;
if(from&&s.dateto)return false;
return s.items.some(function(it){return it.tid===tid;});
});
var totalItems=0,totalRevenue=0,cardSales=0,saleRows='';
sales.forEach(function(s){
var trItems=s.items.filter(function(it){return it.tid===tid;});
var trRev=trItems.reduce(function(a,it){return a+it.qty*it.price;},0);
var trQty=trItems.reduce(function(a,it){return a+it.qty;},0);
var trCardFee=(s.method==='card'&&cFee)?trRev*cFee/100:0;
totalItems+=trQty; totalRevenue+=trRev;
if(s.method==='card')cardSales+=trRev;
var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'}[s.method]||s.method;
saleRows+='
';
});
var boutCommAmt=totalRevenue*comm/100;
var vatAmt=vat?totalRevenue*vat/100:0;
var cardFeeAmt=cFee?cardSales*cFee/100:0;
var netDue=totalRevenue-boutCommAmt-vatAmt-cardFeeAmt;
var settles=DB.settlements.filter(function(x){return x.traderId===tid&&(!from||x.date>=from)&&(!to||x.date<=to);});
var totalPaid=settles.reduce(function(a,x){return a+x.paid;},0);
var remaining=netDue-totalPaid;
var html='';
html+='
';
}
var body=document.getElementById('tr-rep-body'); if(body)body.innerHTML=html;
window._lastTraderReport={trader:tr,boutique:b,from:from,to:to,totalRevenue:totalRevenue,totalItems:totalItems,boutCommAmt:boutCommAmt,vatAmt:vatAmt,cardFeeAmt:cardFeeAmt,netDue:netDue,totalPaid:totalPaid,remaining:remaining,comm:comm,vat:vat,cFee:cFee,cardSales:cardSales};
}
function sendTraderReportWA(){
var r=window._lastTraderReport;
if(!r||!r.trader.phone){alert('لا يوجد رقم جوال');return;}
var ph=r.trader.phone.replace(/\D/g,'');
if(ph.indexOf('968')!==0)ph='968'+ph.replace(/^0/,'');
var lines=[
'كشف حساب - '+(r.boutique.name||'البوتيك'),
'التاجرة: '+r.trader.name,
'الفترة: '+(r.from||'من البداية')+' الى '+(r.to||'الآن'),
'---',
'اجمالي مبيعاتك: '+fmtM(r.totalRevenue),
'عدد القطع: '+r.totalItems,
'---',
'ايجار البوتيك '+r.comm+'%: -'+fmtM(r.boutCommAmt)
];
if(r.vatAmt>0)lines.push('ضريبة VAT '+r.vat+'%: -'+fmtM(r.vatAmt));
if(r.cardFeeAmt>0)lines.push('رسوم جهاز الدفع '+r.cFee+'%: -'+fmtM(r.cardFeeAmt));
lines.push('---');
lines.push('الصافي المستحق لك: '+fmtM(r.netDue));
if(r.totalPaid>0)lines.push('تم استلامه: '+fmtM(r.totalPaid));
lines.push('المتبقي: '+fmtM(r.remaining));
lines.push('---');
lines.push('شكرا لتعاملك معنا');
window.open('https://wa.me/'+ph+'?text='+encodeURIComponent(lines.join('\n')),'_blank');
}
// ═══════════════════════════════════════════
// SIZE FIELDS
// ═══════════════════════════════════════════
var SIZE_TEMPLATES = {
abaya: [{id:'length',label:'الطول (سم)'},{id:'chest',label:'الصدر (سم)'},{id:'shoulder',label:'الكتف (سم)'},{id:'sleeve',label:'الكم (سم)'},{id:'waist',label:'الخصر (سم)'},{id:'size_label',label:'المقاس (S/M/L/XL)'}],
top: [{id:'chest',label:'الصدر (سم)'},{id:'shoulder',label:'الكتف (سم)'},{id:'length',label:'الطول (سم)'},{id:'sleeve',label:'الكم (سم)'},{id:'size_label',label:'المقاس'}],
pants: [{id:'waist',label:'الخصر (سم)'},{id:'hips',label:'الورك (سم)'},{id:'length',label:'الطول (سم)'},{id:'size_label',label:'المقاس'}],
scarf: [{id:'length',label:'الطول (سم)'},{id:'width',label:'العرض (سم)'},{id:'material',label:'الخامة'}],
bag: [{id:'width',label:'العرض (سم)'},{id:'height',label:'الارتفاع (سم)'},{id:'depth',label:'العمق (سم)'},{id:'color',label:'اللون'}],
shoes: [{id:'size_label',label:'المقاس'},{id:'color',label:'اللون'},{id:'material',label:'الخامة'}],
accessory: [{id:'size_label',label:'المقاس/الحجم'},{id:'color',label:'اللون'},{id:'material',label:'الخامة'}],
custom:[{id:'f1',label:'قياس 1'},{id:'f2',label:'قياس 2'},{id:'f3',label:'قياس 3'},{id:'f4',label:'قياس 4'},{id:'f5',label:'قياس 5'},{id:'f6',label:'قياس 6'}]
};
var _aiResult = null;
function buildSizeFields() {
var type = (document.getElementById('size-type')||{}).value;
var container = document.getElementById('size-fields');
if (!container) return;
if (!type) { container.innerHTML = ''; return; }
var fields = SIZE_TEMPLATES[type] || [];
// Load existing values if editing
var existing = {};
try { existing = JSON.parse((document.getElementById('p-sizes')||{}).value||'{}'); } catch(e) {}
var html = '';
for (var i=0; i';
html += '';
html += '';
}
container.innerHTML = html;
}
function collectSizes() {
var type = (document.getElementById('size-type')||{}).value;
if (!type) return '';
var fields = SIZE_TEMPLATES[type] || [];
var obj = { _type: type };
for (var i=0; i -1) continue;
parts.push(obj[k]);
}
return parts.slice(0,3).join(' / ');
} catch(e) { return ''; }
}
// ═══════════════════════════════════════════
// AI PRODUCT SCAN
// ═══════════════════════════════════════════
function getApiKey() {
return DB.settings && DB.settings.apiKey ? DB.settings.apiKey : '';
}
function saveApiKey() {
var key = (document.getElementById('cfg-apikey')||{}).value||'';
if (!key.trim()) { alert('ادخل المفتاح'); return; }
if (!DB.settings) DB.settings = {};
DB.settings.apiKey = key.trim();
save();
alert('تم حفظ المفتاح');
}
function testApiKey() {
var el = document.getElementById('api-test-result');
if (el) { el.style.color='var(--mu)'; el.textContent='جاري الاختبار...'; }
var key = getApiKey();
if (!key) { if(el){el.style.color='var(--er)';el.textContent='لا يوجد مفتاح - احفظه اولا';} return; }
fetch('https://api.anthropic.com/v1/messages', {
method:'POST',
headers:{'Content-Type':'application/json','x-api-key':key,'anthropic-version':'2023-06-01'},
body:JSON.stringify({model:'claude-haiku-4-5-20251001',max_tokens:20,messages:[{role:'user',content:'قل نعم فقط'}]})
}).then(function(r){return r.json();}).then(function(d){
if(d.content&&d.content[0]){if(el){el.style.color='var(--ok)';el.textContent='المفتاح يعمل';}}
else{if(el){el.style.color='var(--er)';el.textContent='خطأ: '+(d.error&&d.error.message||'غير معروف');}}
}).catch(function(e){if(el){el.style.color='var(--er)';el.textContent='فشل الاتصال';}});
}
function aiScanProduct(input) {
if (!input.files || !input.files[0]) return;
var key = getApiKey();
if (!key) { alert('اضف مفتاح Claude API في الاعدادات اولا'); return; }
var statusEl = document.getElementById('ai-status');
var wrapEl = document.getElementById('ai-wrap');
var prevEl = document.getElementById('ai-prev');
var outEl = document.getElementById('ai-out');
var applyBtn = document.getElementById('ai-apply');
var btn = document.getElementById('ai-btn');
if(statusEl) { statusEl.style.color='var(--gold)'; statusEl.textContent='جاري قراءة الصورة...'; }
if(btn) btn.disabled = true;
var reader = new FileReader();
reader.onload = function(e) {
var b64 = e.target.result.split(',')[1];
var mime = input.files[0].type || 'image/jpeg';
if(prevEl) { prevEl.src=e.target.result; }
if(wrapEl) { wrapEl.style.display='block'; }
if(outEl) { outEl.textContent='جاري التحليل...'; }
// Get category from size-type if selected
var sizeType = (document.getElementById('size-type')||{}).value || '';
var catHint = sizeType ? ' (نوع المنتج: ' + sizeType + ')' : '';
var prompt = 'انت خبير في الموضة والملابس. حلل هذه الصورة لمنتج في بوتيك'+catHint+'.'
+' استخرج المعلومات التالية وأجب بهذا التنسيق فقط: '
+'الاسم: [اسم المنتج] | '
+'اللون: [الالوان] | '
+'الخامة: [نوع القماش] | '
+'المقاس: [المقاس ان كان واضحا] | '
+'الطول: [بالسم ان كان واضحا] | '
+'الصدر: [بالسم ان كان واضحا] | '
+'الوصف: [وصف مختصر] | '
+'السعر المقترح: [بالريال العماني] '
+'اذا لم تكن المعلومة واضحة اكتب: غير محدد';
fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'Content-Type':'application/json', 'x-api-key':key, 'anthropic-version':'2023-06-01' },
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 400,
messages: [{
role: 'user',
content: [
{ type:'image', source:{ type:'base64', media_type:mime, data:b64 } },
{ type:'text', text:prompt }
]
}]
})
})
.then(function(r) { return r.json(); })
.then(function(d) {
if(btn) btn.disabled = false;
if (d.content && d.content[0] && d.content[0].text) {
var text = d.content[0].text;
_aiResult = parseAiResult(text);
if(outEl) outEl.innerHTML = text.replace(/\n/g,' ').replace(/\|/g,' ');
if(applyBtn) applyBtn.style.display = 'inline-flex';
if(statusEl) { statusEl.style.color='var(--ok)'; statusEl.textContent='تم التحليل'; }
} else {
var errMsg = d.error ? d.error.message : 'غير معروف';
if(outEl) { outEl.style.color='var(--er)'; outEl.textContent='خطأ: '+errMsg; }
if(statusEl) { statusEl.style.color='var(--er)'; statusEl.textContent='فشل'; }
}
})
.catch(function(e) {
if(btn) btn.disabled = false;
if(outEl) { outEl.style.color='var(--er)'; outEl.textContent='فشل الاتصال بـ Claude'; }
if(statusEl) { statusEl.style.color='var(--er)'; statusEl.textContent='خطأ في الاتصال'; }
});
};
reader.readAsDataURL(input.files[0]);
}
function parseAiResult(text) {
var result = {};
var parts = text.indexOf('|')>-1 ? text.split('|') : text.split('\n');
for (var i=0; ito) return false;
return true;
});
// KPI cards
var totalSal=list.reduce(function(a,s){return a+(s.salary||0);},0);
var totalComm=list.reduce(function(a,s){
var ss=allSales.filter(function(x){return x.staffId===s.id;});
return a+calcStaffComm(s,ss);
},0);
var sc=document.getElementById('staff-stats-cards');
if(sc){
sc.innerHTML=
'
عدد الموظفات
'+list.length+'
'
+'
إجمالي الرواتب
'+fmtM(totalSal)+'
'
+'
إجمالي العمولات
'+fmtM(totalComm)+'
'
+'
إجمالي المستحقات
'+fmtM(totalSal+totalComm)+'
';
}
// Performance table
var perf=document.getElementById('tbl-staff-perf');
if(perf){
var rows='';
for(var i=0;ibestC){bestC=hmap[h];bestH=h+':00';}});
rows+='
'
+'
'+st.name[0]+'
'+st.name+'
'
+'
'+ss.length+'
'
+'
'+fmtM(sTotal)+'
'
+'
'+fmtM(sComm)+'
'
+'
'+fmtM(st.salary||0)+'
'
+'
'+fmtM(sDue)+'
'
+'
'+bestH+'
'
+'
'
+'
';
}
perf.innerHTML=rows||'
لا توجد موظفات
';
}
// Peak hours chart
var peakEl=document.getElementById('peak-chart');
var peakLbl=document.getElementById('peak-labels');
if(peakEl){
var hours={};
for(var h=8;h<=22;h++) hours[String(h).padStart(2,'0')]=0;
allSales.forEach(function(x){
if(!x.time) return;
var hk=x.time.slice(0,2);
if(hours[hk]!==undefined) hours[hk]+=x.total;
});
var maxH=Math.max.apply(null,Object.keys(hours).map(function(k){return hours[k];}))||1;
var ch='',lb='';
Object.keys(hours).forEach(function(hk){
var val=hours[hk];
var ht=Math.max(2,Math.round(val/maxH*90));
ch+='
'
+(val>0?'
'+Math.round(val)+'
':'')
+''
+'
';
lb+='
'+parseInt(hk)+'
';
});
peakEl.innerHTML=ch;
if(peakLbl)peakLbl.innerHTML=lb;
}
// Staff comparison bars
var cmp=document.getElementById('staff-compare');
if(cmp){
var data=[];
for(var j=0;j0;}).sort(function(a,b){return b.total-a.total;});
var maxT=data.length?data[0].total:1;
var html='';
if(!data.length){
html='
ربط المبيعات بالموظفة يتم تلقائياً عند تسجيل الدخول قبل إتمام البيع
';
} else {
data.forEach(function(x){
var pct=Math.round(x.total/maxT*100);
html+='
'
+ ''
+ '';
document.body.appendChild(banner);
setTimeout(function(){ if(banner.parentElement) banner.remove(); }, 8000);
}
function showLowStock() {
var threshold = parseInt((DB.settings||{}).stockAlert || 5);
var low = DB.products.filter(function(p){ return p.qty > 0 && p.qty <= threshold; });
var msg = 'منتجات توشك النفاد:\n';
low.forEach(function(p){
var t = DB.traders.find(function(x){return x.id===p.traderId;})||{};
msg += '• ' + p.name + ' (' + (t.name||'') + ') — متبقي: ' + p.qty + '\n';
});
alert(msg);
}
function saveStockSettings() {
if (!DB.settings) DB.settings = {};
var el = document.getElementById('cfg-stock-alert');
var chk = document.getElementById('cfg-stock-notify');
DB.settings.stockAlert = el ? parseInt(el.value)||5 : 5;
DB.settings.stockNotify = chk ? chk.checked : true;
save();
showToast('تم حفظ إعدادات التنبيه', 'ok');
checkStockAlerts();
}
function saveTaxSettings() {
if (!DB.settings) DB.settings = {};
var who = document.querySelector('input[name="tax-who"]:checked');
var pct = document.getElementById('cfg-tax-pct');
DB.settings.taxWho = who ? who.value : 'boutique';
DB.settings.vat = pct ? parseFloat(pct.value)||0 : 0;
save();
showToast('تم حفظ إعدادات الضريبة', 'ok');
}
// ═══════════════════════════════════════════
// TRADER COLOR + LOGO
// ═══════════════════════════════════════════
function setTraderColor(color) {
var inp = document.getElementById('t-color');
var prev = document.getElementById('t-color-preview');
if (inp) inp.value = color;
if (prev) prev.style.background = color;
}
function prevTraderLogo(inp) {
if (!inp.files || !inp.files[0]) return;
var reader = new FileReader();
reader.onload = function(e) {
var prev = document.getElementById('t-logo-prev');
var hid = document.getElementById('t-logo');
if (prev) prev.innerHTML = '';
if (hid) hid.value = e.target.result;
};
reader.readAsDataURL(inp.files[0]);
}
function clearTraderLogo() {
var prev = document.getElementById('t-logo-prev');
var hid = document.getElementById('t-logo');
var fi = document.getElementById('t-logo-file');
if (prev) prev.innerHTML = '💼';
if (hid) hid.value = '';
if (fi) fi.value = '';
}
// ═══════════════════════════════════════════
// INIT
// ═══════════════════════════════════════════
// ═══════════════════════════════════════════
// PREMIUM TOAST SYSTEM
// ═══════════════════════════════════════════
var _toastId = 0;
function showToast(msg, type, title) {
var wrap = document.getElementById('toast-wrap');
if (!wrap) { alert(msg); return; }
var tp = type || 'ok';
var icons = {ok:'✔', er:'✖', warn:'⚠', info:'ℹ'};
var titles = {ok:'تم بنجاح', er:'خطأ', warn:'تنبيه', info:'معلومة'};
var id = 'toast-' + (++_toastId);
var el = document.createElement('div');
el.id = id;
el.className = 'toast toast-' + tp;
el.innerHTML = '
'
+ '
' + (icons[tp]||icons.ok) + '
'
+ '
'
+ '
' + (title || titles[tp] || '') + '
'
+ '
' + msg + '
'
+ '
'
+ ''
+ '
'
+ '
';
wrap.appendChild(el);
setTimeout(function(){ el.classList.add('show'); }, 10);
setTimeout(function(){
var bar = document.getElementById(id + '-bar');
if (bar) bar.style.width = '0%';
}, 50);
setTimeout(function(){
el.classList.remove('show');
setTimeout(function(){ if(el.parentElement) el.remove(); }, 300);
}, 3500);
}
// ═══════════════════════════════════════════
// COST FIELD VISIBILITY
// ═══════════════════════════════════════════
function toggleCostField() {
var chk = document.getElementById('cfg-hide-cost');
if (!DB.settings) DB.settings = {};
DB.settings.hideCost = chk ? chk.checked : false;
save();
applyCostVisibility();
showToast(DB.settings.hideCost ? 'تم إخفاء سعر التكلفة' : 'تم إظهار سعر التكلفة', 'ok');
}
function applyCostVisibility() {
var hide = DB.settings && DB.settings.hideCost;
var wrap = document.getElementById('cost-field-wrap');
if (wrap) wrap.style.display = hide ? 'none' : '';
}
load();
// Ensure admin account always exists
if (!DB.staff) DB.staff = [];
var _hasAdmin = DB.staff.find(function(x){ return x.email === 'admin'; });
if (!_hasAdmin) {
DB.staff.push({
id:'st1', name:'مدير النظام', email:'admin', pass:'admin123',
salary:0, join:'2024-01-01', end:'', ct:'none', cp:0, cf:0,
perms:['لوحة التحكم','نقطة البيع','البوتيكات','التاجرات','البضاعة',
'المبيعات','التسويات','الموظفات','التقارير','الاعدادات'],
active:true
});
save();
}
// Ensure settings exist
if (!DB.settings) {
DB.settings = { currency:'OMR', sym:'ر.ع',
rates:{USD:2.59,AED:0.706,SAR:0.691,EUR:2.80,GBP:3.26,KWD:0.122},
codes:[], vat:0, cardFee:0 };
save();
}
fillBouts();
loadTheme();
checkStockAlerts();
applyCostVisibility();
applyCostVisibility();
var _sdEl = document.getElementById('sales-date');
if (_sdEl) _sdEl.value = nowDate();
// Focus login username
var _uEl = document.getElementById('login-user');
if (_uEl) setTimeout(function(){ _uEl.focus(); }, 100);
function save(){try{localStorage.setItem('bpro3',JSON.stringify(DB));}catch(e){}}
function load(){try{var d=localStorage.getItem('bpro3');if(d){DB=JSON.parse(d);return;}}catch(e){}seedDemo();}
function seedDemo(){
DB.boutiques=[{id:'b1',name:'بوتيك لالة',loc:'مسقط - الموج',phone:'',comm:20,notes:''},{id:'b2',name:'بوتيك نجمة',loc:'مسقط - المطرح',phone:'',comm:15,notes:''}];
DB.curBout='b1';
DB.traders=[{id:'t1',name:'ام خالد',phone:'+96891234567',idn:'',boutId:'b1',notes:''},{id:'t2',name:'ام سالم',phone:'+96892345678',idn:'',boutId:'b1',notes:''},{id:'t3',name:'ام ماجد',phone:'+96893456789',idn:'',boutId:'b2',notes:''}];
var t=new Date().toISOString().slice(0,10);
DB.products=[{id:'p1',sku:'SKU001',name:'عباية مطرزة',traderId:'t1',boutId:'b1',cost:25,price:45,qty:3,cat:'عبايات',img:'',notes:''},{id:'p2',sku:'SKU002',name:'طرحة حرير',traderId:'t1',boutId:'b1',cost:8,price:18,qty:5,cat:'طرح',img:'',notes:''},{id:'p3',sku:'SKU003',name:'حقيبة جلد',traderId:'t2',boutId:'b1',cost:12,price:28,qty:2,cat:'حقائب',img:'',notes:''},{id:'p4',sku:'SKU004',name:'اكسسوار فضي',traderId:'t2',boutId:'b1',cost:5,price:12,qty:8,cat:'اكسسوارات',img:'',notes:''},{id:'p5',sku:'SKU005',name:'عطر عود',traderId:'t3',boutId:'b2',cost:30,price:65,qty:4,cat:'عطور',img:'',notes:''}];
DB.sales=[{id:'s1',boutId:'b1',inv:'INV-1001',date:t,time:'09:00',method:'cash',items:[{pid:'p1',name:'عباية مطرزة',qty:1,price:45,tid:'t1'}],sub:45,disc:0,total:45,cname:'',cphone:'',status:'completed'},{id:'s2',boutId:'b1',inv:'INV-1002',date:t,time:'11:30',method:'card',items:[{pid:'p4',name:'اكسسوار فضي',qty:2,price:12,tid:'t2'}],sub:24,disc:0,total:24,cname:'',cphone:'',status:'completed'}];
DB.settlements=[];
DB.staff=[{id:'st1',name:'مدير النظام',email:'admin',pass:'admin123',salary:0,join:'2024-01-01',end:'',ct:'none',cp:0,cf:0,perms:PERMS.slice(),active:true}];
DB.inv=1003;
DB.settings={currency:'OMR',sym:'ر.ع',rates:{USD:2.59,AED:0.706,SAR:0.691,EUR:2.80,GBP:3.26,KWD:0.122},codes:[]};
save();
}
function sym(){return DB.settings&&DB.settings.sym?DB.settings.sym:'ر.ع';}
function fmt(n){return(parseFloat(n)||0).toFixed(3);}
function fmtM(n){return fmt(n)+' '+sym();}
function nowDate(){return new Date().toISOString().slice(0,10);}
function nowTime(){return new Date().toLocaleTimeString('ar',{hour:'2-digit',minute:'2-digit'});}
function nextInv(){return 'INV-'+(DB.inv++);}
function goPage(id,navId){
var pgs=document.querySelectorAll('.pg');
for(var i=0;i'+b.name+'';}).join('');
var ids=['t-bout','p-bout','dash-bout','pos-b'];
for(var i=0;i'+t.name+(b?' ('+b.name+')':'')+'';}).join('');
}
function switchBout(id){DB.curBout=id;save();renderDashboard();}
function renderBoutiques(){
var tb=document.getElementById('tbl-bouts');if(!tb)return;
var rows='';
for(var i=0;i
'+b.name+'
'+(b.loc||'—')+'
'+b.comm+'%
'+tc+'
'+fmtM(ms)+'
';}
tb.innerHTML=rows||'
لا توجد بوتيكات
';
}
function openBoutForm(id){var b=id?DB.boutiques.find(function(x){return x.id===id;}):null;document.getElementById('b-title').textContent=b?'تعديل البوتيك':'بوتيك جديد';document.getElementById('b-id').value=b?b.id:'';document.getElementById('b-name').value=b?b.name:'';document.getElementById('b-loc').value=b?(b.loc||''):'';document.getElementById('b-phone').value=b?(b.phone||''):'';document.getElementById('b-comm').value=b?b.comm:'20';document.getElementById('b-notes').value=b?(b.notes||''):'';openOv('ov-boutique');}
function editBout(id){openBoutForm(id);}
function saveBout(){var id=document.getElementById('b-id').value;var name=document.getElementById('b-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'b'+Date.now(),name:name,loc:document.getElementById('b-loc').value.trim(),phone:document.getElementById('b-phone').value.trim(),comm:parseFloat(document.getElementById('b-comm').value)||0,notes:document.getElementById('b-notes').value.trim()};if(id){var i=DB.boutiques.findIndex(function(x){return x.id===id;});if(i>-1)DB.boutiques[i]=obj;}else{DB.boutiques.push(obj);if(!DB.curBout)DB.curBout=obj.id;}save();closeOv('ov-boutique');fillBouts();renderBoutiques();showToast('تم حفظ البوتيك','ok');}
function delBout(id){if(!confirm('حذف؟'))return; DB.boutiques=DB.boutiques.filter(function(b){return b.id!==id;});if(DB.curBout===id)DB.curBout=DB.boutiques[0]?DB.boutiques[0].id:null;save();fillBouts();renderBoutiques();}
function renderTraders(){
var tb=document.getElementById('tbl-traders');if(!tb)return;
var q=((document.getElementById('trader-q')||{}).value||'').toLowerCase();
var tlist=q?DB.traders.filter(function(t){return t.name.toLowerCase().indexOf(q)>-1||(t.phone&&t.phone.indexOf(q)>-1);}):DB.traders;
var rows='';
for(var i=0;i
'+tr.name[0]+'
'+tr.name+'
'+(b.name||'—')+'
'+(tr.phone||'—')+'
'+prods+'
'+fmtM(tsales)+'
'+fmtM(trem)+'
';}
tb.innerHTML=rows||'
لا توجد تاجرات
';
}
function openTraderForm(id){var t=id?DB.traders.find(function(x){return x.id===id;}):null;document.getElementById('t-title').textContent=t?'تعديل التاجرة':'اضافة تاجرة';document.getElementById('t-id').value=t?t.id:'';document.getElementById('t-name').value=t?t.name:'';document.getElementById('t-phone').value=t?(t.phone||''):'';document.getElementById('t-idn').value=t?(t.idn||''):'';document.getElementById('t-notes').value=t?(t.notes||''):'';fillBouts();var tb=document.getElementById('t-bout');if(tb&&t)tb.value=t.boutId;openOv('ov-trader');}
function editTrader(id){openTraderForm(id);}
function saveTrader(){var id=document.getElementById('t-id').value;var name=document.getElementById('t-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'t'+Date.now(),name:name,phone:document.getElementById('t-phone').value.trim(),idn:document.getElementById('t-idn').value.trim(),boutId:document.getElementById('t-bout').value,notes:document.getElementById('t-notes').value.trim()};if(id){var i=DB.traders.findIndex(function(x){return x.id===id;});if(i>-1)DB.traders[i]=obj;}else DB.traders.push(obj);save();closeOv('ov-trader');renderTraders();showToast('تم حفظ التاجرة','ok');}
function delTrader(id){if(!confirm('حذف؟'))return; DB.traders=DB.traders.filter(function(t){return t.id!==id;});save();renderTraders();}
function renderProducts(){
var tb=document.getElementById('tbl-prods');if(!tb)return;
var q=(document.getElementById('prod-q')||{}).value||'';
var list=q?DB.products.filter(function(p){return p.name.indexOf(q)>-1||p.sku.indexOf(q)>-1;}):DB.products.slice();
var rows='';
for(var i=0;i
'+p.sku+'
'+(p.img?'':'📦')+'
'+p.name+'
'+(p.cat||'')+'
'+(t?t.name:'—')+'
'+fmtM(p.price)+'
'+p.qty+'
';}
tb.innerHTML=rows||'
لا توجد منتجات
';
}
function openProdForm(id){var p=id?DB.products.find(function(x){return x.id===id;}):null;document.getElementById('p-title').textContent=p?'تعديل المنتج':'اضافة منتج';document.getElementById('p-id').value=p?p.id:'';document.getElementById('p-sku').value=p?p.sku:('SKU'+String(DB.products.length+1).padStart(3,'0'));document.getElementById('p-name').value=p?p.name:'';document.getElementById('p-cost').value=p?p.cost:'';document.getElementById('p-price').value=p?p.price:'';document.getElementById('p-qty').value=p?p.qty:'1';document.getElementById('p-cat').value=p?(p.cat||''):'';document.getElementById('p-notes').value=p?(p.notes||''):'';document.getElementById('p-img').value=p?(p.img||''):'';var prev=document.getElementById('p-img-prev');if(prev)prev.innerHTML=(p&&p.img)?'':'📦';fillTraders('p-trader');fillBouts();var pt=document.getElementById('p-trader');var pb=document.getElementById('p-bout');if(p&&pt)pt.value=p.traderId;if(p&&pb)pb.value=p.boutId;var aiWrap=document.getElementById('ai-wrap');if(aiWrap)aiWrap.style.display='none';var aiSt=document.getElementById('ai-status');if(aiSt)aiSt.textContent='';_aiResult=null;var pSizes=document.getElementById('p-sizes');if(pSizes)pSizes.value=p?(p.sizes||''):'';loadSizesIntoForm(p?p.sizes:'');openOv('ov-product');}
function editProd(id){openProdForm(id);}
function autoFillBout(){var t=DB.traders.find(function(x){return x.id===document.getElementById('p-trader').value;});var pb=document.getElementById('p-bout');if(t&&pb)pb.value=t.boutId;}
function prevImg(inp){if(!inp.files||!inp.files[0])return;var r=new FileReader();r.onload=function(e){var prev=document.getElementById('p-img-prev');var hid=document.getElementById('p-img');if(prev)prev.innerHTML='';if(hid)hid.value=e.target.result;};r.readAsDataURL(inp.files[0]);}
function clearImg(){var prev=document.getElementById('p-img-prev');var hid=document.getElementById('p-img');var fi=document.getElementById('p-img-file');if(prev)prev.innerHTML='📦';if(hid)hid.value='';if(fi)fi.value='';}
function saveProd(){var id=document.getElementById('p-id').value;var name=document.getElementById('p-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var obj={id:id||'p'+Date.now(),sku:document.getElementById('p-sku').value||('SKU'+Date.now()),name:name,traderId:document.getElementById('p-trader').value,boutId:document.getElementById('p-bout').value,cost:parseFloat(document.getElementById('p-cost').value)||0,price:parseFloat(document.getElementById('p-price').value)||0,qty:parseInt(document.getElementById('p-qty').value)||0,cat:document.getElementById('p-cat').value.trim(),img:document.getElementById('p-img').value||'',notes:document.getElementById('p-notes').value.trim(),sizes:collectSizes()};if(id){var i=DB.products.findIndex(function(x){return x.id===id;});if(i>-1)DB.products[i]=obj;}else DB.products.push(obj);save();closeOv('ov-product');renderProducts();showToast('تم حفظ المنتج','ok');}
function delProd(id){if(!confirm('حذف؟'))return; DB.products=DB.products.filter(function(p){return p.id!==id;});save();renderProducts();}
function renderPos(){fillBouts();fillTraders('pos-t');var posT=document.getElementById('pos-t');if(posT){var opt=document.createElement('option');opt.value='';opt.textContent='جميع التاجرات';posT.insertBefore(opt,posT.firstChild);posT.value='';}renderPosGrid();renderCart();if(!activeStaffId&&(DB.staff||[]).length>0)openStaffSelector();}
function renderPosGrid(){
var grid=document.getElementById('pos-grid');if(!grid)return;
var bid=(document.getElementById('pos-b')||{}).value||'';var tid=(document.getElementById('pos-t')||{}).value||'';var q=((document.getElementById('pos-q')||{}).value||'').toLowerCase();
var list=DB.products.filter(function(p){if(p.qty<=0)return false;if(bid&&p.boutId!==bid)return false;if(tid&&p.traderId!==tid)return false;if(q&&p.name.toLowerCase().indexOf(q)<0&&p.sku.toLowerCase().indexOf(q)<0)return false;return true;});
if(!list.length){grid.innerHTML='
لا توجد منتجات
';return;}
var html='';
for(var i=0;i'+(p.img?'':'
📦
')+'
'+p.name+'
'+(t?t.name:'')+'
'+fmtM(p.price)+'
متاح: '+p.qty+'
';}
grid.innerHTML=html;
}
function posKey(e){if(e.key==='Enter'){var q=(document.getElementById('pos-q')||{}).value||'';var match=DB.products.find(function(p){return p.sku===q||p.sku===q.replace(/^0+/,'');});if(match){addToCart(match.id);document.getElementById('pos-q').value='';renderPosGrid();}}}
function addToCart(pid){var p=DB.products.find(function(x){return x.id===pid;});if(!p||p.qty<=0)return;var ex=CART.find(function(c){return c.pid===pid;});if(ex){if(ex.qtymaxQty){
showToast('الكمية المتوفرة في المخزن: '+maxQty+' فقط','er');
ci.qty=maxQty;
} else {
ci.qty=Math.max(1,newQty);
}
renderCart();calcCart();
}
function renderCart(){
var container=document.getElementById('cart-items');if(!container)return;
if(!CART.length){container.innerHTML='
السلة فارغة
';return;}
var html='';
for(var i=0;i'+(c.img?'':'
📦
')+'
'+c.name+'
'+fmt(c.price)+' x '+c.qty+'
'+c.qty+'
'+fmt(c.price*c.qty)+'
';}
container.innerHTML=html;
}
function getDisc(sub){var t=(document.getElementById('disc-t')||{}).value||'0';var v=parseFloat((document.getElementById('disc-v')||{}).value)||0;if(t==='pct')return Math.min(sub,sub*v/100);if(t==='fixed')return Math.min(sub,v);return 0;}
function calcCart(){var sub=CART.reduce(function(a,c){return a+c.price*c.qty;},0);var disc=getDisc(sub);var total=Math.max(0,sub-disc);var subEl=document.getElementById('s-sub');var dRow=document.getElementById('s-disc-row');var dEl=document.getElementById('s-disc');var totEl=document.getElementById('s-total');if(subEl)subEl.textContent=fmtM(sub);if(dRow)dRow.style.display=disc>0?'flex':'none';if(dEl)dEl.textContent='-'+fmtM(disc);if(totEl)totEl.textContent=fmtM(total);}
function discChange(){var t=(document.getElementById('disc-t')||{}).value;var cr=document.getElementById('code-row');if(cr)cr.style.display=t==='code'?'block':'none';calcCart();}
function applyCode(){var inp=document.getElementById('code-inp');var msg=document.getElementById('code-msg');if(!inp)return;var code=inp.value.trim().toUpperCase();var codes=DB.settings.codes||[];var gc=codes.find(function(c){return c.code===code&&c.active;});if(!gc){if(msg){msg.style.color='var(--er)';msg.textContent='الكود غير صالح';}return;}var dt=document.getElementById('disc-t');var dv=document.getElementById('disc-v');if(dt)dt.value=gc.type;if(dv)dv.value=gc.val;if(msg){msg.style.color='var(--ok)';msg.textContent='تم تطبيق: '+gc.label;}calcCart();}
function startSale(){if(!CART.length){showToast('أضف منتجاً للسلة أولاً','warn','السلة فارغة');return;}document.getElementById('c-name').value='';document.getElementById('c-phone').value='';openOv('ov-customer');}
function skipCust(){closeOv('ov-customer');finalizeSale('','');}
function confirmCust(){var cn=(document.getElementById('c-name')||{}).value||'';var cp=(document.getElementById('c-phone')||{}).value||'';closeOv('ov-customer');finalizeSale(cn,cp);}
function finalizeSale(cname,cphone){var sub=CART.reduce(function(a,c){return a+c.price*c.qty;},0);var disc=getDisc(sub);var total=Math.max(0,sub-disc);var method=(document.getElementById('pay-m')||{}).value||'cash';var boutId=CART[0]?CART[0].boutId:DB.curBout;var inv=nextInv();var items=CART.map(function(c){return{pid:c.pid,name:c.name,qty:c.qty,price:c.price,tid:c.tid};});var sale={id:'s'+Date.now(),boutId:boutId,inv:inv,date:nowDate(),time:nowTime(),method:method,items:items,sub:sub,disc:disc,total:total,cname:cname,cphone:cphone,status:'completed',staffId:activeStaffId||null};CART.forEach(function(c){var p=DB.products.find(function(x){return x.id===c.pid;});if(p)p.qty-=c.qty;});DB.sales.push(sale);save();LAST_SALE=sale;CART=[];renderCart();calcCart();renderPosGrid();showReceipt(sale);}
function showReceipt(sale){var b=DB.boutiques.find(function(x){return x.id===sale.boutId;})||{};var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'};document.getElementById('r-bname').textContent=b.name||'—';document.getElementById('r-bloc').textContent=b.loc||'';document.getElementById('r-dt').textContent=sale.date+' '+sale.time;document.getElementById('r-inv').textContent='فاتورة: '+sale.inv;var rc=document.getElementById('r-cust');if(rc){if(sale.cname||sale.cphone){rc.style.display='block';rc.innerHTML='العميل: '+(sale.cname||'')+''+(sale.cphone?' | +968'+sale.cphone:'');}else rc.style.display='none';}var ri=document.getElementById('r-items');if(ri){var html='';for(var i=0;i'+it.name+' x'+it.qty+''+fmtM(it.qty*it.price)+'';}ri.innerHTML=html;}var rs=document.getElementById('r-sum');if(rs){var s='';if(sale.disc>0)s+='
خصم-'+fmtM(sale.disc)+'
';s+='
الدفع'+(mL[sale.method]||sale.method)+'
';s+='
الاجمالي'+fmtM(sale.total)+'
';rs.innerHTML=s;}var rwa=document.getElementById('r-wa-btn');if(rwa)rwa.style.display=(sale.cphone&&sale.cphone.length>=7)?'block':'none';openOv('ov-receipt');}
function sendReceiptWA(){if(!LAST_SALE)return;var s=LAST_SALE;var b=DB.boutiques.find(function(x){return x.id===s.boutId;})||{};var ph='968'+s.cphone.replace(/\D/g,'');var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'};var lines=[b.name||'البوتيك','فاتورة: '+s.inv,'التاريخ: '+s.date,'---'];for(var i=0;i0)lines.push('خصم: -'+fmtM(s.disc));lines.push('الدفع: '+(mL[s.method]||s.method));lines.push('الاجمالي: '+fmtM(s.total));lines.push('شكرا لتسوقك معنا');window.open('https://wa.me/'+ph+'?text='+encodeURIComponent(lines.join('\n')),'_blank');}
function newSale(){closeOv('ov-receipt');}
function renderSales(){var tb=document.getElementById('tbl-sales');if(!tb)return;var fd=(document.getElementById('sales-date')||{}).value||'';var list=DB.sales.slice().reverse();if(fd)list=list.filter(function(s){return s.date===fd;});var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'};var rows='';for(var i=0;i
'+s.inv+'
'+s.date+' '+s.time+'
'+(s.cname||'—')+'
'+fmtM(s.total)+'
'+(mL[s.method]||s.method)+'
'+(s.status==='completed'?'مكتملة':'مسترجعة')+'
';}tb.innerHTML=rows||'
لا توجد مبيعات
';}
function viewSale(id){var sale=DB.sales.find(function(x){return x.id===id;});if(!sale)return;VIEW_SALE=sale;var b=DB.boutiques.find(function(x){return x.id===sale.boutId;})||{};var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'};var html='
';}}
function recordPay(tid,bid){var el=document.getElementById('pamt-'+tid);var amt=el?parseFloat(el.value):0;if(!amt||amt<=0){showToast('أدخل مبلغ الدفعة','er','حقل مطلوب');return;}DB.settlements.push({id:'set'+Date.now(),traderId:tid,boutiqueId:bid,date:nowDate(),paid:amt,notes:'دفعة '+nowDate()});save();if(el)el.value='';renderSettlements();}
function sendSettleWA(tid,from,to){var tr=DB.traders.find(function(x){return x.id===tid;});if(!tr||!tr.phone)return;var b=DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};var comm=b.comm||0;var sales=DB.sales.filter(function(s){return s.status==='completed'&&(!from||s.date>=from)&&(!to||s.date<=to)&&s.items.some(function(it){return it.tid===tid;});});var tsales=sales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tid;}).reduce(function(x,it){return x+it.qty*it.price;},0);},0);var tcomm=tsales*comm/100;var tnet=tsales-tcomm;var tpaid=DB.settlements.filter(function(x){return x.traderId===tid&&(!from||x.date>=from)&&(!to||x.date<=to);}).reduce(function(a,x){return a+x.paid;},0);var trem=tnet-tpaid;var ph=tr.phone.replace(/\D/g,'');if(ph.indexOf('968')!==0)ph='968'+ph.replace(/^0/,'');var lines=['تسوية حساب - '+(b.name||''),'التاجرة: '+tr.name,'الفترة: '+(from||'')+' الى '+(to||''),'---','مبيعاتك: '+fmtM(tsales),'الايجار '+comm+'%: '+fmtM(tcomm),'الصافي لك: '+fmtM(tnet),(tpaid>0?'تم صرفه: '+fmtM(tpaid):''),'المتبقي: '+fmtM(trem),'---','شكرا لتعاملك معنا'].filter(function(l){return l!=='';});window.open('https://wa.me/'+ph+'?text='+encodeURIComponent(lines.join('\n')),'_blank');}
function setStaffPeriod(p){
var t=nowDate(),f='';
if(p==='month') f=t.slice(0,8)+'01';
var fe=document.getElementById('st-from');
var te=document.getElementById('st-to');
if(fe)fe.value=f; if(te)te.value=t;
renderStaffStats();
}
function calcStaffComm(staff,sales){
if(!staff.ct||staff.ct==='none') return 0;
var total=0;
sales.forEach(function(s){
if(staff.ct==='pct'||staff.ct==='both') total+=s.total*(staff.cp||0)/100;
if(staff.ct==='fixed'||staff.ct==='both') total+=(staff.cf||0)*s.items.length;
});
return total;
}
function renderStaff(){
var tb=document.getElementById("tbl-staff");
if(!tb)return;
var list=DB.staff||[];
var rows="";
for(var i=0;i";
rows+='
'+s.name[0]+'
'+s.name+"
";
rows+="
"+s.email+"
";
rows+="
"+(s.join||"—")+(s.end?'
انتهت: '+s.end+"
":"")+"
";
rows+="
"+fmtM(s.salary||0)+"
";
rows+="
"+cl+"
";
rows+='
'+((s.perms||[]).length)+" صلاحية
";
rows+="
";
rows+=' ';
rows+='';
rows+="
";
}
tb.innerHTML=rows||'
لا توجد موظفات
';
renderStaffStats();
}
function openStaffForm(id){var s=id?((DB.staff||[]).find(function(x){return x.id===id;})):null;document.getElementById('st-title').textContent=s?'تعديل الموظفة':'اضافة موظفة';document.getElementById('st-id').value=s?s.id:'';document.getElementById('st-name').value=s?s.name:'';document.getElementById('st-email').value=s?(s.email||''):'';document.getElementById('st-pass').value='';document.getElementById('st-salary').value=s?(s.salary||0):0;document.getElementById('st-join').value=s?(s.join||nowDate()):nowDate();document.getElementById('st-end').value=s?(s.end||''):'';document.getElementById('st-ct').value=s?(s.ct||'none'):'none';document.getElementById('st-cp').value=s?(s.cp||0):0;document.getElementById('st-cf').value=s?(s.cf||0):0;commTypeChg();var pg=document.getElementById('perms-grid');if(pg){var ph='';for(var i=0;i-1))?'checked':'';ph+='';}pg.innerHTML=ph;}openOv('ov-staff');}
function editStaff(id){openStaffForm(id);}
function commTypeChg(){var t=(document.getElementById('st-ct')||{}).value;var cp=document.getElementById('st-cp');var cf=document.getElementById('st-cf');if(cp)cp.style.display=(t==='pct'||t==='both')?'block':'none';if(cf)cf.style.display=(t==='fixed'||t==='both')?'block':'none';}
function saveStaff(){var id=document.getElementById('st-id').value;var name=document.getElementById('st-name').value.trim();if(!name){showToast('ادخل الاسم','er','حقل مطلوب');return;}var pass=document.getElementById('st-pass').value;var existing=id?((DB.staff||[]).find(function(x){return x.id===id;})):null;var perms=[];var chks=document.querySelectorAll('#perms-grid input:checked');for(var i=0;i-1)DB.staff[i]=obj;else DB.staff.push(obj);save();closeOv('ov-staff');renderStaff();showToast('تم حفظ الموظفة','ok');}
function delStaff(id){if(!confirm('حذف؟'))return; DB.staff=DB.staff.filter(function(x){return x.id!==id;});save();renderStaff();}
function setRepPeriod(p) {
var t = nowDate();
var f = '';
if (p === 'today') { f = t; }
else if (p === 'week') {
var d = new Date(); d.setDate(d.getDate()-6);
f = d.toISOString().slice(0,10);
} else if (p === 'month') { f = t.slice(0,8)+'01'; }
else { f = ''; }
var fe = document.getElementById('rep-from');
var te = document.getElementById('rep-to');
if (fe) fe.value = f;
if (te) te.value = t;
renderReports();
}
function renderReports() {
var from = (document.getElementById('rep-from')||{}).value||'';
var to = (document.getElementById('rep-to')||{}).value||'';
// Filter sales by period
var sales = DB.sales.filter(function(s) {
if (s.status !== 'completed') return false;
if (from && s.date < from) return false;
if (to && s.date > to) return false;
return true;
});
var totalRev = sales.reduce(function(a,s){return a+s.total;},0);
var totalComm = sales.reduce(function(a,s){
var b = DB.boutiques.find(function(x){return x.id===s.boutId;})||{};
return a + s.total*(b.comm||0)/100;
},0);
var totalPaid = DB.settlements.reduce(function(a,x){return a+x.paid;},0);
var totalDue = DB.traders.reduce(function(a,tr){
var b = DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var ts= sales.filter(function(s){return s.items.some(function(it){return it.tid===tr.id;});})
.reduce(function(x,s){return x+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(y,it){return y+it.qty*it.price;},0);},0);
var net=ts-ts*(b.comm||0)/100;
var paid=DB.settlements.filter(function(x){return x.traderId===tr.id;}).reduce(function(x,y){return x+y.paid;},0);
return a+Math.max(0,net-paid);
},0);
// KPI Cards
var rs = document.getElementById('rep-stats');
if (rs) rs.innerHTML =
'
اجمالي الإيرادات
'+fmtM(totalRev)+'
'
+'
عمولة البوتيك
'+fmtM(totalComm)+'
'
+'
المستحقات المتبقية
'+fmtM(totalDue)+'
'
+'
عدد الفواتير
'+sales.length+'
';
// Daily sales chart
renderDailyChart(sales, from, to);
// Payment methods
renderPaymentMethods(sales);
// Traders detailed
renderTraderReport(sales, from, to);
// Top products
renderTopProducts(sales);
// Slow movers
renderSlowMovers(sales);
// Inventory
renderInventory();
}
function renderDailyChart(sales, from, to) {
var chartEl = document.getElementById('rep-chart-days');
var labelsEl = document.getElementById('rep-chart-labels');
if (!chartEl) return;
// Build last 14 days or period
var days = [];
var end = to || nowDate();
var start = from;
if (!start) {
var d = new Date(end); d.setDate(d.getDate()-13);
start = d.toISOString().slice(0,10);
}
var cur = new Date(start);
var endD = new Date(end);
while (cur <= endD && days.length < 30) {
days.push(cur.toISOString().slice(0,10));
cur.setDate(cur.getDate()+1);
}
var dayTotals = {};
days.forEach(function(d){ dayTotals[d]=0; });
sales.forEach(function(s){ if(dayTotals[s.date]!==undefined) dayTotals[s.date]+=s.total; });
var maxVal = Math.max.apply(null, days.map(function(d){return dayTotals[d];})) || 1;
var html = '';
var labelHtml = '';
days.forEach(function(d) {
var h = Math.max(4, Math.round((dayTotals[d]/maxVal)*100));
var hasVal = dayTotals[d] > 0;
html += '
'
+(hasVal?'
'+Math.round(dayTotals[d])+'
':'')
+''
+'
';
labelHtml += '
'+d.slice(8)+'
';
});
chartEl.innerHTML = html;
if (labelsEl) labelsEl.innerHTML = labelHtml;
}
function renderPaymentMethods(sales) {
var el = document.getElementById('rep-payment-methods');
if (!el) return;
var methods = { cash:'نقدا', card:'بطاقة', transfer:'تحويل' };
var totals = { cash:0, card:0, transfer:0 };
var counts = { cash:0, card:0, transfer:0 };
sales.forEach(function(s) {
if (totals[s.method] !== undefined) { totals[s.method]+=s.total; counts[s.method]++; }
});
var grandTotal = sales.reduce(function(a,s){return a+s.total;},0) || 1;
var colors = { cash:'var(--ok)', card:'var(--in)', transfer:'var(--gold)' };
var html = '';
['cash','card','transfer'].forEach(function(m) {
if (!totals[m]) return;
var pct = Math.round(totals[m]/grandTotal*100);
html += '
'
+'
'
+''+methods[m]+''+fmtM(totals[m])+' ('+pct+'%)
'
+'
'
+'
'+counts[m]+' فاتورة
'
+'
';
});
el.innerHTML = html || '
لا توجد مبيعات
';
}
function renderTraderReport(sales, from, to) {
var tb = document.getElementById('rep-traders');
if (!tb) return;
var rows = '';
var traderData = DB.traders.map(function(tr) {
var b = DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var comm = b.comm||0;
var trSales = sales.filter(function(s){return s.items.some(function(it){return it.tid===tr.id;});});
var items = trSales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(x,it){return x+it.qty;},0);},0);
var revenue = trSales.reduce(function(a,s){return a+s.items.filter(function(it){return it.tid===tr.id;}).reduce(function(x,it){return x+it.qty*it.price;},0);},0);
var boutComm = revenue*comm/100;
var net = revenue-boutComm;
var paid = DB.settlements.filter(function(x){return x.traderId===tr.id;}).reduce(function(a,x){return a+x.paid;},0);
return {tr:tr, items:items, revenue:revenue, boutComm:boutComm, net:net, paid:paid, rem:net-paid};
}).filter(function(x){return x.revenue>0;}).sort(function(a,b){return b.revenue-a.revenue;});
traderData.forEach(function(x) {
rows += '
'
+'
'+x.tr.name[0]+'
'+x.tr.name+'
'
+'
'+x.items+'
'
+'
'+fmtM(x.revenue)+'
'
+'
'+fmtM(x.boutComm)+'
'
+'
'+fmtM(x.net)+'
'
+'
'+fmtM(x.paid)+'
'
+'
'+fmtM(x.rem)+'
'
+'
';
});
tb.innerHTML = rows || '
لا توجد بيانات
';
}
function renderTopProducts(sales) {
var tb = document.getElementById('rep-top-prods');
if (!tb) return;
var prodMap = {};
sales.forEach(function(s) {
s.items.forEach(function(it) {
if (!prodMap[it.pid]) prodMap[it.pid] = {name:it.name, tid:it.tid, qty:0, rev:0};
prodMap[it.pid].qty += it.qty;
prodMap[it.pid].rev += it.qty*it.price;
});
});
var sorted = Object.keys(prodMap).map(function(k){return prodMap[k];}).sort(function(a,b){return b.qty-a.qty;}).slice(0,10);
var rows = '';
sorted.forEach(function(p, i) {
var tr = DB.traders.find(function(x){return x.id===p.tid;})||{};
rows += '
'
+'
'+(i+1)+''+p.name+'
'
+'
'+(tr.name||'—')+'
'
+'
'+p.qty+'
'
+'
'+fmtM(p.rev)+'
'
+'
';
});
tb.innerHTML = rows || '
لا توجد بيانات
';
}
function renderSlowMovers(sales) {
var tb = document.getElementById('rep-slow-prods');
var cnt = document.getElementById('rep-slow-count');
if (!tb) return;
// Products with qty > 0 that had zero sales in the period
var soldPids = {};
sales.forEach(function(s){s.items.forEach(function(it){soldPids[it.pid]=true;});});
var slow = DB.products.filter(function(p){return p.qty>0 && !soldPids[p.id];});
if (cnt) cnt.textContent = slow.length + ' منتج';
var rows = '';
slow.sort(function(a,b){return b.qty*b.price - a.qty*a.price;}).slice(0,15).forEach(function(p) {
var tr = DB.traders.find(function(x){return x.id===p.traderId;})||{};
rows += '
'
+'
'+p.name+'
'
+'
'+(tr.name||'—')+'
'
+'
'+p.qty+'
'
+'
'+fmtM(p.price)+'
'
+'
'+fmtM(p.qty*p.price)+'
'
+'
';
});
tb.innerHTML = rows || '
جميع المنتجات تتحرك
';
}
function renderInventory() {
var invEl = document.getElementById('rep-inventory');
var tb = document.getElementById('rep-stock');
var active = DB.products.filter(function(p){return p.qty>0;});
var totalVal = active.reduce(function(a,p){return a+p.qty*p.price;},0);
var totalCost= active.reduce(function(a,p){return a+p.qty*p.cost;},0);
var totalQty = active.reduce(function(a,p){return a+p.qty;},0);
if (invEl) invEl.innerHTML =
'
إجمالي القطع'+totalQty+' قطعة
'
+'
قيمة التكلفة'+fmtM(totalCost)+'
'
+'
قيمة البيع'+fmtM(totalVal)+'
'
+'
هامش الربح المتوقع'+fmtM(totalVal-totalCost)+'
';
if (!tb) return;
var rows = '';
active.sort(function(a,b){return b.qty*b.price-a.qty*a.price;}).slice(0,15).forEach(function(p) {
rows += '
';}
}
// ═══════════════════════════════════════════
// AUTH — LOGIN / LOGOUT
// ═══════════════════════════════════════════
var currentUser = null;
function doLogin() {
var user = (document.getElementById('login-user')||{}).value||'';
var pass = (document.getElementById('login-pass')||{}).value||'';
var errEl = document.getElementById('login-error');
if (!user.trim()) {
if(errEl){errEl.style.display='block';errEl.textContent='ادخل اسم المستخدم';}
return;
}
// Find staff member
var staff = (DB.staff||[]).find(function(s){
return s.email === user.trim() && s.pass === pass;
});
if (!staff) {
if(errEl){errEl.style.display='block';errEl.textContent='اسم المستخدم أو كلمة المرور غير صحيحة';}
// Shake animation
var btn = document.querySelector('#login-screen .btn-gold');
if(btn){btn.style.transform='translateX(8px)';setTimeout(function(){btn.style.transform='translateX(-8px)';setTimeout(function(){btn.style.transform='';},100);},100);}
return;
}
// Success
currentUser = staff;
activeStaffId = staff.id;
// Hide login screen
var ls = document.getElementById('login-screen');
if(ls) ls.style.display='none';
// Update sidebar user info
updateUserBar();
// Apply permissions — hide nav items not in perms
applyPermissions(staff.perms||[]);
// Navigate to POS or dashboard
var startPage = (staff.perms||[]).indexOf('نقطة البيع') > -1 ? 'pos' : 'dashboard';
var navEl = document.getElementById('nav-'+startPage);
goPage(startPage, navEl);
// Clear password field
var passEl = document.getElementById('login-pass');
if(passEl) passEl.value='';
}
function resetToDemo() {
if (!confirm('سيتم حذف كل البيانات وإعادة ضبط النظام. متأكد؟')) return;
localStorage.removeItem('bpro3');
location.reload();
}
function doLogout() {
if(!confirm('تسجيل خروج؟')) return;
currentUser = null;
activeStaffId = null;
// Show all nav items again
var navItems = document.querySelectorAll('.sb-a');
for(var i=0;i -1) ? '' : 'none';
});
}
// Allow Enter key on login form
document.addEventListener('keydown', function(e){
var ls = document.getElementById('login-screen');
if(ls && ls.style.display !== 'none' && e.key === 'Enter') doLogin();
});
// Active staff tracking
var activeStaffId = null;
function selectStaff(id) {
activeStaffId = id;
var nameEl = document.getElementById('pos-staff-name');
var avatarEl = document.getElementById('pos-staff-avatar');
if (id) {
var s = (DB.staff||[]).find(function(x){return x.id===id;});
if (s) {
if (nameEl) nameEl.textContent = s.name;
if (avatarEl) { avatarEl.textContent = s.name[0]; avatarEl.style.background = 'linear-gradient(135deg,var(--gold2),var(--rose))'; }
}
} else {
if (nameEl) nameEl.textContent = 'لم تُحدد بعد';
if (avatarEl) { avatarEl.textContent = '؟'; avatarEl.style.background = 'var(--s3)'; }
}
closeOv('ov-select-staff');
}
function openStaffSelector() {
var list = document.getElementById('staff-select-list');
if (!list) return;
var staff = DB.staff||[];
if (!staff.length) {
list.innerHTML = '
لا توجد موظفات
';
openOv('ov-select-staff');
return;
}
var html = '';
for (var i=0; i';
html += '
' + s.name[0] + '
';
html += '
';
html += '
' + s.name + '
';
html += '
' + s.email + '
';
html += '
';
if (isActive) html += '✓';
html += '';
}
list.innerHTML = html;
openOv('ov-select-staff');
}
function getVAT(){ return parseFloat((DB.settings&&DB.settings.vat)||0)||0; }
function getCardFee(){ return parseFloat((DB.settings&&DB.settings.cardFee)||0)||0; }
// TRADER REPORT
var _traderReportId = null;
function setTrRepPeriod(p){
var t=nowDate(),f='',d=new Date();
if(p==='month'){f=t.slice(0,8)+'01';}
else if(p==='last'){
d.setDate(0);
var y=d.getFullYear(),m=String(d.getMonth()+1).padStart(2,'0');
f=y+'-'+m+'-01';
t=y+'-'+m+'-'+String(d.getDate()).padStart(2,'0');
}
var fe=document.getElementById('tr-rep-from');
var te=document.getElementById('tr-rep-to');
if(fe)fe.value=f; if(te)te.value=t;
buildTraderReport();
}
function openTraderReport(tid){
_traderReportId=tid;
var t=nowDate(),f=t.slice(0,8)+'01';
var fe=document.getElementById('tr-rep-from');
var te=document.getElementById('tr-rep-to');
if(fe)fe.value=f; if(te)te.value=t;
buildTraderReport();
openOv('ov-trader-report');
}
function buildTraderReport(){
var tid=_traderReportId; if(!tid)return;
var tr=DB.traders.find(function(x){return x.id===tid;}); if(!tr)return;
var b=DB.boutiques.find(function(x){return x.id===tr.boutId;})||{};
var comm=b.comm||0, vat=getVAT(), cFee=getCardFee();
var from=(document.getElementById('tr-rep-from')||{}).value||'';
var to=(document.getElementById('tr-rep-to')||{}).value||'';
var title=document.getElementById('tr-rep-title');
if(title)title.textContent='تقرير: '+tr.name;
var sales=DB.sales.filter(function(s){
if(s.status!=='completed')return false;
if(from&&s.dateto)return false;
return s.items.some(function(it){return it.tid===tid;});
});
var totalItems=0,totalRevenue=0,cardSales=0,saleRows='';
sales.forEach(function(s){
var trItems=s.items.filter(function(it){return it.tid===tid;});
var trRev=trItems.reduce(function(a,it){return a+it.qty*it.price;},0);
var trQty=trItems.reduce(function(a,it){return a+it.qty;},0);
var trCardFee=(s.method==='card'&&cFee)?trRev*cFee/100:0;
totalItems+=trQty; totalRevenue+=trRev;
if(s.method==='card')cardSales+=trRev;
var mL={cash:'نقدا',card:'بطاقة',transfer:'تحويل'}[s.method]||s.method;
saleRows+='
';
});
var boutCommAmt=totalRevenue*comm/100;
var vatAmt=vat?totalRevenue*vat/100:0;
var cardFeeAmt=cFee?cardSales*cFee/100:0;
var netDue=totalRevenue-boutCommAmt-vatAmt-cardFeeAmt;
var settles=DB.settlements.filter(function(x){return x.traderId===tid&&(!from||x.date>=from)&&(!to||x.date<=to);});
var totalPaid=settles.reduce(function(a,x){return a+x.paid;},0);
var remaining=netDue-totalPaid;
var html='';
html+='
';
}
var body=document.getElementById('tr-rep-body'); if(body)body.innerHTML=html;
window._lastTraderReport={trader:tr,boutique:b,from:from,to:to,totalRevenue:totalRevenue,totalItems:totalItems,boutCommAmt:boutCommAmt,vatAmt:vatAmt,cardFeeAmt:cardFeeAmt,netDue:netDue,totalPaid:totalPaid,remaining:remaining,comm:comm,vat:vat,cFee:cFee,cardSales:cardSales};
}
function sendTraderReportWA(){
var r=window._lastTraderReport;
if(!r||!r.trader.phone){alert('لا يوجد رقم جوال');return;}
var ph=r.trader.phone.replace(/\D/g,'');
if(ph.indexOf('968')!==0)ph='968'+ph.replace(/^0/,'');
var lines=[
'كشف حساب - '+(r.boutique.name||'البوتيك'),
'التاجرة: '+r.trader.name,
'الفترة: '+(r.from||'من البداية')+' الى '+(r.to||'الآن'),
'---',
'اجمالي مبيعاتك: '+fmtM(r.totalRevenue),
'عدد القطع: '+r.totalItems,
'---',
'ايجار البوتيك '+r.comm+'%: -'+fmtM(r.boutCommAmt)
];
if(r.vatAmt>0)lines.push('ضريبة VAT '+r.vat+'%: -'+fmtM(r.vatAmt));
if(r.cardFeeAmt>0)lines.push('رسوم جهاز الدفع '+r.cFee+'%: -'+fmtM(r.cardFeeAmt));
lines.push('---');
lines.push('الصافي المستحق لك: '+fmtM(r.netDue));
if(r.totalPaid>0)lines.push('تم استلامه: '+fmtM(r.totalPaid));
lines.push('المتبقي: '+fmtM(r.remaining));
lines.push('---');
lines.push('شكرا لتعاملك معنا');
window.open('https://wa.me/'+ph+'?text='+encodeURIComponent(lines.join('\n')),'_blank');
}
// ═══════════════════════════════════════════
// SIZE FIELDS
// ═══════════════════════════════════════════
var SIZE_TEMPLATES = {
abaya: [{id:'length',label:'الطول (سم)'},{id:'chest',label:'الصدر (سم)'},{id:'shoulder',label:'الكتف (سم)'},{id:'sleeve',label:'الكم (سم)'},{id:'waist',label:'الخصر (سم)'},{id:'size_label',label:'المقاس (S/M/L/XL)'}],
top: [{id:'chest',label:'الصدر (سم)'},{id:'shoulder',label:'الكتف (سم)'},{id:'length',label:'الطول (سم)'},{id:'sleeve',label:'الكم (سم)'},{id:'size_label',label:'المقاس'}],
pants: [{id:'waist',label:'الخصر (سم)'},{id:'hips',label:'الورك (سم)'},{id:'length',label:'الطول (سم)'},{id:'size_label',label:'المقاس'}],
scarf: [{id:'length',label:'الطول (سم)'},{id:'width',label:'العرض (سم)'},{id:'material',label:'الخامة'}],
bag: [{id:'width',label:'العرض (سم)'},{id:'height',label:'الارتفاع (سم)'},{id:'depth',label:'العمق (سم)'},{id:'color',label:'اللون'}],
shoes: [{id:'size_label',label:'المقاس'},{id:'color',label:'اللون'},{id:'material',label:'الخامة'}],
accessory: [{id:'size_label',label:'المقاس/الحجم'},{id:'color',label:'اللون'},{id:'material',label:'الخامة'}],
custom:[{id:'f1',label:'قياس 1'},{id:'f2',label:'قياس 2'},{id:'f3',label:'قياس 3'},{id:'f4',label:'قياس 4'},{id:'f5',label:'قياس 5'},{id:'f6',label:'قياس 6'}]
};
var _aiResult = null;
function buildSizeFields() {
var type = (document.getElementById('size-type')||{}).value;
var container = document.getElementById('size-fields');
if (!container) return;
if (!type) { container.innerHTML = ''; return; }
var fields = SIZE_TEMPLATES[type] || [];
// Load existing values if editing
var existing = {};
try { existing = JSON.parse((document.getElementById('p-sizes')||{}).value||'{}'); } catch(e) {}
var html = '';
for (var i=0; i';
html += '';
html += '';
}
container.innerHTML = html;
}
function collectSizes() {
var type = (document.getElementById('size-type')||{}).value;
if (!type) return '';
var fields = SIZE_TEMPLATES[type] || [];
var obj = { _type: type };
for (var i=0; i -1) continue;
parts.push(obj[k]);
}
return parts.slice(0,3).join(' / ');
} catch(e) { return ''; }
}
// ═══════════════════════════════════════════
// AI PRODUCT SCAN
// ═══════════════════════════════════════════
function getApiKey() {
return DB.settings && DB.settings.apiKey ? DB.settings.apiKey : '';
}
function saveApiKey() {
var key = (document.getElementById('cfg-apikey')||{}).value||'';
if (!key.trim()) { alert('ادخل المفتاح'); return; }
if (!DB.settings) DB.settings = {};
DB.settings.apiKey = key.trim();
save();
alert('تم حفظ المفتاح');
}
function testApiKey() {
var el = document.getElementById('api-test-result');
if (el) { el.style.color='var(--mu)'; el.textContent='جاري الاختبار...'; }
var key = getApiKey();
if (!key) { if(el){el.style.color='var(--er)';el.textContent='لا يوجد مفتاح - احفظه اولا';} return; }
fetch('https://api.anthropic.com/v1/messages', {
method:'POST',
headers:{'Content-Type':'application/json','x-api-key':key,'anthropic-version':'2023-06-01'},
body:JSON.stringify({model:'claude-haiku-4-5-20251001',max_tokens:20,messages:[{role:'user',content:'قل نعم فقط'}]})
}).then(function(r){return r.json();}).then(function(d){
if(d.content&&d.content[0]){if(el){el.style.color='var(--ok)';el.textContent='المفتاح يعمل';}}
else{if(el){el.style.color='var(--er)';el.textContent='خطأ: '+(d.error&&d.error.message||'غير معروف');}}
}).catch(function(e){if(el){el.style.color='var(--er)';el.textContent='فشل الاتصال';}});
}
function aiScanProduct(input) {
if (!input.files || !input.files[0]) return;
var key = getApiKey();
if (!key) { alert('اضف مفتاح Claude API في الاعدادات اولا'); return; }
var statusEl = document.getElementById('ai-status');
var wrapEl = document.getElementById('ai-wrap');
var prevEl = document.getElementById('ai-prev');
var outEl = document.getElementById('ai-out');
var applyBtn = document.getElementById('ai-apply');
var btn = document.getElementById('ai-btn');
if(statusEl) { statusEl.style.color='var(--gold)'; statusEl.textContent='جاري قراءة الصورة...'; }
if(btn) btn.disabled = true;
var reader = new FileReader();
reader.onload = function(e) {
var b64 = e.target.result.split(',')[1];
var mime = input.files[0].type || 'image/jpeg';
if(prevEl) { prevEl.src=e.target.result; }
if(wrapEl) { wrapEl.style.display='block'; }
if(outEl) { outEl.textContent='جاري التحليل...'; }
// Get category from size-type if selected
var sizeType = (document.getElementById('size-type')||{}).value || '';
var catHint = sizeType ? ' (نوع المنتج: ' + sizeType + ')' : '';
var prompt = 'انت خبير في الموضة والملابس. حلل هذه الصورة لمنتج في بوتيك'+catHint+'.'
+' استخرج المعلومات التالية وأجب بهذا التنسيق فقط: '
+'الاسم: [اسم المنتج] | '
+'اللون: [الالوان] | '
+'الخامة: [نوع القماش] | '
+'المقاس: [المقاس ان كان واضحا] | '
+'الطول: [بالسم ان كان واضحا] | '
+'الصدر: [بالسم ان كان واضحا] | '
+'الوصف: [وصف مختصر] | '
+'السعر المقترح: [بالريال العماني] '
+'اذا لم تكن المعلومة واضحة اكتب: غير محدد';
fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'Content-Type':'application/json', 'x-api-key':key, 'anthropic-version':'2023-06-01' },
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 400,
messages: [{
role: 'user',
content: [
{ type:'image', source:{ type:'base64', media_type:mime, data:b64 } },
{ type:'text', text:prompt }
]
}]
})
})
.then(function(r) { return r.json(); })
.then(function(d) {
if(btn) btn.disabled = false;
if (d.content && d.content[0] && d.content[0].text) {
var text = d.content[0].text;
_aiResult = parseAiResult(text);
if(outEl) outEl.innerHTML = text.replace(/\n/g,' ').replace(/\|/g,' ');
if(applyBtn) applyBtn.style.display = 'inline-flex';
if(statusEl) { statusEl.style.color='var(--ok)'; statusEl.textContent='تم التحليل'; }
} else {
var errMsg = d.error ? d.error.message : 'غير معروف';
if(outEl) { outEl.style.color='var(--er)'; outEl.textContent='خطأ: '+errMsg; }
if(statusEl) { statusEl.style.color='var(--er)'; statusEl.textContent='فشل'; }
}
})
.catch(function(e) {
if(btn) btn.disabled = false;
if(outEl) { outEl.style.color='var(--er)'; outEl.textContent='فشل الاتصال بـ Claude'; }
if(statusEl) { statusEl.style.color='var(--er)'; statusEl.textContent='خطأ في الاتصال'; }
});
};
reader.readAsDataURL(input.files[0]);
}
function parseAiResult(text) {
var result = {};
var parts = text.indexOf('|')>-1 ? text.split('|') : text.split('\n');
for (var i=0; ito) return false;
return true;
});
// KPI cards
var totalSal=list.reduce(function(a,s){return a+(s.salary||0);},0);
var totalComm=list.reduce(function(a,s){
var ss=allSales.filter(function(x){return x.staffId===s.id;});
return a+calcStaffComm(s,ss);
},0);
var sc=document.getElementById('staff-stats-cards');
if(sc){
sc.innerHTML=
'
عدد الموظفات
'+list.length+'
'
+'
إجمالي الرواتب
'+fmtM(totalSal)+'
'
+'
إجمالي العمولات
'+fmtM(totalComm)+'
'
+'
إجمالي المستحقات
'+fmtM(totalSal+totalComm)+'
';
}
// Performance table
var perf=document.getElementById('tbl-staff-perf');
if(perf){
var rows='';
for(var i=0;ibestC){bestC=hmap[h];bestH=h+':00';}});
rows+='
'
+'
'+st.name[0]+'
'+st.name+'
'
+'
'+ss.length+'
'
+'
'+fmtM(sTotal)+'
'
+'
'+fmtM(sComm)+'
'
+'
'+fmtM(st.salary||0)+'
'
+'
'+fmtM(sDue)+'
'
+'
'+bestH+'
'
+'
'
+'
';
}
perf.innerHTML=rows||'
لا توجد موظفات
';
}
// Peak hours chart
var peakEl=document.getElementById('peak-chart');
var peakLbl=document.getElementById('peak-labels');
if(peakEl){
var hours={};
for(var h=8;h<=22;h++) hours[String(h).padStart(2,'0')]=0;
allSales.forEach(function(x){
if(!x.time) return;
var hk=x.time.slice(0,2);
if(hours[hk]!==undefined) hours[hk]+=x.total;
});
var maxH=Math.max.apply(null,Object.keys(hours).map(function(k){return hours[k];}))||1;
var ch='',lb='';
Object.keys(hours).forEach(function(hk){
var val=hours[hk];
var ht=Math.max(2,Math.round(val/maxH*90));
ch+='
'
+(val>0?'
'+Math.round(val)+'
':'')
+''
+'
';
lb+='
'+parseInt(hk)+'
';
});
peakEl.innerHTML=ch;
if(peakLbl)peakLbl.innerHTML=lb;
}
// Staff comparison bars
var cmp=document.getElementById('staff-compare');
if(cmp){
var data=[];
for(var j=0;j0;}).sort(function(a,b){return b.total-a.total;});
var maxT=data.length?data[0].total:1;
var html='';
if(!data.length){
html='
ربط المبيعات بالموظفة يتم تلقائياً عند تسجيل الدخول قبل إتمام البيع
';
} else {
data.forEach(function(x){
var pct=Math.round(x.total/maxT*100);
html+='