Skip to content

Commit e74fce3

Browse files
Update page title and version in index.html
1 parent 59cd2d0 commit e74fce3

1 file changed

Lines changed: 32 additions & 32 deletions

File tree

index.html

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6-
<title>فَوْتَرَة كامل - نظام الفوترة الجزائري (كاميرا خلفية للمسح)</title>
6+
<title>فَوْتَرَة كامل - نظام الفوترة الجزائري (إضافة منتج من QR)</title>
77
<script src="https://cdn.tailwindcss.com"></script>
88
<link rel="preconnect" href="https://fonts.googleapis.com">
99
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -106,7 +106,6 @@
106106
.product-grid-card .add-btn:hover { transform: scale(1.1); background: #0284c7; }
107107
.dark .product-grid-card .add-btn { background: #0284c7; }
108108

109-
/* تنسيق زر تبديل الكاميرا في الماسح */
110109
.scanner-controls {
111110
display: flex;
112111
justify-content: center;
@@ -154,7 +153,7 @@
154153
</div>
155154
<div>
156155
<h1 class="font-extrabold text-lg leading-none">فَوْتَرَة</h1>
157-
<p class="text-[11px] text-slate-500 dark:text-slate-400">الإصدار الجزائري v3.9</p>
156+
<p class="text-[11px] text-slate-500 dark:text-slate-400">الإصدار الجزائري v4.0</p>
158157
</div>
159158
</div>
160159
<nav class="p-3 space-y-1.5 overflow-y-auto">
@@ -502,7 +501,6 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
502501
<button id="close-scan" class="w-9 h-9 grid place-items-center rounded-xl bg-white/10" aria-label="إغلاق الماسح"><i class="fa-solid fa-xmark"></i></button>
503502
</div>
504503
<div id="reader" class="w-full aspect-square bg-black"></div>
505-
<!-- أزرار التحكم في الماسح -->
506504
<div class="scanner-controls">
507505
<span class="camera-label" id="camera-label">📷 كاميرا: خلفية</span>
508506
<button id="toggle-camera" class="flex items-center gap-1">
@@ -716,8 +714,10 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
716714
}
717715

718716
// ============================================================
719-
// PRODUCTS (with images)
717+
// PRODUCTS (with images and scan-to-add)
720718
// ============================================================
719+
let pendingAddToInvoice = false; // لتحديد ما إذا نضيف المنتج للفاتورة بعد الحفظ
720+
721721
function renderProducts() {
722722
$('#products-table').innerHTML = state.products.map(p => `
723723
<tr class="border-b dark:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800/50">
@@ -758,12 +758,14 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
758758

759759
$('#btn-add-product').onclick = () => openProduct();
760760

761-
function openProduct(p = null) {
762-
$('#modal-title').textContent = p ? 'تعديل منتج' : 'منتج جديد';
761+
function openProduct(p = null, ref = '', addToInvoice = false) {
762+
pendingAddToInvoice = addToInvoice;
763+
$('#modal-title').textContent = p ? 'تعديل منتج' : (ref ? 'إضافة منتج جديد من المسح' : 'منتج جديد');
764+
const refValue = p?.ref || ref || '';
763765
$('#modal-body').innerHTML = `
764766
<div class="grid sm:grid-cols-2 gap-3">
765767
<div class="sm:col-span-2"><label class="text-xs">اسم المنتج</label><input id="p-name" value="${p?.name||''}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700"></div>
766-
<div><label class="text-xs">المرجع / باركود</label><input id="p-ref" value="${p?.ref||''}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border"></div>
768+
<div><label class="text-xs">المرجع / باركود</label><input id="p-ref" value="${refValue}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700"></div>
767769
<div><label class="text-xs">المخزون</label><input id="p-stock" type="number" value="${p?.stock||0}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border"></div>
768770
<div><label class="text-xs">سعر الشراء</label><input id="p-buy" type="number" value="${p?.buy||0}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border"></div>
769771
<div><label class="text-xs">سعر البيع HT</label><input id="p-price" type="number" value="${p?.price||0}" class="w-full h-11 px-3 rounded-xl bg-slate-50 dark:bg-slate-800 border"></div>
@@ -826,17 +828,28 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
826828
const tva = +$('#p-tva').value || state.company.tva;
827829
const stock = +$('#p-stock').value || 0;
828830
const o = { id: id || Date.now(), name, ref, buy, price, tva, stock, image: imageData };
831+
let isNew = false;
829832
updateState(s => {
830833
if (id) {
831834
const idx = s.products.findIndex(p => p.id === id);
832835
if (idx > -1) s.products[idx] = o;
833836
} else {
834837
s.products.unshift(o);
838+
isNew = true;
835839
}
836840
});
837841
showModal(false);
838842
renderProducts();
839843
showToast('تم حفظ المنتج', 'success');
844+
845+
// إذا كنا في وضع الإضافة من المسح، نضيف المنتج للفاتورة
846+
if (pendingAddToInvoice && isNew) {
847+
// نضيف المنتج للفاتورة باستخدام المعرف الجديد (o.id)
848+
addItemById(o.id);
849+
pendingAddToInvoice = false;
850+
// ننتقل إلى صفحة البيع إذا لم نكن فيها
851+
go('pos');
852+
}
840853
}
841854

842855
function editProduct(id) { openProduct(state.products.find(p => p.id === id)); }
@@ -851,7 +864,7 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
851864
}
852865

853866
// ============================================================
854-
// CUSTOMERS (unchanged)
867+
// CUSTOMERS
855868
// ============================================================
856869
function renderCustomers() {
857870
$('#customers-table').innerHTML = state.customers.map(c => `<tr class="border-b dark:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800/50">
@@ -1349,22 +1362,18 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
13491362
document.addEventListener('click', e => { if (e.target.matches('[data-close]')) showModal(false); });
13501363

13511364
// ============================================================
1352-
// SCANNER (محسّن لاستخدام الكاميرا الخلفية)
1365+
// SCANNER (محسّن: إضافة منتج عند عدم العثور عليه)
13531366
// ============================================================
13541367
let html5Qr = null;
13551368
let currentCameraId = null;
13561369
let availableCameras = [];
13571370

1358-
// دالة للحصول على الكاميرا المفضلة (خلفية إن وجدت)
13591371
function getPreferredCameraId(cameras) {
1360-
// البحث عن كاميرا خلفية (environment)
13611372
const backCamera = cameras.find(cam => cam.label.toLowerCase().includes('back') || cam.label.toLowerCase().includes('rear') || cam.label.toLowerCase().includes('environment'));
13621373
if (backCamera) return backCamera.id;
1363-
// إذا لم توجد، نأخذ الأولى
13641374
return cameras[0]?.id || null;
13651375
}
13661376

1367-
// دالة لبدء الماسح بكاميرا محددة
13681377
async function startScanner(cameraId) {
13691378
try {
13701379
if (html5Qr) {
@@ -1374,12 +1383,10 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
13741383
const config = { fps: 10, qrbox: 250 };
13751384
await html5Qr.start(cameraId, config, onScanSuccess);
13761385
currentCameraId = cameraId;
1377-
// تحديث اسم الكاميرا المعروض
13781386
const cam = availableCameras.find(c => c.id === cameraId);
13791387
const label = cam ? cam.label : 'غير معروف';
13801388
const isBack = label.toLowerCase().includes('back') || label.toLowerCase().includes('rear') || label.toLowerCase().includes('environment');
13811389
document.getElementById('camera-label').textContent = `📷 كاميرا: ${isBack ? 'خلفية' : 'أمامية'}`;
1382-
// حفظ اختيار الكاميرا
13831390
localStorage.setItem('preferred_camera', cameraId);
13841391
} catch(err) {
13851392
console.error('خطأ في بدء الماسح:', err);
@@ -1388,30 +1395,30 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
13881395
}
13891396
}
13901397

1391-
// دالة معالجة نتيجة المسح
13921398
function onScanSuccess(decodedText) {
1393-
try {
1394-
if (html5Qr) html5Qr.stop();
1395-
} catch(e) {}
1399+
try { if (html5Qr) html5Qr.stop(); } catch(e) {}
13961400
$('#scanner').classList.add('hidden');
1397-
// البحث عن المنتج بالباركود
1401+
13981402
const prod = state.products.find(p => p.ref === decodedText);
13991403
if (prod) {
14001404
addItemById(prod.id);
14011405
go('pos');
14021406
showToast('تم إضافة المنتج: ' + prod.name, 'success');
14031407
} else {
1404-
showToast('الباركود: ' + decodedText + ' (غير مسجل)', 'info');
1408+
// عرض خيار إضافة منتج جديد بالمرجع المقروء
1409+
if (confirm(`الباركود "${decodedText}" غير مسجل. هل تريد إضافة منتج جديد بهذا المرجع؟`)) {
1410+
openProduct(null, decodedText, true); // addToInvoice = true
1411+
} else {
1412+
showToast('الباركود: ' + decodedText + ' (غير مسجل)', 'info');
1413+
}
14051414
}
14061415
}
14071416

1408-
// أزرار فتح الماسح
14091417
$('#btn-scan').onclick = $('#btn-scan-add').onclick = async function() {
14101418
try {
14111419
Sound.camera();
14121420
$('#scanner').classList.remove('hidden');
14131421

1414-
// الحصول على قائمة الكاميرات المتاحة
14151422
const cameras = await Html5Qrcode.getCameras();
14161423
if (cameras.length === 0) {
14171424
showToast('لا توجد كاميرا متاحة', 'error');
@@ -1420,9 +1427,7 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
14201427
}
14211428
availableCameras = cameras;
14221429

1423-
// تحديد الكاميرا المفضلة: من localStorage أو الكاميرا الخلفية
14241430
let preferredId = localStorage.getItem('preferred_camera');
1425-
// التحقق من صحة المعرف
14261431
if (!preferredId || !cameras.some(c => c.id === preferredId)) {
14271432
preferredId = getPreferredCameraId(cameras);
14281433
}
@@ -1436,13 +1441,11 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
14361441
}
14371442
};
14381443

1439-
// زر تبديل الكاميرا
14401444
$('#toggle-camera').onclick = async function() {
14411445
if (availableCameras.length < 2) {
14421446
showToast('لا توجد كاميرات أخرى للتبديل', 'warning');
14431447
return;
14441448
}
1445-
// البحث عن الكاميرا التالية في القائمة
14461449
const currentIndex = availableCameras.findIndex(c => c.id === currentCameraId);
14471450
const nextIndex = (currentIndex + 1) % availableCameras.length;
14481451
const nextCamera = availableCameras[nextIndex];
@@ -1452,11 +1455,8 @@ <h3 id="modal-title" class="font-extrabold text-lg">إضافة</h3>
14521455
}
14531456
};
14541457

1455-
// إغلاق الماسح
14561458
$('#close-scan').onclick = async function() {
1457-
try {
1458-
if (html5Qr) await html5Qr.stop();
1459-
} catch(e) {}
1459+
try { if (html5Qr) await html5Qr.stop(); } catch(e) {}
14601460
$('#scanner').classList.add('hidden');
14611461
};
14621462

0 commit comments

Comments
 (0)