Bhuvi13 commited on
Commit
5a88635
Β·
verified Β·
1 Parent(s): f637372

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +659 -657
src/streamlit_app.py CHANGED
@@ -537,687 +537,689 @@ elif st.session_state.page == 'viewer':
537
 
538
  # LEFT SIDE: Image Display with OCR Canvas
539
  with left_col:
540
- file_name = current_record.get('file_name', '')
541
-
542
- if file_name:
543
- # Find the actual file name (handle cases where extension is missing)
544
- actual_file_name = None
545
- if file_name in st.session_state.images:
546
- actual_file_name = file_name
547
- else:
548
- # Try adding common extensions
549
- for ext in ['.pdf', '.png', '.jpg', '.jpeg', '.tiff', '.tif', '.bmp']:
550
- if file_name + ext in st.session_state.images:
551
- actual_file_name = file_name + ext
552
- break
553
-
554
- # Try matching without extension
555
- if not actual_file_name:
556
- for uploaded_name in st.session_state.images.keys():
557
- uploaded_base = uploaded_name.rsplit('.', 1)[0]
558
- if uploaded_base == file_name:
559
- actual_file_name = uploaded_name
560
- break
561
 
562
- if actual_file_name:
563
- # Check if this is a PDF with multiple pages
564
- is_pdf = actual_file_name in st.session_state.pdf_metadata
565
-
566
- if is_pdf:
567
- pdf_meta = st.session_state.pdf_metadata[actual_file_name]
568
- total_pages = pdf_meta['total_pages']
569
- current_page = st.session_state.current_page_num.get(actual_file_name, 0)
570
-
571
- # PDF Navigation Header
572
- col_prev, col_info, col_next = st.columns([1, 2, 1])
573
-
574
- with col_prev:
575
- prev_clicked = st.button("⬅️ Previous", key=f"prev_page_{selected_file}_{actual_file_name}",
576
- disabled=(current_page == 0), use_container_width=True)
577
 
