🚙 ELLEITHY MANAGER

النظام السحابي — سجّل دخولك علشان تفتح نفس السجلات من أي جهاز.

لوحة القيادة

ELLEITHY MANAGER / نظام إدارة الأسطول
● نظام سحابي
EM
✨ وضع المعاينة — كل الأسماء والأرقام الظاهرة تجريبية
استكشف الحسابات والورديات أولًا، ثم امسح بيانات العرض وابدأ تسجيل عربياتك وسائقينك من الصفر.

أهلاً بيك في مركز التحكم 👋

من هنا تتابع حركة الأسطول وحصص السائقين وصافي التشغيل في نظرة واحدة.

مؤشر تشغيل الأسطول
حالة العربيات خلال الفترة المحددة
20 عربية
الورديات المسجلة
إجمالي وقت التشغيل الفعلي
0 س
0 وردية
أعلى العربيات في صافي التشغيل
الإيراد ناقص الوقود والتشغيل والغسيل فقط
آخر الورديات
كل وردية تُحسب لوحدها قبل تجميع حساب العربية والسواق
ملخص الحسابات
حقوق السائقين وحصص الملاك بعد المدفوعات
مصاريفك الشخصية على الصيانة
للمتابعة فقط — لا تؤثر على تقسيم الإيراد
خارج التقسيم

الأسطول 🚚

ملف مستقل لكل عربية: نتيجة التشغيل، الحصص، ساعات العمل، واستهلاك الوقود.

0 عربية

ملفات السائقين ♙

تدخل بيانات السواق مرة واحدة، وبعدها كل الورديات والمستحقات تُجمع تلقائيًا.

0 سائق

الورديات وساعات العمل ◷

الوردية الواحدة تضم الإيراد والتكاليف والعداد والوقود وحصة كل طرف.

الصيانة من جيبك الشخصي 🔧

الزيت والإصلاحات والإطارات تتسجل للمتابعة فقط، ولا تُخصم من إيراد العربية أو حصة السواق.

قاعدة محاسبية ثابتة: مصروف الصيانة مصروف شخصي منفصل. لا يدخل في معادلة التلت والتلتين، ولا يقلل صافي الوردية القابل للتقسيم.

كشوف الحسابات ▤

المستحق، المدفوع، السلف، الرصيد النهائي — كل سواق في كشف مستقل.

الحسابات تُجمع من الورديات المسجلة. الدفعات والسلف والتسويات تُسجل في دفتر منفصل ولا تغير الإيرادات الأصلية.
حسابات السائقين
حصة السواق − السلف − الدفعات − الخصومات + المكافآت
حسابات الملاك حسب العربية
حصة المالك − المبالغ المسددة له، والصيانة خارج الحساب
آخر حركات التسوية
دفعات، سلف، خصومات ومكافآت مسجلة

التقارير والتحليلات ▥

قارن أداء العربيات واستهلاك الوقود وحصص السائقين على مستوى اليوم والشهر.

صافي التشغيل القابل للتقسيم · الفترة المختارة

0 ج.م

الإيراد − الوقود − مصاريف التشغيل − الغسيل فقط

◈
ربحية كل عربية واستهلاكها
مصاريف الصيانة الشخصية معروضة منفصلة ولا تدخل في صافي التقسيم.
كشف استهلاك الوقود
اللترات، كم/لتر، لتر لكل 100 كم، وتكلفة الكيلومتر.

النسخ والإعدادات ⚙

حافظ على سجلاتك، وابدأ بيانات حقيقية بعد تجربة الواجهة.

