verschiedene fehler behoben
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
## * Initialisierung ----
|
## * Initialisierung ----
|
||||||
|
|
||||||
max_id <- function(conn, tablle){
|
max_id <- function(conn, tabelle){
|
||||||
paste0("SELECT max(id) FROM ", tabelle) %>%
|
paste0("SELECT max(id) FROM ", tabelle) %>%
|
||||||
dbxSelect(conn,.) %>%
|
dbxSelect(conn,.) %>%
|
||||||
pull
|
pull
|
||||||
|
|||||||
+15
-11
@@ -1,18 +1,22 @@
|
|||||||
|
f_reactable <- function(daten, coldefs = NULL, selection = "single", defaultSelected = NULL) {
|
||||||
f_reactable <- function(daten, coldefs = NULL){
|
reactable(
|
||||||
reactable(daten,
|
daten,
|
||||||
selection = "single",
|
selection = selection,
|
||||||
bordered = TRUE,
|
defaultSelected = defaultSelected, # Ermöglicht das Wiederherstellen der Auswahl
|
||||||
|
pagination = TRUE,
|
||||||
defaultPageSize = 17,
|
defaultPageSize = 17,
|
||||||
|
showPageSizeOptions = TRUE,
|
||||||
filterable = TRUE,
|
filterable = TRUE,
|
||||||
highlight = TRUE,
|
highlight = TRUE,
|
||||||
striped = F,
|
bordered = TRUE,
|
||||||
theme = reactableTheme(
|
striped = FALSE,
|
||||||
highlightColor = "#00f200",
|
|
||||||
borderColor = "#dfe2e5",
|
|
||||||
rowSelectedStyle = list(backgroundColor = "#98F5FF"),
|
|
||||||
),
|
|
||||||
compact = TRUE,
|
compact = TRUE,
|
||||||
|
# Styling
|
||||||
|
theme = reactableTheme(
|
||||||
|
highlightColor = "#e6f7ff", # Etwas dezenter als knallgrün, optional
|
||||||
|
# borderColor = "#dfe2e5",
|
||||||
|
rowSelectedStyle = list(backgroundColor = "#98F5FF")
|
||||||
|
),
|
||||||
rowStyle = list(cursor = "pointer"),
|
rowStyle = list(cursor = "pointer"),
|
||||||
onClick = "select",
|
onClick = "select",
|
||||||
columns = coldefs
|
columns = coldefs
|
||||||
|
|||||||
+53
-36
@@ -1,59 +1,76 @@
|
|||||||
|
# module_buchungen.R
|
||||||
|
|
||||||
buchungenUI <- function(id) {
|
buchungenUI <- function(id) {
|
||||||
ns <- NS(id)
|
ns <- NS(id)
|
||||||
tagList(
|
tagList(
|
||||||
|
h3("Hauptbuchungen"),
|
||||||
reactableOutput(ns("buchungen_table")),
|
reactableOutput(ns("buchungen_table")),
|
||||||
|
hr(),
|
||||||
|
h3("Details / Gegenbuchungen"),
|
||||||
reactableOutput(ns("details_table")),
|
reactableOutput(ns("details_table")),
|
||||||
postingModuleUI(ns("posting_modal")),
|
br(),
|
||||||
actionBttn(ns("add_trans"), "Transaktion hinzu", size = "sm", style = "material-flat", color = "warning"),
|
actionBttn(ns("add_detail"), "Detail hinzufügen", size = "sm", style = "material-flat", color = "success"),
|
||||||
actionBttn(ns("add_trans"), "Transaktion Löschen", size = "sm", style = "material-flat", color = "danger"),
|
# Das UI-Element des Moduls (auch wenn es leer ist)
|
||||||
actionBttn(ns("add_detail"), "Detail hinzu", size = "sm", style = "material-flat", color = "success")
|
postingModuleUI(ns("posting_modal"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buchungenServer <- function(id, conn) {
|
||||||
buchungenServer <- function(id) {
|
|
||||||
moduleServer(id, function(input, output, session) {
|
moduleServer(id, function(input, output, session) {
|
||||||
ns <- session$ns
|
ns <- session$ns
|
||||||
|
|
||||||
postings <- reactiveVal(read_buch_tabelle(conn))
|
# Reactive States
|
||||||
details <- reactiveVal()
|
postings_data <- reactiveVal(read_buch_tabelle(conn))
|
||||||
tabelle_neu <- reactiveVal()
|
details_data <- reactiveVal(NULL)
|
||||||
# NEU: Eine reactive variable für die ID, die wir editieren wollen
|
selected_trans_id <- reactiveVal(NULL)
|
||||||
# current_entry_id <- reactiveVal(NULL)
|
|
||||||
|
|
||||||
# NEU: Den Modul-Server EINMALIG hier oben starten (nicht im Observer!)
|
# Trigger-Objekt für das Modal: enthält post_id und einen Counter
|
||||||
# entryEditServer("entry_edit", entry_id = current_entry_id, conn = conn)
|
# 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({
|
output$buchungen_table <- renderReactable({
|
||||||
# req(postings())
|
req(postings_data())
|
||||||
f_reactable(postings(), coldefs = coldef_entries_tabelle)
|
f_reactable(daten = postings_data(), coldefs = coldef_entries_tabelle, selection = "single")
|
||||||
})
|
})
|
||||||
|
|
||||||
# Buchungen und gegenbuchungen anzeigen
|
# Details laden wenn Zeile gewählt wird
|
||||||
selected <- reactive(getReactableState("buchungen_table", "selected"))
|
sel_details <- reactive(getReactableState("buchungen_table", "selected"))
|
||||||
observeEvent(selected(), {
|
observeEvent(sel_details(), ignoreInit = T, {
|
||||||
idwert <- postings()[selected(),"entry_id"] %>% pull
|
t_id <- postings_data()[sel_details(), "entry_id"] %>% pull()
|
||||||
details(read_buch_tabelle(conn, trans_id = idwert))
|
selected_trans_id(t_id)
|
||||||
output$details_table <- renderReactable(
|
details_data(read_buch_tabelle(conn, trans_id = t_id))
|
||||||
f_reactable(details(), coldefs = coldef_entries_tabelle)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# Buchunge auswähle
|
output$details_table <- renderReactable({
|
||||||
selected_det <- reactive(getReactableState("details_table", "selected"))
|
req(details_data())
|
||||||
observeEvent(selected_det(),{
|
f_reactable(details_data(), coldefs = coldef_entries_tabelle, selection = "single")
|
||||||
idwert <- postings()[selected(),"id"] %>% pull
|
|
||||||
tabelle_neu(postingModuleServer("posting_modal",conn, idwert))
|
|
||||||
})
|
})
|
||||||
# Buchungstail hinzufügen
|
|
||||||
observeEvent(input$add_detail, ignoreInit = T, {
|
# Event: Detail hinzufügen (Neu)
|
||||||
trans_id <- idwert <- postings()[selected(),"entry_id"] %>% pull
|
observeEvent(input$add_detail, {
|
||||||
post_id <- max_id(conn, "posting") + 1
|
req(selected_trans_id())
|
||||||
tabelle_neu(postingModuleServer("posting_modal",conn, idwert, post_id + 1))
|
modal_trigger(list(post_id = NULL, counter = modal_trigger()$counter + 1))
|
||||||
})
|
})
|
||||||
# Tabelle aktualisieren
|
|
||||||
observeEvent(tabelle_neu(), ignoreInit = T, {
|
# Event: Detail editieren (Klick auf Detail-Tabelle)
|
||||||
details(read_buch_tabelle(conn, trans_id = idwert))
|
sel_detail <- reactive(getReactableState("details_table", "selected"))
|
||||||
|
observeEvent(sel_detail(), ignoreInit = T, {
|
||||||
|
p_id <- details_data()$id[sel]
|
||||||
|
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))
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
+81
-71
@@ -1,105 +1,115 @@
|
|||||||
|
# module_posting.R
|
||||||
|
|
||||||
# --- MODUL UI ---
|
|
||||||
postingModuleUI <- function(id) {
|
postingModuleUI <- function(id) {
|
||||||
ns <- NS(id)
|
ns <- NS(id)
|
||||||
tagList(
|
tagList() # Das UI wird dynamisch via showModal erzeugt
|
||||||
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- MODUL SERVER ---
|
postingModuleServer <- function(id, conn, r_trans_id, r_trigger_list) {
|
||||||
postingModuleServer <- function(id, conn, trans_id, post_id = NULL) {
|
|
||||||
moduleServer(id, function(input, output, session) {
|
moduleServer(id, function(input, output, session) {
|
||||||
ns <- session$ns # Wichtig für das Namespacing innerhalb des Modals
|
ns <- session$ns
|
||||||
if(is.null(post_id)){
|
|
||||||
record <- read_posting(conn, trans_id)
|
# Dieser Trigger signalisiert dem Hauptmodul: "Daten haben sich geändert!"
|
||||||
}else {
|
db_updated <- reactiveVal(0)
|
||||||
wertstellung <- dbxSelect(conn, paste0("SELECT max(valuta) from Postings WHERE entry_id=", trans_id)) %>%
|
|
||||||
pull
|
# Hilfsvariablen für den aktuellen Edit-Status
|
||||||
|
current_record <- reactiveVal()
|
||||||
|
current_trans <- reactiveVal()
|
||||||
|
|
||||||
|
# Beobachte den Trigger aus dem Hauptmodul
|
||||||
|
observeEvent(r_trigger_list(), {
|
||||||
|
req(r_trans_id())
|
||||||
|
|
||||||
|
# 1. Daten laden
|
||||||
|
t_id <- r_trans_id()
|
||||||
|
p_id <- r_trigger_list()$post_id
|
||||||
|
|
||||||
|
trans_data <- dbxSelect(conn, paste0("SELECT * FROM entries WHERE id=", t_id))
|
||||||
|
current_trans(trans_data)
|
||||||
|
|
||||||
|
if (!is.null(p_id)) {
|
||||||
|
record <- read_posting(conn, p_id)
|
||||||
|
} else {
|
||||||
|
# Logik für neuen Eintrag
|
||||||
|
new_p_id <- max_id(conn, "postings") + 1
|
||||||
|
wertstellung <- dbxSelect(conn, paste0("SELECT max(valuta) from Postings WHERE entry_id=", t_id)) %>% pull()
|
||||||
|
|
||||||
record <- leer_df_from_table(conn, "postings")
|
record <- leer_df_from_table(conn, "postings")
|
||||||
record[1, "id"] <- post_id
|
record[1, "id"] <- new_p_id
|
||||||
record$entry_id <- trans_id
|
record$entry_id <- t_id
|
||||||
record$account_id <- 0
|
record$account_id <- 0
|
||||||
record$valuta <- wertstellung
|
record$valuta <- wertstellung
|
||||||
record$booking_date <- wertstellung
|
record$booking_date <- wertstellung
|
||||||
}
|
}
|
||||||
trans <- dbxSelect(conn, paste0("SELECT * FROM entries WHERE id=", record$entry_id))
|
current_record(record)
|
||||||
# Modal öffnen
|
|
||||||
|
|
||||||
|
# 2. Modal anzeigen
|
||||||
showModal(modalDialog(
|
showModal(modalDialog(
|
||||||
title = "Buchung-Eingabe",
|
title = paste("Buchung bearbeiten - Transaktion", t_id),
|
||||||
|
|
||||||
|
|
||||||
f_airdatepicker_UI(ns("valuta"), "Wertstellung", record$valuta),
|
f_airdatepicker_UI(ns("valuta"), "Wertstellung", record$valuta),
|
||||||
f_airdatepicker_UI(ns("buchungsdatum"), "Buchungsdatum", record$booking_date),
|
f_airdatepicker_UI(ns("buchungsdatum"), "Buchungsdatum", record$booking_date),
|
||||||
selectizeInput(ns("kontakt"), "Kontakt:",selected = trans$contact_id, choices = get_contact_choices(conn), width = "100%"),
|
selectizeInput(ns("kontakt"), "Kontakt:", selected = trans_data$contact_id, choices = get_contact_choices(conn), width = "100%"),
|
||||||
selectizeInput(ns("konto"), "Kontoname:",selected = record$account_id, choices = get_account_choices(conn), width = "100%"),
|
selectizeInput(ns("konto"), "Kontoname:", selected = record$account_id, choices = get_account_choices(conn), width = "100%"),
|
||||||
selectizeInput(ns("projekt"), "Projektname", selected = NULL, choices = get_project_choices(conn), width = "100%"),
|
selectizeInput(ns("projekt"), "Projektname", selected = record$project_id, choices = get_project_choices(conn), width = "100%"),
|
||||||
splitLayout(cellWidths = c("70%", "30%"),
|
splitLayout(cellWidths = c("70%", "30%"),
|
||||||
numericInput(ns("amount"), "Betrag:", value = record$amount, width = "100%"),
|
numericInput(ns("amount"), "Betrag:", value = record$amount, width = "100%"),
|
||||||
numericInput(ns("coin_share_amount"), "Münzen:", value = record$coin_share_amount, width = "100%")
|
numericInput(ns("coin_share_amount"), "Münzen:", value = record$coin_share_amount, width = "100%")
|
||||||
),
|
),
|
||||||
textAreaInput(ns("trans_notiz"), label= "Notiz (Transaktion)", value = trans$note, width = "100%"),
|
textAreaInput(ns("trans_notiz"), label = "Notiz (Transaktion)", value = trans_data$note, width = "100%"),
|
||||||
splitLayout(cellWidths = c("50%", "50%"),
|
|
||||||
numericInput(ns("receipt_id"), "Umsatz_id:", value = record$receipt_id, width = "100%"),
|
|
||||||
numericInput(ns("wiso_id"), "Wiso_id:", value = record$wiso_id, width = "100%")
|
|
||||||
),
|
|
||||||
#
|
|
||||||
footer = tagList(
|
footer = tagList(
|
||||||
modalButton("Abbrechen"),
|
modalButton("Abbrechen"),
|
||||||
actionBttn(ns("confirm"), "Bestätigen", style = "minimal", color = "success"),
|
|
||||||
actionBttn(ns("delete"), "Löschen", style = "minimal", color = "danger"),
|
actionBttn(ns("delete"), "Löschen", style = "minimal", color = "danger"),
|
||||||
splitLayout(cellWidths = c("50%", "50%"),
|
actionBttn(ns("confirm"), "Bestätigen", style = "minimal", color = "success")
|
||||||
numericInput(ns("bid"), "ID:", value = record$id),
|
|
||||||
numericInput(ns("trans_id"), "Trans_id:", value = record$entry_id)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
easyClose = TRUE
|
easyClose = TRUE
|
||||||
))
|
))
|
||||||
|
|
||||||
# Aktion beim Bestätigen
|
|
||||||
observeEvent(input$confirm, ignoreInit = T, {
|
|
||||||
trans$contact_id <- input$kontakt
|
|
||||||
trans$note <- input$trans_notiz
|
|
||||||
record$amount <- input$amount
|
|
||||||
record$account_id <- input$konto
|
|
||||||
record$project_id <- input$projekt
|
|
||||||
record$valuta <- as.character(input$valuta)
|
|
||||||
record$booking_date <- as.character(input$buchungsdatum)
|
|
||||||
record$coin_share_amount <- input$coin_share_amount
|
|
||||||
record$receipt_id <- input$receipt_id
|
|
||||||
|
|
||||||
# Check - Postings constraint
|
|
||||||
## Entweder 1 oder 0 (neu)
|
|
||||||
anz <- dbxSelect(conn, paste0("SELECT count(id) FROM postings WHERE id=", record$id)) %>% pull
|
|
||||||
ok <- anz <=1
|
|
||||||
ok <- !(is.na(record$entry_id) | record$entry_id == "") & ok
|
|
||||||
ok <- !(is.na(record$valuta) | record$valuta == "") & ok
|
|
||||||
ok <- !is.na(record$amount)
|
|
||||||
ok <- record$account_id > 0 & ok
|
|
||||||
|
|
||||||
|
|
||||||
if(ok) {
|
|
||||||
dbxUpsert(conn, "postings", records = record, where_cols = "id")
|
|
||||||
dbxUpsert(conn, "entries", records = trans, where_cols = "id")
|
|
||||||
removeModal()
|
|
||||||
return(reactive(input$confirm))
|
|
||||||
} else showNotification("Die Buchung enthält Fehler", type = "error")
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# Aktion Detail löschen
|
# Speichern
|
||||||
observeEvent(input$delete, ignoreInit = T, {
|
observeEvent(input$confirm, {
|
||||||
anz <- dbxSelect(conn, paste0("SELECT count(entry_id) FROM postings WHERE entry_id=", record$entry_id) ) %>% pull
|
req(current_record(), current_trans())
|
||||||
if(anz>1){
|
|
||||||
dbxDelete(conn, "postings", where = data.frame(id=record$id))
|
# Daten aus UI einsammeln
|
||||||
|
rec <- current_record()
|
||||||
|
tra <- current_trans()
|
||||||
|
|
||||||
|
tra$contact_id <- input$kontakt
|
||||||
|
tra$note <- input$trans_notiz
|
||||||
|
rec$amount <- input$amount
|
||||||
|
rec$account_id <- input$konto
|
||||||
|
rec$project_id <- input$projekt
|
||||||
|
rec$valuta <- as.character(input$valuta)
|
||||||
|
rec$booking_date <- as.character(input$buchungsdatum)
|
||||||
|
rec$coin_share_amount <- input$coin_share_amount
|
||||||
|
|
||||||
|
# Validierung
|
||||||
|
ok <- !is.na(rec$amount) && rec$account_id > 0
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
dbxUpsert(conn, "postings", records = rec, where_cols = "id")
|
||||||
|
dbxUpsert(conn, "entries", records = tra, where_cols = "id")
|
||||||
removeModal()
|
removeModal()
|
||||||
return(reactive(input$delete))
|
db_updated(db_updated() + 1) # Hauptmodul triggern
|
||||||
} else {
|
} else {
|
||||||
showNotification("Das ist der letzte Buchungsteil, er kann nicht gelöscht werden -> Transaktion löschen", type = "error")
|
showNotification("Eingabe ungültig", type = "error")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
#
|
# Löschen
|
||||||
|
observeEvent(input$delete, {
|
||||||
|
rec <- current_record()
|
||||||
|
anz <- dbxSelect(conn, paste0("SELECT count(*) FROM postings WHERE entry_id=", rec$entry_id)) %>% pull()
|
||||||
|
|
||||||
|
if (anz > 1) {
|
||||||
|
dbxDelete(conn, "postings", where = data.frame(id = rec$id))
|
||||||
|
removeModal()
|
||||||
|
db_updated(db_updated() + 1)
|
||||||
|
} else {
|
||||||
|
showNotification("Letzter Teil kann nicht gelöscht werden.", type = "error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return(db_updated)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user