578
- with col_info:
579
- st.markdown(f"<div style='text-align: center; padding: 5px;'><b>πŸ“„ Page {current_page + 1} of {total_pages}</b></div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
580
 
581
- with col_next:
582
- next_clicked = st.button("Next ➑️", key=f"next_page_{selected_file}_{actual_file_name}",
583
- disabled=(current_page >= total_pages - 1), use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
 
585
- # Handle navigation only if not already navigating
586
- if not st.session_state.navigating_page:
587
- if prev_clicked:
588
- st.session_state.navigating_page = True
589
- st.session_state.current_page_num[actual_file_name] = max(0, current_page - 1)
590
- st.session_state.canvas_key += 1
591
- st.session_state.ocr_active_section = None
592
- st.session_state.ocr_active_field = None
593
- st.rerun()
594
- elif next_clicked:
595
- st.session_state.navigating_page = True
596
- st.session_state.current_page_num[actual_file_name] = min(total_pages - 1, current_page + 1)
597
- st.session_state.canvas_key += 1
598
- st.session_state.ocr_active_section = None
599
- st.session_state.ocr_active_field = None
600
- st.rerun()
601
  else:
602
- # Reset the flag after rerun
603
- st.session_state.navigating_page = False
604
-
605
- if actual_file_name:
606
- # Determine if PDF and get the appropriate image
607
- is_pdf = actual_file_name in st.session_state.pdf_metadata
608
-
609
- if is_pdf:
610
- # Get the current page image
611
- current_page = st.session_state.current_page_num.get(actual_file_name, 0)
612
- pdf_meta = st.session_state.pdf_metadata[actual_file_name]
613
- current_image = pdf_meta['pages'][current_page]
614
  else:
615
- current_image = st.session_state.images[actual_file_name]
616
- else:
617
- st.error(f"❌ File '{file_name}' not found in uploaded files")
618
- st.info("πŸ’‘ Available files:")
619
- with st.expander("Show available files"):
620
- for img_name in list(st.session_state.images.keys())[:20]:
621
- st.text(f" β€’ {img_name}")
622
- if len(st.session_state.images) > 20:
623
- st.text(f" ... and {len(st.session_state.images) - 20} more")
624
-
625
- if current_image:
626
- # Scale to a reasonable size so canvas doesn't become excessively large
627
- scaled_image, scale_ratio, paste_x, paste_y = scale_image_to_fixed_size(current_image)
628
 
629
- # Render the canvas. Its internal canvas will be constrained by the wrapper due to CSS above.
630
- canvas_result = st_canvas(
631
- fill_color="rgba(255, 165, 0, 0.3)",
632
- stroke_width=2,
633
- stroke_color="#FF0000",
634
- background_image=scaled_image,
635
- update_streamlit=True,
636
- height=scaled_image.height,
637
- width=scaled_image.width,
638
- drawing_mode="rect",
639
- key=f"canvas_{selected_file}_{st.session_state.canvas_key}",
640
- )
641
-
642
- # Only attempt OCR if there's an active OCR target AND the user has drawn something (objects exist)
643
- if canvas_result.json_data is not None and st.session_state.ocr_active_field:
644
- objects = canvas_result.json_data.get("objects", [])
645
- if len(objects) > 0:
646
- rect = objects[-1]
647
-
648
- bbox = [
649
- (rect["left"] - paste_x) / scale_ratio,
650
- (rect["top"] - paste_y) / scale_ratio,
651
- (rect["left"] + rect["width"] - paste_x) / scale_ratio,
652
- (rect["top"] + rect["height"] - paste_y) / scale_ratio
653
- ]
654
-
655
- with st.spinner("Performing OCR..."):
656
- ocr_text = perform_ocr(current_image, bbox)
657
-
658
- if ocr_text and not ocr_text.startswith("OCR Error"):
659
- st.success(f"βœ… OCR Result: {ocr_text}")
660
 
661
- gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
 
662
 
663
- if st.session_state.ocr_active_section == 'Line_items':
664
- line_items = gt_parse.get('Line_items', [])
665
- row_idx = st.session_state.ocr_line_item_row
666
- if row_idx is not None and row_idx < len(line_items):
667
- line_items[row_idx][st.session_state.ocr_active_field] = ocr_text
668
- gt_parse['Line_items'] = line_items
 
 
 
 
 
669
 
670
- # ensure expander stays open for this row after OCR
671
- expander_key = f"line_item_expander_{selected_file}_{row_idx}"
672
- st.session_state[expander_key] = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
  else:
674
- section = st.session_state.ocr_active_section
675
- field = st.session_state.ocr_active_field
676
- if section not in gt_parse:
677
- gt_parse[section] = {}
678
- gt_parse[section][field] = ocr_text
679
-
680
- st.session_state.edited_data[selected_file]['gt_parse'] = gt_parse
681
- st.session_state.modified_indices.add(selected_file)
682
-
683
- # After successful OCR, deactivate OCR target to prevent repeated triggers/loops
684
- st.session_state.ocr_active_section = None
685
- st.session_state.ocr_active_field = None
686
- st.session_state.ocr_line_item_row = None
687
-
688
- # Clear canvas for next OCR by bumping canvas_key then rerun
689
- st.session_state.canvas_key += 1
690
- st.rerun()
691
- else:
692
- st.error(ocr_text)
693
- else:
694
- st.warning("No file name specified in record")
695
 
696
  # RIGHT SIDE: Editable Details
697
  with right_col:
698
- st.markdown("### πŸ“ Document Details")
699
-
700
- gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
701
-
702
- tab1, tab2, tab3, tab4 = st.tabs([
703
- "πŸ“„ Remittance Details",
704
- "πŸ‘₯ Party Details",
705
- "🏦 Bank Details",
706
- "πŸ“‹ Line Items"
707
- ])
708
-
709
- # TAB 1: Remittance Details
710
- with tab1:
711
- remittance = gt_parse.get('Remittance_details', {})
712
-
713
- # Each field with OCR button
714
- col_input, col_btn = st.columns([5, 1])
715
- with col_input:
716
- remittance['Remittance_adv_no'] = st.text_input(
717
- "Remittance Advice No",
718
- value=remittance.get('Remittance_adv_no', ''),
719
- key=f"rem_adv_no_{selected_file}"
720
- )
721
- with col_btn:
722
- st.markdown("<br>", unsafe_allow_html=True)
723
- if st.button("πŸ”", key=f"ocr_rem_adv_no_{selected_file}",
724
- type="primary" if is_ocr_active('Remittance_details', 'Remittance_adv_no') else "secondary"):
725
- activate_ocr_field('Remittance_details', 'Remittance_adv_no')
726
-
727
- col_input, col_btn = st.columns([5, 1])
728
- with col_input:
729
- remittance['Remittance_adv_date'] = st.text_input(
730
- "Remittance Advice Date",
731
- value=remittance.get('Remittance_adv_date', ''),
732
- key=f"rem_adv_date_{selected_file}"
733
- )
734
- with col_btn:
735
- st.markdown("<br>", unsafe_allow_html=True)
736
- if st.button("πŸ”", key=f"ocr_rem_adv_date_{selected_file}",
737
- type="primary" if is_ocr_active('Remittance_details', 'Remittance_adv_date') else "secondary"):
738
- activate_ocr_field('Remittance_details', 'Remittance_adv_date')
739
-
740
- col_input, col_btn = st.columns([5, 1])
741
- with col_input:
742
- remittance['Payment_method'] = st.text_input(
743
- "Payment Method",
744
- value=remittance.get('Payment_method', ''),
745
- key=f"payment_method_{selected_file}"
746
- )
747
- with col_btn:
748
- st.markdown("<br>", unsafe_allow_html=True)
749
- if st.button("πŸ”", key=f"ocr_payment_method_{selected_file}",
750
- type="primary" if is_ocr_active('Remittance_details', 'Payment_method') else "secondary"):
751
- activate_ocr_field('Remittance_details', 'Payment_method')
752
-
753
- col_input, col_btn = st.columns([5, 1])
754
- with col_input:
755
- remittance['FCY'] = st.text_input(
756
- "FCY (Foreign Currency)",
757
- value=remittance.get('FCY', ''),
758
- key=f"fcy_{selected_file}"
759
- )
760
- with col_btn:
761
- st.markdown("<br>", unsafe_allow_html=True)
762
- if st.button("πŸ”", key=f"ocr_fcy_{selected_file}",
763
- type="primary" if is_ocr_active('Remittance_details', 'FCY') else "secondary"):
764
- activate_ocr_field('Remittance_details', 'FCY')
765
-
766
- col_input, col_btn = st.columns([5, 1])
767
- with col_input:
768
- remittance['Total_payment_amt_FCY'] = st.text_input(
769
- "Total Payment Amount (FCY)",
770
- value=remittance.get('Total_payment_amt_FCY', ''),
771
- key=f"total_payment_{selected_file}"
772
- )
773
- with col_btn:
774
- st.markdown("<br>", unsafe_allow_html=True)
775
- if st.button("πŸ”", key=f"ocr_total_payment_{selected_file}",
776
- type="primary" if is_ocr_active('Remittance_details', 'Total_payment_amt_FCY') else "secondary"):
777
- activate_ocr_field('Remittance_details', 'Total_payment_amt_FCY')
778
-
779
- col_input, col_btn = st.columns([5, 1])
780
- with col_input:
781
- remittance['Payment_date'] = st.text_input(
782
- "Payment Date",
783
- value=remittance.get('Payment_date', ''),
784
- key=f"payment_date_{selected_file}"
785
- )
786
- with col_btn:
787
- st.markdown("<br>", unsafe_allow_html=True)
788
- if st.button("πŸ”", key=f"ocr_payment_date_{selected_file}",
789
- type="primary" if is_ocr_active('Remittance_details', 'Payment_date') else "secondary"):
790
- activate_ocr_field('Remittance_details', 'Payment_date')
791
-
792
- col_input, col_btn = st.columns([5, 1])
793
- with col_input:
794
- remittance['Payment_ref_no'] = st.text_input(
795
- "Payment Reference No",
796
- value=remittance.get('Payment_ref_no', ''),
797
- key=f"payment_ref_{selected_file}"
798
- )
799
- with col_btn:
800
- st.markdown("<br>", unsafe_allow_html=True)
801
- if st.button("πŸ”", key=f"ocr_payment_ref_{selected_file}",
802
- type="primary" if is_ocr_active('Remittance_details', 'Payment_ref_no') else "secondary"):
803
- activate_ocr_field('Remittance_details', 'Payment_ref_no')
804
-
805
- gt_parse['Remittance_details'] = remittance
806
-
807
- # TAB 2: Customer/Supplier Details with SWAP button
808
- with tab2:
809
- # SWAP BUTTON - Centered and prominent
810
- col1, col2, col3 = st.columns([1, 2, 1])
811
- with col2:
812
- if st.button("πŸ”„ Swap Customer ↔ Supplier", key=f"swap_btn_{selected_file}",
813
- type="primary", use_container_width=True):
814
- if not st.session_state.just_swapped:
815
- st.session_state.just_swapped = True
816
- swap_customer_supplier_details(selected_file)
817
- st.rerun()
818
-
819
- # Reset the flag after rerun
820
- if st.session_state.just_swapped:
821
- st.session_state.just_swapped = False
822
 
823
- st.markdown("**Customer Details**")
824
- customer_supplier = gt_parse.get('Customer_supplier_details', {})
825
 
826
- col_input, col_btn = st.columns([5, 1])
827
- with col_input:
828
- customer_supplier['Customer_name'] = st.text_input(
829
- "Customer Name",
830
- value=customer_supplier.get('Customer_name', ''),
831
- key=f"cust_name_{selected_file}"
832
- )
833
- with col_btn:
834
- st.markdown("<br>", unsafe_allow_html=True)
835
- if st.button("πŸ”", key=f"ocr_cust_name_{selected_file}",
836
- type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_name') else "secondary"):
837
- activate_ocr_field('Customer_supplier_details', 'Customer_name')
838
 
839
- col_input, col_btn = st.columns([5, 1])
840
- with col_input:
841
- customer_supplier['Customer_address'] = st.text_area(
842
- "Customer Address",
843
- value=customer_supplier.get('Customer_address', ''),
844
- key=f"cust_addr_{selected_file}",
845
- height=60
846
- )
847
- with col_btn:
848
- st.markdown("<br>", unsafe_allow_html=True)
849
- if st.button("πŸ”", key=f"ocr_cust_addr_{selected_file}",
850
- type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_address') else "secondary"):
851
- activate_ocr_field('Customer_supplier_details', 'Customer_address')
852
-
853
- col_input, col_btn = st.columns([5, 1])
854
- with col_input:
855
- customer_supplier['Customer_contact_info'] = st.text_input(
856
- "Customer Contact Info",
857
- value=customer_supplier.get('Customer_contact_info', ''),
858
- key=f"cust_contact_{selected_file}"
859
- )
860
- with col_btn:
861
- st.markdown("<br>", unsafe_allow_html=True)
862
- if st.button("πŸ”", key=f"ocr_cust_contact_{selected_file}",
863
- type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_contact_info') else "secondary"):
864
- activate_ocr_field('Customer_supplier_details', 'Customer_contact_info')
865
-
866
- st.markdown("**Supplier Details**")
867
-
868
- col_input, col_btn = st.columns([5, 1])
869
- with col_input:
870
- customer_supplier['Supplier_name'] = st.text_input(
871
- "Supplier Name",
872
- value=customer_supplier.get('Supplier_name', ''),
873
- key=f"supp_name_{selected_file}"
874
- )
875
- with col_btn:
876
- st.markdown("<br>", unsafe_allow_html=True)
877
- if st.button("πŸ”", key=f"ocr_supp_name_{selected_file}",
878
- type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_name') else "secondary"):
879
- activate_ocr_field('Customer_supplier_details', 'Supplier_name')
880
-
881
- col_input, col_btn = st.columns([5, 1])
882
- with col_input:
883
- customer_supplier['Supplier_address'] = st.text_area(
884
- "Supplier Address",
885
- value=customer_supplier.get('Supplier_address', ''),
886
- key=f"supp_addr_{selected_file}",
887
- height=60
888
- )
889
- with col_btn:
890
- st.markdown("<br>", unsafe_allow_html=True)
891
- if st.button("πŸ”", key=f"ocr_supp_addr_{selected_file}",
892
- type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_address') else "secondary"):
893
- activate_ocr_field('Customer_supplier_details', 'Supplier_address')
894
-
895
- col_input, col_btn = st.columns([5, 1])
896
- with col_input:
897
- customer_supplier['Supplier_contact_info'] = st.text_input(
898
- "Supplier Contact Info",
899
- value=customer_supplier.get('Supplier_contact_info', ''),
900
- key=f"supp_contact_{selected_file}"
901
- )
902
- with col_btn:
903
- st.markdown("<br>", unsafe_allow_html=True)
904
- if st.button("πŸ”", key=f"ocr_supp_contact_{selected_file}",
905
- type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_contact_info') else "secondary"):
906
- activate_ocr_field('Customer_supplier_details', 'Supplier_contact_info')
907
-
908
- gt_parse['Customer_supplier_details'] = customer_supplier
909
-
910
- # TAB 3: Bank Details
911
- with tab3:
912
- bank = gt_parse.get('Bank_details', {})
913
-
914
- col_input, col_btn = st.columns([5, 1])
915
- with col_input:
916
- bank['Bank_name'] = st.text_input(
917
- "Bank Name",
918
- value=bank.get('Bank_name', ''),
919
- key=f"bank_name_{selected_file}"
920
- )
921
- with col_btn:
922
- st.markdown("<br>", unsafe_allow_html=True)
923
- if st.button("πŸ”", key=f"ocr_bank_name_{selected_file}",
924
- type="primary" if is_ocr_active('Bank_details', 'Bank_name') else "secondary"):
925
- activate_ocr_field('Bank_details', 'Bank_name')
926
-
927
- col_input, col_btn = st.columns([5, 1])
928
- with col_input:
929
- bank['Bank_acc_no'] = st.text_input(
930
- "Bank Account No",
931
- value=bank.get('Bank_acc_no', ''),
932
- key=f"bank_acc_{selected_file}"
933
- )
934
- with col_btn:
935
- st.markdown("<br>", unsafe_allow_html=True)
936
- if st.button("πŸ”", key=f"ocr_bank_acc_{selected_file}",
937
- type="primary" if is_ocr_active('Bank_details', 'Bank_acc_no') else "secondary"):
938
- activate_ocr_field('Bank_details', 'Bank_acc_no')
939
-
940
- col_input, col_btn = st.columns([5, 1])
941
- with col_input:
942
- bank['Bank_routing_no'] = st.text_input(
943
- "Bank Routing No",
944
- value=bank.get('Bank_routing_no', ''),
945
- key=f"bank_routing_{selected_file}"
946
- )
947
- with col_btn:
948
- st.markdown("<br>", unsafe_allow_html=True)
949
- if st.button("πŸ”", key=f"ocr_bank_routing_{selected_file}",
950
- type="primary" if is_ocr_active('Bank_details', 'Bank_routing_no') else "secondary"):
951
- activate_ocr_field('Bank_details', 'Bank_routing_no')
952
 
953
- col_input, col_btn = st.columns([5, 1])
954
- with col_input:
955
- bank['Swift_code'] = st.text_input(
956
- "SWIFT Code",
957
- value=bank.get('Swift_code', ''),
958
- key=f"swift_{selected_file}"
959
- )
960
- with col_btn:
961
- st.markdown("<br>", unsafe_allow_html=True)
962
- if st.button("πŸ”", key=f"ocr_swift_{selected_file}",
963
- type="primary" if is_ocr_active('Bank_details', 'Swift_code') else "secondary"):
964
- activate_ocr_field('Bank_details', 'Swift_code')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
965
 
966
- gt_parse['Bank_details'] = bank
967
-
968
- # TAB 4: Line Items
969
- with tab4:
970
- current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
971
- line_items = current_gt_parse.get('Line_items', [])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
972
 
973
- # Add/Remove row buttons
974
- col_add, col_remove = st.columns([1, 1])
975
- with col_add:
976
- if st.button("βž• Add New Row", key=f"add_row_{selected_file}", use_container_width=True):
977
- if not st.session_state.button_clicked:
978
- st.session_state.button_clicked = True
979
- new_row = {
980
- "Po_number": "", "Invoice_no": "", "Other_doc_ref_no": "",
981
- "Invoice_date": "", "Invoice_amount_FCY": "",
982
- "Amount_paid_for_each_invoice": "", "Outstanding_balance_FCY": "",
983
- "Discounts_taken_FCY": "", "Adjustments(without_holding_tax)_FCY": "",
984
- "Descriptions": ""
985
- }
986
- current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
987
- current_line_items = current_gt_parse.get('Line_items', [])
988
- current_line_items.append(new_row)
989
- current_gt_parse['Line_items'] = current_line_items
990
- st.session_state.edited_data[selected_file]['gt_parse'] = current_gt_parse
991
- st.session_state.modified_indices.add(selected_file)
992
-
993
- # Ensure the newly added row's expander is open
994
- new_idx = len(current_line_items) - 1
995
- expander_key_new = f"line_item_expander_{selected_file}_{new_idx}"
996
- st.session_state[expander_key_new] = True
997
 
998
- st.rerun()
999
-
1000
- with col_remove:
1001
- if st.button("βž– Remove Last Row", key=f"remove_row_{selected_file}",
1002
- disabled=(len(line_items) == 0), use_container_width=True):
1003
- if not st.session_state.button_clicked and len(line_items) > 0:
1004
- st.session_state.button_clicked = True
1005
- current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
1006
- current_line_items = current_gt_parse.get('Line_items', [])
1007
- N = len(current_line_items)
1008
- current_line_items.pop()
1009
- current_gt_parse['Line_items'] = current_line_items
1010
- st.session_state.edited_data[selected_file]['gt_parse'] = current_gt_parse
1011
- st.session_state.modified_indices.add(selected_file)
1012
 
1013
- # Remove the expander flag for the popped row (if present)
1014
- popped_idx = N - 1
1015
- expander_key_popped = f"line_item_expander_{selected_file}_{popped_idx}"
1016
- if expander_key_popped in st.session_state:
1017
- del st.session_state[expander_key_popped]
 
 
 
 
 
 
 
 
 
1018
 
1019
- st.rerun()
1020
-
1021
- if st.session_state.button_clicked:
1022
- st.session_state.button_clicked = False
1023
-
1024
- # Display each row as an expander with OCR buttons
1025
- current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
1026
- line_items = current_gt_parse.get('Line_items', [])
1027
-
1028
- if line_items:
1029
- for idx, item in enumerate(line_items):
1030
- # Use a persistent session_state flag so expansion state is preserved across reruns.
1031
- expander_key = f"line_item_expander_{selected_file}_{idx}"
1032
- expanded_default = st.session_state.get(expander_key, False)
1033
 
1034
- # Note: do NOT pass a 'key' arg to st.expander to maintain compatibility; control expanded via session_state flag.
1035
- with st.expander(f"**Row {idx + 1}** - Invoice: {item.get('Invoice_no', 'N/A')}", expanded=expanded_default):
1036
- # PO Number
1037
- col_input, col_btn = st.columns([5, 1])
1038
- with col_input:
1039
- item['Po_number'] = st.text_input(
1040
- "PO Number",
1041
- value=item.get('Po_number', ''),
1042
- key=f"po_num_{selected_file}_{idx}"
1043
- )
1044
- with col_btn:
1045
- st.markdown("<br>", unsafe_allow_html=True)
1046
- if st.button("πŸ”", key=f"ocr_po_{selected_file}_{idx}",
1047
- type="primary" if is_ocr_active('Line_items', 'Po_number', idx) else "secondary"):
1048
- # ensure expander stays open when user explicitly requests OCR
1049
- st.session_state[expander_key] = True
1050
- activate_ocr_field('Line_items', 'Po_number', idx)
1051
-
1052
- # Invoice No
1053
- col_input, col_btn = st.columns([5, 1])
1054
- with col_input:
1055
- item['Invoice_no'] = st.text_input(
1056
- "Invoice No",
1057
- value=item.get('Invoice_no', ''),
1058
- key=f"inv_no_{selected_file}_{idx}"
1059
- )
1060
- with col_btn:
1061
- st.markdown("<br>", unsafe_allow_html=True)
1062
- if st.button("πŸ”", key=f"ocr_inv_{selected_file}_{idx}",
1063
- type="primary" if is_ocr_active('Line_items', 'Invoice_no', idx) else "secondary"):
1064
- st.session_state[expander_key] = True
1065
- activate_ocr_field('Line_items', 'Invoice_no', idx)
1066
-
1067
- # Other Doc Ref No
1068
- col_input, col_btn = st.columns([5, 1])
1069
- with col_input:
1070
- item['Other_doc_ref_no'] = st.text_input(
1071
- "Other Doc Ref No",
1072
- value=item.get('Other_doc_ref_no', ''),
1073
- key=f"other_doc_{selected_file}_{idx}"
1074
- )
1075
- with col_btn:
1076
- st.markdown("<br>", unsafe_allow_html=True)
1077
- if st.button("πŸ”", key=f"ocr_other_{selected_file}_{idx}",
1078
- type="primary" if is_ocr_active('Line_items', 'Other_doc_ref_no', idx) else "secondary"):
1079
- st.session_state[expander_key] = True
1080
- activate_ocr_field('Line_items', 'Other_doc_ref_no', idx)
1081
-
1082
- # Invoice Date
1083
- col_input, col_btn = st.columns([5, 1])
1084
- with col_input:
1085
- item['Invoice_date'] = st.text_input(
1086
- "Invoice Date",
1087
- value=item.get('Invoice_date', ''),
1088
- key=f"inv_date_{selected_file}_{idx}"
1089
- )
1090
- with col_btn:
1091
- st.markdown("<br>", unsafe_allow_html=True)
1092
- if st.button("πŸ”", key=f"ocr_inv_date_{selected_file}_{idx}",
1093
- type="primary" if is_ocr_active('Line_items', 'Invoice_date', idx) else "secondary"):
1094
- st.session_state[expander_key] = True
1095
- activate_ocr_field('Line_items', 'Invoice_date', idx)
1096
-
1097
- # Invoice Amount FCY
1098
- col_input, col_btn = st.columns([5, 1])
1099
- with col_input:
1100
- item['Invoice_amount_FCY'] = st.text_input(
1101
- "Invoice Amount FCY",
1102
- value=item.get('Invoice_amount_FCY', ''),
1103
- key=f"inv_amt_{selected_file}_{idx}"
1104
- )
1105
- with col_btn:
1106
- st.markdown("<br>", unsafe_allow_html=True)
1107
- if st.button("πŸ”", key=f"ocr_inv_amt_{selected_file}_{idx}",
1108
- type="primary" if is_ocr_active('Line_items', 'Invoice_amount_FCY', idx) else "secondary"):
1109
- st.session_state[expander_key] = True
1110
- activate_ocr_field('Line_items', 'Invoice_amount_FCY', idx)
1111
-
1112
- # Amount Paid
1113
- col_input, col_btn = st.columns([5, 1])
1114
- with col_input:
1115
- item['Amount_paid_for_each_invoice'] = st.text_input(
1116
- "Amount Paid",
1117
- value=item.get('Amount_paid_for_each_invoice', ''),
1118
- key=f"amt_paid_{selected_file}_{idx}"
1119
- )
1120
- with col_btn:
1121
- st.markdown("<br>", unsafe_allow_html=True)
1122
- if st.button("πŸ”", key=f"ocr_amt_paid_{selected_file}_{idx}",
1123
- type="primary" if is_ocr_active('Line_items', 'Amount_paid_for_each_invoice', idx) else "secondary"):
1124
- st.session_state[expander_key] = True
1125
- activate_ocr_field('Line_items', 'Amount_paid_for_each_invoice', idx)
1126
-
1127
- # Outstanding Balance
1128
- col_input, col_btn = st.columns([5, 1])
1129
- with col_input:
1130
- item['Outstanding_balance_FCY'] = st.text_input(
1131
- "Outstanding Balance FCY",
1132
- value=item.get('Outstanding_balance_FCY', ''),
1133
- key=f"out_bal_{selected_file}_{idx}"
1134
- )
1135
- with col_btn:
1136
- st.markdown("<br>", unsafe_allow_html=True)
1137
- if st.button("πŸ”", key=f"ocr_out_bal_{selected_file}_{idx}",
1138
- type="primary" if is_ocr_active('Line_items', 'Outstanding_balance_FCY', idx) else "secondary"):
1139
- st.session_state[expander_key] = True
1140
- activate_ocr_field('Line_items', 'Outstanding_balance_FCY', idx)
1141
-
1142
- # Discounts
1143
- col_input, col_btn = st.columns([5, 1])
1144
- with col_input:
1145
- item['Discounts_taken_FCY'] = st.text_input(
1146
- "Discounts Taken FCY",
1147
- value=item.get('Discounts_taken_FCY', ''),
1148
- key=f"disc_{selected_file}_{idx}"
1149
- )
1150
- with col_btn:
1151
- st.markdown("<br>", unsafe_allow_html=True)
1152
- if st.button("πŸ”", key=f"ocr_disc_{selected_file}_{idx}",
1153
- type="primary" if is_ocr_active('Line_items', 'Discounts_taken_FCY', idx) else "secondary"):
1154
- st.session_state[expander_key] = True
1155
- activate_ocr_field('Line_items', 'Discounts_taken_FCY', idx)
1156
-
1157
- # Adjustments
1158
- col_input, col_btn = st.columns([5, 1])
1159
- with col_input:
1160
- item['Adjustments(without_holding_tax)_FCY'] = st.text_input(
1161
- "Adjustments FCY",
1162
- value=item.get('Adjustments(without_holding_tax)_FCY', ''),
1163
- key=f"adj_{selected_file}_{idx}"
1164
- )
1165
- with col_btn:
1166
- st.markdown("<br>", unsafe_allow_html=True)
1167
- if st.button("πŸ”", key=f"ocr_adj_{selected_file}_{idx}",
1168
- type="primary" if is_ocr_active('Line_items', 'Adjustments(without_holding_tax)_FCY', idx) else "secondary"):
1169
- st.session_state[expander_key] = True
1170
- activate_ocr_field('Line_items', 'Adjustments(without_holding_tax)_FCY', idx)
1171
-
1172
- # Descriptions
1173
- col_input, col_btn = st.columns([5, 1])
1174
- with col_input:
1175
- item['Descriptions'] = st.text_area(
1176
- "Descriptions",
1177
- value=item.get('Descriptions', ''),
1178
- key=f"desc_{selected_file}_{idx}",
1179
- height=60
1180
- )
1181
- with col_btn:
1182
- st.markdown("<br>", unsafe_allow_html=True)
1183
- if st.button("πŸ”", key=f"ocr_desc_{selected_file}_{idx}",
1184
- type="primary" if is_ocr_active('Line_items', 'Descriptions', idx) else "secondary"):
1185
- st.session_state[expander_key] = True
1186
- activate_ocr_field('Line_items', 'Descriptions', idx)
1187
-
1188
- # Update line items back to gt_parse
1189
- current_gt_parse['Line_items'] = line_items
1190
 
1191
- st.markdown("**πŸ“Š Line Items Summary Table**")
 
1192
 
1193
- # Display summary table with index starting from 1
1194
- df = pd.DataFrame(line_items)
1195
- df.index = df.index + 1 # Start index from 1
1196
- df.index.name = 'SL No'
1197
 
1198
- st.dataframe(
1199
- df,
1200
- use_container_width=True,
1201
- height=300
1202
- )
1203
- else:
1204
- st.info("No line items. Click 'βž• Add New Row' to add a new row.")
1205
-
1206
- st.session_state.edited_data[selected_file]['gt_parse'] = gt_parse
1207
-
1208
- # Save button
1209
- col1, col2 = st.columns([1, 1])
1210
- with col1:
1211
- if st.button("πŸ’Ύ Save Changes", type="primary", use_container_width=True, key=f"save_btn_{selected_file}"):
1212
- if not st.session_state.just_saved:
1213
- st.session_state.just_saved = True
1214
- auto_save(selected_file)
1215
- st.session_state.save_message = "βœ… Changes saved successfully!"
1216
- st.session_state.save_message_time = time.time()
1217
- st.rerun()
1218
-
1219
- if st.session_state.just_saved:
1220
- st.session_state.just_saved = False
1221
-
1222
- if st.session_state.save_message:
1223
- st.success(st.session_state.save_message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
 
538
  # LEFT SIDE: Image Display with OCR Canvas
539
  with left_col:
540
+ with st.container(height=700, border=True):
541
+ file_name = current_record.get('file_name', '')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
 
543
+ if file_name:
544
+ # Find the actual file name (handle cases where extension is missing)
545
+ actual_file_name = None
546
+ if file_name in st.session_state.images:
547
+ actual_file_name = file_name
548
+ else:
549
+ # Try adding common extensions
550
+ for ext in ['.pdf', '.png', '.jpg', '.jpeg', '.tiff', '.tif', '.bmp']:
551
+ if file_name + ext in st.session_state.images:
552
+ actual_file_name = file_name + ext
553
+ break
 
 
 
 
554
 
555
+ # Try matching without extension
556
+ if not actual_file_name:
557
+ for uploaded_name in st.session_state.images.keys():
558
+ uploaded_base = uploaded_name.rsplit('.', 1)[0]
559
+ if uploaded_base == file_name:
560
+ actual_file_name = uploaded_name
561
+ break
562
+
563
+ if actual_file_name:
564
+ # Check if this is a PDF with multiple pages
565
+ is_pdf = actual_file_name in st.session_state.pdf_metadata
566
 
567
+ if is_pdf:
568
+ pdf_meta = st.session_state.pdf_metadata[actual_file_name]
569
+ total_pages = pdf_meta['total_pages']
570
+ current_page = st.session_state.current_page_num.get(actual_file_name, 0)
571
+
572
+ # PDF Navigation Header
573
+ col_prev, col_info, col_next = st.columns([1, 2, 1])
574
+
575
+ with col_prev:
576
+ prev_clicked = st.button("⬅️ Previous", key=f"prev_page_{selected_file}_{actual_file_name}",
577
+ disabled=(current_page == 0), use_container_width=True)
578
+
579
+ with col_info:
580
+ st.markdown(f"<div style='text-align: center; padding: 5px;'><b>πŸ“„ Page {current_page + 1} of {total_pages}</b></div>", unsafe_allow_html=True)
581
+
582
+ with col_next:
583
+ next_clicked = st.button("Next ➑️", key=f"next_page_{selected_file}_{actual_file_name}",
584
+ disabled=(current_page >= total_pages - 1), use_container_width=True)
585
+
586
+ # Handle navigation only if not already navigating
587
+ if not st.session_state.navigating_page:
588
+ if prev_clicked:
589
+ st.session_state.navigating_page = True
590
+ st.session_state.current_page_num[actual_file_name] = max(0, current_page - 1)
591
+ st.session_state.canvas_key += 1
592
+ st.session_state.ocr_active_section = None
593
+ st.session_state.ocr_active_field = None
594
+ st.rerun()
595
+ elif next_clicked:
596
+ st.session_state.navigating_page = True
597
+ st.session_state.current_page_num[actual_file_name] = min(total_pages - 1, current_page + 1)
598
+ st.session_state.canvas_key += 1
599
+ st.session_state.ocr_active_section = None
600
+ st.session_state.ocr_active_field = None
601
+ st.rerun()
602
+ else:
603
+ # Reset the flag after rerun
604
+ st.session_state.navigating_page = False
605
+
606
+ if actual_file_name:
607
+ # Determine if PDF and get the appropriate image
608
+ is_pdf = actual_file_name in st.session_state.pdf_metadata
609
 
610
+ if is_pdf:
611
+ # Get the current page image
612
+ current_page = st.session_state.current_page_num.get(actual_file_name, 0)
613
+ pdf_meta = st.session_state.pdf_metadata[actual_file_name]
614
+ current_image = pdf_meta['pages'][current_page]
 
 
 
 
 
 
 
 
 
 
 
615
  else:
616
+ current_image = st.session_state.images[actual_file_name]
 
 
 
 
 
 
 
 
 
 
 
617
  else:
618
+ st.error(f"❌ File '{file_name}' not found in uploaded files")
619
+ st.info("πŸ’‘ Available files:")
620
+ with st.expander("Show available files"):
621
+ for img_name in list(st.session_state.images.keys())[:20]:
622
+ st.text(f" β€’ {img_name}")
623
+ if len(st.session_state.images) > 20:
624
+ st.text(f" ... and {len(st.session_state.images) - 20} more")
 
 
 
 
 
 
625
 
626
+ if current_image:
627
+ # Scale to a reasonable size so canvas doesn't become excessively large
628
+ scaled_image, scale_ratio, paste_x, paste_y = scale_image_to_fixed_size(current_image)
629
+
630
+ # Render the canvas. Its internal canvas will be constrained by the wrapper due to CSS above.
631
+ canvas_result = st_canvas(
632
+ fill_color="rgba(255, 165, 0, 0.3)",
633
+ stroke_width=2,
634
+ stroke_color="#FF0000",
635
+ background_image=scaled_image,
636
+ update_streamlit=True,
637
+ height=scaled_image.height,
638
+ width=scaled_image.width,
639
+ drawing_mode="rect",
640
+ key=f"canvas_{selected_file}_{st.session_state.canvas_key}",
641
+ )
642
+
643
+ # Only attempt OCR if there's an active OCR target AND the user has drawn something (objects exist)
644
+ if canvas_result.json_data is not None and st.session_state.ocr_active_field:
645
+ objects = canvas_result.json_data.get("objects", [])
646
+ if len(objects) > 0:
647
+ rect = objects[-1]
648
+
649
+ bbox = [
650
+ (rect["left"] - paste_x) / scale_ratio,
651
+ (rect["top"] - paste_y) / scale_ratio,
652
+ (rect["left"] + rect["width"] - paste_x) / scale_ratio,
653
+ (rect["top"] + rect["height"] - paste_y) / scale_ratio
654
+ ]
 
 
655
 
656
+ with st.spinner("Performing OCR..."):
657
+ ocr_text = perform_ocr(current_image, bbox)
658
 
659
+ if ocr_text and not ocr_text.startswith("OCR Error"):
660
+ st.success(f"βœ… OCR Result: {ocr_text}")
661
+
662
+ gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
663
+
664
+ if st.session_state.ocr_active_section == 'Line_items':
665
+ line_items = gt_parse.get('Line_items', [])
666
+ row_idx = st.session_state.ocr_line_item_row
667
+ if row_idx is not None and row_idx < len(line_items):
668
+ line_items[row_idx][st.session_state.ocr_active_field] = ocr_text
669
+ gt_parse['Line_items'] = line_items
670
 
671
+ # ensure expander stays open for this row after OCR
672
+ expander_key = f"line_item_expander_{selected_file}_{row_idx}"
673
+ st.session_state[expander_key] = True
674
+ else:
675
+ section = st.session_state.ocr_active_section
676
+ field = st.session_state.ocr_active_field
677
+ if section not in gt_parse:
678
+ gt_parse[section] = {}
679
+ gt_parse[section][field] = ocr_text
680
+
681
+ st.session_state.edited_data[selected_file]['gt_parse'] = gt_parse
682
+ st.session_state.modified_indices.add(selected_file)
683
+
684
+ # After successful OCR, deactivate OCR target to prevent repeated triggers/loops
685
+ st.session_state.ocr_active_section = None
686
+ st.session_state.ocr_active_field = None
687
+ st.session_state.ocr_line_item_row = None
688
+
689
+ # Clear canvas for next OCR by bumping canvas_key then rerun
690
+ st.session_state.canvas_key += 1
691
+ st.rerun()
692
  else:
693
+ st.error(ocr_text)
694
+ else:
695
+ st.warning("No file name specified in record")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696
 
697
  # RIGHT SIDE: Editable Details
698
  with right_col:
699
+ with st.container(height=700, border=True):
700
+ st.markdown("### πŸ“ Document Details")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
 
702
+ gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
 
703
 
704
+ tab1, tab2, tab3, tab4 = st.tabs([
705
+ "πŸ“„ Remittance Details",
706
+ "πŸ‘₯ Party Details",
707
+ "🏦 Bank Details",
708
+ "πŸ“‹ Line Items"
709
+ ])
 
 
 
 
 
 
710
 
711
+ # TAB 1: Remittance Details
712
+ with tab1:
713
+ remittance = gt_parse.get('Remittance_details', {})
714
+
715
+ # Each field with OCR button
716
+ col_input, col_btn = st.columns([5, 1])
717
+ with col_input:
718
+ remittance['Remittance_adv_no'] = st.text_input(
719
+ "Remittance Advice No",
720
+ value=remittance.get('Remittance_adv_no', ''),
721
+ key=f"rem_adv_no_{selected_file}"
722
+ )
723
+ with col_btn:
724
+ st.markdown("<br>", unsafe_allow_html=True)
725
+ if st.button("πŸ”", key=f"ocr_rem_adv_no_{selected_file}",
726
+ type="primary" if is_ocr_active('Remittance_details', 'Remittance_adv_no') else "secondary"):
727
+ activate_ocr_field('Remittance_details', 'Remittance_adv_no')
728
+
729
+ col_input, col_btn = st.columns([5, 1])
730
+ with col_input:
731
+ remittance['Remittance_adv_date'] = st.text_input(
732
+ "Remittance Advice Date",
733
+ value=remittance.get('Remittance_adv_date', ''),
734
+ key=f"rem_adv_date_{selected_file}"
735
+ )
736
+ with col_btn:
737
+ st.markdown("<br>", unsafe_allow_html=True)
738
+ if st.button("πŸ”", key=f"ocr_rem_adv_date_{selected_file}",
739
+ type="primary" if is_ocr_active('Remittance_details', 'Remittance_adv_date') else "secondary"):
740
+ activate_ocr_field('Remittance_details', 'Remittance_adv_date')
741
+
742
+ col_input, col_btn = st.columns([5, 1])
743
+ with col_input:
744
+ remittance['Payment_method'] = st.text_input(
745
+ "Payment Method",
746
+ value=remittance.get('Payment_method', ''),
747
+ key=f"payment_method_{selected_file}"
748
+ )
749
+ with col_btn:
750
+ st.markdown("<br>", unsafe_allow_html=True)
751
+ if st.button("πŸ”", key=f"ocr_payment_method_{selected_file}",
752
+ type="primary" if is_ocr_active('Remittance_details', 'Payment_method') else "secondary"):
753
+ activate_ocr_field('Remittance_details', 'Payment_method')
754
+
755
+ col_input, col_btn = st.columns([5, 1])
756
+ with col_input:
757
+ remittance['FCY'] = st.text_input(
758
+ "FCY (Foreign Currency)",
759
+ value=remittance.get('FCY', ''),
760
+ key=f"fcy_{selected_file}"
761
+ )
762
+ with col_btn:
763
+ st.markdown("<br>", unsafe_allow_html=True)
764
+ if st.button("πŸ”", key=f"ocr_fcy_{selected_file}",
765
+ type="primary" if is_ocr_active('Remittance_details', 'FCY') else "secondary"):
766
+ activate_ocr_field('Remittance_details', 'FCY')
767
+
768
+ col_input, col_btn = st.columns([5, 1])
769
+ with col_input:
770
+ remittance['Total_payment_amt_FCY'] = st.text_input(
771
+ "Total Payment Amount (FCY)",
772
+ value=remittance.get('Total_payment_amt_FCY', ''),
773
+ key=f"total_payment_{selected_file}"
774
+ )
775
+ with col_btn:
776
+ st.markdown("<br>", unsafe_allow_html=True)
777
+ if st.button("πŸ”", key=f"ocr_total_payment_{selected_file}",
778
+ type="primary" if is_ocr_active('Remittance_details', 'Total_payment_amt_FCY') else "secondary"):
779
+ activate_ocr_field('Remittance_details', 'Total_payment_amt_FCY')
780
+
781
+ col_input, col_btn = st.columns([5, 1])
782
+ with col_input:
783
+ remittance['Payment_date'] = st.text_input(
784
+ "Payment Date",
785
+ value=remittance.get('Payment_date', ''),
786
+ key=f"payment_date_{selected_file}"
787
+ )
788
+ with col_btn:
789
+ st.markdown("<br>", unsafe_allow_html=True)
790
+ if st.button("πŸ”", key=f"ocr_payment_date_{selected_file}",
791
+ type="primary" if is_ocr_active('Remittance_details', 'Payment_date') else "secondary"):
792
+ activate_ocr_field('Remittance_details', 'Payment_date')
793
+
794
+ col_input, col_btn = st.columns([5, 1])
795
+ with col_input:
796
+ remittance['Payment_ref_no'] = st.text_input(
797
+ "Payment Reference No",
798
+ value=remittance.get('Payment_ref_no', ''),
799
+ key=f"payment_ref_{selected_file}"
800
+ )
801
+ with col_btn:
802
+ st.markdown("<br>", unsafe_allow_html=True)
803
+ if st.button("πŸ”", key=f"ocr_payment_ref_{selected_file}",
804
+ type="primary" if is_ocr_active('Remittance_details', 'Payment_ref_no') else "secondary"):
805
+ activate_ocr_field('Remittance_details', 'Payment_ref_no')
806
+
807
+ gt_parse['Remittance_details'] = remittance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
808
 
809
+ # TAB 2: Customer/Supplier Details with SWAP button
810
+ with tab2:
811
+ # SWAP BUTTON - Centered and prominent
812
+ col1, col2, col3 = st.columns([1, 2, 1])
813
+ with col2:
814
+ if st.button("πŸ”„ Swap Customer ↔ Supplier", key=f"swap_btn_{selected_file}",
815
+ type="primary", use_container_width=True):
816
+ if not st.session_state.just_swapped:
817
+ st.session_state.just_swapped = True
818
+ swap_customer_supplier_details(selected_file)
819
+ st.rerun()
820
+
821
+ # Reset the flag after rerun
822
+ if st.session_state.just_swapped:
823
+ st.session_state.just_swapped = False
824
+
825
+ st.markdown("**Customer Details**")
826
+ customer_supplier = gt_parse.get('Customer_supplier_details', {})
827
+
828
+ col_input, col_btn = st.columns([5, 1])
829
+ with col_input:
830
+ customer_supplier['Customer_name'] = st.text_input(
831
+ "Customer Name",
832
+ value=customer_supplier.get('Customer_name', ''),
833
+ key=f"cust_name_{selected_file}"
834
+ )
835
+ with col_btn:
836
+ st.markdown("<br>", unsafe_allow_html=True)
837
+ if st.button("πŸ”", key=f"ocr_cust_name_{selected_file}",
838
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_name') else "secondary"):
839
+ activate_ocr_field('Customer_supplier_details', 'Customer_name')
840
+
841
+ col_input, col_btn = st.columns([5, 1])
842
+ with col_input:
843
+ customer_supplier['Customer_address'] = st.text_area(
844
+ "Customer Address",
845
+ value=customer_supplier.get('Customer_address', ''),
846
+ key=f"cust_addr_{selected_file}",
847
+ height=60
848
+ )
849
+ with col_btn:
850
+ st.markdown("<br>", unsafe_allow_html=True)
851
+ if st.button("πŸ”", key=f"ocr_cust_addr_{selected_file}",
852
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_address') else "secondary"):
853
+ activate_ocr_field('Customer_supplier_details', 'Customer_address')
854
+
855
+ col_input, col_btn = st.columns([5, 1])
856
+ with col_input:
857
+ customer_supplier['Customer_contact_info'] = st.text_input(
858
+ "Customer Contact Info",
859
+ value=customer_supplier.get('Customer_contact_info', ''),
860
+ key=f"cust_contact_{selected_file}"
861
+ )
862
+ with col_btn:
863
+ st.markdown("<br>", unsafe_allow_html=True)
864
+ if st.button("πŸ”", key=f"ocr_cust_contact_{selected_file}",
865
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Customer_contact_info') else "secondary"):
866
+ activate_ocr_field('Customer_supplier_details', 'Customer_contact_info')
867
+
868
+ st.markdown("**Supplier Details**")
869
+
870
+ col_input, col_btn = st.columns([5, 1])
871
+ with col_input:
872
+ customer_supplier['Supplier_name'] = st.text_input(
873
+ "Supplier Name",
874
+ value=customer_supplier.get('Supplier_name', ''),
875
+ key=f"supp_name_{selected_file}"
876
+ )
877
+ with col_btn:
878
+ st.markdown("<br>", unsafe_allow_html=True)
879
+ if st.button("πŸ”", key=f"ocr_supp_name_{selected_file}",
880
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_name') else "secondary"):
881
+ activate_ocr_field('Customer_supplier_details', 'Supplier_name')
882
+
883
+ col_input, col_btn = st.columns([5, 1])
884
+ with col_input:
885
+ customer_supplier['Supplier_address'] = st.text_area(
886
+ "Supplier Address",
887
+ value=customer_supplier.get('Supplier_address', ''),
888
+ key=f"supp_addr_{selected_file}",
889
+ height=60
890
+ )
891
+ with col_btn:
892
+ st.markdown("<br>", unsafe_allow_html=True)
893
+ if st.button("πŸ”", key=f"ocr_supp_addr_{selected_file}",
894
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_address') else "secondary"):
895
+ activate_ocr_field('Customer_supplier_details', 'Supplier_address')
896
+
897
+ col_input, col_btn = st.columns([5, 1])
898
+ with col_input:
899
+ customer_supplier['Supplier_contact_info'] = st.text_input(
900
+ "Supplier Contact Info",
901
+ value=customer_supplier.get('Supplier_contact_info', ''),
902
+ key=f"supp_contact_{selected_file}"
903
+ )
904
+ with col_btn:
905
+ st.markdown("<br>", unsafe_allow_html=True)
906
+ if st.button("πŸ”", key=f"ocr_supp_contact_{selected_file}",
907
+ type="primary" if is_ocr_active('Customer_supplier_details', 'Supplier_contact_info') else "secondary"):
908
+ activate_ocr_field('Customer_supplier_details', 'Supplier_contact_info')
909
+
910
+ gt_parse['Customer_supplier_details'] = customer_supplier
911
 
912
+ # TAB 3: Bank Details
913
+ with tab3:
914
+ bank = gt_parse.get('Bank_details', {})
915
+
916
+ col_input, col_btn = st.columns([5, 1])
917
+ with col_input:
918
+ bank['Bank_name'] = st.text_input(
919
+ "Bank Name",
920
+ value=bank.get('Bank_name', ''),
921
+ key=f"bank_name_{selected_file}"
922
+ )
923
+ with col_btn:
924
+ st.markdown("<br>", unsafe_allow_html=True)
925
+ if st.button("πŸ”", key=f"ocr_bank_name_{selected_file}",
926
+ type="primary" if is_ocr_active('Bank_details', 'Bank_name') else "secondary"):
927
+ activate_ocr_field('Bank_details', 'Bank_name')
928
+
929
+ col_input, col_btn = st.columns([5, 1])
930
+ with col_input:
931
+ bank['Bank_acc_no'] = st.text_input(
932
+ "Bank Account No",
933
+ value=bank.get('Bank_acc_no', ''),
934
+ key=f"bank_acc_{selected_file}"
935
+ )
936
+ with col_btn:
937
+ st.markdown("<br>", unsafe_allow_html=True)
938
+ if st.button("πŸ”", key=f"ocr_bank_acc_{selected_file}",
939
+ type="primary" if is_ocr_active('Bank_details', 'Bank_acc_no') else "secondary"):
940
+ activate_ocr_field('Bank_details', 'Bank_acc_no')
941
+
942
+ col_input, col_btn = st.columns([5, 1])
943
+ with col_input:
944
+ bank['Bank_routing_no'] = st.text_input(
945
+ "Bank Routing No",
946
+ value=bank.get('Bank_routing_no', ''),
947
+ key=f"bank_routing_{selected_file}"
948
+ )
949
+ with col_btn:
950
+ st.markdown("<br>", unsafe_allow_html=True)
951
+ if st.button("πŸ”", key=f"ocr_bank_routing_{selected_file}",
952
+ type="primary" if is_ocr_active('Bank_details', 'Bank_routing_no') else "secondary"):
953
+ activate_ocr_field('Bank_details', 'Bank_routing_no')
954
+
955
+ col_input, col_btn = st.columns([5, 1])
956
+ with col_input:
957
+ bank['Swift_code'] = st.text_input(
958
+ "SWIFT Code",
959
+ value=bank.get('Swift_code', ''),
960
+ key=f"swift_{selected_file}"
961
+ )
962
+ with col_btn:
963
+ st.markdown("<br>", unsafe_allow_html=True)
964
+ if st.button("πŸ”", key=f"ocr_swift_{selected_file}",
965
+ type="primary" if is_ocr_active('Bank_details', 'Swift_code') else "secondary"):
966
+ activate_ocr_field('Bank_details', 'Swift_code')
967
+
968
+ gt_parse['Bank_details'] = bank
969
 
970
+ # TAB 4: Line Items
971
+ with tab4:
972
+ current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
973
+ line_items = current_gt_parse.get('Line_items', [])
974
+
975
+ # Add/Remove row buttons
976
+ col_add, col_remove = st.columns([1, 1])
977
+ with col_add:
978
+ if st.button("βž• Add New Row", key=f"add_row_{selected_file}", use_container_width=True):
979
+ if not st.session_state.button_clicked:
980
+ st.session_state.button_clicked = True
981
+ new_row = {
982
+ "Po_number": "", "Invoice_no": "", "Other_doc_ref_no": "",
983
+ "Invoice_date": "", "Invoice_amount_FCY": "",
984
+ "Amount_paid_for_each_invoice": "", "Outstanding_balance_FCY": "",
985
+ "Discounts_taken_FCY": "", "Adjustments(without_holding_tax)_FCY": "",
986
+ "Descriptions": ""
987
+ }
988
+ current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
989
+ current_line_items = current_gt_parse.get('Line_items', [])
990
+ current_line_items.append(new_row)
991
+ current_gt_parse['Line_items'] = current_line_items
992
+ st.session_state.edited_data[selected_file]['gt_parse'] = current_gt_parse
993
+ st.session_state.modified_indices.add(selected_file)
994
 
995
+ # Ensure the newly added row's expander is open
996
+ new_idx = len(current_line_items) - 1
997
+ expander_key_new = f"line_item_expander_{selected_file}_{new_idx}"
998
+ st.session_state[expander_key_new] = True
 
 
 
 
 
 
 
 
 
 
999
 
1000
+ st.rerun()
1001
+
1002
+ with col_remove:
1003
+ if st.button("βž– Remove Last Row", key=f"remove_row_{selected_file}",
1004
+ disabled=(len(line_items) == 0), use_container_width=True):
1005
+ if not st.session_state.button_clicked and len(line_items) > 0:
1006
+ st.session_state.button_clicked = True
1007
+ current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
1008
+ current_line_items = current_gt_parse.get('Line_items', [])
1009
+ N = len(current_line_items)
1010
+ current_line_items.pop()
1011
+ current_gt_parse['Line_items'] = current_line_items
1012
+ st.session_state.edited_data[selected_file]['gt_parse'] = current_gt_parse
1013
+ st.session_state.modified_indices.add(selected_file)
1014
 
1015
+ # Remove the expander flag for the popped row (if present)
1016
+ popped_idx = N - 1
1017
+ expander_key_popped = f"line_item_expander_{selected_file}_{popped_idx}"
1018
+ if expander_key_popped in st.session_state:
1019
+ del st.session_state[expander_key_popped]
 
 
 
 
 
 
 
 
 
1020
 
1021
+ st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1022
 
1023
+ if st.session_state.button_clicked:
1024
+ st.session_state.button_clicked = False
1025
 
1026
+ # Display each row as an expander with OCR buttons
1027
+ current_gt_parse = st.session_state.edited_data[selected_file].get('gt_parse', {})
1028
+ line_items = current_gt_parse.get('Line_items', [])
 
1029
 
1030
+ if line_items:
1031
+ for idx, item in enumerate(line_items):
1032
+ # Use a persistent session_state flag so expansion state is preserved across reruns.
1033
+ expander_key = f"line_item_expander_{selected_file}_{idx}"
1034
+ expanded_default = st.session_state.get(expander_key, False)
1035
+
1036
+ # Note: do NOT pass a 'key' arg to st.expander to maintain compatibility; control expanded via session_state flag.
1037
+ with st.expander(f"**Row {idx + 1}** - Invoice: {item.get('Invoice_no', 'N/A')}", expanded=expanded_default):
1038
+ # PO Number
1039
+ col_input, col_btn = st.columns([5, 1])
1040
+ with col_input:
1041
+ item['Po_number'] = st.text_input(
1042
+ "PO Number",
1043
+ value=item.get('Po_number', ''),
1044
+ key=f"po_num_{selected_file}_{idx}"
1045
+ )
1046
+ with col_btn:
1047
+ st.markdown("<br>", unsafe_allow_html=True)
1048
+ if st.button("πŸ”", key=f"ocr_po_{selected_file}_{idx}",
1049
+ type="primary" if is_ocr_active('Line_items', 'Po_number', idx) else "secondary"):
1050
+ # ensure expander stays open when user explicitly requests OCR
1051
+ st.session_state[expander_key] = True
1052
+ activate_ocr_field('Line_items', 'Po_number', idx)
1053
+
1054
+ # Invoice No
1055
+ col_input, col_btn = st.columns([5, 1])
1056
+ with col_input:
1057
+ item['Invoice_no'] = st.text_input(
1058
+ "Invoice No",
1059
+ value=item.get('Invoice_no', ''),
1060
+ key=f"inv_no_{selected_file}_{idx}"
1061
+ )
1062
+ with col_btn:
1063
+ st.markdown("<br>", unsafe_allow_html=True)
1064
+ if st.button("πŸ”", key=f"ocr_inv_{selected_file}_{idx}",
1065
+ type="primary" if is_ocr_active('Line_items', 'Invoice_no', idx) else "secondary"):
1066
+ st.session_state[expander_key] = True
1067
+ activate_ocr_field('Line_items', 'Invoice_no', idx)
1068
+
1069
+ # Other Doc Ref No
1070
+ col_input, col_btn = st.columns([5, 1])
1071
+ with col_input:
1072
+ item['Other_doc_ref_no'] = st.text_input(
1073
+ "Other Doc Ref No",
1074
+ value=item.get('Other_doc_ref_no', ''),
1075
+ key=f"other_doc_{selected_file}_{idx}"
1076
+ )
1077
+ with col_btn:
1078
+ st.markdown("<br>", unsafe_allow_html=True)
1079
+ if st.button("πŸ”", key=f"ocr_other_{selected_file}_{idx}",
1080
+ type="primary" if is_ocr_active('Line_items', 'Other_doc_ref_no', idx) else "secondary"):
1081
+ st.session_state[expander_key] = True
1082
+ activate_ocr_field('Line_items', 'Other_doc_ref_no', idx)
1083
+
1084
+ # Invoice Date
1085
+ col_input, col_btn = st.columns([5, 1])
1086
+ with col_input:
1087
+ item['Invoice_date'] = st.text_input(
1088
+ "Invoice Date",
1089
+ value=item.get('Invoice_date', ''),
1090
+ key=f"inv_date_{selected_file}_{idx}"
1091
+ )
1092
+ with col_btn:
1093
+ st.markdown("<br>", unsafe_allow_html=True)
1094
+ if st.button("πŸ”", key=f"ocr_inv_date_{selected_file}_{idx}",
1095
+ type="primary" if is_ocr_active('Line_items', 'Invoice_date', idx) else "secondary"):
1096
+ st.session_state[expander_key] = True
1097
+ activate_ocr_field('Line_items', 'Invoice_date', idx)
1098
+
1099
+ # Invoice Amount FCY
1100
+ col_input, col_btn = st.columns([5, 1])
1101
+ with col_input:
1102
+ item['Invoice_amount_FCY'] = st.text_input(
1103
+ "Invoice Amount FCY",
1104
+ value=item.get('Invoice_amount_FCY', ''),
1105
+ key=f"inv_amt_{selected_file}_{idx}"
1106
+ )
1107
+ with col_btn:
1108
+ st.markdown("<br>", unsafe_allow_html=True)
1109
+ if st.button("πŸ”", key=f"ocr_inv_amt_{selected_file}_{idx}",
1110
+ type="primary" if is_ocr_active('Line_items', 'Invoice_amount_FCY', idx) else "secondary"):
1111
+ st.session_state[expander_key] = True
1112
+ activate_ocr_field('Line_items', 'Invoice_amount_FCY', idx)
1113
+
1114
+ # Amount Paid
1115
+ col_input, col_btn = st.columns([5, 1])
1116
+ with col_input:
1117
+ item['Amount_paid_for_each_invoice'] = st.text_input(
1118
+ "Amount Paid",
1119
+ value=item.get('Amount_paid_for_each_invoice', ''),
1120
+ key=f"amt_paid_{selected_file}_{idx}"
1121
+ )
1122
+ with col_btn:
1123
+ st.markdown("<br>", unsafe_allow_html=True)
1124
+ if st.button("πŸ”", key=f"ocr_amt_paid_{selected_file}_{idx}",
1125
+ type="primary" if is_ocr_active('Line_items', 'Amount_paid_for_each_invoice', idx) else "secondary"):
1126
+ st.session_state[expander_key] = True
1127
+ activate_ocr_field('Line_items', 'Amount_paid_for_each_invoice', idx)
1128
+
1129
+ # Outstanding Balance
1130
+ col_input, col_btn = st.columns([5, 1])
1131
+ with col_input:
1132
+ item['Outstanding_balance_FCY'] = st.text_input(
1133
+ "Outstanding Balance FCY",
1134
+ value=item.get('Outstanding_balance_FCY', ''),
1135
+ key=f"out_bal_{selected_file}_{idx}"
1136
+ )
1137
+ with col_btn:
1138
+ st.markdown("<br>", unsafe_allow_html=True)
1139
+ if st.button("πŸ”", key=f"ocr_out_bal_{selected_file}_{idx}",
1140
+ type="primary" if is_ocr_active('Line_items', 'Outstanding_balance_FCY', idx) else "secondary"):
1141
+ st.session_state[expander_key] = True
1142
+ activate_ocr_field('Line_items', 'Outstanding_balance_FCY', idx)
1143
+
1144
+ # Discounts
1145
+ col_input, col_btn = st.columns([5, 1])
1146
+ with col_input:
1147
+ item['Discounts_taken_FCY'] = st.text_input(
1148
+ "Discounts Taken FCY",
1149
+ value=item.get('Discounts_taken_FCY', ''),
1150
+ key=f"disc_{selected_file}_{idx}"
1151
+ )
1152
+ with col_btn:
1153
+ st.markdown("<br>", unsafe_allow_html=True)
1154
+ if st.button("πŸ”", key=f"ocr_disc_{selected_file}_{idx}",
1155
+ type="primary" if is_ocr_active('Line_items', 'Discounts_taken_FCY', idx) else "secondary"):
1156
+ st.session_state[expander_key] = True
1157
+ activate_ocr_field('Line_items', 'Discounts_taken_FCY', idx)
1158
+
1159
+ # Adjustments
1160
+ col_input, col_btn = st.columns([5, 1])
1161
+ with col_input:
1162
+ item['Adjustments(without_holding_tax)_FCY'] = st.text_input(
1163
+ "Adjustments FCY",
1164
+ value=item.get('Adjustments(without_holding_tax)_FCY', ''),
1165
+ key=f"adj_{selected_file}_{idx}"
1166
+ )
1167
+ with col_btn:
1168
+ st.markdown("<br>", unsafe_allow_html=True)
1169
+ if st.button("πŸ”", key=f"ocr_adj_{selected_file}_{idx}",
1170
+ type="primary" if is_ocr_active('Line_items', 'Adjustments(without_holding_tax)_FCY', idx) else "secondary"):
1171
+ st.session_state[expander_key] = True
1172
+ activate_ocr_field('Line_items', 'Adjustments(without_holding_tax)_FCY', idx)
1173
+
1174
+ # Descriptions
1175
+ col_input, col_btn = st.columns([5, 1])
1176
+ with col_input:
1177
+ item['Descriptions'] = st.text_area(
1178
+ "Descriptions",
1179
+ value=item.get('Descriptions', ''),
1180
+ key=f"desc_{selected_file}_{idx}",
1181
+ height=60
1182
+ )
1183
+ with col_btn:
1184
+ st.markdown("<br>", unsafe_allow_html=True)
1185
+ if st.button("πŸ”", key=f"ocr_desc_{selected_file}_{idx}",
1186
+ type="primary" if is_ocr_active('Line_items', 'Descriptions', idx) else "secondary"):
1187
+ st.session_state[expander_key] = True
1188
+ activate_ocr_field('Line_items', 'Descriptions', idx)
1189
+
1190
+ # Update line items back to gt_parse
1191
+ current_gt_parse['Line_items'] = line_items
1192
+
1193
+ st.markdown("**πŸ“Š Line Items Summary Table**")
1194
+
1195
+ # Display summary table with index starting from 1
1196
+ df = pd.DataFrame(line_items)
1197
+ df.index = df.index + 1 # Start index from 1
1198
+ df.index.name = 'SL No'
1199
+
1200
+ st.dataframe(
1201
+ df,
1202
+ use_container_width=True,
1203
+ height=300
1204
+ )
1205
+ else:
1206
+ st.info("No line items. Click 'βž• Add New Row' to add a new row.")
1207
+
1208
+ st.session_state.edited_data[selected_file]['gt_parse'] = gt_parse
1209
+
1210
+ # Save button
1211
+ col1, col2 = st.columns([1, 1])
1212
+ with col1:
1213
+ if st.button("πŸ’Ύ Save Changes", type="primary", use_container_width=True, key=f"save_btn_{selected_file}"):
1214
+ if not st.session_state.just_saved:
1215
+ st.session_state.just_saved = True
1216
+ auto_save(selected_file)
1217
+ st.session_state.save_message = "βœ… Changes saved successfully!"
1218
+ st.session_state.save_message_time = time.time()
1219
+ st.rerun()
1220
+
1221
+ if st.session_state.just_saved:
1222
+ st.session_state.just_saved = False
1223
+
1224
+ if st.session_state.save_message:
1225
+ st.success(st.session_state.save_message)