البيانات والنسخ الاحتياطي
تنزيل نسخة أو استعادة ملف سابق
💾
تصدير كل البياناتالعربيات والسائقون والورديات والصيانة والتسويات في ملف واحد.
استعادة نسخة احتياطيةاستبدال البيانات الحالية من ملف JSON صادر من النظام.
تصدير تقرير CSVيفتح في Excel أو Google Sheets.
قواعد الحساب المعتمدة
ثابتة حسب اتفاقنا
🧮
حصة السواقثلث صافي الوردية بعد الوقود والتشغيل والغسيل.
⅓ · 33.33%
حصة مالك العربيةثلثا صافي الوردية بعد المصروفات التشغيلية المعتمدة.
⅔ · 66.67%
الصيانة والزيت والإصلاحاتتُسجل من جيبك الشخصي ولا تُخصم من إيراد الوردية.
خارج التقسيم
الحفظ السحابيبعد تسجيل الدخول، تُحفظ التغييرات في قاعدة بيانات حسابك ويمكن فتحها من أي جهاز.
سحابي
مهم: يتم حفظ التغييرات سحابيًا بعد تسجيل الدخول بنجاح. احتفظ بنسخة احتياطية دورية من بياناتك.
');w.document.close();w.focus();w.print()} function driverStats(driverId,period=''){let ss=db.shifts.filter(s=>inPeriod(s.date,period)&&s.driverId===driverId);let earned=ss.reduce((a,s)=>a+calcShift(s).driverShare,0),hours=ss.reduce((a,s)=>a+shiftHours(s),0);let led=db.settlements.filter(x=>x.kind==='driver'&&x.driverId===driverId&&inPeriod(x.date,period));let payments=led.filter(x=>x.type==='payment').reduce((a,x)=>a+num(x.amount),0),advances=led.filter(x=>x.type==='advance').reduce((a,x)=>a+num(x.amount),0),deductions=led.filter(x=>x.type==='deduction').reduce((a,x)=>a+num(x.amount),0),bonuses=led.filter(x=>x.type==='bonus').reduce((a,x)=>a+num(x.amount),0);return {shifts:ss,earned,hours,payments,advances,deductions,bonuses,balance:earned+bonuses-payments-advances-deductions,ledger:led}} function ownerStats(vehicleId,period=''){let ss=db.shifts.filter(s=>inPeriod(s.date,period)&&s.vehicleId===vehicleId);let share=ss.reduce((a,s)=>a+calcShift(s).ownerShare,0);let pay=db.settlements.filter(x=>x.kind==='owner'&&x.vehicleId===vehicleId&&inPeriod(x.date,period)).reduce((a,x)=>a+num(x.amount),0);let maint=db.maintenance.filter(x=>x.vehicleId===vehicleId&&inPeriod(x.date,period)).reduce((a,x)=>a+num(x.cost),0);return {shifts:ss,share,pay,balance:share-pay,maint}} function monthVal(id){return $(id)?.value||''} const definitions={ vehicle:{title:'عربية',collection:'vehicles',fields:[['name','اسم / كود العربية','text',true],['plate','رقم اللوحة','text',true],['model','النوع / الموديل','text',false],['ownerName','اسم مالك العربية','text',true],['status','حالة العربية','select',true,[['active','تعمل'],['maintenance','في الصيانة'],['idle','متوقفة']]],['odometer','قراءة العداد الحالية (كم)','number',false]]}, driver:{title:'سواق',collection:'drivers',fields:[['name','اسم السواق','text',true],['phone','رقم الموبايل','tel',false],['license','نوع الرخصة / رقمها','text',false],['status','الحالة','select',true,[['active','يعمل'],['inactive','غير متاح']]]]}, shift:{title:'وردية تشغيل',collection:'shifts',fields:[['date','تاريخ الوردية','date',true],['vehicleId','العربية','vehicle',true],['driverId','السواق','driver',true],['shift','نوع الوردية','select',true,[['morning','صباحية'],['evening','مسائية'],['night','ليلية']]],['startTime','ساعة بداية الشغل','time',true],['endTime','ساعة نهاية الشغل','time',true],['breakMinutes','مدة الاستراحة بالدقائق','number',false],['kmStart','العداد أول الوردية (كم)','number',false],['kmEnd','العداد آخر الوردية (كم)','number',false],['revenue','إيراد الوردية (جنيه)','number',true],['fuelLiters','كمية الوقود (لتر)','number',false],['fuelCost','تكلفة الوقود (جنيه)','number',false],['roadCost','رسوم الطرق / البوابات (جنيه)','number',false],['operationCost','مصاريف تشغيل أخرى (جنيه)','number',false],['washCost','الغسيل (جنيه)','number',false],['note','ملاحظات الوردية','textarea',false]]}, maintenance:{title:'مصروف صيانة شخصي',collection:'maintenance',fields:[['date','تاريخ الصيانة','date',true],['vehicleId','العربية','vehicle',true],['category','نوع الصيانة','select',true,[['oil','زيت وفلاتر'],['repair','إصلاحات'],['tires','إطارات'],['battery','بطارية'],['service','صيانة دورية'],['other','أخرى']]],['cost','المبلغ المدفوع من جيبك (جنيه)','number',true],['odometer','العداد وقت الصيانة (كم)','number',false],['vendor','الورشة / مركز الخدمة','text',false],['note','تفاصيل وملاحظات','textarea',false]]}, driverEntry:{title:'حركة حساب سواق',collection:'settlements',fields:[['date','التاريخ','date',true],['driverId','السواق','driver',true],['type','نوع الحركة','select',true,[['payment','دفعة للسواق'],['advance','سلفة'],['bonus','مكافأة تضاف للمستحقات'],['deduction','خصم من المستحقات']]],['amount','المبلغ (جنيه)','number',true],['note','البيان / سبب الحركة','textarea',false]]}, ownerPayment:{title:'دفعة لمالك عربية',collection:'settlements',fields:[['date','التاريخ','date',true],['vehicleId','العربية / حساب المالك','vehicle',true],['amount','المبلغ المسدد (جنيه)','number',true],['note','البيان','textarea',false]]} }; function openForm(k,id=null){kind=k;editId=id;const def=definitions[k];if(!def)return;let data=id?safe(id,db[def.collection]):{};if(id&&!data)return toast('السجل غير موجود');$('modalTitle').textContent=(id?'تعديل ':'إضافة ')+def.title;const defaults={date:today,status:'active',shift:'morning',startTime:'07:00',endTime:'15:00',breakMinutes:30,category:'oil',type:k==='driverEntry'?'payment':'',amount:''};let html='';for(let [key,label,type,req,options] of def.fields){let val=data?.[key]??defaults[key]??'';let required=req?'required':'';let inp='';if(type==='select'||type==='vehicle'||type==='driver'){let opts=type==='vehicle'?db.vehicles.map(v=>[v.id,v.name+' · '+v.plate]):type==='driver'?db.drivers.map(d=>[d.id,d.name]):options;inp=``}else if(type==='textarea')inp=``;else inp=``;let helper=(k==='shift'&&['operationCost','washCost','fuelCost','roadCost'].includes(key))?'
هذه التكاليف فقط هي التي تخصم قبل توزيع الثلث والثلثين.
':(k==='maintenance'&&key==='cost')?'
تُسجل للمتابعة فقط، ولا تخصم من الإيراد.
':'';html+=`
${inp}${helper}
`} if(k==='shift')html+=`
ساعات العمل0 س
صافي قابل للتقسيم0 ج.م
حصة السواق · ⅓0 ج.م
حصة المالك · ⅔0 ج.م
`; $('formFields').innerHTML=html;$('modalBack').classList.add('show');if(k==='shift'){const upd=()=>previewShift();$('formFields').querySelectorAll('input,select').forEach(el=>el.addEventListener('input',upd));previewShift()}} function previewShift(){let f=$('form'),get=n=>f.elements[n]?.value||'',obj={startTime:get('startTime'),endTime:get('endTime'),breakMinutes:num(get('breakMinutes')),kmStart:num(get('kmStart')),kmEnd:num(get('kmEnd')),revenue:num(get('revenue')),fuelCost:num(get('fuelCost')),roadCost:num(get('roadCost')),operationCost:num(get('operationCost')),washCost:num(get('washCost'))};let c=calcShift(obj),wrap=$('calcPreview');if(!wrap)return;wrap.innerHTML=`
ساعات العمل${nf(c.hours)} س
صافي قابل للتقسيم${money(c.net)}
حصة السواق · ⅓${money(c.driverShare)}
حصة المالك · ⅔${money(c.ownerShare)}
`} function closeModal(){$('modalBack').classList.remove('show')} function saveForm(e){e.preventDefault();if(db.isDemo&&!confirm('أنت الآن في وضع المعاينة التجريبية. لو بتسجل بيانات حقيقية، اضغط إلغاء ثم اختر «ابدأ ببياناتي الحقيقية» لمسح أمثلة العرض أولًا. هل تريد الإضافة داخل المعاينة؟'))return;const def=definitions[kind],values=Object.fromEntries(new FormData(e.target).entries());const numericFields={vehicle:['odometer'],shift:['breakMinutes','kmStart','kmEnd','revenue','fuelLiters','fuelCost','roadCost','operationCost','washCost'],maintenance:['cost','odometer'],driverEntry:['amount'],ownerPayment:['amount']};(numericFields[kind]||[]).forEach(k=>values[k]=num(values[k]));if(kind==='shift'&&num(values.kmEnd)>0&&num(values.kmStart)>0&&num(values.kmEnd)s.date===values.date&&s.vehicleId===values.vehicleId&&s.driverId===values.driverId&&s.shift===values.shift);if(duplicate)return toast('التسجيل ده موجود بالفعل لنفس العربية والسواق والوردية في اليوم ده؛ افتح السجل الموجود وعدّله بدل التكرار.')}if(editId){let idx=db[def.collection].findIndex(x=>x.id===editId);if(idx<0)return;let old=db[def.collection][idx];db[def.collection][idx]={...old,...values};if(kind==='driverEntry')db.settlements[idx]={...db.settlements[idx],...values,kind:'driver'};if(kind==='ownerPayment')db.settlements[idx]={...db.settlements[idx],...values,kind:'owner',type:'ownerPayment'}}else{let obj={id:uid(),...values};if(kind==='driverEntry')Object.assign(obj,{kind:'driver'});if(kind==='ownerPayment')Object.assign(obj,{kind:'owner',type:'ownerPayment'});db[def.collection].push(obj)}if(kind==='shift'||kind==='maintenance'){let vv=safe(values.vehicleId,db.vehicles),odo=kind==='shift'?num(values.kmEnd):num(values.odometer);if(vv&&odo>num(vv.odometer))vv.odometer=odo}save();closeModal();renderAll();toast('تم حفظ السجل وتحديث الحسابات ✓')} function removeRecord(k,id){const def=definitions[k],col=def.collection;if(k==='vehicle'&&(db.shifts.some(s=>s.vehicleId===id)||db.maintenance.some(m=>m.vehicleId===id)||db.settlements.some(s=>s.vehicleId===id)))return alert('العربية مرتبطة بسجلات؛ غيّر حالتها إلى متوقفة بدل حذفها.');if(k==='driver'&&(db.shifts.some(s=>s.driverId===id)||db.settlements.some(s=>s.driverId===id)))return alert('السواق مرتبط بحسابات؛ غيّر حالته إلى غير متاح بدل الحذف.');if(!confirm('تأكيد حذف السجل؟'))return;db[col]=db[col].filter(x=>x.id!==id);save();renderAll();toast('تم حذف السجل')} function renderDashboard(){let t=totals(month);let maint=db.maintenance.filter(m=>m.date?.startsWith(month)).reduce((a,m)=>a+num(m.cost),0);let driversDue=db.drivers.reduce((a,d)=>a+driverStats(d.id,month).balance,0);let active=db.vehicles.filter(v=>v.status==='active').length;let fuelKm=t.km>0?t.fuel/t.km:0;const stats=[['إيرادات الشهر',t.rev,'↗','#08a882','#e6faf4','قبل خصم التكاليف'],['صافي قابل للتقسيم',t.net,'◈','#4263eb','#edf0ff','بعد الوقود والتشغيل والغسيل'],['مستحقات السائقين',driversDue,'♙','#f0a943','#fff4e4','بعد الدفعات والسلف'],['تكلفة الوقود',t.fuel,'⛽','#dc6a54','#fff0eb',nf(t.litres)+' لتر مسجل'],['ساعات العمل',t.hours,'◷','#735edb','#f0edff',t.ss.length+' وردية مسجلة'],['صيانة من جيبك',maint,'🔧','#7a8799','#eef2f7','خارج حساب التقسيم']];$('dashStats').innerHTML=stats.map(([l,v,ic,c,tint,n])=>`
${l}${ic}
${typeof v==='number'&&l==='ساعات العمل'?nf(v)+' س':money(v)}
${n}
`).join('');$('splitHero').innerHTML=`
توزيع صافي تشغيل الفترة · ${new Date().toLocaleDateString('ar-EG',{month:'long',year:'numeric'})}

