Saharaai commited on
Commit
6f6d171
1 Parent(s): 2b9be59

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +318 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import pdfkit
4
+ from io import BytesIO
5
+ from num2words import num2words
6
+ from datetime import date
7
+
8
+ def montant_en_lettres(montant):
9
+ """Convertit un montant en lettres avec la devise TND."""
10
+ parties = str(montant).split('.')
11
+ dinars = int(parties[0])
12
+ millimes = int(parties[1]) if len(parties) > 1 else 0
13
+
14
+ texte_dinars = num2words(dinars, lang='fr')
15
+ texte_millimes = num2words(millimes, lang='fr') if millimes > 0 else "zéro"
16
+
17
+ resultat = f"{texte_dinars.upper()} DINARS"
18
+ if millimes > 0:
19
+ resultat += f" ET {texte_millimes.upper()} MILLIMES"
20
+
21
+ return resultat
22
+
23
+ def generate_html(data):
24
+ html = f"""
25
+ <html>
26
+ <head>
27
+ <meta charset="UTF-8">
28
+ <style>
29
+ body {{
30
+ font-family: Arial, sans-serif;
31
+ margin: 0;
32
+ padding: 0;
33
+ color: #333;
34
+ background-color: #f4f4f4;
35
+ }}
36
+ .container {{
37
+ width: 210mm;
38
+ margin: 20mm auto;
39
+ padding: 20mm;
40
+ background-color: #fff;
41
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
42
+ }}
43
+ .header {{
44
+ text-align: center;
45
+ margin-bottom: 20px;
46
+ padding: 10px;
47
+ background-color: #2c3e50;
48
+ color: #fff;
49
+ border-radius: 8px;
50
+ }}
51
+ .header h1 {{
52
+ margin: 0;
53
+ font-size: 24px;
54
+ }}
55
+ .header h2 {{
56
+ margin: 5px 0 0 0;
57
+ font-size: 18px;
58
+ }}
59
+ .header p {{
60
+ margin: 5px 0;
61
+ font-size: 14px;
62
+ }}
63
+ .client-info, .invoice-info {{
64
+ margin-bottom: 20px;
65
+ padding: 10px;
66
+ border: 1px solid #ddd;
67
+ border-radius: 8px;
68
+ }}
69
+ .client-info p, .invoice-info p {{
70
+ margin: 0 0 5px;
71
+ }}
72
+ .table {{
73
+ width: 100%;
74
+ border-collapse: collapse;
75
+ margin-bottom: 20px;
76
+ }}
77
+ .table th, .table td {{
78
+ border: 1px solid #ddd;
79
+ padding: 12px;
80
+ text-align: left;
81
+ }}
82
+ .table th {{
83
+ background-color: #2c3e50;
84
+ color: #fff;
85
+ font-weight: bold;
86
+ }}
87
+ .table tr:nth-child(even) {{
88
+ background-color: #f9f9f9;
89
+ }}
90
+ .totals {{
91
+ margin-top: 20px;
92
+ }}
93
+ .totals table {{
94
+ width: 50%;
95
+ float: right;
96
+ border-collapse: collapse;
97
+ }}
98
+ .totals table td {{
99
+ padding: 5px;
100
+ text-align: right;
101
+ border: 1px solid #ddd;
102
+ }}
103
+ .totals table td:first-child {{
104
+ text-align: left;
105
+ font-weight: bold;
106
+ background-color: #f2f2f2;
107
+ }}
108
+ .footer {{
109
+ margin-top: 50px;
110
+ padding: 20px;
111
+ background-color: #2c3e50;
112
+ color: #fff;
113
+ text-align: center;
114
+ border-radius: 8px;
115
+ }}
116
+ .footer p {{
117
+ margin: 5px 0;
118
+ font-size: 14px;
119
+ }}
120
+ .footer .contact {{
121
+ font-size: 16px;
122
+ font-weight: bold;
123
+ }}
124
+ </style>
125
+ </head>
126
+ <body>
127
+ <div class="container">
128
+ <div class="header">
129
+ <h1>STE Standard Waste Management</h1>
130
+ <p>Matricule Fiscal: {data['matricule_fiscal']}</p>
131
+ <h2>FACTURE N° {data['numero_facture']}</h2>
132
+ <p>Date de facturation : {data['date_facturation']}</p>
133
+ </div>
134
+ <div class="client-info">
135
+ <p><strong>Client :</strong> {data['client_nom']}</p>
136
+ <p><strong>Adresse :</strong> {data['client_adresse']}</p>
137
+ <p><strong>MF :</strong> {data['client_mf']}</p>
138
+ </div>
139
+ <div class="invoice-info">
140
+ <p><strong>Condition de paiement :</strong> {data['condition_paiement']} jours</p>
141
+ </div>
142
+ <table class="table">
143
+ <tr>
144
+ <th>DESIGNATION</th>
145
+ <th>QTE</th>
146
+ <th>PRIX UNIT HT</th>
147
+ <th>MONTANT HT</th>
148
+ </tr>
149
+ """
150
+ for article in data['articles']:
151
+ html += f"""
152
+ <tr>
153
+ <td>{article[0]}</td>
154
+ <td>{article[1]}</td>
155
+ <td>{article[2]}</td>
156
+ <td>{article[3]}</td>
157
+ </tr>
158
+ """
159
+
160
+ html += f"""
161
+ </table>
162
+ <div class="totals">
163
+ <table>
164
+ <tr>
165
+ <td>TOTAL HT</td>
166
+ <td>{data['total_ht']:.3f}</td>
167
+ </tr>
168
+ <tr>
169
+ <td>Timbre Fiscal</td>
170
+ <td>{data['timbre_fiscal']:.3f}</td>
171
+ </tr>
172
+ <tr>
173
+ <td>TVA {data['tva_rate']}%</td>
174
+ <td>{data['tva']:.3f}</td>
175
+ </tr>
176
+ <tr>
177
+ <td>TOTAL</td>
178
+ <td>{data['total']:.3f}</td>
179
+ </tr>
180
+ </table>
181
+ </div>
182
+ <p>Arrêtée la présente facture à la somme de : <strong>{montant_en_lettres(data['total'])}</strong></p>
183
+ <div class="footer">
184
+ <p>STE Standard Waste Management est une société qui vise à fidéliser sa clientèle à travers le conditionnement de leur produit</p>
185
+ <p class="contact">Pour plus de renseignements, veuillez contacter : +216 20 798 429</p>
186
+ <p class="contact">Adresse : Sidi Hssine, 1095-Tunis, Tunisie</p>
187
+ </div>
188
+ </div>
189
+ </body>
190
+ </html>
191
+ """
192
+ return html
193
+
194
+
195
+ def main():
196
+ st.set_page_config(page_title="Générateur de Factures", page_icon="📄", layout="wide")
197
+
198
+ st.title("Générateur de Factures - STE Standard Wast Management")
199
+ with st.sidebar.expander("Informations de l'entreprise", expanded=True):
200
+ col1, col2 = st.columns(2)
201
+ with col1:
202
+ matricule_fiscal = st.text_input("Matricule Fiscal", "1568806Q/A/M/000")
203
+ numero_facture = st.text_input("Numéro de Facture", "390")
204
+ with col2:
205
+ date_facturation = st.date_input("Date de Facturation", value=date.today())
206
+ st.sidebar.info("Developped by Ayoub ABRAICH")
207
+
208
+ with st.expander("Informations du client", expanded=True):
209
+ col1, col2 = st.columns(2)
210
+ with col1:
211
+ client_nom = st.text_input("Nom du Client", "STE SABER POUR COLLECT DE DECHET")
212
+ client_adresse = st.text_input("Adresse du Client", "SIDI HSSINE 1095-TUNIS")
213
+ with col2:
214
+ client_mf = st.text_input("MF du Client", "1568806Q/A/M 000")
215
+ condition_paiement = st.number_input("Condition de paiement (jours)", value=45, min_value=0, max_value=365)
216
+
217
+ st.subheader("Détails de la facture")
218
+
219
+ nombre_articles = st.number_input("Nombre d'articles", value=5, min_value=1, step=1)
220
+
221
+ articles = []
222
+ for i in range(nombre_articles):
223
+ with st.expander(f"Article {i+1}", expanded=i == 0):
224
+ col1, col2, col3, col4 = st.columns(4)
225
+ with col1:
226
+ designation = st.text_input(f"Désignation", key=f"des_{i}")
227
+ with col2:
228
+ quantite = st.number_input(f"Quantité", value=0, min_value=0, step=1, key=f"qte_{i}")
229
+ with col3:
230
+ prix_unitaire = st.number_input(f"Prix unitaire HT", value=0.0, min_value=0.0, format="%.3f", key=f"prix_{i}")
231
+ with col4:
232
+ montant_ht = quantite * prix_unitaire
233
+ st.metric(f"Montant HT", f"{montant_ht:.3f}")
234
+
235
+ if designation and quantite > 0 and prix_unitaire > 0:
236
+ articles.append([designation, quantite, f"{prix_unitaire:.3f}", f"{montant_ht:.3f}"])
237
+
238
+ total_ht = sum(float(article[3]) for article in articles)
239
+
240
+ with st.expander("Calculs finaux", expanded=True):
241
+ col1, col2, col3 = st.columns(3)
242
+ with col1:
243
+ timbre_fiscal = st.number_input("Timbre Fiscal", value=1.000, min_value=0.0, format="%.3f")
244
+ with col2:
245
+ tva_rate = st.number_input("Taux de TVA (%)", value=19, min_value=0, max_value=100)
246
+ with col3:
247
+ tva = total_ht * (tva_rate / 100)
248
+ total = total_ht + timbre_fiscal + tva
249
+ st.metric("Total", f"{total:.3f}")
250
+
251
+ st.write(f"Total HT: {total_ht:.3f}")
252
+ st.write(f"TVA: {tva:.3f}")
253
+ st.write(f"Total: {total:.3f}")
254
+
255
+ total_en_lettres = montant_en_lettres(total)
256
+ st.info(f"Total en lettres: {total_en_lettres}")
257
+
258
+ data = {
259
+ 'matricule_fiscal': matricule_fiscal,
260
+ 'numero_facture': numero_facture,
261
+ 'date_facturation': date_facturation.strftime("%d/%m/%Y"),
262
+ 'client_nom': client_nom,
263
+ 'client_adresse': client_adresse,
264
+ 'client_mf': client_mf,
265
+ 'condition_paiement': condition_paiement,
266
+ 'articles': articles,
267
+ 'total_ht': total_ht,
268
+ 'timbre_fiscal': timbre_fiscal,
269
+ 'tva_rate': tva_rate,
270
+ 'tva': tva,
271
+ 'total': total
272
+ }
273
+
274
+ col1, col2 = st.columns(2)
275
+ with col1:
276
+ if st.button("Générer PDF", type="primary"):
277
+ html = generate_html(data)
278
+ pdf = pdfkit.from_string(html, False)
279
+ st.download_button(
280
+ label="Télécharger le PDF",
281
+ data=pdf,
282
+ file_name=f"facture_{numero_facture}.pdf",
283
+ mime="application/pdf"
284
+ )
285
+
286
+ with col2:
287
+ if st.button("Générer Excel", type="primary"):
288
+ df = pd.DataFrame(data['articles'], columns=["DESIGNATION", "QTE", "PRIX UNIT HT", "MONTANT HT"])
289
+ df.loc["TOTAL HT"] = ["", "", "", total_ht]
290
+ df.loc["TVA"] = ["", "", f"{tva_rate}%", tva]
291
+ df.loc["TIMBRE FISCAL"] = ["", "", "", timbre_fiscal]
292
+ df.loc["TOTAL GENERAL"] = ["", "", "", total]
293
+
294
+ output = BytesIO()
295
+ with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
296
+ df.to_excel(writer, index=True, sheet_name='Facture')
297
+ workbook = writer.book
298
+ worksheet = writer.sheets['Facture']
299
+
300
+ # Formatting
301
+ money_fmt = workbook.add_format({'num_format': '#,##0.000'})
302
+ header_fmt = workbook.add_format({'bold': True, 'bg_color': '#D9D9D9'})
303
+
304
+ worksheet.set_column('A:A', 30)
305
+ worksheet.set_column('B:D', 15, money_fmt)
306
+ worksheet.set_row(0, None, header_fmt)
307
+
308
+ output.seek(0)
309
+
310
+ st.download_button(
311
+ label="Télécharger Excel",
312
+ data=output,
313
+ file_name=f"facture_{numero_facture}.xlsx",
314
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
315
+ )
316
+
317
+ if __name__ == "__main__":
318
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ pandas
3
+ pdfkit
4
+ num2words
5
+ xlsxwriter