Skip links
"; } function factureHTML_FactureX(f){ /* … gabarit visuel … */ return "Gabarit 'Facture X' visuel. Utilise le bouton conforme pour PDF Factur-X."; }function buildInvoiceHTML(f,fmt){ return fmt==="facturex"?factureHTML_FactureX(f):factureHTML_Classique(f); } function ouvrirImpressionFormat(f,fmt){ var w=window.open("","_blank"); if(!w) return; w.document.open(); w.document.write(buildInvoiceHTML(f,fmt)); w.document.close(); } function telechargerHTMLFormat(f,fmt){ var blob=new Blob([buildInvoiceHTML(f,fmt)],{type:"text/html;charset=utf-8"}); var url=URL.createObjectURL(blob); var a=document.createElement("a"); a.href=url; a.download="facture-brouillon-"+(fmt==="facturex"?"facturex":"classique")+".html"; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); }async function telechargerFacturXConforme(){ // Appelle le backend pour créer un PDF/A-3 + XML const payload = { client: form.client, statut: form.statut, lignes: form.lignes, tva: 0.20, currency: "EUR", seller: {name:"Votre Société",siret:"00000000000000",vat:"FR00000000000",address:"1 rue Exemple, 75000 Paris"}, buyer: {name: form.client} }; const res = await fetch("/api/facturx", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify(payload) }); if(!res.ok){ alert("Erreur génération Factur-X : " + res.status); return; } const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "facture-facturx.pdf"; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); }const filtered=p.factures.filter(f=> q?f.client.toLowerCase().indexOf(q.toLowerCase())!==-1:true);return h('div',{style:{display:"grid",gap:16}},[ h('div',{style:{display:"grid",gridTemplateColumns:"1fr",gap:8}},h('input',{style:input,placeholder:"Rechercher un client…",value:q,onChange:e=>setQ(e.target.value)})), h('div',{style:box},[ h('h3',{style:{marginTop:0}},'Créer une facture'), h('form',{onSubmit:e=>{e.preventDefault(); var max=0; p.factures.forEach(x=>{if(x.id>max)max=x.id;}); p.setFactures([{client:form.client,statut:form.statut,lignes:form.lignes.slice(),id:max+1}].concat(p.factures)); setForm({client:"",statut:"Brouillon",lignes:[]}); setFormat("classique"); },style:{display:"grid",gap:8}},[ h('input',{style:input,placeholder:"Client",value:form.client,onChange:e=>setForm(Object.assign({},form,{client:e.target.value}))}), h('select',{style:select,value:form.statut,onChange:e=>setForm(Object.assign({},form,{statut:e.target.value}))},[h('option',null,'Brouillon'),h('option',null,'Envoyée'),h('option',null,'Payée'),h('option',null,'En retard')]), h('div',null,[ h('label',{style:{fontSize:12,color:"#374151"}},'Format'), h('div',{style:{display:"grid",gridTemplateColumns:m?"1fr":"1fr 1fr 1fr",gap:8,marginTop:6}},[ h('label',{style:{border:"1px solid #e5e7eb",borderRadius:12,padding:10,display:"flex",alignItems:"center",gap:8}},[h('input',{type:"radio",name:"format",value:"classique",checked:format==="classique",onChange:e=>setFormat(e.target.value)}),'Classique (HTML)']), h('label',{style:{border:"1px solid #e5e7eb",borderRadius:12,padding:10,display:"flex",alignItems:"center",gap:8}},[h('input',{type:"radio",name:"format",value:"facturex",checked:format==="facturex",onChange:e=>setFormat(e.target.value)}),'Facture X (visuel)']), h('label',{style:{border:"1px solid #e5e7eb",borderRadius:12,padding:10,display:"flex",alignItems:"center",gap:8}},[h('input',{type:"radio",name:"format",value:"facturex_conforme",checked:format==="facturex_conforme",onChange:e=>setFormat(e.target.value)}),'Factur-X conforme (PDF/A-3)']) ]) ]), h('div',{style:{display:"grid",gap:8}},[ form.lignes.map((l,i)=>h('div',{key:i,style:{display:"grid",gridTemplateColumns:m?"1fr":"1fr 120px 120px",gap:8}},[ h('input',{style:input,placeholder:"Libellé",value:l.libelle,onChange:e=>updateLigne(i,{libelle:e.target.value})}), h('input',{style:input,type:"number",placeholder:"Qté",value:l.qte,onChange:e=>updateLigne(i,{qte:Number(e.target.value)})}), h('input',{style:input,type:"number",placeholder:"PU",value:l.pu,onChange:e=>updateLigne(i,{pu:Number(e.target.value)})}) ])), h('div',null,h('button',{type:"button",style:btnGhost,onClick:addLigne},'Ajouter une ligne')) ]), h('div',{style:{textAlign:"right",color:"#374151"}},['Total TTC : ',h('strong',null,(totalTTC(form)||0).toFixed(2)+' €')]), h('div',{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"}},[ (format!=="facturex_conforme")?h('button',{type:"button",style:btnGhost,onClick:()=>ouvrirImpressionFormat({client:form.client,statut:form.statut,lignes:form.lignes.slice(),id:null},format)},'Aperçu / Imprimer ('+(format==="facturex"?'Facture X':'Classique')+')'):null, (format!=="facturex_conforme")?h('button',{type:"button",style:btnGhost,onClick:()=>telechargerHTMLFormat({client:form.client,statut:form.statut,lignes:form.lignes.slice(),id:null},format)},'Télécharger ('+(format==="facturex"?'Facture X':'Classique')+')'):null, h('button',{type:"button",style:btn,onClick:telechargerFacturXConforme,disabled:!form.client||form.lignes.length===0||format!=="facturex_conforme"},'Télécharger (Factur-X conforme)') ]) ]) ]), h('div',{style:box},[ h('h3',{style:{marginTop:0}},'Factures'), h('div',{style:{overflowX:"auto"}},h('table',{style:{width:"100%",minWidth:720,borderCollapse:"collapse"}},[ h('thead',null,h('tr',{style:{textAlign:"left"}},[h('th',null,'Client'),h('th',null,'Statut'),h('th',null,'Total TTC'),h('th',{style:{textAlign:"right"}},'Actions')])), h('tbody',null, (p.factures.filter(f=>q?f.client.toLowerCase().indexOf(q.toLowerCase())!==-1:true)).map(f=>{ function th(x){var s=0;x.lignes.forEach(l=>s+=(Number(l.qte)||0)*(Number(l.pu)||0));return s;} return h('tr',{key:f.id},[ h('td',null,f.client),h('td',null,h('span',{style:chip("#fde68a")},f.statut)),h('td',null,(th(f)*1.2).toFixed(2)+' €'), h('td',{style:{textAlign:"right"}},h('div',{style:{display:"inline-flex",gap:8,flexWrap:"wrap"}},[ h('button',{style:btnGhost,onClick:()=>alert("Utilise le bouton 'Factur-X conforme' en haut pour la PDF A-3 + XML")},'Imprimer (Classique)'), h('button',{style:btnGhost,onClick:()=>alert("Utilise le bouton 'Factur-X conforme' en haut pour la PDF A-3 + XML")},'Imprimer (Facture X)'), ])) ]); }) ) ])) ]) ]); }function Utilisateurs(){ return h('div',{style:box},[h('h3',{style:{marginTop:0}},'Utilisateurs'),h('div',{style:{overflowX:"auto"}},h('table',{style:{width:"100%",minWidth:520,borderCollapse:"collapse"}},[h('thead',null,h('tr',{style:{textAlign:"left"}},[h('th',null,'Nom'),h('th',null,'Email'),h('th',null,'Rôle')])),h('tbody',null,seedUsers.map(u=>h('tr',{key:u.id},[h('td',null,u.name),h('td',null,u.email),h('td',null,u.role)])))]))]); }function App(){ const [session,setSession]=useState(null); const [route,setRoute]=useState("dashboard"); const [missions,setMissions]=useState(seedMissionsInit); const [factures,setFactures]=useState(seedFacturesInit); if(!session) return h(Login,{onLogin:s=>setSession(s)}); return h(Layout,{user:session.user,onLogout:()=>setSession(null),route:route,setRoute:setRoute},[ route==='dashboard'?h(Dashboard,{missions:missions,factures:factures}):null, route==='missions'?h(Missions,{missions:missions,setMissions:setMissions}):null, route==='factures'?h(Factures,{factures:factures,setFactures:setFactures}):null, route==='utilisateurs'?h(Utilisateurs,null):null ]); }const root=ReactDOM.createRoot(document.getElementById('root')); root.render(h(App,null)); })();
Anydesk
Prendre RDV
Coworking
Explore
Glisse