كل جنيه متوزع بحسابه الصحيح.

حصة السواق${money(t.driver)}⅓ · 33.33%
حصة مالك العربية${money(t.owner)}⅔ · 66.67%
الإيراد ${money(t.rev)} − التشغيل ${money(t.fuel+t.road+t.ops+t.wash)}صافي ${money(t.net)}
`;$('fleetCountTag').textContent=db.vehicles.length+' عربية';const types=[['active','تعمل','#17b998'],['maintenance','في الصيانة','#f1af4e'],['idle','متوقفة','#e55c70']];$('fleetStatusBars').innerHTML=types.map(([k,label,col])=>{let n=db.vehicles.filter(v=>v.status===k).length,p=db.vehicles.length?n/db.vehicles.length*100:0;return `
${label}${n} / ${db.vehicles.length}
`}).join('');$('dashHours').textContent=nf(t.hours)+' س';$('dashShiftCount').textContent=t.ss.length+' وردية';let per=db.vehicles.map(v=>{let ss=t.ss.filter(s=>s.vehicleId===v.id),net=ss.reduce((a,s)=>a+eligibleNet(s),0);return {v,net}}).sort((a,b)=>b.net-a.net).slice(0,5),max=Math.max(1,...per.map(x=>x.net));$('topVehicles').innerHTML=per.map(x=>`
${esc(x.v.name)}
${money(x.net)}
`).join('')||emptyHTML();let rec=[...db.shifts].sort((a,b)=>b.date.localeCompare(a.date)).slice(0,5);$('recentShifts').innerHTML=rec.map(s=>`
🚚
${esc(vehicleName(s.vehicleId))} · ${esc(driverName(s.driverId))}
${fmtDate(s.date)} · ${nf(shiftHours(s))} ساعة · ${shiftText[s.shift]||'وردية'}
${money(s.revenue)}
`).join('')||emptyHTML();$('accountSummary').innerHTML=`
إجمالي حصة السائقين هذا الشهرقبل تسويات السلف والدفعات
${money(t.driver)}
إجمالي حصة الملاك هذا الشهرقبل المبالغ المسددة
${money(t.owner)}
الرصيد المستحق للسائقين بعد التسوياتيشمل السلف والدفعات والخصومات والمكافآت
${money(driversDue)}
`;let mThis=db.maintenance.filter(m=>m.date?.startsWith(month));$('maintSummary').innerHTML=`
مصروفات الصيانة المسجلة${mThis.length} عملية صيانة هذا الشهر
${money(maint)}
أكثر بند صيانة تكلفةحسب السجل الحالي
${mThis.length?money(Math.max(...mThis.map(m=>num(m.cost)) )):'0 ج.م'}
`} function renderFleet(){let q=$('fleetSearch').value.trim().toLowerCase(),f=$('fleetFilter').value;let all=db.vehicles.filter(v=>(v.name+' '+v.plate+' '+v.model+' '+v.ownerName).toLowerCase().includes(q)&&(!f||v.status===f));$('vehicleCount').textContent=db.vehicles.length+' عربية مسجلة';$('fleetList').innerHTML=all.map(v=>{let ss=db.shifts.filter(s=>s.vehicleId===v.id),rev=ss.reduce((a,s)=>a+num(s.revenue),0),fuel=ss.reduce((a,s)=>a+num(s.fuelCost),0),ops=ss.reduce((a,s)=>a+num(s.roadCost)+num(s.operationCost)+num(s.washCost),0),net=rev-fuel-ops,owner=ownerStats(v.id),maint=db.maintenance.filter(m=>m.vehicleId===v.id).reduce((a,m)=>a+num(m.cost),0),litres=ss.reduce((a,s)=>a+num(s.fuelLiters),0),km=ss.reduce((a,s)=>a+kmDriven(s),0);return `
🚛
${badge(statusText[v.status]||'غير محددة',statusClass[v.status]||'blue')}
${esc(v.name)}
${esc(v.plate)} · ${esc(v.model||'—')}
مالك العربية: ${esc(v.ownerName||'—')}
إجمالي الإيراد${money(rev)}
صافي التقسيم${money(net)}
حصة السواقين${money(net/3)}
حصة المالك${money(net*2/3)}
الوقود / الكيلومترات${nf(litres)} ل · ${nf(km)} كم
العداد الحالي${nf(v.odometer)} كم
تكلفة الوقود لكل كم${km?money(fuel/km):'—'}
صيانة شخصية منفصلة${money(maint)}
${ss.length} وردية · ${nf(ss.reduce((a,s)=>a+shiftHours(s),0))} ساعة${actions('vehicle',v.id)}
`}).join('')||emptyHTML('لا توجد عربيات','أضف أول عربية، أو غيّر معايير البحث.')} function renderDrivers(){let q=$('driverSearch').value.trim().toLowerCase(),items=db.drivers.filter(d=>(d.name+' '+d.phone+' '+d.license).toLowerCase().includes(q));$('driverCount').textContent=db.drivers.length+' سائق';$('driversTable').innerHTML=table(['السواق','رقم الهاتف','الرخصة','الورديات','ساعات العمل','إجمالي الحصة','الرصيد','الحالة','إجراءات'],items.map(d=>{let st=driverStats(d.id);return `
${esc(d.name.slice(0,1))}${esc(d.name)}
${esc(d.phone||'—')}${esc(d.license||'—')}${st.shifts.length}${nf(st.hours)} س${money(st.earned+st.bonuses)}${money(st.balance)}${badge(d.status==='active'?'يعمل':'غير متاح',d.status==='active'?'green':'orange')}
${actions('driver',d.id)}
`}))} function renderShifts(){let q=$('shiftSearch').value.trim().toLowerCase(),m=monthVal('shiftMonth'),items=[...filteredShifts(m)].sort((a,b)=>b.date.localeCompare(a.date)).filter(s=>(vehicleName(s.vehicleId)+' '+driverName(s.driverId)+' '+s.date).toLowerCase().includes(q));$('shiftsTable').innerHTML=table(['التاريخ','العربية / السواق','الوردية','الساعات','كم مقطوعة','الإيراد','الوقود','طرق + تشغيل + غسيل','صافي التقسيم','حصة السواق','حصة المالك','إجراءات'],items.map(s=>{let c=calcShift(s);return `${fmtDate(s.date)}${esc(vehicleName(s.vehicleId))}
${esc(driverName(s.driverId))}${badge(shiftText[s.shift]||'—','blue')}${nf(c.hours)} س${nf(c.km)} كم${money(s.revenue)}${money(s.fuelCost)}
${nf(s.fuelLiters)} لتر${money(num(s.roadCost)+num(s.operationCost)+num(s.washCost))}${money(c.net)}${money(c.driverShare)}${money(c.ownerShare)}${actions('shift',s.id)}`}))} function renderMaintenance(){let q=$('maintSearch').value.trim().toLowerCase(),m=monthVal('maintMonth'),items=[...db.maintenance].sort((a,b)=>b.date.localeCompare(a.date)).filter(x=>(vehicleName(x.vehicleId)+' '+(catText[x.category]||x.category)+' '+x.vendor+' '+x.note).toLowerCase().includes(q)&&(!m||x.date.startsWith(m)));let total=items.reduce((a,x)=>a+num(x.cost),0),oil=items.filter(x=>x.category==='oil').reduce((a,x)=>a+num(x.cost),0);$('maintenanceStats').innerHTML=[['إجمالي الصيانة المعروضة',money(total)],['زيوت وفلاتر',money(oil)],['عدد عمليات الصيانة',items.length]].map(([l,v])=>`
${l}
${v}
`).join('');$('maintenanceTable').innerHTML=table(['التاريخ','العربية','نوع الصيانة','العداد','الورشة','المبلغ الشخصي','ملاحظات','إجراءات'],items.map(x=>`${fmtDate(x.date)}${esc(vehicleName(x.vehicleId))}${badge(catText[x.category]||x.category,'blue')}${num(x.odometer)?nf(x.odometer)+' كم':'—'}${esc(x.vendor||'—')}${money(x.cost)}${esc(x.note||'—')}${actions('maintenance',x.id)}`))} function renderAccounts(){let period=accountPeriod();let dr=db.drivers.map(d=>({d,...driverStats(d.id,period)}));$('driverAccounts').innerHTML=table(['السواق','الورديات','الساعات','الحصة','الدفعات','السلف','الرصيد المستحق','كشف'],dr.map(x=>`${esc(x.d.name)}${x.shifts.length}${nf(x.hours)}${money(x.earned+x.bonuses)}${money(x.payments)}${money(x.advances)}${money(x.balance)} `));let own=db.vehicles.map(v=>({v,...ownerStats(v.id,period)}));$('ownerAccounts').innerHTML=table(['العربية / المالك','حصة المالك','المدفوع','المتبقي','الصيانة خارج الحساب','إجراء'],own.map(x=>`${esc(x.v.name)}
${esc(x.v.ownerName||'—')}${money(x.share)}${money(x.pay)}${money(x.balance)}${money(x.maint)}`));let logs=[...db.settlements].sort((a,b)=>b.date.localeCompare(a.date)).slice(0,25);$('ledgerTable').innerHTML=table(['التاريخ','نوع الحساب','الاسم / العربية','نوع الحركة','المبلغ','البيان','إجراء'],logs.map(x=>`${fmtDate(x.date)}${x.kind==='owner'?'مالك':'سواق'}${esc(x.kind==='owner'?vehicleName(x.vehicleId):driverName(x.driverId))}${esc(settleText[x.type]||x.type)}${money(x.amount)}${esc(x.note||'—')}`))} function removeSettlement(id){if(!confirm('حذف حركة التسوية؟ ستُعاد حسبة الرصيد بعدها.'))return;db.settlements=db.settlements.filter(x=>x.id!==id);save();renderAll();toast('تم حذف حركة التسوية')} function renderReports(){let p=monthVal('reportMonth'),t=totals(p),maint=db.maintenance.filter(x=>!p||x.date.startsWith(p)).reduce((a,x)=>a+num(x.cost),0);$('reportNet').textContent=money(t.net);$('reportStats').innerHTML=[['إجمالي الإيرادات',money(t.rev)],['الوقود',money(t.fuel)],['الطرق والتشغيل والغسيل',money(t.road+t.ops+t.wash)],['صيانة شخصية خارج التقسيم',money(maint)]].map(([l,v])=>`
${l}
${v}
`).join('');let vs=db.vehicles.map(v=>{let ss=t.ss.filter(s=>s.vehicleId===v.id),rev=ss.reduce((a,s)=>a+num(s.revenue),0),fuel=ss.reduce((a,s)=>a+num(s.fuelCost),0),ops=ss.reduce((a,s)=>a+num(s.roadCost)+num(s.operationCost)+num(s.washCost),0),km=ss.reduce((a,s)=>a+kmDriven(s),0),lit=ss.reduce((a,s)=>a+num(s.fuelLiters),0),mt=db.maintenance.filter(m=>m.vehicleId===v.id&&(!p||m.date.startsWith(p))).reduce((a,m)=>a+num(m.cost),0);return {v,ss,rev,fuel,ops,net:rev-fuel-ops,km,lit,mt}}).sort((a,b)=>b.net-a.net);$('reportTable').innerHTML=table(['العربية / اللوحة','الورديات','الإيراد','الوقود','التشغيل والغسيل','صافي التقسيم','⅓ السواقين','⅔ المالك','صيانة منفصلة'],vs.map(x=>`${esc(x.v.name)}
${esc(x.v.plate)}${x.ss.length}${money(x.rev)}${money(x.fuel)}${money(x.ops)}${money(x.net)}${money(x.net/3)}${money(x.net*2/3)}${money(x.mt)}`));let fuelVehicles=vs.filter(x=>x.km>0||x.lit>0);$('fuelReport').innerHTML=table(['العربية','عدد الورديات','اللترات','الكيلومترات','كم لكل لتر','لتر / 100 كم','تكلفة الوقود','تكلفة الوقود / كم'],fuelVehicles.map(x=>`${esc(x.v.name)}${x.ss.length}${nf(x.lit)} ل${nf(x.km)} كم${x.lit&&x.km?nf(x.km/x.lit):'—'}${x.km&&x.lit?nf(x.lit/x.km*100):'—'}${money(x.fuel)}${x.km?money(x.fuel/x.km):'—'}`))} function renderAll(){let demo=$('demoBanner');demo.classList.toggle('hide',!db.isDemo);renderDashboard();renderFleet();renderDrivers();renderShifts();renderMaintenance();renderAccounts();renderReports()} const pageNames={dashboard:'لوحة القيادة',fleet:'الأسطول والعربيات',drivers:'ملفات السائقين',shifts:'الورديات والساعات',maintenance:'الصيانة الشخصية',accounts:'كشوف الحسابات',reports:'التقارير والتحليلات',settings:'النسخ والإعدادات'};function goto(p){if(!pageNames[p])return;page=p;document.querySelectorAll('.section').forEach(s=>s.classList.toggle('active',s.id===p));document.querySelectorAll('[data-page]').forEach(b=>b.classList.toggle('active',b.dataset.page===p));$('pageTitle').textContent=pageNames[p];$('side').classList.remove('open');if(p==='dashboard')renderDashboard();window.scrollTo({top:0,behavior:'smooth'})}document.querySelectorAll('[data-page]').forEach(b=>b.addEventListener('click',()=>goto(b.dataset.page)));$('hamb').onclick=()=> $('side').classList.toggle('open');$('modalBack').onclick=e=>{if(e.target===$('modalBack'))closeModal()};$('statementBack').onclick=e=>{if(e.target===$('statementBack'))closeStatement()};document.addEventListener('keydown',e=>{if(e.key==='Escape'){closeModal();closeStatement()}}); let currentStatementDriverId=''; function openDriverStatement(id){currentStatementDriverId=id;let d=safe(id,db.drivers);if(!d)return;let period=accountPeriod(),st=driverStats(id,period),periodLabel=period?fmtDate(period+'-01').replace(/\d+/g,m=>m):'كل الفترات';let rows=st.shifts.sort((a,b)=>a.date.localeCompare(b.date)).map(s=>{let c=calcShift(s);return `${fmtDate(s.date)}${esc(vehicleName(s.vehicleId))}${shiftText[s.shift]||''}${nf(c.hours)} س${money(s.revenue)}${money(num(s.fuelCost)+num(s.roadCost)+num(s.operationCost)+num(s.washCost))}${money(c.net)}${money(c.driverShare)}`});let ledger=st.ledger.map(l=>`${fmtDate(l.date)}${esc(settleText[l.type]||l.type)}${esc(l.note||'—')}${money(l.amount)}`);$('statementContent').innerHTML=`
ELLEITHY MANAGER · كشف حساب سواق

