Update: 2026-05-04 17:29:56

This commit is contained in:
Hamza-Ayed
2026-05-04 17:29:56 +03:00
parent 47652b4d95
commit 98c4b922be
12 changed files with 480 additions and 104 deletions

View File

@@ -179,7 +179,7 @@
</td>
<td class="p-5 text-sm text-gray-500" x-text="c.address"></td>
<td class="p-5 text-xs text-gray-500" x-text="c.tenant_name || '-'"></td>
<td class="p-5">
<td class="p-5 flex gap-2">
<button x-show="user?.role === 'super_admin' || user?.role === 'admin'" @click="confirmDeleteCompany(c)" class="text-gray-500 hover:text-red-500 p-2 rounded-lg hover:bg-red-500/10 transition">🗑️</button>
</td>
</tr>
@@ -324,6 +324,26 @@
</div>
</div>
</div>
<!-- Official JoFotara Submission Display -->
<template x-if="currentInvoice?.jofotara">
<div class="p-6 bg-emerald-950/20 border border-emerald-500/30 rounded-2xl flex items-center gap-8">
<div class="bg-white p-2 rounded-lg shadow-xl">
<img :src="currentInvoice.jofotara.qr_image_uri" class="w-32 h-32" alt="QR Code">
</div>
<div class="space-y-2 flex-1">
<h4 class="text-emerald-500 font-bold"> فاتورة معتمدة رسمياً</h4>
<p class="text-xs text-gray-400">الرقم الموحد (UUID): <span class="font-mono select-all text-gray-200" x-text="currentInvoice.jofotara.uuid"></span></p>
<p class="text-xs text-gray-400">تاريخ الرفع: <span x-text="currentInvoice.jofotara.submitted_at"></span></p>
<div class="pt-2 flex gap-3">
<a :href="'/index.php?route=v1/invoices/download_xml&id=' + currentInvoice.id + '&token=' + token()"
class="inline-flex items-center gap-2 text-[10px] bg-emerald-600/20 hover:bg-emerald-600/40 text-emerald-400 px-4 py-2 rounded-lg transition-all border border-emerald-500/30">
⬇️ تحميل ملف XML الرسمي
</a>
</div>
</div>
</div>
</template>
</div>
<div class="p-6 bg-gray-950/50 border-t border-gray-800 flex gap-4">
@@ -335,14 +355,12 @@
<span x-show="isApproving">جارِ الإرسال إلى جوفوترة... </span>
</button>
</template>
<template x-if="currentInvoice?.status === 'approved'">
<template x-if="currentInvoice?.status === 'approved' && !currentInvoice.jofotara">
<div class="flex-1 flex flex-col items-center justify-center bg-gray-900 rounded-xl p-4 border border-emerald-500/20">
<span class="text-xs text-emerald-500 font-bold mb-2">تم الاعتماد لدى جوفوترة</span>
<template x-if="currentInvoice?.qr_code">
<img :src="'data:image/png;base64,' + generateQRPng(currentInvoice.qr_code)" class="w-24 h-24 rounded bg-white p-1" alt="QR Code">
</template>
<span class="text-xs text-emerald-500 font-bold mb-2">تم الاعتماد محلياً</span>
</div>
</template>
<button @click="showViewModal = false" class="px-8 py-3 border border-gray-800 rounded-xl hover:bg-gray-800 transition text-sm">إغلاق</button>
</div>
</div>
@@ -383,7 +401,7 @@
<!-- Add User Modal -->
<div x-show="showAddModal" x-cloak class="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center p-4 z-50">
<div class="bg-surface border border-gray-800 w-full max-w-md p-8 rounded-3xl shadow-2xl glass" @click.away="showAddModal = false">
<div class="bg-surface border border-gray-800 w-full max-md p-8 rounded-3xl shadow-2xl glass" @click.away="showAddModal = false">
<h3 class="text-xl font-bold mb-6">إضافة مستخدم جديد 👥</h3>
<form @submit.prevent="createUser" class="space-y-4">
<div><input type="text" x-model="newUser.name" placeholder="الاسم الكامل" class="w-full bg-gray-950 border border-gray-800 p-3 rounded-xl outline-none" required></div>
@@ -444,12 +462,34 @@
showError(msg) { this.globalError = msg; setTimeout(() => this.globalError = '', 6000); },
token() { return localStorage.getItem('access_token'); },
async apiGet(route) {
const res = await fetch('/index.php?route=' + route, { headers: { 'Authorization': 'Bearer ' + this.token() } });
async apiRequest(route, method = 'GET', body = null) {
const options = {
method: method,
headers: {
'Authorization': 'Bearer ' + this.token(),
'Content-Type': 'application/json'
}
};
if (body) options.body = JSON.stringify(body);
const res = await fetch('/index.php?route=' + route, options);
// Session Expired Check
if (res.status === 401) {
const json = await res.json();
if (json.code === 'TOKEN_EXPIRED') {
localStorage.clear();
window.location.href = '/login.php';
return null;
}
}
const json = await res.json();
return json.success ? json.data : (this.showError(json.message), null);
},
async apiGet(route) { return this.apiRequest(route); },
async loadAll() {
this.loadStats();
this.loadCompanies();
@@ -476,22 +516,11 @@
if (!confirm('هل أنت متأكد من اعتماد الفاتورة وإرسالها إلى جوفوترة؟')) return;
this.isApproving = true;
try {
const res = await fetch('/index.php?route=v1/invoices/approve', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + this.token(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: id })
});
const json = await res.json();
if (json.success) {
const data = await this.apiRequest('v1/invoices/approve', 'POST', { id: id });
if (data) {
alert('✅ تم الاعتماد بنجاح!');
this.viewInvoice(id); // Reload to show QR
this.loadInvoices();
} else {
this.showError(json.message || 'فشل الاتصال بنظام جوفوترة');
}
} catch (e) {
this.showError('خطأ غير متوقع: ' + e.message);