Update: 2026-05-11 01:09:54

This commit is contained in:
Hamza-Ayed
2026-05-11 01:09:55 +03:00
parent d6a06cadf9
commit d86a00fe03
8 changed files with 268 additions and 24 deletions

View File

@@ -1759,6 +1759,9 @@
<button @click="viewInvoice(inv.id)" class="btn-table-action btn-ta-navy">
👁️ عرض
</button>
<button @click="deleteInvoice(inv.id)" class="btn-table-action btn-ta-red" style="margin-right:4px;">
🗑️ حذف
</button>
</td>
</tr>
</template>
@@ -2395,11 +2398,11 @@
<!-- ── VIEW INVOICE MODAL ──────────────────────────── -->
<div x-show="showViewModal" x-cloak class="modal-backdrop" @click.self="showViewModal = false">
<div
style="background:var(--bg-card); border-radius:22px; box-shadow:var(--shadow-lg); width:100%; max-width:900px; height:88vh; display:flex; overflow:hidden;">
style="background:var(--bg-card); border-radius:22px; box-shadow:var(--shadow-lg); width:100%; max-width:95vw; height:95vh; display:flex; overflow:hidden;">
<!-- Document Preview -->
<div
style="flex:1; background:#F2F1FA; border-left:1px solid var(--border); position:relative; overflow:hidden;">
style="flex:3; background:#F2F1FA; border-left:1px solid var(--border); position:relative; overflow:hidden;">
<div style="position:absolute; top:12px; right:12px; z-index:10;">
<span class="badge badge-navy">معاينة الملف</span>
</div>
@@ -2415,15 +2418,20 @@
</div>
<!-- Invoice Data Panel -->
<div style="width:345px; flex-shrink:0; display:flex; flex-direction:column; overflow:hidden;">
<div style="width:25%; min-width:320px; max-width:450px; flex-shrink:0; display:flex; flex-direction:column; overflow:hidden;">
<!-- Header -->
<div
style="padding:18px 20px 14px; border-bottom:1px solid var(--border); display:flex; align-items:center; justify-content:space-between;">
<div>
<div style="font-size:16px; font-weight:700; color:var(--text-1);">تفاصيل الفاتورة</div>
<div style="font-size:16px; font-weight:700; color:var(--text-1); display:flex; gap:10px; align-items:center;">
تفاصيل الفاتورة
<button x-show="currentInvoice?.status === 'extracted' && !isEditingInvoice" @click="isEditingInvoice = true" class="btn-sm btn-ghost" style="font-size:11px; padding:2px 8px;">تعديل ✏️</button>
<button x-show="isEditingInvoice" @click="updateInvoice" class="btn-sm btn-teal" style="font-size:11px; padding:2px 8px;">حفظ 💾</button>
<button x-show="isEditingInvoice" @click="isEditingInvoice = false" class="btn-sm btn-ghost" style="font-size:11px; padding:2px 8px;">إلغاء </button>
</div>
<span class="badge" style="margin-top:4px;"
:class="currentInvoice?.status==='extracted' ? 'badge-blue' : (currentInvoice?.status==='approved' ? 'badge-teal' : 'badge-gray')"
x-text="currentInvoice?.status === 'approved' ? '✓ مدققة' : (currentInvoice?.status === 'extracted' ? 'جاهزة للتدقيق' : currentInvoice?.status)">
:class="currentInvoice?.status==='extracted' ? 'badge-blue' : (currentInvoice?.status==='approved' ? 'badge-teal' : (currentInvoice?.status==='rejected' ? 'badge-red' : 'badge-gray'))"
x-text="currentInvoice?.status === 'approved' ? '✓ مدققة' : (currentInvoice?.status === 'extracted' ? 'جاهزة للتدقيق' : (currentInvoice?.status === 'rejected' ? 'مرفوضة' : currentInvoice?.status))">
</span>
</div>
<button @click="showViewModal = false" class="modal-close-btn"></button>
@@ -2455,26 +2463,35 @@
<div class="invoice-field-card">
<div class="invoice-field-label">المورد (البائع)</div>
<div class="invoice-field-value" x-text="currentInvoice?.supplier_name || 'غير متوفر'"></div>
<div style="font-size:12px; color:var(--text-3); font-family:'Outfit',sans-serif; margin-top:4px;"
<div x-show="!isEditingInvoice" class="invoice-field-value" x-text="currentInvoice?.supplier_name || 'غير متوفر'"></div>
<input x-show="isEditingInvoice" type="text" x-model="currentInvoice.supplier_name" class="form-input" style="padding:4px; font-size:13px; margin-bottom:4px;" placeholder="اسم المورد">
<div x-show="!isEditingInvoice" style="font-size:12px; color:var(--text-3); font-family:'Outfit',sans-serif; margin-top:4px;"
x-text="'TIN: ' + (currentInvoice?.supplier_tin || '—')"></div>
<input x-show="isEditingInvoice" type="text" x-model="currentInvoice.supplier_tin" class="form-input" placeholder="الرقم الضريبي" style="padding:4px; font-size:12px;">
</div>
<div class="invoice-field-card">
<div class="invoice-field-label">رقم الفاتورة والتاريخ</div>
<div class="invoice-field-value" x-text="currentInvoice?.invoice_number || '—'"></div>
<div style="font-size:13px; color:var(--text-2); font-family:'Outfit',sans-serif; margin-top:3px;"
<div x-show="!isEditingInvoice" class="invoice-field-value" x-text="currentInvoice?.invoice_number || '—'"></div>
<input x-show="isEditingInvoice" type="text" x-model="currentInvoice.invoice_number" class="form-input" style="padding:4px; font-size:13px; margin-bottom:4px;" placeholder="رقم الفاتورة">
<div x-show="!isEditingInvoice" style="font-size:13px; color:var(--text-2); font-family:'Outfit',sans-serif; margin-top:3px;"
x-text="currentInvoice?.invoice_date || '—'"></div>
<input x-show="isEditingInvoice" type="date" x-model="currentInvoice.invoice_date" class="form-input" style="padding:4px; font-size:13px;">
</div>
<div class="invoice-field-card"
style="background:var(--green-subtle); border-color:rgba(5,150,105,0.2);">
<div class="invoice-field-label" style="color:var(--green-mid);">المجموع الكلي</div>
<div style="font-size:26px; font-weight:700; color:var(--green-mid); font-family:'El Messiri',sans-serif;"
<div x-show="!isEditingInvoice" style="font-size:26px; font-weight:700; color:var(--green-mid); font-family:'El Messiri',sans-serif;"
x-text="parseFloat(currentInvoice?.grand_total || 0).toLocaleString() + ' JOD'"></div>
<div style="font-size:12px; color:var(--amber-mid); margin-top:4px; font-family:'Outfit',sans-serif;"
<input x-show="isEditingInvoice" type="number" step="0.01" x-model="currentInvoice.grand_total" class="form-input" style="padding:4px; font-size:16px; font-weight:bold; color:var(--green-mid); margin-bottom:4px;" placeholder="المجموع">
<div x-show="!isEditingInvoice" style="font-size:12px; color:var(--amber-mid); margin-top:4px; font-family:'Outfit',sans-serif;"
x-text="'الضريبة: ' + parseFloat(currentInvoice?.tax_amount || 0).toLocaleString() + ' JOD'">
</div>
<input x-show="isEditingInvoice" type="number" step="0.01" x-model="currentInvoice.tax_amount" class="form-input" style="padding:4px; font-size:13px; color:var(--amber-mid);" placeholder="الضريبة">
</div>
<!-- Items Table -->
@@ -2562,10 +2579,18 @@
<span x-show="isBusy"> جاري التدقيق...</span>
</button>
<button x-show="currentInvoice?.status === 'extracted'"
style="width:100%; background:var(--red-subtle); color:var(--red-mid); border:none; padding:10px; border-radius:11px; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:all 0.18s;"
onmouseover="this.style.background='#FECACA'"
onmouseout="this.style.background='var(--red-subtle)'"> رفض الفاتورة</button>
<div style="display:flex; gap:8px;">
<button x-show="currentInvoice?.status === 'extracted' || currentInvoice?.status === 'rejected'"
@click="rejectInvoice(currentInvoice.id)"
style="flex:1; background:var(--amber-subtle); color:var(--amber-mid); border:none; padding:10px; border-radius:11px; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:all 0.18s;"
onmouseover="this.style.background='#FDE68A'"
onmouseout="this.style.background='var(--amber-subtle)'"> رفض</button>
<button @click="deleteInvoice(currentInvoice.id)"
style="flex:1; background:var(--red-subtle); color:var(--red-mid); border:none; padding:10px; border-radius:11px; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:all 0.18s;"
onmouseover="this.style.background='#FECACA'"
onmouseout="this.style.background='var(--red-subtle)'">🗑️ حذف</button>
</div>
<div x-show="currentInvoice?.status === 'approved'"
style="width:100%; background:var(--green-subtle); color:var(--green-mid); border:1px solid rgba(5,150,105,0.2); padding:10px; border-radius:11px; font-size:14px; font-weight:700; text-align:center;">
@@ -2829,7 +2854,7 @@
showExcelModal: false, showBatchUploadModal: false,
isUploadingBatch: false, batchProgress: { total: 0, current: 0 },
showAddTenantModal: false, showEditTenantModal: false, showTenantStatsModal: false,
acknowledgedWarnings: false,
acknowledgedWarnings: false, isEditingInvoice: false,
isBusy: false, globalError: '',
newUser: { name: '', email: '', password: '', role: 'accountant', tenant_id: '' },
@@ -2849,14 +2874,8 @@
subtitle() { return { dashboard: 'نظرة شاملة على نشاط النظام', users: 'إدارة المستخدمين والصلاحيات', companies: 'إدارة الشركات والربط بالفوترة الحكومية', invoices: 'رفع ومعالجة الفواتير الضريبية', tenants: 'إدارة المكاتب المحاسبية المشتركة', subscription: 'تفاصيل باقتك الحالية واستهلاك الموارد' }[this.page] || ''; },
get filteredInvoices() {
const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
return this.invoices.filter(inv => {
// 1. Time Filter (Current Month)
const invDate = new Date(inv.invoice_date || inv.created_at);
if (invDate < startOfMonth) return false;
// Removed time filter to prevent invoices from disappearing after a month
// 2. Company Filter
if (this.invoiceCompanyFilter && inv.company_id != this.invoiceCompanyFilter) return false;
@@ -3155,6 +3174,83 @@
}
},
async rejectInvoice(id) {
if (this.isBusy) return;
if (!confirm('هل أنت متأكد من رفض هذه الفاتورة؟')) return;
this.isBusy = true;
try {
const res = await fetch('/index.php?route=v1/invoices/reject', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + this.token(), 'Content-Type': 'application/json' },
body: JSON.stringify({ id: id })
});
const json = await res.json();
this.isBusy = false;
if (json.success) {
alert('تم رفض الفاتورة بنجاح!');
this.showViewModal = false;
this.loadAll();
} else {
this.showError(json.message);
}
} catch (e) {
this.isBusy = false;
this.showError('حدث خطأ أثناء رفض الفاتورة');
}
},
async deleteInvoice(id) {
if (this.isBusy) return;
if (!confirm('هل أنت متأكد من حذف هذه الفاتورة بشكل نهائي؟ لا يمكن التراجع عن هذا الإجراء.')) return;
this.isBusy = true;
try {
const res = await fetch('/index.php?route=v1/invoices/delete', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + this.token(), 'Content-Type': 'application/json' },
body: JSON.stringify({ id: id })
});
const json = await res.json();
this.isBusy = false;
if (json.success) {
alert('تم حذف الفاتورة بنجاح!');
this.showViewModal = false;
this.loadAll();
} else {
this.showError(json.message);
}
} catch (e) {
this.isBusy = false;
this.showError('حدث خطأ أثناء حذف الفاتورة');
}
},
async updateInvoice() {
if (!this.currentInvoice || this.isBusy) return;
this.isBusy = true;
try {
const res = await fetch('/index.php?route=v1/invoices/update', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + this.token(), 'Content-Type': 'application/json' },
body: JSON.stringify(this.currentInvoice)
});
const json = await res.json();
this.isBusy = false;
if (json.success) {
alert('تم تحديث بيانات الفاتورة بنجاح!');
this.isEditingInvoice = false;
this.loadAll();
} else {
this.showError(json.message);
}
} catch (e) {
this.isBusy = false;
this.showError('حدث خطأ أثناء تحديث الفاتورة');
}
},
async uploadExcel() {
const fileInput = document.getElementById('excelFileInput');
if (!fileInput.files[0]) return alert('الرجاء اختيار ملف اكسل');