${esc(d.name)}

${esc(d.phone||'بدون هاتف')} · ${esc(d.license||'بدون بيانات رخصة')}
الفترة: ${esc(periodTitle(period))}
${badge(d.status==='active'?'يعمل':'غير متاح',d.status==='active'?'green':'orange')}
عدد الورديات${st.shifts.length}
إجمالي ساعات العمل${nf(st.hours)} ساعة
إجمالي حصة السواق${money(st.earned)}
الرصيد المستحق النهائي${money(st.balance)}

تفاصيل الورديات والحصة

${table(['التاريخ','العربية','الوردية','الساعات','الإيراد','التكاليف المخصومة','صافي الوردية','حصة السواق'],rows)}

ملخص التسويات

الدفعات${money(st.payments)}
السلف${money(st.advances)}
الخصومات${money(st.deductions)}
المكافآت${money(st.bonuses)}
${table(['التاريخ','نوع الحركة','البيان','المبلغ'],ledger)}
معادلة الرصيد: حصة السواق + المكافآت − الدفعات − السلف − الخصومات. المصروفات الشخصية للصيانة لا تؤثر في هذا الكشف.
`;$('statementBack').classList.add('show')} function driverSheetDocument(id){ let d=safe(id,db.drivers);if(!d)return ''; let period=accountPeriod(),st=driverStats(id,period); let revenue=st.shifts.reduce((n,s)=>n+num(s.revenue),0),fuel=st.shifts.reduce((n,s)=>n+num(s.fuelCost),0),ops=st.shifts.reduce((n,s)=>n+num(s.roadCost)+num(s.operationCost),0),wash=st.shifts.reduce((n,s)=>n+num(s.washCost),0); let net=revenue-fuel-ops-wash,owner=net*2/3,totalKm=st.shifts.reduce((n,s)=>n+kmDriven(s),0),totalLitres=st.shifts.reduce((n,s)=>n+num(s.fuelLiters),0); let line=(label,value,strong=false)=>`${label}${money(value)}`; let days=new Map(); st.shifts.forEach(s=>{let x=days.get(s.date)||{date:s.date,revenue:0,fuel:0,ops:0,wash:0,net:0,driver:0,owner:0,shifts:0,hours:0,km:0,litres:0};let c=calcShift(s);x.revenue+=num(s.revenue);x.fuel+=num(s.fuelCost);x.ops+=num(s.roadCost)+num(s.operationCost);x.wash+=num(s.washCost);x.net+=c.net;x.driver+=c.driverShare;x.owner+=c.ownerShare;x.shifts++;x.hours+=c.hours;x.km+=c.km;x.litres+=c.litres;days.set(s.date,x)}); let shifts=[...days.values()].sort((a,b)=>a.date.localeCompare(b.date)).map(x=>`${esc(x.date)}${x.shifts}${nf(x.hours)} س${nf(x.km)} كم${nf(x.litres)} ل${x.km&&x.litres?nf(x.litres/x.km*100):'—'}${money(x.revenue)}${money(x.fuel)}${money(x.ops)}${money(x.wash)}${money(x.net)}${money(x.driver)}${money(x.owner)}`).join(''); let dayTotals=`إجمالي الأسبوع${st.shifts.length}${nf(st.hours)} س${nf(totalKm)} كم${nf(totalLitres)} ل${totalKm&&totalLitres?nf(totalLitres/totalKm*100):'—'}${money(revenue)}${money(fuel)}${money(ops)}${money(wash)}${money(net)}${money(st.earned)}${money(owner)}`; return `كشف حساب ${esc(d.name)} - ${esc(periodTitle(period))}

