Spaces:
Running on Zero
Running on Zero
Update shipper_data.py
Browse files- shipper_data.py +13 -183
shipper_data.py
CHANGED
|
@@ -1,18 +1,14 @@
|
|
| 1 |
-
import streamlit as st
|
| 2 |
import os
|
| 3 |
import json
|
| 4 |
-
import
|
| 5 |
-
import io
|
| 6 |
from io import BytesIO
|
| 7 |
-
import
|
| 8 |
|
| 9 |
from pdf_engine import detect_igst_status, extract_header_value
|
| 10 |
-
from test_suite import render_universal_test_suite
|
| 11 |
from google_sheet_sync import (
|
| 12 |
fetch_all_from_sheet, push_rules_to_sheet, push_template_file_to_sheet,
|
| 13 |
load_template_bytes_from_sheet
|
| 14 |
)
|
| 15 |
-
import requests
|
| 16 |
|
| 17 |
LOCAL_DATA_DIR = "local_shipper_data"
|
| 18 |
TEMPLATES_DIR = os.path.join(LOCAL_DATA_DIR, "templates")
|
|
@@ -32,14 +28,15 @@ def fetch_data_from_google_sheet():
|
|
| 32 |
pass
|
| 33 |
return {}
|
| 34 |
|
| 35 |
-
def save_local_shippers():
|
| 36 |
ensure_local_directories()
|
| 37 |
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
|
| 38 |
try:
|
| 39 |
with open(json_path, "w", encoding="utf-8") as f:
|
| 40 |
-
json.dump(
|
|
|
|
| 41 |
shippers_payload = {}
|
| 42 |
-
for s_name, s_data in
|
| 43 |
shippers_payload[s_name] = {
|
| 44 |
"mapping_rules": s_data.get("mapping_rules", {}),
|
| 45 |
"item_table_rules": s_data.get("item_table_rules", {}),
|
|
@@ -47,17 +44,17 @@ def save_local_shippers():
|
|
| 47 |
"igst_config": s_data.get("igst_config", {})
|
| 48 |
}
|
| 49 |
push_rules_to_sheet(shippers_payload)
|
|
|
|
| 50 |
except Exception as e:
|
| 51 |
-
|
| 52 |
|
| 53 |
def load_local_shippers():
|
| 54 |
ensure_local_directories()
|
| 55 |
-
if "shipper_database" in st.session_state and st.session_state["shipper_database"]:
|
| 56 |
-
return
|
| 57 |
sheet_data = fetch_data_from_google_sheet()
|
| 58 |
shippers_dict = sheet_data.get("shippers", {}) if isinstance(sheet_data, dict) else {}
|
|
|
|
| 59 |
if shippers_dict:
|
| 60 |
-
|
| 61 |
else:
|
| 62 |
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
|
| 63 |
if os.path.exists(json_path):
|
|
@@ -65,177 +62,10 @@ def load_local_shippers():
|
|
| 65 |
with open(json_path, "r", encoding="utf-8") as f:
|
| 66 |
saved_data = json.load(f)
|
| 67 |
if isinstance(saved_data, dict) and saved_data:
|
| 68 |
-
|
| 69 |
except Exception:
|
| 70 |
pass
|
|
|
|
| 71 |
|
| 72 |
def ensure_default_shipper():
|
| 73 |
-
load_local_shippers()
|
| 74 |
-
|
| 75 |
-
def render_shipper_data():
|
| 76 |
-
load_local_shippers()
|
| 77 |
-
|
| 78 |
-
st.header("🏢 Add Shipper Name & No-Code Visual Mapping Builder")
|
| 79 |
-
st.caption("कीवर्ड, बॉक्स एक्सट्रैक्शन और पोजीशन के जरिए स्मार्ट टेस्ट और सेव टूल।")
|
| 80 |
-
|
| 81 |
-
shippers_list = sorted(list(st.session_state["shipper_database"].keys()))
|
| 82 |
-
if shippers_list:
|
| 83 |
-
selected_shipper = st.selectbox("कॉन्फ़िगर करने के लिए शिपर चुनें:", shippers_list, index=None, placeholder="शिपर चुनें...")
|
| 84 |
-
if selected_shipper:
|
| 85 |
-
st.write(f"### ⚙️ शिपर प्रोफाइल: **{selected_shipper}**")
|
| 86 |
-
shipper_info = st.session_state["shipper_database"][selected_shipper]
|
| 87 |
-
|
| 88 |
-
# 📁 1. टेम्पलेट फ़ाइल अपलोड
|
| 89 |
-
st.write("---")
|
| 90 |
-
st.subheader("📁 1. टेम्पलेट फ़ाइल अपलोड (Full Job Excel Template)")
|
| 91 |
-
|
| 92 |
-
t_bytes = load_template_bytes_from_sheet(selected_shipper)
|
| 93 |
-
has_saved_template = t_bytes is not None and len(t_bytes) > 0
|
| 94 |
-
|
| 95 |
-
if has_saved_template:
|
| 96 |
-
st.success(f"✅ 'Full Job Excel Format File (Template)' गूगल शीट पर अपलोडेड एवं सुरक्षित है।")
|
| 97 |
-
col_rep, col_del = st.columns([3, 1])
|
| 98 |
-
with col_rep:
|
| 99 |
-
f_replace = st.file_uploader("🔄 Replace Template (नई एक्सेल फाइल चुनें):", type=["xlsx", "xls"], key=f"repl_tpl_{selected_shipper}")
|
| 100 |
-
if f_replace is not None:
|
| 101 |
-
if st.button("🚀 Confirm & Replace", type="primary", key=f"btn_repl_{selected_shipper}"):
|
| 102 |
-
with st.spinner("⏳ गूगल शीट पर टेम्पलेट अपलोड हो रही है..."):
|
| 103 |
-
if push_template_file_to_sheet(selected_shipper, f_replace.getvalue()):
|
| 104 |
-
st.success("🎉 टेम्पलेट सफलतापूर्वक गूगल शीट पर रिप्लेस हो गई!")
|
| 105 |
-
st.rerun()
|
| 106 |
-
else:
|
| 107 |
-
st.error("❌ अपलोड फेल हो गया!")
|
| 108 |
-
with col_del:
|
| 109 |
-
st.write("##")
|
| 110 |
-
if st.button("🗑️ Delete Template", type="secondary", use_container_width=True, key=f"btn_del_tpl_{selected_shipper}"):
|
| 111 |
-
push_template_file_to_sheet(selected_shipper, b"")
|
| 112 |
-
st.success("🗑️ टेम्पलेट डिलीट हो गई!")
|
| 113 |
-
st.rerun()
|
| 114 |
-
else:
|
| 115 |
-
st.info("ℹ️ इस शिपर के लिए अभी कोई टेम्पलेट अपलोड नहीं की गई है।")
|
| 116 |
-
f_upload = st.file_uploader("➡️ Blank Full Job Excel Format File (Template) चुनें", type=["xlsx", "xls"], key=f"tpl_{selected_shipper}")
|
| 117 |
-
if f_upload is not None:
|
| 118 |
-
if st.button("🚀 Save Template to Google Sheet", type="primary", use_container_width=True, key=f"btn_upload_tpl_{selected_shipper}"):
|
| 119 |
-
with st.spinner("⏳ गूगल शीट पर टेम्पलेट अपलोड हो रही है..."):
|
| 120 |
-
if push_template_file_to_sheet(selected_shipper, f_upload.getvalue()):
|
| 121 |
-
st.success("🎉 टेम्पलेट एक्सेल फाइल सफलतापर्वक गूगल शीट पर सेव हो गई!")
|
| 122 |
-
st.rerun()
|
| 123 |
-
else:
|
| 124 |
-
st.error("❌ अपलोड फेल हो गया!")
|
| 125 |
-
|
| 126 |
-
# 🛠️ 4. Header Fields Mapping Rules Table
|
| 127 |
-
st.write("---")
|
| 128 |
-
st.subheader("🛠️ 4. Header Fields Mapping & Regex Rules")
|
| 129 |
-
|
| 130 |
-
current_rules = shipper_info.get("mapping_rules", {})
|
| 131 |
-
updated_rules = {}
|
| 132 |
-
doc_source_options = ["Main Invoice", "GST Invoice (PDF/Excel)", "DEEC Declaration (PDF/Excel)"]
|
| 133 |
-
|
| 134 |
-
if current_rules:
|
| 135 |
-
h1, h2, h3, h4, h5, h6, h7, h8 = st.columns([1.3, 1.0, 1.2, 0.6, 1.4, 1.2, 1.8, 0.4])
|
| 136 |
-
with h1: st.markdown("**Field Name**")
|
| 137 |
-
with h2: st.markdown("**Source Doc**")
|
| 138 |
-
with h3: st.markdown("**Keyword**")
|
| 139 |
-
with h4: st.markdown("**Cell**")
|
| 140 |
-
with h5: st.markdown("**Prompt**")
|
| 141 |
-
with h6: st.markdown("**Result Ex**")
|
| 142 |
-
with h7: st.markdown("**⚡ Local Python/Regex Logic**")
|
| 143 |
-
with h8: st.markdown("**Del**")
|
| 144 |
-
|
| 145 |
-
for field in list(current_rules.keys()):
|
| 146 |
-
s_val = current_rules[field]
|
| 147 |
-
c1, c2, c3, c4, c5, c6, c7, c8 = st.columns([1.3, 1.0, 1.2, 0.6, 1.4, 1.2, 1.8, 0.4])
|
| 148 |
-
|
| 149 |
-
with c1: edited_name = st.text_input(f"f_{field}", value=field, label_visibility="collapsed")
|
| 150 |
-
with c2: final_logic = st.selectbox(f"logic_{field}", doc_source_options, index=doc_source_options.index(s_val.get("logic", doc_source_options[0])) if s_val.get("logic") in doc_source_options else 0, label_visibility="collapsed")
|
| 151 |
-
with c3: ky = st.text_input(f"k_{field}", value=s_val.get("keyword", ""), label_visibility="collapsed")
|
| 152 |
-
with c4: cl = st.text_input(f"c_{field}", value=s_val.get("cell", ""), label_visibility="collapsed")
|
| 153 |
-
with c5: ai_p = st.text_input(f"ai_{field}", value=s_val.get("ai_prompt", ""), placeholder="उदा: नीचे वाली लाइन", label_visibility="collapsed")
|
| 154 |
-
with c6: res_ex = st.text_input(f"ex_{field}", value=s_val.get("result_example", ""), placeholder="उदा: MONREALE", label_visibility="collapsed")
|
| 155 |
-
|
| 156 |
-
saved_ext_logic = s_val.get("extracted_logic", "")
|
| 157 |
-
with c7: ext_logic = st.text_input(f"elogic_{field}", value=saved_ext_logic, placeholder="यहाँ लॉजिक सेव है", label_visibility="collapsed")
|
| 158 |
-
|
| 159 |
-
with c8:
|
| 160 |
-
if st.button("🗑️", key=f"del_h_{field}"):
|
| 161 |
-
del shipper_info["mapping_rules"][field]
|
| 162 |
-
save_local_shippers()
|
| 163 |
-
st.rerun()
|
| 164 |
-
|
| 165 |
-
updated_rules[edited_name] = {
|
| 166 |
-
"logic": final_logic, "keyword": ky, "cell": cl, "ai_prompt": ai_p, "result_example": res_ex, "extracted_logic": ext_logic
|
| 167 |
-
}
|
| 168 |
-
shipper_info["mapping_rules"] = updated_rules
|
| 169 |
-
|
| 170 |
-
# 🛠️ 5. Dynamic Item Table Rules & Mapping Table
|
| 171 |
-
st.write("---")
|
| 172 |
-
st.subheader("📋 5. Dynamic Item Table Rules & Mapping")
|
| 173 |
-
|
| 174 |
-
current_parser_name = shipper_info.get("item_table_rule_name", "parser_welspun")
|
| 175 |
-
parser_options = ["parser_welspun", "parser_polycab", "parser_bkt", "parser_vapi_welspun"]
|
| 176 |
-
selected_parser = st.selectbox(
|
| 177 |
-
"इस शिपर के लिए आइटम पार्सर चुनें:",
|
| 178 |
-
parser_options,
|
| 179 |
-
index=parser_options.index(current_parser_name) if current_parser_name in parser_options else 0,
|
| 180 |
-
key=f"parser_sel_{selected_shipper}"
|
| 181 |
-
)
|
| 182 |
-
shipper_info["item_table_rule_name"] = selected_parser
|
| 183 |
-
|
| 184 |
-
item_rules = shipper_info.setdefault("item_table_rules", {})
|
| 185 |
-
updated_item_rules = {}
|
| 186 |
-
|
| 187 |
-
if item_rules:
|
| 188 |
-
it_c1, it_c2, it_c3, it_c4, it_c5, it_c6 = st.columns([1.5, 0.8, 1.5, 1.8, 1.8, 0.5])
|
| 189 |
-
with it_c1: st.markdown("**Item Field Name**")
|
| 190 |
-
with it_c2: st.markdown("**Excel Col**")
|
| 191 |
-
with it_c3: st.markdown("**Source Type**")
|
| 192 |
-
with it_c4: st.markdown("**Extraction Rule / Keyword**")
|
| 193 |
-
with it_c5: st.markdown("**Result Example**")
|
| 194 |
-
with it_c6: st.markdown("**Del**")
|
| 195 |
-
|
| 196 |
-
source_type_opts = ["PDF Row Item", "Header Field Mapping", "Constant Text", "DEEC Declaration (PDF/Excel)", "GST Invoice (PDF/Excel)"]
|
| 197 |
-
|
| 198 |
-
for it_field, it_val in list(item_rules.items()):
|
| 199 |
-
ic1, ic2, ic3, ic4, ic5, ic6 = st.columns([1.5, 0.8, 1.5, 1.8, 1.8, 0.5])
|
| 200 |
-
|
| 201 |
-
with ic1: edited_it_name = st.text_input(f"it_name_{it_field}", value=it_field, label_visibility="collapsed")
|
| 202 |
-
with ic2: it_col = st.text_input(f"it_col_{it_field}", value=it_val.get("col", "K"), label_visibility="collapsed")
|
| 203 |
-
|
| 204 |
-
saved_type = it_val.get("type", "PDF Row Item")
|
| 205 |
-
if saved_type not in source_type_opts: saved_type = source_type_opts[0]
|
| 206 |
-
with ic3: it_type = st.selectbox(f"it_type_{it_field}", source_type_opts, index=source_type_opts.index(saved_type), label_visibility="collapsed")
|
| 207 |
-
|
| 208 |
-
with ic4: it_rule = st.text_input(f"it_rule_{it_field}", value=it_val.get("rule", ""), placeholder="उदा: HSN / Description", label_visibility="collapsed")
|
| 209 |
-
with ic5: it_ex = st.text_input(f"it_ex_{it_field}", value=it_val.get("result_example", ""), placeholder="उदा: 8544...", label_visibility="collapsed")
|
| 210 |
-
|
| 211 |
-
with ic6:
|
| 212 |
-
if st.button("🗑️", key=f"del_it_{it_field}"):
|
| 213 |
-
del shipper_info["item_table_rules"][it_field]
|
| 214 |
-
save_local_shippers()
|
| 215 |
-
st.rerun()
|
| 216 |
-
|
| 217 |
-
updated_item_rules[edited_it_name] = {
|
| 218 |
-
"col": it_col.upper(),
|
| 219 |
-
"type": it_type,
|
| 220 |
-
"rule": it_rule,
|
| 221 |
-
"result_example": it_ex
|
| 222 |
-
}
|
| 223 |
-
shipper_info["item_table_rules"] = updated_item_rules
|
| 224 |
-
|
| 225 |
-
# 🛠️ 6. IGST & Lut Configuration
|
| 226 |
-
st.write("---")
|
| 227 |
-
st.subheader("⚙️ 6. IGST & Lut Configuration")
|
| 228 |
-
igst_cfg = shipper_info.setdefault("igst_config", {})
|
| 229 |
-
c_igst1, c_igst2 = st.columns(2)
|
| 230 |
-
with c_igst1:
|
| 231 |
-
lut_kws = st.text_input("LUT Keywords (कॉमा से अलग करें):", value=igst_cfg.get("lut_keywords", "LUT, UNDER LUT, UNDER BOND"), key=f"lut_{selected_shipper}")
|
| 232 |
-
with c_igst2:
|
| 233 |
-
paid_kws = st.text_input("Paid Keywords (कॉमा से अलग करें):", value=igst_cfg.get("paid_keywords", "SUPPLY MEANT FOR EXPORT ON PAYMENT OF IGST."), key=f"paid_{selected_shipper}")
|
| 234 |
-
|
| 235 |
-
igst_cfg["lut_keywords"] = lut_kws
|
| 236 |
-
igst_cfg["paid_keywords"] = paid_kws
|
| 237 |
-
|
| 238 |
-
st.write("---")
|
| 239 |
-
if st.button("💾 Save All Rules & Sync to Google Sheet", type="primary", use_container_width=True, key="btn_save_rules_local"):
|
| 240 |
-
save_local_shippers()
|
| 241 |
-
st.success("🎉 आपके सारे रूल्स, डाइनैमिक आइटम टेबल मैपिंग और IGST कॉन्फ़िगरेशन सफलतापूर्वक गूगल शीट पर सिंक हो गए हैं!")
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import json
|
| 3 |
+
import requests
|
|
|
|
| 4 |
from io import BytesIO
|
| 5 |
+
import openpyxl
|
| 6 |
|
| 7 |
from pdf_engine import detect_igst_status, extract_header_value
|
|
|
|
| 8 |
from google_sheet_sync import (
|
| 9 |
fetch_all_from_sheet, push_rules_to_sheet, push_template_file_to_sheet,
|
| 10 |
load_template_bytes_from_sheet
|
| 11 |
)
|
|
|
|
| 12 |
|
| 13 |
LOCAL_DATA_DIR = "local_shipper_data"
|
| 14 |
TEMPLATES_DIR = os.path.join(LOCAL_DATA_DIR, "templates")
|
|
|
|
| 28 |
pass
|
| 29 |
return {}
|
| 30 |
|
| 31 |
+
def save_local_shippers(shipper_database):
|
| 32 |
ensure_local_directories()
|
| 33 |
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
|
| 34 |
try:
|
| 35 |
with open(json_path, "w", encoding="utf-8") as f:
|
| 36 |
+
json.dump(shipper_database, f, indent=4)
|
| 37 |
+
|
| 38 |
shippers_payload = {}
|
| 39 |
+
for s_name, s_data in shipper_database.items():
|
| 40 |
shippers_payload[s_name] = {
|
| 41 |
"mapping_rules": s_data.get("mapping_rules", {}),
|
| 42 |
"item_table_rules": s_data.get("item_table_rules", {}),
|
|
|
|
| 44 |
"igst_config": s_data.get("igst_config", {})
|
| 45 |
}
|
| 46 |
push_rules_to_sheet(shippers_payload)
|
| 47 |
+
return True, "🎉 Rules successfully saved and synced to Google Sheet!"
|
| 48 |
except Exception as e:
|
| 49 |
+
return False, f"Save Error: {str(e)}"
|
| 50 |
|
| 51 |
def load_local_shippers():
|
| 52 |
ensure_local_directories()
|
|
|
|
|
|
|
| 53 |
sheet_data = fetch_data_from_google_sheet()
|
| 54 |
shippers_dict = sheet_data.get("shippers", {}) if isinstance(sheet_data, dict) else {}
|
| 55 |
+
|
| 56 |
if shippers_dict:
|
| 57 |
+
return shippers_dict
|
| 58 |
else:
|
| 59 |
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
|
| 60 |
if os.path.exists(json_path):
|
|
|
|
| 62 |
with open(json_path, "r", encoding="utf-8") as f:
|
| 63 |
saved_data = json.load(f)
|
| 64 |
if isinstance(saved_data, dict) and saved_data:
|
| 65 |
+
return saved_data
|
| 66 |
except Exception:
|
| 67 |
pass
|
| 68 |
+
return {}
|
| 69 |
|
| 70 |
def ensure_default_shipper():
|
| 71 |
+
return load_local_shippers()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|