191 lines
6.9 KiB
R
Executable File
191 lines
6.9 KiB
R
Executable File
# module_buchungen.R
|
|
|
|
buchungenUI <- function(id) {
|
|
ns <- NS(id)
|
|
tagList(
|
|
useShinyjs(),
|
|
h3("Hauptbuchungen"),
|
|
fluidRow(
|
|
column(8, reactableOutput(ns("buchungen_table"))),
|
|
|
|
column(4,
|
|
selectizeInput(ns("contact"), label = "Kontakt", choices = get_contact_choices(conn),
|
|
selected = NA, width = "100%"),
|
|
textAreaInput(ns("note"), label = "Verwendungszweck", value = NA, width = "100%"),
|
|
h3("Dateien"),
|
|
uiOutput(ns("attachments_ui")),
|
|
fileInput(ns("anhang"), NULL, multiple = TRUE,
|
|
accept = c(".pdf", ".jpg", ".png", ".xlsx", ".docx"),
|
|
width = "100%"),
|
|
div(
|
|
style = "display: flex; flex-direction: column; gap: 10px; align-items: flex-start;",
|
|
|
|
actionBttn(ns("add_detail"), "Detail hinzu",
|
|
size = "sm", style = "material-flat", color = "default", block = TRUE),
|
|
actionBttn(ns("del_detail"), "Detail Löschen",
|
|
size = "sm", style = "material-flat", color = "danger", block = TRUE),
|
|
actionBttn(ns("add_trans"), "Transaktion hinzu",
|
|
size = "sm", style = "material-flat", color = "default", block = TRUE),
|
|
|
|
actionBttn(ns("del_trans"), "Transaktion Löschen",
|
|
size = "sm", style = "material-flat", color = "danger", block = TRUE),
|
|
actionBttn(ns("save_trans"), "Transaktion speichern",
|
|
size = "sm", style = "material-flat", color = "success", block = TRUE, icon = icon("floppy-disk")),
|
|
)
|
|
)
|
|
),
|
|
|
|
hr(),
|
|
h3("Details / Gegenbuchungen"),
|
|
uiOutput(ns("details_table")) ,
|
|
|
|
|
|
|
|
)
|
|
}
|
|
|
|
buchungenServer <- function(id, conn, r_global) {
|
|
moduleServer(id, function(input, output, session) {
|
|
ns <- session$ns
|
|
|
|
# ── Reactive Variablen ----
|
|
postings_data <- reactiveVal(read_buch_tabelle(conn))
|
|
sel_details <- reactiveVal(NULL)
|
|
selected_trans_id <- reactiveVal(NULL)
|
|
reset_trigger <- reactiveVal(NULL)
|
|
current_main_idx <- reactiveVal(NULL)
|
|
|
|
|
|
|
|
|
|
# ── Filter ----
|
|
aktiver_filter <- reactive(r_global$buchungen_filter)
|
|
|
|
gefilterte_daten <- reactive({
|
|
d <- postings_data()
|
|
f <- aktiver_filter()
|
|
if (f == "alle") d
|
|
else if (f == "giro") d |> filter(grepl("0130", account_name))
|
|
else if (f == "monat") d |> filter(
|
|
floor_date(as.Date(valuta), "month") == floor_date(Sys.Date(), "month")
|
|
)
|
|
else if (startsWith(f, "contact:")) d |> filter(contact_id == as.integer(sub("contact:", "", f)))
|
|
else if (startsWith(f, "project:")) d |> filter(project_id == as.integer(sub("project:", "", f)))
|
|
else if (startsWith(f, "account:")) d |> filter(account_id == as.integer(sub("account:", "", f)))
|
|
else d
|
|
})
|
|
|
|
|
|
# ── Haupttabelle rendern ----
|
|
output$buchungen_table <- renderReactable({
|
|
reset_trigger()
|
|
f_reactable(
|
|
daten = gefilterte_daten(),
|
|
coldefs = coldef_entries_tabelle,
|
|
selection = "single",
|
|
hoehe = "60vh",
|
|
filterable = TRUE,
|
|
)
|
|
})
|
|
|
|
sel <- reactive(getReactableState("buchungen_table", "selected"))
|
|
observeEvent(sel(), ignoreInit = T, {
|
|
output$details_table <- renderUI({
|
|
req(sel())
|
|
# Daten laden
|
|
df <- read_buch_entries(conn, gefilterte_daten()$entry_id[sel()])
|
|
sel_details(df)
|
|
|
|
rows <- lapply(1:nrow(df), function(ind) {
|
|
fluidRow(class = "details-row",
|
|
# HIER: Index an die ID hängen!
|
|
column(1, numericInput(ns(paste0("id_", ind)), label = NULL, width = "100%", value = df$id[ind])),
|
|
column(2, dateInput(ns(paste0("valuta_", ind)), label = NULL, width = "100%", value = df$valuta[ind])),
|
|
column(3, selectizeInput(ns(paste0("account_", ind)), label = NULL,
|
|
choices = get_account_choices(conn),
|
|
selected = df$account_id[ind], width = "100%")),
|
|
column(3, selectizeInput(ns(paste0("projekt_", ind)), label = NULL,
|
|
choices = get_project_choices(conn),
|
|
selected = df$projekt_id[ind], width = "100%")),
|
|
column(2, numericInput(ns(paste0("betrag_", ind)), label = NULL, width = "100%", value = df$amount[ind]))
|
|
)
|
|
})
|
|
tagList(rows)
|
|
})
|
|
|
|
|
|
})
|
|
|
|
observeEvent(input$save_trans, {
|
|
req(sel_details())
|
|
n_rows <- nrow(sel_details())
|
|
|
|
# Alle Zeilen in einer Liste sammeln
|
|
all_records <- lapply(1:n_rows, function(ind) {
|
|
data.frame(
|
|
id = as.integer(input[[paste0("id_", ind)]]),
|
|
valuta = as.Date(input[[paste0("valuta_", ind)]]),
|
|
amount = as.numeric(input[[paste0("betrag_", ind)]]),
|
|
account_id = input[[paste0("account_", ind)]],
|
|
projekt_id = input[[paste0("projekt_", ind)]],
|
|
stringsAsFactors = FALSE
|
|
)
|
|
})
|
|
|
|
# Zu einem großen Dataframe zusammenfügen
|
|
final_df <- do.call(rbind, all_records)
|
|
browser()
|
|
|
|
# Datenbank-Update-Logik
|
|
tryCatch({
|
|
# Beispiel: Für jede Zeile ein Update ausführen
|
|
for(i in 1:nrow(final_df)) {
|
|
update_buchung_detail(conn, final_df[i, ]) # Deine DB-Funktion
|
|
}
|
|
|
|
showNotification("Daten erfolgreich gespeichert", type = "message")
|
|
|
|
# Optional: Haupttabelle aktualisieren, falls sich Summen geändert haben
|
|
# trigger_refresh(trigger_refresh() + 1)
|
|
|
|
}, error = function(e) {
|
|
showNotification(paste("Fehler beim Speichern:", e$message), type = "error")
|
|
})
|
|
})
|
|
|
|
|
|
# ── Anhänge ----
|
|
output$attachments_ui <- renderUI({
|
|
req(sel_details())
|
|
entry_id <-
|
|
dbxSelect(conn, paste0("SELECT entry_id FROM postings WHERE id=",
|
|
sel_details()$id[1])) %>% pull
|
|
att <- dbxSelect(conn, paste0(
|
|
"SELECT * FROM attachments WHERE entry_id = ", entry_id
|
|
))
|
|
if (nrow(att) == 0) return(p("Keine Anhänge vorhanden."))
|
|
|
|
tagList(lapply(seq_len(nrow(att)), function(i) {
|
|
ext <- tools::file_ext(att$original_name[i])
|
|
filename <- paste0("attachments/", att$id[i], ".", ext)
|
|
|
|
observeEvent(input[[paste0("open_att_", att$id[i])]], {
|
|
showModal(modalDialog(
|
|
tags$iframe(src = filename, width = "100%", height = "600px",
|
|
style = "border:none;"),
|
|
title = att$original_name[i],
|
|
size = "l",
|
|
easyClose = TRUE,
|
|
footer = modalButton("Schließen")
|
|
))
|
|
}, ignoreInit = TRUE, once = FALSE)
|
|
|
|
div(
|
|
actionLink(ns(paste0("open_att_", att$id[i])), att$original_name[i]),
|
|
actionLink(ns(paste0("del_att_", att$id[i])), "✕",
|
|
style = "color:red; margin-left:8px;")
|
|
)
|
|
}))
|
|
})
|
|
})
|
|
} |