ELLEITHY MANAGER

كشف حساب أسبوعي منفصل — خاص بالسائق ده فقط، ولا يحتوي على حسابات السائقين الآخرين

السائق: ${esc(d.name)}

${esc(periodTitle(period))}
عدد الورديات${st.shifts.length}
إجمالي ساعات العمل${nf(st.hours)} ساعة
إجمالي المسافة${nf(totalKm)} كم
إجمالي الوقود${nf(totalLitres)} لتر

ملخص الحساب الأسبوعي

${line('إجمالي الإيراد',revenue)}${line('تكلفة الوقود',fuel)}${line('مصاريف التشغيل والطرق',ops)}${line('الغسيل',wash)}${line('صافي الإيراد بعد المصاريف',net,true)}${line('حقك كسائق (الثلث)',st.earned,true)}${line('حق المالك (الثلثين)',owner)}${line('مكافآت',st.bonuses)}${line('السُلف',st.advances)}${line('مدفوعات سابقة',st.payments)}${line('الخصومات',st.deductions)}
المتبقي ليك في التسوية: ${money(st.balance)}

تفصيل الحساب يوم بيوم

${shifts||''}${dayTotals}
التاريخالوردياتساعات العملالمسافةالوقود (لتر)لتر / 100 كمإيراد اليومتكلفة الوقودالتشغيل والطرقالغسيلصافي اليومحق السواق ⅓حق المالك ⅔
لا توجد ورديات مسجلة في هذه الفترة

