pasquale991 commited on
Commit
5049b40
·
verified ·
1 Parent(s): 84b8a87

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +157 -63
src/streamlit_app.py CHANGED
@@ -1,116 +1,199 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import json
4
- from datetime import datetime
5
  import io
6
  import os
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  # Funzione di conversione
9
- def convert_json_to_excel_data(json_file_content: str, sheet_name: str = 'Dati Ordine'):
10
  try:
11
  json_data = json.loads(json_file_content)
12
 
13
- channel = json_data.get('channel')
14
  company_code = json_data.get('companyCode')
15
- site_code = json_data.get('siteCode')
16
-
17
  order_info = json_data.get('order', {})
18
- order_number = order_info.get('orderNumber')
19
- order_date_str = order_info.get('orderDate')
20
  partner_code = order_info.get('partnerCode')
21
 
 
 
22
  order_date_formatted = None
23
  if order_date_str:
24
  try:
25
  dt_object = datetime.fromisoformat(order_date_str.replace('Z', '+00:00'))
26
  order_date_formatted = dt_object.strftime('%d/%m/%Y')
27
  except ValueError:
28
- st.warning(f"Attenzione: Impossibile parsare la data '{order_date_str}'. Verrà usata la stringa originale.")
29
- order_date_formatted = order_date_str
30
 
31
  details = order_info.get('details', [])
32
 
33
- processed_data = []
34
  for item in details:
35
  row = {
36
- 'Site': site_code,
37
- 'Data': order_date_formatted,
38
- 'Company': company_code,
39
- 'Furniture': partner_code,
40
- 'Stato': 'CREATED',
41
- 'Posizione': item.get('positionId'),
42
- 'Stato. Articolo': None,
43
- 'Codice Articolo': item.get('itemCode'),
44
- 'Quantità': item.get('quantity'),
45
- 'Proprietario': item.get('stockOwner'),
46
- 'Centro di Costo': item.get('warehouse'),
47
- 'Disponibilità': item.get('availability'),
48
- 'RefOrder': item.get('refOrder'),
49
- 'ReasonCO': item.get('reasonCode'),
50
- 'CancelPosOdA': False if item.get('cancelPosOdA') is None else bool(item.get('cancelPosOdA'))
51
  }
52
- processed_data.append(row)
53
 
54
- if not processed_data:
55
- st.error("Nessun dato di dettaglio trovato per la conversione. Assicurati che il JSON contenga 'order.details'.")
56
- return None
57
 
58
- df = pd.DataFrame(processed_data)
59
- return df
60
 
61
- except json.JSONDecodeError:
62
- st.error(f"Errore: Il contenuto del file non è un JSON valido.")
63
- return None
64
  except KeyError as ke:
65
  st.error(f"Errore: Chiave JSON mancante o struttura inattesa: {ke}. Assicurati che il JSON abbia la struttura attesa (es. 'order.details').")
66
  return None
67
  except Exception as e:
68
- st.error(f"Si è verificato un errore durante la conversione: {e}")
69
  return None
70
 
71
  # --- Interfaccia Streamlit ---
72
- st.title("Convertitore JSON a Excel Ordini")
73
- st.write("Carica il tuo file JSON degli ordini e scarica il foglio Excel formattato.")
74
-
75
- uploaded_file = st.file_uploader("Scegli un file JSON", type=["json"])
76
 
77
- if uploaded_file is not None:
78
- file_name = uploaded_file.name
79
- _, file_extension = os.path.splitext(file_name)
80
 
81
- if file_extension.lower() != '.json':
82
- st.error("Per favore, carica un file con estensione .json.")
83
- else:
84
- json_content_bytes = uploaded_file.read()
85
- json_content_string = json_content_bytes.decode('utf-8')
86
 
87
- st.info(f"File '{file_name}' caricato. Tentativo di conversione...")
88
 
