leadingbridge commited on
Commit
8c03e92
·
verified ·
1 Parent(s): 57d62a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -28
app.py CHANGED
@@ -6,6 +6,7 @@ from huggingface_hub import hf_hub_download
6
  import tempfile
7
  import os, re
8
  from collections import defaultdict
 
9
 
10
  HF_DATASET_REPO = "leadingbridge/ammu"
11
  TEMPLATE_FILENAME = "AMMU-order-form-template.xlsx"
@@ -63,6 +64,17 @@ def _download_template():
63
  repo_id=HF_DATASET_REPO, filename=TEMPLATE_FILENAME, repo_type="dataset"
64
  )
65
 
 
 
 
 
 
 
 
 
 
 
 
66
  def process(input_file):
67
  try:
68
  if input_file is None:
@@ -71,6 +83,11 @@ def process(input_file):
71
  # --- INPUT: detect headers by name ---
72
  wb_in = load_workbook(input_file.name, data_only=True)
73
  ws_in = wb_in.active
 
 
 
 
 
74
  header_row_idx, header_map = _find_header_row(
75
  ws_in, {"SKU", "Product Option Value", "Quantity"}
76
  )
@@ -78,7 +95,6 @@ def process(input_file):
78
  col_pov = header_map["product option value"]
79
  col_qty = header_map["quantity"]
80
 
81
- in_max_col = ws_in.max_column
82
  header_values = [ws_in.cell(row=header_row_idx, column=c).value for c in range(1, in_max_col + 1)]
83
 
84
  entries = []
@@ -123,10 +139,12 @@ def process(input_file):
123
 
124
  for r in range(1, 11):
125
  row_vals = [ws_out.cell(row=r, column=c).value for c in range(1, ws_out.max_column + 1)]
 
126
  for c, v in enumerate(row_vals, start=1):
127
  if isinstance(v, str) and v.strip().lower() == "my sku":
128
  mysku_header_row = r
129
  mysku_col_idx = c
 
130
  labels = {}
131
  for c, v in enumerate(row_vals, start=1):
132
  if isinstance(v, str):
@@ -136,6 +154,7 @@ def process(input_file):
136
  if len(labels) >= 5 and power_label_row is None:
137
  power_label_row = r
138
  power_col_map = labels
 
139
  trip = {}
140
  for c, v in enumerate(row_vals, start=1):
141
  if isinstance(v, str) and re.fullmatch(r"\d{2,3}", v.strip()):
@@ -145,10 +164,11 @@ def process(input_file):
145
  triplet_col_map = trip
146
 
147
  if mysku_header_row is None or mysku_col_idx is None:
148
- raise ValueError("Could not find the 'MY SKU' header in the template.")
149
  if not (power_label_row or triplet_row):
150
- raise ValueError("Could not find power-column headers in the template.")
151
 
 
152
  sku_to_row = {}
153
  for r in range(mysku_header_row + 1, ws_out.max_row + 1):
154
  val = ws_out.cell(row=r, column=mysku_col_idx).value
@@ -156,6 +176,7 @@ def process(input_file):
156
  continue
157
  sku_to_row[str(val).strip()] = r
158
 
 
159
  agg = defaultdict(int)
160
  unmatched_rows = []
161
 
@@ -177,6 +198,7 @@ def process(input_file):
177
  continue
178
  agg[(sku, power)] += qty
179
 
 
180
  written_count = 0
181
  for (sku, power), qty in agg.items():
182
  row_idx = sku_to_row.get(sku)
@@ -199,40 +221,49 @@ def process(input_file):
199
  ws_out.cell(row=row_idx, column=col_idx).value = current_val + int(qty)
200
  written_count += 1
201
 
202
- # --- Create the "additional order" tab ---
203
- sheet_name = "additional order"
204
- if sheet_name in wb_out.sheetnames:
205
- wb_out.remove(wb_out[sheet_name])
206
- ws_extra = wb_out.create_sheet(title=sheet_name)
207
 
208
- # Write header
209
  for c, val in enumerate(header_values, start=1):
210
- ws_extra.cell(row=1, column=c).value = val
211
- # Write unmatched rows
212
  for i, row_vals in enumerate(unmatched_rows, start=2):
213
  for c, val in enumerate(row_vals, start=1):