معادلة اليوم: الإيراد − الوقود − التشغيل والطرق − الغسيل = صافي قابل للتقسيم. حصة السائق ⅓ وحصة المالك ⅔. الصيانة والزيوت والإطارات مسجلة في حساب شخصي منفصل ولا تُخصم من الإيراد.

`; } function driverSheetFilename(id){let d=safe(id,db.drivers);let week=accountPeriod().replace(/[^0-9-]/g,'')||'all';return 'ELLEITHY-driver-'+String(d?.name||'driver').replace(/[\\/:*?"<>|]/g,'-')+'-'+week+'.html'} function downloadDriverSheet(id=currentStatementDriverId){let html=driverSheetDocument(id);if(!html)return;download(html,driverSheetFilename(id),'text/html;charset=utf-8');toast('تم تنزيل شيت السائق منفردًا — يمكنك إرساله كملف')} function printDriverSheet(id=currentStatementDriverId){let html=driverSheetDocument(id);if(!html)return;let w=window.open('','_blank');if(!w){alert('اسمح بفتح نافذة جديدة لحفظ PDF');return}w.document.open();w.document.write(html);w.document.close();w.focus();setTimeout(()=>w.print(),350)} function closeStatement(){$('statementBack').classList.remove('show')} function startFresh(){if(!confirm('سيتم مسح بيانات المعاينة أو السجلات المحلية في هذا المتصفح والبدء من الصفر. لو عندك بيانات حقيقية سبق تسجيلها، نزّل نسخة احتياطية أولًا. هل نبدأ؟'))return;db=emptyDb();save();renderAll();goto('dashboard');toast('تم تجهيز النظام لبياناتك من الصفر')} function download(text,name,type){let blob=new Blob(['\ufeff'+text],{type}),url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1200)}function backup(){download(JSON.stringify(db,null,2),'ELLEITHY-backup-'+today+'.json','application/json;charset=utf-8');toast('تم تنزيل النسخة الاحتياطية')}function restoreFile(e){let file=e.target.files?.[0];if(!file)return;let r=new FileReader();r.onload=()=>{try{let x=JSON.parse(r.result);if(!x||!['vehicles','drivers','shifts','maintenance','settlements'].every(k=>Array.isArray(x[k])))throw Error('format');if(!confirm('استعادة النسخة ستستبدل السجلات الحالية. متابعة؟'))return;db={version:1,isDemo:false,vehicles:x.vehicles,drivers:x.drivers,shifts:x.shifts,maintenance:x.maintenance,settlements:x.settlements};save();renderAll();toast('تمت الاستعادة')}catch(err){alert('الملف غير صالح أو ليس نسخة احتياطية من ELLEITHY MANAGER')}finally{e.target.value=''}};r.readAsText(file)}function exportCSV(){let t=[['التاريخ','العربية','اللوحة','السواق','الوردية','ساعات العمل','كم مقطوعة','الإيراد','لترات الوقود','تكلفة الوقود','رسوم الطرق','تشغيل','غسيل','صافي قابل للتقسيم','حصة السواق','حصة المالك']];db.shifts.forEach(s=>{let c=calcShift(s),v=safe(s.vehicleId,db.vehicles);t.push([s.date,vehicleName(s.vehicleId),v?.plate||'',driverName(s.driverId),shiftText[s.shift]||s.shift,c.hours,c.km,s.revenue,s.fuelLiters,s.fuelCost,s.roadCost,s.operationCost,s.washCost,c.net,c.driverShare,c.ownerShare])});download(t.map(r=>r.map(v=>'"'+String(v??'').replace(/"/g,'""')+'"').join(',')).join('\r\n'),'ELLEITHY-shifts-'+today+'.csv','text/csv;charset=utf-8');toast('تم تصدير تقرير الورديات')} $('today').textContent=new Intl.DateTimeFormat('ar-EG',{weekday:'long',day:'numeric',month:'long',year:'numeric'}).format(new Date());$('accountWeek').value=mondayISO();$('shiftMonth').value=month;$('maintMonth').value=month;$('reportMonth').value=month;window.addEventListener('resize',()=>{});renderAll();