create or replace package body pck_auto_import as c_module constant varchar2(20) := 'PCK_AUTO_IMPORT'; c_eingang_prefix constant varchar2(10) := 'eingang/'; c_marker constant varchar2(50) := '_READY_FOR_DB_PROCESSING_'; -- Zielordner nach erfolgreicher Verarbeitung — ggf. in sy_parameter auslagern c_target_prefix constant varchar2(20) := 'verarbeitet/'; procedure p_import_file ( i_object_key in varchar2 ,i_content in blob ) /*Kopf------------------------------------------------------------------------------------------------ -- Beschreibung: Importiert eine einzelne Datei aus dem OCI Eingangsordner in die Datenbank. -- Stub — muss pro Dateityp fachlich implementiert werden. -- Kein Commit hier — wird von p_process_incoming_files übernommen. ------------------------------------------------------------------------------------------------------ -- Parameter: i_object_key Vollständiger OCI-Objektkey der zu verarbeitenden Datei -- i_content Dateiinhalt als BLOB ------------------------------------------------------------------------------------------------------ -- MA Datum Änderung -- SCK 2026-04-08 Stub erstellt ------------------------------------------------------------------------------------------------Kopf*/ is begin -- TODO: Fachliche Verarbeitung implementieren -- Beispiel: CSV parsen und in Zieltabellen schreiben null; end p_import_file; procedure p_process_incoming_ba_data /*Kopf------------------------------------------------------------------------------------------------ -- Beschreibung: Verarbeitet alle fertigen Eingangs-Batches aus dem OCI Eingangsordner. -- Wird von ORDS-Endpunkt und APEX Automation aufgerufen. -- Pro Datei: Import → Move → Commit (Rollback + Fehlereintrag bei Exception). -- Marker wird gelöscht wenn keine Dateien mehr im Unterordner verbleiben. ------------------------------------------------------------------------------------------------------ -- MA Datum Änderung -- SCK 2026-04-08 Prozedur erstellt ------------------------------------------------------------------------------------------------Kopf*/ is l_folder_cursor sys_refcursor; l_file_cursor sys_refcursor; l_check_cursor sys_refcursor; -- Cursor-Felder für Unterordner l_folder_name varchar2(1024); l_dummy_size number; l_dummy_modified date; l_dummy_is_folder varchar2(1); l_dummy_etag varchar2(256); -- Cursor-Felder für Dateien l_file_name varchar2(1024); l_file_size number; l_file_modified date; l_file_is_folder varchar2(1); l_file_etag varchar2(256); -- Verarbeitungsvariablen l_marker_key varchar2(1024); l_target_folder varchar2(1024); l_zip_name varchar2(512); l_file_content blob; l_meta pck_net_storage.t_object_meta; l_remaining number; begin -- Unterordner in eingang/ auflisten (Delimiter '/' liefert nur direkte Kinder) l_folder_cursor := pck_net_storage.f_list_objects( i_prefix => c_eingang_prefix ,i_delimiter => '/' ); loop fetch l_folder_cursor into l_folder_name, l_dummy_size, l_dummy_modified, l_dummy_is_folder, l_dummy_etag; exit when l_folder_cursor%notfound; -- Nur Unterordner verarbeiten if l_dummy_is_folder != 'Y' then continue; end if; -- Der Marker ist eine Datei mit speziellem Namen, welche vom quarkus automaton in einen entpackten zip-ordner gelegt wird um zu signalisieren, dass alle Dateien des ZIPs erfolgreich in den ordner gelegt wurden. -- Das verhindert die verarbeitung von unvollständig entpackten zips l_marker_key := l_folder_name || c_marker; -- Marker prüfen: -20001 = nicht vorhanden → Upload noch nicht abgeschlossen begin l_meta := pck_net_storage.f_get_object_metadata(l_marker_key); exception when others then if sqlcode = -20001 then continue; end if; raise; end; -- Zip-Namen aus Ordnerpfad ableiten: eingang// → l_zip_name := substr( l_folder_name ,length(c_eingang_prefix) + 1 ,length(l_folder_name) - length(c_eingang_prefix) - 1 ); l_target_folder := c_target_prefix || l_zip_name || '/'; -- Alle Dateien im Unterordner auflisten (kein Delimiter = flach, alle Tiefen) l_file_cursor := pck_net_storage.f_list_objects( i_prefix => l_folder_name ,i_delimiter => '' ); loop fetch l_file_cursor into l_file_name, l_file_size, l_file_modified, l_file_is_folder, l_file_etag; exit when l_file_cursor%notfound; -- Marker und Pseudo-Ordner überspringen if l_file_name = l_marker_key or l_file_is_folder = 'Y' then continue; end if; begin -- 1. Dateiinhalt laden l_file_content := pck_net_storage.f_download_object(l_file_name); -- 2. Fachliche Verarbeitung (noch kein Commit) p_import_file(l_file_name, l_file_content); -- 3. Datei in Zielordner verschieben (noch kein Commit) -- Rollback von p_move_object macht auch den Import rückgängig pck_net_storage.p_move_object( i_object_key => l_file_name ,i_target_prefix => l_target_folder ); commit; pck_log.p_info( i_module => c_module ,i_action => 'IMPORT_FILE' ,i_message => 'Datei erfolgreich verarbeitet' ,i_object_ref => l_file_name ); exception when others then rollback; pck_log.p_error( i_module => c_module ,i_action => 'IMPORT_FILE' ,i_message => 'Fehler bei Dateiverarbeitung: ' || sqlerrm ,i_detail => to_clob(dbms_utility.format_error_backtrace) ,i_object_ref => l_file_name ); end; end loop; close l_file_cursor; -- Prüfen ob noch nicht verarbeitete Dateien im Unterordner verbleiben l_remaining := 0; l_check_cursor := pck_net_storage.f_list_objects( i_prefix => l_folder_name ,i_delimiter => '' ); loop fetch l_check_cursor into l_file_name, l_file_size, l_file_modified, l_file_is_folder, l_file_etag; exit when l_check_cursor%notfound; if l_file_name != l_marker_key and l_file_is_folder = 'N' then l_remaining := l_remaining + 1; end if; end loop; close l_check_cursor; -- Marker löschen wenn Batch vollständig abgeschlossen if l_remaining = 0 then pck_net_storage.p_delete_object(l_marker_key); pck_log.p_info( i_module => c_module ,i_action => 'PROCESS_INCOMING' ,i_message => 'Batch abgeschlossen, Marker gelöscht' ,i_object_ref => l_folder_name ); end if; end loop; close l_folder_cursor; exception when others then if l_folder_cursor%isopen then close l_folder_cursor; end if; if l_file_cursor%isopen then close l_file_cursor; end if; if l_check_cursor%isopen then close l_check_cursor; end if; raise; end p_process_incoming_ba_data; end pck_auto_import; /