214
- ws_extra.cell(row=i, column=c).value = val
215
-
216
- # --- Auto adjust column widths ---
217
- for c in range(1, in_max_col + 1):
218
- max_len = 0
219
- col_letter = get_column_letter(c)
220
- for r in range(1, len(unmatched_rows) + 2): # +1 header
221
- val = ws_extra.cell(row=r, column=c).value
222
- if val is not None:
223
- max_len = max(max_len, len(str(val)))
224
- ws_extra.column_dimensions[col_letter].width = max_len + 2 # padding
225
-
226
- # Save output
 
 
 
 
 
 
 
227
  tmpdir = tempfile.mkdtemp()
228
- out_path = os.path.join(tmpdir, "AMMU-order-form-FILLED.xlsx")
 
229
  wb_out.save(out_path)
230
 
231
  log_lines = [
232
  f"Rows scanned in input: {rows_scanned}",
233
  f"Unique matched (SKU, power) pairs aggregated: {len(agg)}",
234
  f"Entries written into template: {written_count}",
235
- f"Unmatched rows copied to '{sheet_name}': {len(unmatched_rows)}",
 
 
236
  ]
237
  log = "\n".join(log_lines)
238
  return out_path, log
@@ -246,7 +277,9 @@ with gr.Blocks(title="AMMU Order Form Filler") as demo:
246
  "• Uses **MY SKU** column to map rows\n"
247
  "• Matches power columns (text like `-1.25` or fallback triplets like `125`)\n"
248
  "• Aggregates quantities for matched lines\n"
249
- "• Copies **unmatched lines** to new sheet **`additional order`**, with auto column width"
 
 
250
  )
251
  with gr.Row():
252
  in_file = gr.File(label="Upload input Excel (.xlsx)", file_types=[".xlsx"])
@@ -254,7 +287,7 @@ with gr.Blocks(title="AMMU Order Form Filler") as demo:
254
  run_btn = gr.Button("Process")
255
  with gr.Row():
256
  out_file = gr.File(label="Download filled template (.xlsx)")
257
- log_box = gr.Textbox(label="Log", lines=10)
258
 
259
  run_btn.click(fn=process, inputs=in_file, outputs=[out_file, log_box])
260
 
 
6
  import tempfile
7
  import os, re
8
  from collections import defaultdict
9
+ from datetime import datetime
10
 
11
  HF_DATASET_REPO = "leadingbridge/ammu"
12
  TEMPLATE_FILENAME = "AMMU-order-form-template.xlsx"
 
64
  repo_id=HF_DATASET_REPO, filename=TEMPLATE_FILENAME, repo_type="dataset"
65
  )
66
 
67
+ def _auto_fit_columns(ws: Worksheet, max_col: int, max_row: int):
68
+ # Width = longest string in column + small padding
69
+ for c in range(1, max_col + 1):
70
+ max_len = 0
71
+ col_letter = get_column_letter(c)
72
+ for r in range(1, max_row + 1):
73
+ val = ws.cell(row=r, column=c).value
74
+ if val is not None:
75
+ max_len = max(max_len, len(str(val)))
76
+ ws.column_dimensions[col_letter].width = max(10, max_len + 2)
77
+
78
  def process(input_file):
79
  try:
80
  if input_file is None:
 
83
  # --- INPUT: detect headers by name ---
84
  wb_in = load_workbook(input_file.name, data_only=True)
85
  ws_in = wb_in.active
86
+
87
+ # Copy ALL input (for "raw data" sheet later)
88
+ in_max_row = ws_in.max_row
89
+ in_max_col = ws_in.max_column
90
+
91
  header_row_idx, header_map = _find_header_row(
92
  ws_in, {"SKU", "Product Option Value", "Quantity"}
93
  )
 
95
  col_pov = header_map["product option value"]
96
  col_qty = header_map["quantity"]
97
 
 
98
  header_values = [ws_in.cell(row=header_row_idx, column=c).value for c in range(1, in_max_col + 1)]
99
 
100
  entries = []
 
139
 
140
  for r in range(1, 11):
141
  row_vals = [ws_out.cell(row=r, column=c).value for c in range(1, ws_out.max_column + 1)]
142
+ # "MY SKU" header
143
  for c, v in enumerate(row_vals, start=1):
144
  if isinstance(v, str) and v.strip().lower() == "my sku":
145
  mysku_header_row = r
146
  mysku_col_idx = c
147
+ # textual power labels
148
  labels = {}
149
  for c, v in enumerate(row_vals, start=1):
150
  if isinstance(v, str):
 
154
  if len(labels) >= 5 and power_label_row is None:
155
  power_label_row = r
156
  power_col_map = labels
157
+ # numeric triplets
158
  trip = {}
159
  for c, v in enumerate(row_vals, start=1):
160
  if isinstance(v, str) and re.fullmatch(r"\d{2,3}", v.strip()):
 
