Optic Naciria

Gestion professionnelle d’optique médicale

Tableau de bord

Chiffre d'affaires aujourd'hui
0 DA
Ventes enregistrées
Dépenses aujourd'hui
0 DA
Dépenses enregistrées
Résultat du jour
0 DA
Recettes − dépenses
Valeur du stock
0 DA
0 références

Accès rapide

Alertes de stock

Dernières ventes

Les données sont enregistrées dans le stockage local de ce navigateur sur cet appareil. Effectue régulièrement une sauvegarde depuis Paramètres. Cette version ne synchronise pas les données entre plusieurs appareils.

Clients

Articles & stock

Ventes & factures

Dépenses

Comptabilité

Recettes
0 DA
Dépenses
0 DA
Résultat net
0 DA
Nombre de ventes
0

Détail des ventes

Attention

Le résultat affiché correspond aux recettes encaissées moins les dépenses saisies. Pour une comptabilité fiscale officielle, fais valider les règles de TVA, taxes et obligations locales par ton comptable.

Paramètres

Personnalisation du magasin

Sauvegarde et restauration

Exportez toutes les données dans un fichier JSON. Conservez-le dans Fichiers ou iCloud Drive. La restauration remplace les données actuellement présentes.

Gestion des données

Conseil iPhone : ouvre ce fichier dans Safari pour utiliser l'application. Pour une utilisation durable comme une application installée, il est préférable de publier ce fichier sur un hébergement HTTPS puis de choisir « Partager » → « Sur l’écran d’accueil ». L'installation d'un fichier HTML seul ne crée pas une application iOS native (.ipa).

Optic Naciria · Application locale · Version 1.0

`);w.document.close()} function addPayment(x){let s=db.sales.find(a=>a.id===x),n=prompt('Montant du paiement supplémentaire (reste dû : '+money(s.total-s.paid)+')');if(n===null)return;n=Number(n);if(!Number.isFinite(n)||n<=0||n>s.total-s.paid)return alert('Montant invalide.');s.paid+=n;s.status=s.paid>=s.total?'Payée':'Partiellement payée';save()} function deleteSale(x){if(confirm('Annuler cette vente ? Le stock des articles vendus sera réintégré.')){let s=db.sales.find(a=>a.id===x);(s.lines||[]).forEach(l=>{let p=db.products.find(p=>p.id===l.productId);if(p)p.qty+=l.qty});db.sales=db.sales.filter(a=>a.id!==x);save()}} function openExpense(){modal('Nouvelle dépense',`
`)} function saveExpense(ev){ev.preventDefault();let o=Object.fromEntries(new FormData(ev.target).entries());o.id=id();o.amount=Number(o.amount);db.expenses.push(o);closeModal();save()} function renderExpenses(){let a=[...db.expenses].sort((a,b)=>b.date.localeCompare(a.date));document.getElementById('expenseList').innerHTML=a.length?a.map(e=>`
${esc(e.label)}${money(e.amount)}

${dateLabel(e.date)} · ${esc(e.category)} ${e.note?'· '+esc(e.note):''}

`).join(''):'
Aucune dépense enregistrée.
'} function deleteExpense(x){if(confirm('Supprimer cette dépense ?')){db.expenses=db.expenses.filter(e=>e.id!==x);save()}} function inPeriod(d,p){let t=dateNow();if(p==='day')return d===t;if(p==='month')return d.slice(0,7)===t.slice(0,7);if(p==='year')return d.slice(0,4)===t.slice(0,4);return true} function renderReports(){let p=document.getElementById('reportPeriod')?.value||'month',ss=db.sales.filter(s=>inPeriod(s.date,p)),ee=db.expenses.filter(e=>inPeriod(e.date,p)),a=ss.reduce((n,s)=>n+ +s.paid,0),e=ee.reduce((n,x)=>n+ +x.amount,0);document.getElementById('rSales').textContent=money(a);document.getElementById('rExpenses').textContent=money(e);document.getElementById('rNet').textContent=money(a-e);document.getElementById('rCount').textContent=ss.length;let days={};ss.forEach(s=>days[s.date]=(days[s.date]||0)+Number(s.paid));let rows=Object.entries(days).sort((a,b)=>b[0].localeCompare(a[0]));document.getElementById('reportDetails').innerHTML=rows.length?`${rows.map(([d,n])=>``).join('')}
DateVentesEncaissé
${dateLabel(d)}${ss.filter(s=>s.date===d).length}${money(n)}
`:'
Aucune vente pour cette période.
'} function fillSettings(){['Name','Phone','Address','Currency'].forEach(k=>{let el=document.getElementById('set'+k);if(el)el.value=db.settings[k.toLowerCase()]||''})} function saveSettings(){db.settings={name:document.getElementById('setName').value.trim()||'Optic Naciria',phone:document.getElementById('setPhone').value,address:document.getElementById('setAddress').value,currency:document.getElementById('setCurrency').value.trim()||'DA'};save();alert('Paramètres enregistrés.')} function backup(){let blob=new Blob([JSON.stringify(db,null,2)],{type:'application/json'}),a=document.createElement('a'),u=URL.createObjectURL(blob);a.href=u;a.download='optic-naciria-sauvegarde-'+dateNow()+'.json';a.click();URL.revokeObjectURL(u)} function restoreBackup(ev){let f=ev.target.files[0];if(!f)return;let r=new FileReader();r.onload=()=>{try{let x=JSON.parse(r.result);if(!x.clients||!x.products||!x.sales||!x.expenses||!x.settings)throw Error();if(confirm('Remplacer toutes les données actuelles par cette sauvegarde ?')){db=x;save();alert('Sauvegarde restaurée.')}}catch(e){alert('Fichier de sauvegarde invalide.')}};r.readAsText(f);ev.target.value=''} function clearData(){if(confirm('Effacer définitivement toutes les données de cette application sur cet appareil ?')){db=fresh();save();alert('Données effacées.')}} renderAll();