89
- df_output = convert_json_to_excel_data(json_content_string)
90
-
91
- if df_output is not None:
92
- st.success("Conversione completata!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  output = io.BytesIO()
95
  writer = pd.ExcelWriter(output, engine='xlsxwriter')
96
- df_output.to_excel(writer, sheet_name='Dati Ordine', index=False)
 
 
97
 
98
  workbook = writer.book
99
- worksheet = writer.sheets['Dati Ordine']
100
 
101
  header_format = workbook.add_format({
102
- 'bold': True, 'font_color': '#FFFFFF', 'bg_color': '#4F81BD',
103
  'align': 'center', 'valign': 'vcenter', 'border': 1
104
  })
105
 
106
  col_widths = {
107
- 'Site': 10, 'Data': 12, 'Company': 15, 'Furniture': 15, 'Stato': 10,
108
- 'Posizione': 10, 'Stato. Articolo': 15, 'Codice Articolo': 25,
109
- 'Quantità': 10, 'Proprietario': 15, 'Centro di Costo': 15,
110
- 'Disponibilità': 15, 'RefOrder': 15, 'ReasonCO': 10, 'CancelPosOdA': 15
 
 
 
 
 
111
  }
112
-
113
- for col_num, col_name in enumerate(df_output.columns.values):
114
  worksheet.write(0, col_num, col_name, header_format)
115
  if col_name in col_widths:
116
  worksheet.set_column(col_num, col_num, col_widths[col_name])
@@ -120,12 +203,23 @@ if uploaded_file is not None:
120
  writer.close()
121
  output.seek(0)
122
 
 
 
 
 
123
  st.download_button(
124
- label="Scarica file Excel",
125
  data=output.getvalue(),
126
- file_name="ordine_convertito.xlsx",
127
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
128
  )
 
 
 
 
 
 
129
 
130
  st.markdown("---")
 
131
  st.markdown("Sviluppato con Streamlit e Python.")
 
1
  import streamlit as st
2
  import pandas as pd
3
  import json
4
+ from datetime import datetime # Importa datetime
5
  import io
6
  import os
7
 
8
+ # --- CSS personalizzato per sfondo giallo e testo blu ---
9
+ st.markdown(
10
+ """
11
+ <style>
12
+ /* Colore di sfondo dell'intera app (giallo) */
13
+ .stApp {
14
+ background-color: #FFFFCC; /* Giallo pastello, puoi cambiare il codice esadecimale */
15
+ background-attachment: fixed;
16
+ }
17
+ /* Colore per i titoli (blu) */
18
+ h1, h2 {
19
+ color: #1E90FF; /* Blu acceso */
20
+ }
21
+ /* Colore per il testo normale e le etichette (blu scuro/navy) */
22
+ p, label {
23
+ color: #000080; /* Blu scuro */
24
+ }
25
+ /* Stili per i bottoni (per coerenza) */
26
+ .stButton>button {
27
+ color: white;
28
+ background-color: #1E90FF; /* Blu acceso */
29
+ border: none;
30
+ border-radius: 5px;
31
+ padding: 10px 20px;
32
+ font-size: 16px;
33
+ }
34
+ .stButton>button:hover {
35
+ background-color: #4169E1; /* Blu medio al passaggio del mouse */
36
+ }
37
+ </style>
38
+ """,
39
+ unsafe_allow_html=True # Necessario per iniettare CSS
40
+ )
41
+
42
+
43
  # Funzione di conversione
44
+ def convert_json_to_excel_data(json_file_content: str):
45
  try:
46
  json_data = json.loads(json_file_content)
47
 
48
+ # Preleviamo companyCode e partnerCode dal JSON
49
  company_code = json_data.get('companyCode')
 
 
50
  order_info = json_data.get('order', {})
 
 
51
  partner_code = order_info.get('partnerCode')
52
 
53
+ order_date_str = order_info.get('orderDate')
54
+
55
  order_date_formatted = None
56
  if order_date_str:
57
  try:
58
  dt_object = datetime.fromisoformat(order_date_str.replace('Z', '+00:00'))
59
  order_date_formatted = dt_object.strftime('%d/%m/%Y')
60
  except ValueError:
61
+ order_date_formatted = order_date_str # Usiamo la stringa originale
62
+ st.warning(f"Attenzione: Impossibile parsare la data '{order_date_str}' per un file. Verrà usata la stringa originale.")
63
 
64
  details = order_info.get('details', [])
65
 
66
+ processed_data_for_this_file = []
67
  for item in details:
68
  row = {
69
+ # site.code sarà fornito dall'interfaccia utente
70
+ 'company.code': company_code,
71
+ 'supplier.partnerRef.code': partner_code,
72
+ 'docDate': order_date_formatted,
73
+ 'status': 'CREATED', # Colonna 'status' hardcoded a 'CREATED'
74
+ 'positions.status': 'CREATED', # Colonna 'positions.status' hardcoded a 'CREATED'
75
+ 'positions.positionId': item.get('positionId'),
76
+ 'positions.stock.item.itemNumber': item.get('itemCode'),
77
+ 'positions.stock.quantity': item.get('quantity'),
78
+ 'positions.stock.accountingInfo.stockOwner': item.get('stockOwner'),
79
+ 'positions.stock.accountingInfo.costCenter': item.get('warehouse'),
80
+ 'positions.stock.accountingInfo.availability': item.get('availability'),
81
+ 'positions.stock.refOrder': item.get('refOrder'),
82
+ 'positions.stock.reasonCode': item.get('reasonCode'),
83
+ 'positions.stock.cancelPosOda': False if item.get('cancelPosOdA') is None else bool(item.get('cancelPosOdA'))
84
  }
85
+ processed_data_for_this_file.append(row)
86
 
87
+ if not processed_data_for_this_file:
88
+ return pd.DataFrame() # Restituisce un DataFrame vuoto per questo file
 
89
 
90
+ return pd.DataFrame(processed_data_for_this_file)
 
91
 
92
+ except json.JSONDecodeError as e:
93
+ st.error(f"Errore nel file JSON: {e}. Assicurati che il contenuto sia un JSON valido.")
94
+ return None # Ritorna None in caso di errore critico
95
  except KeyError as ke:
96
  st.error(f"Errore: Chiave JSON mancante o struttura inattesa: {ke}. Assicurati che il JSON abbia la struttura attesa (es. 'order.details').")
97
  return None
98
  except Exception as e:
99
+ st.error(f"Si è verificato un errore generico durante la conversione di un file JSON: {e}")
100
  return None
101
 
102
  # --- Interfaccia Streamlit ---
103
+ st.title("Convertitore JSON Oda a Template Excel Oda")
104
+ st.write("Carica i tuoi file JSON degli ordini ODA e scarica il foglio Excel formattato.")
 
 
105
 
106
+ # Sezione per l'input del solo siteCode
107
+ st.header("1. Qual è il Site Code? Inseriscilo qui:")
108
+ user_site_code = st.text_input("Site Code", key="site_code_input")
109
 
110
+ st.header("2. Carica i tuoi file JSON")
111
+ # Permette di caricare più file
112
+ uploaded_files = st.file_uploader("Scegli uno o più file JSON per lo stesso siteCode di tipo 'Ordine_Acquisto'", type=["json"], accept_multiple_files=True)
 
 
113
 
114
+ all_processed_data = [] # Lista per contenere tutti i DataFrame processati
115
 
116
+ if uploaded_files:
117
+ # Controlliamo che il campo siteCode sia riempito prima di procedere
118
+ if not user_site_code:
119
+ st.warning("Per favor, compila il campo 'Site Code' prima di caricare i file.")
120
+ else:
121
+ st.info(f"Caricati {len(uploaded_files)} file. Elaborazione in corso...")
122
+
123
+ conversion_successful = True # Variabile per tracciare se ci sono stati errori
124
+
125
+ for uploaded_file in uploaded_files:
126
+ file_name = uploaded_file.name
127
+
128
+ # Verifica che il nome del file inizi con "Ordine_Acquisto"
129
+ if not file_name.lower().startswith("ordine_acquisto"):
130
+ st.error(f"Errore: Il file '{file_name}' non inizia con 'Ordine_Acquisto'. Verrà ignorato.")
131
+ conversion_successful = False
132
+ continue # Passa al prossimo file
133
+
134
+ try:
135
+ json_content_bytes = uploaded_file.read()
136
+ json_content_string = json_content_bytes.decode('utf-8')
137
+
138
+ df_this_file = convert_json_to_excel_data(json_content_string)
139
+
140
+ if df_this_file is not None:
141
+ # Aggiungi il valore siteCode fornito dall'utente a questo DataFrame
142
+ df_this_file['site.code'] = user_site_code
143
+
144
+ # Riordina le colonne per avere i nuovi nomi nell'ordine corretto
145
+ final_columns_order = [
146
+ 'site.code', 'docDate', 'company.code', 'supplier.partnerRef.code',
147
+ 'status',
148
+ 'positions.status', 'positions.positionId',
149
+ 'positions.stock.item.itemNumber', 'positions.stock.quantity',
150
+ 'positions.stock.accountingInfo.stockOwner',
151
+ 'positions.stock.accountingInfo.costCenter', 'positions.stock.accountingInfo.availability',
152
+ 'positions.stock.refOrder', 'positions.stock.reasonCode', 'positions.stock.cancelPosOda'
153
+ ]
154
+
155
+ cols_present_and_ordered = [col for col in final_columns_order if col in df_this_file.columns]
156
+ df_this_file = df_this_file[cols_present_and_ordered]
157
+
158
+ all_processed_data.append(df_this_file)
159
+ else:
160
+ conversion_successful = False
161
+ st.error(f"Impossibile convertire il file '{file_name}'. Controlla i log per i dettagli.")
162
+ except Exception as e:
163
+ st.error(f"Si è verificato un errore imprevisto durante la lettura o l'elaborazione del file '{file_name}': {e}")
164
+ conversion_successful = False
165
+
166
+ if all_processed_data:
167
+ final_df = pd.concat(all_processed_data, ignore_index=True)
168
+ st.success(f"Elaborazione di {len(all_processed_data)} file JSON completata! Pronto per il download.")
169
 
170
  output = io.BytesIO()
171
  writer = pd.ExcelWriter(output, engine='xlsxwriter')
172
+
173
+ sheet_name_excel = 'PurchaseOrder'
174
+ final_df.to_excel(writer, sheet_name=sheet_name_excel, index=False)
175
 
176
  workbook = writer.book
177
+ worksheet = writer.sheets[sheet_name_excel]
178
 
179
  header_format = workbook.add_format({
180
+ 'bold': True, 'font_color': '#FFFFFF', 'bg_color': '#1E90FF', # Blu acceso
181
  'align': 'center', 'valign': 'vcenter', 'border': 1
182
  })
183
 
184
  col_widths = {
185
+ 'site.code': 10, 'docDate': 12, 'company.code': 15, 'supplier.partnerRef.code': 18,
186
+ 'status': 10,
187
+ 'positions.status': 12, 'positions.positionId': 12,
188
+ 'positions.stock.item.itemNumber': 25, 'positions.stock.quantity': 10,
189
+ 'positions.stock.accountingInfo.stockOwner': 18,
190
+ 'positions.stock.accountingInfo.costCenter': 18,
191
+ 'positions.stock.accountingInfo.availability': 15,
192
+ 'positions.stock.refOrder': 15, 'positions.stock.reasonCode': 15,
193
+ 'positions.stock.cancelPosOda': 18
194
  }
195
+
196
+ for col_num, col_name in enumerate(final_df.columns.values):
197
  worksheet.write(0, col_num, col_name, header_format)
198
  if col_name in col_widths:
199
  worksheet.set_column(col_num, col_num, col_widths[col_name])
 
203
  writer.close()
204
  output.seek(0)
205
 
206
+ # Genera il timestamp attuale e formatta il nome del file
207
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
208
+ output_file_name = f"PurchaseOrder_{timestamp}.xlsx"
209
+
210
  st.download_button(
211
+ label="Scarica file Excel Unificato",
212
  data=output.getvalue(),
213
+ file_name=output_file_name, # Usa il nome del file con timestamp
214
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
215
  )
216
+ elif not conversion_successful:
217
+ st.error("Nessun file valido è stato elaborato con successo. Controlla i messaggi di errore sopra.")
218
+ else:
219
+ st.info("Nessun dato valido estratto dai file selezionati.")
220
+ else:
221
+ st.info("Carica i tuoi file JSON per iniziare. I file devono essere della stessa tipologia!")
222
 
223
  st.markdown("---")
224
+ st.markdown("Buona Fortuna")
225
  st.markdown("Sviluppato con Streamlit e Python.")