164
  triplet_col_map = trip
165
 
166
  if mysku_header_row is None or mysku_col_idx is None:
167
+ raise ValueError("Could not find the 'MY SKU' header in the template (rows 1–10).")
168
  if not (power_label_row or triplet_row):
169
+ raise ValueError("Could not find power-column headers in the template (rows 1–10).")
170
 
171
+ # Build SKU -> row map
172
  sku_to_row = {}
173
  for r in range(mysku_header_row + 1, ws_out.max_row + 1):
174
  val = ws_out.cell(row=r, column=mysku_col_idx).value
 
176
  continue
177
  sku_to_row[str(val).strip()] = r
178
 
179
+ # Classify entries and aggregate matches
180
  agg = defaultdict(int)
181
  unmatched_rows = []
182
 
 
198
  continue
199
  agg[(sku, power)] += qty
200
 
201
+ # Write aggregated matches
202
  written_count = 0
203
  for (sku, power), qty in agg.items():
204
  row_idx = sku_to_row.get(sku)
 
221
  ws_out.cell(row=row_idx, column=col_idx).value = current_val + int(qty)
222
  written_count += 1
223
 
224
+ # --- "additional order" tab with unmatched rows ---
225
+ add_name = "additional order"
226
+ if add_name in wb_out.sheetnames:
227
+ wb_out.remove(wb_out[add_name])
228
+ ws_add = wb_out.create_sheet(title=add_name)
229
 
230
+ # header + rows
231
  for c, val in enumerate(header_values, start=1):
232
+ ws_add.cell(row=1, column=c).value = val
 
233
  for i, row_vals in enumerate(unmatched_rows, start=2):
234
  for c, val in enumerate(row_vals, start=1):
235
+ ws_add.cell(row=i, column=c).value = val
236
+
237
+ # Auto-fit additional order
238
+ _auto_fit_columns(ws_add, max_col=in_max_col, max_row=len(unmatched_rows) + 1)
239
+
240
+ # --- "raw data" tab with ALL input copied verbatim ---
241
+ raw_name = "raw data"
242
+ if raw_name in wb_out.sheetnames:
243
+ wb_out.remove(wb_out[raw_name])
244
+ ws_raw = wb_out.create_sheet(title=raw_name)
245
+
246
+ for r in range(1, in_max_row + 1):
247
+ for c in range(1, in_max_col + 1):
248
+ ws_raw.cell(row=r, column=c).value = ws_in.cell(row=r, column=c).value
249
+
250
+ # Auto-fit raw data
251
+ _auto_fit_columns(ws_raw, max_col=in_max_col, max_row=in_max_row)
252
+
253
+ # --- Save output with date-based filename ---
254
+ yymmdd = datetime.now().strftime("%y%m%d")
255
  tmpdir = tempfile.mkdtemp()
256
+ out_filename = f"AMMU-Order-Form-Leading-Bridge-{yymmdd}.xlsx"
257
+ out_path = os.path.join(tmpdir, out_filename)
258
  wb_out.save(out_path)
259
 
260
  log_lines = [
261
  f"Rows scanned in input: {rows_scanned}",
262
  f"Unique matched (SKU, power) pairs aggregated: {len(agg)}",
263
  f"Entries written into template: {written_count}",
264
+ f"Unmatched rows copied to 'additional order': {len(unmatched_rows)}",
265
+ f"Raw data sheet rows x cols: {in_max_row} x {in_max_col}",
266
+ f"Output file: {out_filename}",
267
  ]
268
  log = "\n".join(log_lines)
269
  return out_path, log
 
277
  "• Uses **MY SKU** column to map rows\n"
278
  "• Matches power columns (text like `-1.25` or fallback triplets like `125`)\n"
279
  "• Aggregates quantities for matched lines\n"
280
+ "• Copies **unmatched lines** to **`additional order`** (auto-fit columns)\n"
281
+ "• Copies **entire input** to **`raw data`** (auto-fit columns)\n"
282
+ "• Exports as **AMMU-Order-Form-Leading-Bridge-YYMMDD.xlsx**"
283
  )
284
  with gr.Row():
285
  in_file = gr.File(label="Upload input Excel (.xlsx)", file_types=[".xlsx"])
 
287
  run_btn = gr.Button("Process")
288
  with gr.Row():
289
  out_file = gr.File(label="Download filled template (.xlsx)")
290
+ log_box = gr.Textbox(label="Log", lines=12)
291
 
292
  run_btn.click(fn=process, inputs=in_file, outputs=[out_file, log_box])
293