# module_buchungen.R buchungenUI <- function(id) { ns <- NS(id) tagList( h3("Hauptbuchungen"), reactableOutput(ns("buchungen_table")), hr(), h3("Details / Gegenbuchungen"), reactableOutput(ns("details_table")), br(), actionBttn(ns("add_trans"), "Transaktion hinzu", size = "sm", style = "material-flat", color = "warning"), actionBttn(ns("del_trans"), "Transaktion Löschen", size = "sm", style = "material-flat", color = "danger"), actionBttn(ns("add_detail"), "Detail hinzu", size = "sm", style = "material-flat", color = "success"), # Das UI-Element des Moduls (auch wenn es leer ist) postingModuleUI(ns("posting_modal")) ) } buchungenServer <- function(id, conn) { moduleServer(id, function(input, output, session) { ns <- session$ns # Reactive States ---- postings_data <- reactiveVal(read_buch_tabelle(conn)) details_data <- reactiveVal(NULL) selected_trans_id <- reactiveVal(NULL) current_main_idx <- reactiveVal(NULL) # Trigger-Objekt für das Modal: enthält post_id und einen Counter # Der Counter erzwingt eine Reaktion, auch wenn die gleiche ID zweimal geklickt wird modal_trigger <- reactiveVal(list(post_id = NULL, counter = 0)) # --- MODUL-SERVER STARTEN (EINMALIG) ---- update_db_trigger <- postingModuleServer("posting_modal", conn, selected_trans_id, modal_trigger) # Haupttabelle rendern ---- output$buchungen_table <- renderReactable({ req(postings_data()) f_reactable(daten = postings_data(), coldefs = coldef_entries_tabelle, selection = "single", defaultSelected = current_main_idx()) }) # Details laden wenn Zeile gewählt wird ---- sel_details <- reactive(getReactableState("buchungen_table", "selected")) observeEvent(sel_details(), ignoreInit = T, { current_main_idx(getReactableState("buchungen_table", "selected")) t_id <- postings_data()[sel_details(), "entry_id"] %>% pull() selected_trans_id(t_id) details_data(read_buch_tabelle(conn, trans_id = t_id)) }) output$details_table <- renderReactable({ req(details_data()) f_reactable(details_data(), coldefs = coldef_entries_tabelle, selection = "single") }) # Event: Detail hinzufügen (Neu) ---- observeEvent(input$add_detail, { req(selected_trans_id()) modal_trigger(list(post_id = NULL, counter = modal_trigger()$counter + 1)) }) # Event: Detail editieren (Klick auf Detail-Tabelle) ---- sel_detail <- reactive(getReactableState("details_table", "selected")) observeEvent(sel_detail(), ignoreInit = T, { p_id <- details_data()$id[sel_detail()] modal_trigger(list(post_id = p_id, counter = modal_trigger()$counter + 1)) }) # --- DAS REAKTIVE UPDATE ---- # Wenn das Modal sagt "Fertig", laden wir die Details neu observeEvent(update_db_trigger(), ignoreInit = TRUE, { req(selected_trans_id()) # Tabellen-Daten neu aus DB ziehen details_data(read_buch_tabelle(conn, trans_id = selected_trans_id())) # Optional: Auch Haupttabelle erneuern, falls sich Summen geändert haben postings_data(read_buch_tabelle(conn)) }) # 'Neue Transaktion' Observer ---- observeEvent(input$add_trans, { new_t_id <- max_id(conn, "entries") + 1 # 1. Entry anlegen dbxInsert(conn, "entries", data.frame(id = new_t_id)) # 2. Zwei Postings direkt vor-anlegen (z.B. mit Betrag 0) p_id1 <- max_id(conn, "postings") + 1 p_id2 <- p_id1 + 1 new_postings <- data.frame( id = c(p_id1, p_id2), entry_id = c(new_t_id, new_t_id), amount = c(0, 0), account_id = c(0, 0), valuta = c(Sys.Date(), Sys.Date()) ) dbxInsert(conn, "postings", new_postings) # 3. UI refreshen selected_trans_id(new_t_id) postings_data(read_buch_tabelle(conn)) details_data(read_buch_tabelle(conn, trans_id = new_t_id)) }) }) }