Spaces:
Running on Zero
Running on Zero
Update processor.py
Browse files- processor.py +163 -270
processor.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
import streamlit as st
|
| 2 |
import openpyxl
|
| 3 |
import pdfplumber
|
| 4 |
import re
|
|
@@ -10,289 +9,183 @@ from parser_bkt import extract_bkt_items
|
|
| 10 |
from parser_polycab import extract_polycab_items, map_polycab_items_to_excel_dynamic
|
| 11 |
from parser_vapi_welspun import extract_vapi_welspun_items, map_vapi_welspun_items_to_excel_dynamic
|
| 12 |
|
| 13 |
-
from shipper_data import fetch_data_from_google_sheet, ensure_default_shipper
|
| 14 |
from pdf_engine import apply_rule_filter, extract_header_value
|
| 15 |
from google_sheet_sync import load_template_from_sheet
|
| 16 |
from supporting_engine import extract_data_from_supporting_file
|
| 17 |
|
| 18 |
-
def
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
if shippers_list:
|
| 28 |
-
selected_shipper = st.selectbox(
|
| 29 |
-
"किस शिपर का इनवॉइस प्रोसेस करना है?",
|
| 30 |
-
shippers_list,
|
| 31 |
-
index=None,
|
| 32 |
-
placeholder="शिपर का नाम टाइप करें या चुनें..."
|
| 33 |
-
)
|
| 34 |
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
st.subheader("📑 Upload Invoices & Supporting Documents")
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
st.write("---")
|
| 73 |
-
|
| 74 |
-
valid_batches = [b for b in uploaded_batches if b[1] is not None]
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
st.session_state["cached_pdf_bytes"] = file_bytes_cache
|
| 104 |
-
|
| 105 |
-
file_name_lower = inv_file.name.lower()
|
| 106 |
-
if file_name_lower.endswith(".pdf"):
|
| 107 |
-
with pdfplumber.open(BytesIO(st.session_state["cached_pdf_bytes"])) as pdf:
|
| 108 |
-
for page in pdf.pages:
|
| 109 |
-
t = page.extract_text()
|
| 110 |
-
if t:
|
| 111 |
-
pdf_text += t + "\n"
|
| 112 |
-
pdf_lines.extend(t.split("\n"))
|
| 113 |
-
else:
|
| 114 |
-
excel_text, _ = extract_data_from_supporting_file(inv_file)
|
| 115 |
-
if excel_text:
|
| 116 |
-
pdf_text = excel_text
|
| 117 |
-
pdf_lines = excel_text.split("\n")
|
| 118 |
-
|
| 119 |
-
gst_text, _ = extract_data_from_supporting_file(gst_file) if gst_file else ("", None)
|
| 120 |
-
deec_text, _ = extract_data_from_supporting_file(deec_file) if deec_file else ("", None)
|
| 121 |
-
|
| 122 |
-
current_inv_number = f"INV_{inv_sr_number}"
|
| 123 |
-
current_inv_date = ""
|
| 124 |
-
inv_data_dict = {}
|
| 125 |
-
|
| 126 |
-
summary_row = 1 + inv_sr_number
|
| 127 |
-
|
| 128 |
-
for field, r_info in rules.items():
|
| 129 |
-
kw = r_info.get("keyword", "").strip()
|
| 130 |
-
if kw.startswith("'") and len(kw) > 1:
|
| 131 |
-
kw = kw[1:].strip()
|
| 132 |
-
|
| 133 |
-
pos = r_info.get("position", "Right (आगे)")
|
| 134 |
-
target_cell = r_info.get("cell", "").strip().upper()
|
| 135 |
-
mode = r_info.get("match_mode", "Exact Word")
|
| 136 |
-
stop_kw = r_info.get("stop_kw", "").strip()
|
| 137 |
-
flt = r_info.get("filter", "None")
|
| 138 |
-
fallback_val = r_info.get("fallback", "").strip()
|
| 139 |
-
doc_source = r_info.get("logic", "Main Invoice")
|
| 140 |
-
|
| 141 |
-
extracted_logic = r_info.get("extracted_logic", "").strip()
|
| 142 |
-
found_val = None
|
| 143 |
-
|
| 144 |
-
target_lines, target_full_text = pdf_lines, pdf_text
|
| 145 |
-
if "gst" in doc_source.lower() and gst_file:
|
| 146 |
-
target_lines = gst_text.split("\n")
|
| 147 |
-
target_full_text = gst_text
|
| 148 |
-
elif "deec" in doc_source.lower() and deec_file:
|
| 149 |
-
target_lines = deec_text.split("\n")
|
| 150 |
-
target_full_text = deec_text
|
| 151 |
-
|
| 152 |
-
# 🚀 मजबूत और क्लीन रेजेक्स एक्सेक्यूशन (Markdown और एस्केप न्यूलाइन फिक्स के साथ)
|
| 153 |
-
if extracted_logic:
|
| 154 |
-
try:
|
| 155 |
-
clean_code = extracted_logic.replace("```python", "").replace("```", "").strip()
|
| 156 |
-
clean_code = clean_code.replace(r"\n", "\n") # एस्केप न्यूलाइन को ठीक करना
|
| 157 |
-
local_vars = {"text": target_full_text, "lines": target_lines, "re": re}
|
| 158 |
-
exec(clean_code, {}, local_vars)
|
| 159 |
-
found_val = local_vars.get("value", None)
|
| 160 |
-
except Exception as e:
|
| 161 |
-
found_val = None
|
| 162 |
-
|
| 163 |
-
if not found_val or not str(found_val).strip():
|
| 164 |
-
pdf_bytes = st.session_state.get("cached_pdf_bytes", None)
|
| 165 |
-
found_val = extract_header_value(target_lines, target_full_text, kw, pos, mode, stop_kw, flt, field_label=field, pdf_bytes=pdf_bytes)
|
| 166 |
-
|
| 167 |
-
if not found_val or not str(found_val).strip():
|
| 168 |
-
if fallback_val:
|
| 169 |
-
found_val = fallback_val
|
| 170 |
-
|
| 171 |
-
inv_data_dict[field.lower()] = found_val
|
| 172 |
-
|
| 173 |
-
if target_cell and "dynamic" not in target_cell.lower():
|
| 174 |
-
try:
|
| 175 |
-
if "\n" in str(found_val):
|
| 176 |
-
col_letters = re.findall(r'[A-Za-z]+', target_cell)[0].upper()
|
| 177 |
-
start_row_num = int(re.findall(r'\d+', target_cell)[0]) if re.findall(r'\d+', target_cell) else summary_row
|
| 178 |
-
|
| 179 |
-
lines = str(found_val).split("\n")
|
| 180 |
-
for idx, line_val in enumerate(lines):
|
| 181 |
-
current_row = start_row_num + idx
|
| 182 |
-
ws[f"{col_letters}{current_row}"] = line_val.strip()
|
| 183 |
-
else:
|
| 184 |
-
if target_cell.isalpha():
|
| 185 |
-
cell_to_write = f"{target_cell}{summary_row}"
|
| 186 |
-
else:
|
| 187 |
-
cell_to_write = target_cell
|
| 188 |
-
ws[cell_to_write] = found_val
|
| 189 |
-
except Exception:
|
| 190 |
-
pass
|
| 191 |
-
|
| 192 |
-
if "inv. no" in field.lower() or "invoice no" in field.lower():
|
| 193 |
-
if found_val:
|
| 194 |
-
current_inv_number = found_val
|
| 195 |
-
if inv_sr_number == 1: first_inv_no = found_val
|
| 196 |
-
|
| 197 |
-
if "date" in field.lower() or "dt" in field.lower():
|
| 198 |
-
d_match = re.search(r'\b\d{2}[./-]\d{2}[./-]\d{4}\b', str(found_val))
|
| 199 |
-
if d_match:
|
| 200 |
-
current_inv_date = d_match.group(0).replace(".", "/").replace("-", "/")
|
| 201 |
-
elif found_val and not str(found_val).lower().startswith("inv"):
|
| 202 |
-
current_inv_date = found_val
|
| 203 |
-
|
| 204 |
-
ws[f"AH{summary_row}"] = inv_sr_number
|
| 205 |
-
ws[f"AI{summary_row}"] = current_inv_number
|
| 206 |
-
|
| 207 |
-
if current_inv_date:
|
| 208 |
-
ws[f"AJ{summary_row}"] = current_inv_date
|
| 209 |
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
if i_rule.startswith("'") and len(i_rule) > 1:
|
| 215 |
-
i_rule = i_rule[1:].strip()
|
| 216 |
-
i_col = i_info.get("col", "K")
|
| 217 |
-
|
| 218 |
-
actual_rule_val = i_rule
|
| 219 |
-
if i_type == "Header Field Mapping":
|
| 220 |
-
matched_header_key = i_rule.lower()
|
| 221 |
-
if matched_header_key in inv_data_dict:
|
| 222 |
-
actual_rule_val = inv_data_dict[matched_header_key]
|
| 223 |
-
|
| 224 |
-
resolved_item_rules[i_name] = {
|
| 225 |
-
"col": i_col,
|
| 226 |
-
"type": i_type if i_type != "Header Field Mapping" else "Constant Text",
|
| 227 |
-
"rule": actual_rule_val
|
| 228 |
-
}
|
| 229 |
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
default_invoice_no=current_inv_number,
|
| 248 |
-
default_invoice_date=current_inv_date,
|
| 249 |
-
pdf_text=pdf_text,
|
| 250 |
-
lut_kws=lut_kws,
|
| 251 |
-
paid_kws=paid_kws,
|
| 252 |
-
parser_rule=assigned_parser
|
| 253 |
-
)
|
| 254 |
-
elif assigned_parser == "parser_vapi_welspun":
|
| 255 |
-
ws, overall_item_sr, excel_write_row = map_vapi_welspun_items_to_excel_dynamic(
|
| 256 |
-
ws, parsed_items, resolved_item_rules,
|
| 257 |
-
inv_sr_no=inv_sr_number,
|
| 258 |
-
start_overall_sr=overall_item_sr,
|
| 259 |
-
start_excel_row=excel_write_row,
|
| 260 |
-
default_invoice_no=current_inv_number,
|
| 261 |
-
default_invoice_date=current_inv_date,
|
| 262 |
-
pdf_text=pdf_text,
|
| 263 |
-
lut_kws=lut_kws,
|
| 264 |
-
paid_kws=paid_kws,
|
| 265 |
-
parser_rule=assigned_parser
|
| 266 |
-
)
|
| 267 |
-
else:
|
| 268 |
-
ws, overall_item_sr, excel_write_row = map_items_to_excel_dynamic(
|
| 269 |
-
ws, parsed_items, resolved_item_rules,
|
| 270 |
-
inv_sr_no=inv_sr_number,
|
| 271 |
-
start_overall_sr=overall_item_sr,
|
| 272 |
-
start_excel_row=excel_write_row,
|
| 273 |
-
default_invoice_no=current_inv_number,
|
| 274 |
-
default_invoice_date=current_inv_date,
|
| 275 |
-
pdf_text=pdf_text,
|
| 276 |
-
lut_kws=lut_kws,
|
| 277 |
-
paid_kws=paid_kws,
|
| 278 |
-
parser_rule=assigned_parser
|
| 279 |
-
)
|
| 280 |
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
st.success(f"🎉 सफलता! सपोर्टिंग डॉक्यूमेंट्स के साथ फाइल '{final_filename}' तैयार है!")
|
| 290 |
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import openpyxl
|
| 2 |
import pdfplumber
|
| 3 |
import re
|
|
|
|
| 9 |
from parser_polycab import extract_polycab_items, map_polycab_items_to_excel_dynamic
|
| 10 |
from parser_vapi_welspun import extract_vapi_welspun_items, map_vapi_welspun_items_to_excel_dynamic
|
| 11 |
|
|
|
|
| 12 |
from pdf_engine import apply_rule_filter, extract_header_value
|
| 13 |
from google_sheet_sync import load_template_from_sheet
|
| 14 |
from supporting_engine import extract_data_from_supporting_file
|
| 15 |
|
| 16 |
+
def process_invoices_backend(selected_shipper, shipper_info, main_inv_file, gst_inv_file, deec_decl_file):
|
| 17 |
+
"""
|
| 18 |
+
Gradio ke file objects ko process karke Excel file ki bytes return karta hai.
|
| 19 |
+
"""
|
| 20 |
+
if main_inv_file is None:
|
| 21 |
+
return None, "⚠️ Mukhya invoice file missing hai!"
|
| 22 |
|
| 23 |
+
try:
|
| 24 |
+
rules = shipper_info.get("mapping_rules", {})
|
| 25 |
+
item_table_rules = shipper_info.get("item_table_rules", {})
|
| 26 |
+
assigned_parser = shipper_info.get("item_table_rule_name", "parser_welspun").strip().lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
igst_cfg = shipper_info.get("igst_config", {})
|
| 29 |
+
lut_kws = igst_cfg.get("lut_keywords", "")
|
| 30 |
+
paid_kws = igst_cfg.get("paid_keywords", "")
|
| 31 |
+
|
| 32 |
+
wb = load_template_from_sheet(selected_shipper)
|
| 33 |
+
if wb is None:
|
| 34 |
+
wb = openpyxl.Workbook()
|
|
|
|
|
|
|
| 35 |
|
| 36 |
+
ws = wb["INV"] if "INV" in wb.sheetnames else wb.active
|
| 37 |
+
|
| 38 |
+
first_inv_no = "INV"
|
| 39 |
+
overall_item_sr = 1
|
| 40 |
+
excel_write_row = 2
|
| 41 |
+
|
| 42 |
+
# Gradio file object ka path ya bytes handle karna
|
| 43 |
+
file_bytes = main_inv_file.read() if hasattr(main_inv_file, "read") else open(main_inv_file, "rb").read()
|
| 44 |
+
file_name = getattr(main_inv_file, "name", "invoice.pdf")
|
| 45 |
+
|
| 46 |
+
pdf_text = ""
|
| 47 |
+
pdf_lines = []
|
| 48 |
+
|
| 49 |
+
if file_name.lower().endswith(".pdf"):
|
| 50 |
+
with pdfplumber.open(BytesIO(file_bytes)) as pdf:
|
| 51 |
+
for page in pdf.pages:
|
| 52 |
+
t = page.extract_text()
|
| 53 |
+
if t:
|
| 54 |
+
pdf_text += t + "\n"
|
| 55 |
+
pdf_lines.extend(t.split("\n"))
|
| 56 |
+
else:
|
| 57 |
+
excel_text, _ = extract_data_from_supporting_file(main_inv_file)
|
| 58 |
+
if excel_text:
|
| 59 |
+
pdf_text = excel_text
|
| 60 |
+
pdf_lines = excel_text.split("\n")
|
| 61 |
|
| 62 |
+
gst_text, _ = extract_data_from_supporting_file(gst_inv_file) if gst_inv_file else ("", None)
|
| 63 |
+
deec_text, _ = extract_data_from_supporting_file(deec_decl_file) if deec_decl_file else ("", None)
|
| 64 |
+
|
| 65 |
+
current_inv_number = "INV_1"
|
| 66 |
+
current_inv_date = ""
|
| 67 |
+
inv_data_dict = {}
|
| 68 |
+
summary_row = 2
|
| 69 |
+
|
| 70 |
+
for field, r_info in rules.items():
|
| 71 |
+
kw = r_info.get("keyword", "").strip()
|
| 72 |
+
if kw.startswith("'") and len(kw) > 1:
|
| 73 |
+
kw = kw[1:].strip()
|
| 74 |
+
|
| 75 |
+
pos = r_info.get("position", "Right (आगे)")
|
| 76 |
+
target_cell = r_info.get("cell", "").strip().upper()
|
| 77 |
+
mode = r_info.get("match_mode", "Exact Word")
|
| 78 |
+
stop_kw = r_info.get("stop_kw", "").strip()
|
| 79 |
+
flt = r_info.get("filter", "None")
|
| 80 |
+
fallback_val = r_info.get("fallback", "").strip()
|
| 81 |
+
doc_source = r_info.get("logic", "Main Invoice")
|
| 82 |
+
extracted_logic = r_info.get("extracted_logic", "").strip()
|
| 83 |
+
found_val = None
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
+
target_lines, target_full_text = pdf_lines, pdf_text
|
| 86 |
+
if "gst" in doc_source.lower() and gst_inv_file:
|
| 87 |
+
target_lines = gst_text.split("\n")
|
| 88 |
+
target_full_text = gst_text
|
| 89 |
+
elif "deec" in doc_source.lower() and deec_decl_file:
|
| 90 |
+
target_lines = deec_text.split("\n")
|
| 91 |
+
target_full_text = deec_text
|
| 92 |
+
|
| 93 |
+
if extracted_logic:
|
| 94 |
+
try:
|
| 95 |
+
clean_code = extracted_logic.replace("```python", "").replace("```", "").strip()
|
| 96 |
+
clean_code = clean_code.replace(r"\n", "\n")
|
| 97 |
+
local_vars = {"text": target_full_text, "lines": target_lines, "re": re}
|
| 98 |
+
exec(clean_code, {}, local_vars)
|
| 99 |
+
found_val = local_vars.get("value", None)
|
| 100 |
+
except Exception:
|
| 101 |
+
found_val = None
|
| 102 |
|
| 103 |
+
if not found_val or not str(found_val).strip():
|
| 104 |
+
found_val = extract_header_value(target_lines, target_full_text, kw, pos, mode, stop_kw, flt, field_label=field, pdf_bytes=file_bytes)
|
| 105 |
+
|
| 106 |
+
if not found_val or not str(found_val).strip():
|
| 107 |
+
if fallback_val:
|
| 108 |
+
found_val = fallback_val
|
| 109 |
|
| 110 |
+
inv_data_dict[field.lower()] = found_val
|
| 111 |
+
|
| 112 |
+
if target_cell and "dynamic" not in target_cell.lower():
|
| 113 |
+
try:
|
| 114 |
+
if "\n" in str(found_val):
|
| 115 |
+
col_letters = re.findall(r'[A-Za-z]+', target_cell)[0].upper()
|
| 116 |
+
start_row_num = int(re.findall(r'\d+', target_cell)[0]) if re.findall(r'\d+', target_cell) else summary_row
|
| 117 |
+
for idx, line_val in enumerate(str(found_val).split("\n")):
|
| 118 |
+
ws[f"{col_letters}{start_row_num + idx}"] = line_val.strip()
|
| 119 |
+
else:
|
| 120 |
+
cell_to_write = f"{target_cell}{summary_row}" if target_cell.isalpha() else target_cell
|
| 121 |
+
ws[cell_to_write] = found_val
|
| 122 |
+
except Exception:
|
| 123 |
+
pass
|
| 124 |
|
| 125 |
+
if "inv. no" in field.lower() or "invoice no" in field.lower():
|
| 126 |
+
if found_val:
|
| 127 |
+
current_inv_number = found_val
|
| 128 |
+
first_inv_no = found_val
|
| 129 |
|
| 130 |
+
if "date" in field.lower() or "dt" in field.lower():
|
| 131 |
+
d_match = re.search(r'\b\d{2}[./-]\d{2}[./-]\d{4}\b', str(found_val))
|
| 132 |
+
if d_match:
|
| 133 |
+
current_inv_date = d_match.group(0).replace(".", "/").replace("-", "/")
|
| 134 |
+
elif found_val and not str(found_val).lower().startswith("inv"):
|
| 135 |
+
current_inv_date = found_val
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
+
ws[f"AH{summary_row}"] = 1
|
| 138 |
+
ws[f"AI{summary_row}"] = current_inv_number
|
| 139 |
+
if current_inv_date:
|
| 140 |
+
ws[f"AJ{summary_row}"] = current_inv_date
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
+
resolved_item_rules = {}
|
| 143 |
+
for i_name, i_info in item_table_rules.items():
|
| 144 |
+
i_type = i_info.get("type", "")
|
| 145 |
+
i_rule = i_info.get("rule", "")
|
| 146 |
+
if i_rule.startswith("'") and len(i_rule) > 1:
|
| 147 |
+
i_rule = i_rule[1:].strip()
|
| 148 |
+
i_col = i_info.get("col", "K")
|
| 149 |
+
|
| 150 |
+
actual_rule_val = i_rule
|
| 151 |
+
if i_type == "Header Field Mapping" and i_rule.lower() in inv_data_dict:
|
| 152 |
+
actual_rule_val = inv_data_dict[i_rule.lower()]
|
| 153 |
+
|
| 154 |
+
resolved_item_rules[i_name] = {
|
| 155 |
+
"col": i_col,
|
| 156 |
+
"type": i_type if i_type != "Header Field Mapping" else "Constant Text",
|
| 157 |
+
"rule": actual_rule_val
|
| 158 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
|
| 160 |
+
if assigned_parser == "parser_bkt":
|
| 161 |
+
parsed_items = extract_bkt_items(pdf_lines)
|
| 162 |
+
elif assigned_parser == "parser_polycab":
|
| 163 |
+
parsed_items = extract_polycab_items(pdf_lines, pdf_text=pdf_text)
|
| 164 |
+
elif assigned_parser == "parser_vapi_welspun":
|
| 165 |
+
parsed_items = extract_vapi_welspun_items(pdf_lines, pdf_text=pdf_text)
|
| 166 |
+
else:
|
| 167 |
+
parsed_items = extract_welspun_items(pdf_lines, pdf_text=pdf_text)
|
|
|
|
| 168 |
|
| 169 |
+
if assigned_parser == "parser_polycab":
|
| 170 |
+
ws, overall_item_sr, excel_write_row = map_polycab_items_to_excel_dynamic(
|
| 171 |
+
ws, parsed_items, resolved_item_rules, 1, overall_item_sr, excel_write_row, current_inv_number, current_inv_date, pdf_text, lut_kws, paid_kws, assigned_parser
|
| 172 |
+
)
|
| 173 |
+
elif assigned_parser == "parser_vapi_welspun":
|
| 174 |
+
ws, overall_item_sr, excel_write_row = map_vapi_welspun_items_to_excel_dynamic(
|
| 175 |
+
ws, parsed_items, resolved_item_rules, 1, overall_item_sr, excel_write_row, current_inv_number, current_inv_date, pdf_text, lut_kws, paid_kws, assigned_parser
|
| 176 |
+
)
|
| 177 |
+
else:
|
| 178 |
+
ws, overall_item_sr, excel_write_row = map_items_to_excel_dynamic(
|
| 179 |
+
ws, parsed_items, resolved_item_rules, 1, overall_item_sr, excel_write_row, current_inv_number, current_inv_date, pdf_text, lut_kws, paid_kws, assigned_parser
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
output = BytesIO()
|
| 183 |
+
wb.save(output)
|
| 184 |
+
|
| 185 |
+
short_shipper = selected_shipper.split(" ")[0].lower()
|
| 186 |
+
clean_inv = re.sub(r'[\\/*?:"<>|]', "", first_inv_no)
|
| 187 |
+
final_filename = f"{clean_inv}_{short_shipper}_MultiDoc.xlsx"
|
| 188 |
+
|
| 189 |
+
return output.getvalue(), final_filename
|
| 190 |
+
except Exception as e:
|
| 191 |
+
return None, str(e)
|