From 1f903ea80efa526093d252c843a553bf031f17fa Mon Sep 17 00:00:00 2001 From: Christian Oswald Date: Mon, 9 Mar 2026 17:23:49 +0100 Subject: [PATCH] Buchungs modal um actions erweitert --- R/_funktionen/f_leer_from_tabelle.R | 15 ++++++ R/_funktionen/f_max_id.R | 17 +++++++ R/accounts/accounts.R | 5 +- R/buchungen_mod.R | 30 ++++++++---- R/entry_edit_modal.R | 70 ++++++++++++++++++++++++---- R/projects/projects.R | 2 +- db/development.sqlite | Bin 1011712 -> 1011712 bytes global.R | 3 +- 8 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 R/_funktionen/f_leer_from_tabelle.R create mode 100644 R/_funktionen/f_max_id.R diff --git a/R/_funktionen/f_leer_from_tabelle.R b/R/_funktionen/f_leer_from_tabelle.R new file mode 100644 index 0000000..c5c54d2 --- /dev/null +++ b/R/_funktionen/f_leer_from_tabelle.R @@ -0,0 +1,15 @@ +## +## Datum: 2024-10-17_14-29 +## Name: Christian Oswald +## Projekt: etatverwaltung +## Datei: f_leer_df_from_table.R +## Kommentar: Erstellt einen leeren DS einer Tabelle +## + +leer_df_from_table <- function(conn, tabelle){ + felder <- dbListFields(conn, tabelle) + record <- data.frame(matrix(ncol = length(felder), nrow = 0)) + colnames(record) <- felder + return(record) +} + diff --git a/R/_funktionen/f_max_id.R b/R/_funktionen/f_max_id.R new file mode 100644 index 0000000..d1390da --- /dev/null +++ b/R/_funktionen/f_max_id.R @@ -0,0 +1,17 @@ +## +## Datum : 2026-03-09_15-47 +## Name : Christian Oswald +## Datei : f_max_id.R +## Projekt : gemfin-shiny +## Kommentar: Ermittelt den maximalen id einer tabelle +## + +## * Initialisierung ---- + +max_id <- function(conn, tablle){ + paste0("SELECT max(id) FROM ", tabelle) %>% + dbxSelect(conn,.) %>% + pull +} + + diff --git a/R/accounts/accounts.R b/R/accounts/accounts.R index 0cb0dd2..44158e3 100644 --- a/R/accounts/accounts.R +++ b/R/accounts/accounts.R @@ -5,9 +5,12 @@ read_accounts <- function(conn){ get_account_choices <- function(conn) { - tbl(conn, "accounts") |> + choices <- tbl(conn, "accounts") |> select(id, account_name) |> collect() |> arrange(account_name) |> (\(df) setNames(df$id, df$account_name))() + return(c("Kein Konto" = 0, choices)) } + + diff --git a/R/buchungen_mod.R b/R/buchungen_mod.R index 5e6578e..244e1bf 100644 --- a/R/buchungen_mod.R +++ b/R/buchungen_mod.R @@ -3,7 +3,10 @@ buchungenUI <- function(id) { tagList( reactableOutput(ns("buchungen_table")), reactableOutput(ns("details_table")), - postingModuleUI(ns("posting_modal")) + postingModuleUI(ns("posting_modal")), + actionBttn(ns("add_trans"), "Transaktion hinzu", size = "sm", style = "material-flat", color = "warning"), + actionBttn(ns("add_trans"), "Transaktion Löschen", size = "sm", style = "material-flat", color = "danger"), + actionBttn(ns("add_detail"), "Detail hinzu", size = "sm", style = "material-flat", color = "success") ) } @@ -13,7 +16,8 @@ buchungenServer <- function(id) { ns <- session$ns postings <- reactiveVal(read_buch_tabelle(conn)) - + details <- reactiveVal() + tabelle_neu <- reactiveVal() # NEU: Eine reactive variable für die ID, die wir editieren wollen # current_entry_id <- reactiveVal(NULL) @@ -25,24 +29,32 @@ buchungenServer <- function(id) { f_reactable(postings(), coldefs = coldef_entries_tabelle) }) - # Modal zum editieren + # Buchungen und gegenbuchungen anzeigen selected <- reactive(getReactableState("buchungen_table", "selected")) - observeEvent(selected(), { idwert <- postings()[selected(),"entry_id"] %>% pull - details <- read_buch_tabelle(conn, trans_id = idwert) + details(read_buch_tabelle(conn, trans_id = idwert)) output$details_table <- renderReactable( - f_reactable(details, coldefs = coldef_entries_tabelle) + f_reactable(details(), coldefs = coldef_entries_tabelle) ) - }) + # Buchunge auswähle selected_det <- reactive(getReactableState("details_table", "selected")) observeEvent(selected_det(),{ idwert <- postings()[selected(),"id"] %>% pull - postingModuleServer("posting_modal",conn, idwert) + tabelle_neu(postingModuleServer("posting_modal",conn, idwert)) + }) + # Buchungstail hinzufügen + observeEvent(input$add_detail, ignoreInit = T, { + trans_id <- idwert <- postings()[selected(),"entry_id"] %>% pull + post_id <- max_id(conn, "posting") + 1 + tabelle_neu(postingModuleServer("posting_modal",conn, idwert, post_id + 1)) + }) + # Tabelle aktualisieren + observeEvent(tabelle_neu(), ignoreInit = T, { + details(read_buch_tabelle(conn, trans_id = idwert)) }) - }) } \ No newline at end of file diff --git a/R/entry_edit_modal.R b/R/entry_edit_modal.R index f681f89..6828ef1 100644 --- a/R/entry_edit_modal.R +++ b/R/entry_edit_modal.R @@ -3,15 +3,26 @@ postingModuleUI <- function(id) { ns <- NS(id) tagList( - + ) } # --- MODUL SERVER --- -postingModuleServer <- function(id, conn, idwert) { +postingModuleServer <- function(id, conn, trans_id, post_id = NULL) { moduleServer(id, function(input, output, session) { ns <- session$ns # Wichtig für das Namespacing innerhalb des Modals - record <- read_posting(conn, idwert) + if(is.null(post_id)){ + record <- read_posting(conn, trans_id) + }else { + wertstellung <- dbxSelect(conn, paste0("SELECT max(valuta) from Postings WHERE entry_id=", trans_id)) %>% + pull + record <- leer_df_from_table(conn, "postings") + record[1, "id"] <- post_id + record$entry_id <- trans_id + record$account_id <- 0 + record$valuta <- wertstellung + record$booking_date <- wertstellung + } trans <- dbxSelect(conn, paste0("SELECT * FROM entries WHERE id=", record$entry_id)) # Modal öffnen @@ -21,12 +32,12 @@ postingModuleServer <- function(id, conn, idwert) { f_airdatepicker_UI(ns("valuta"), "Wertstellung", record$valuta), f_airdatepicker_UI(ns("buchungsdatum"), "Buchungsdatum", record$booking_date), - selectizeInput(ns("kontakt"), "Kontakt:",selected = trans$adress_id, choices = get_contact_choices(conn), width = "100%"), + selectizeInput(ns("kontakt"), "Kontakt:",selected = trans$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("projekt"), "Projektname", selected = NULL, choices = get_project_choices(conn), width = "100%"), splitLayout(cellWidths = c("70%", "30%"), numericInput(ns("amount"), "Betrag:", value = record$amount, width = "100%"), - numericInput(ns("coin_share_amount"), "Münzne:", 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%"), splitLayout(cellWidths = c("50%", "50%"), @@ -36,16 +47,59 @@ postingModuleServer <- function(id, conn, idwert) { # footer = tagList( modalButton("Abbrechen"), - actionButton(ns("confirm"), "Bestätigen", class = "btn-success") + actionBttn(ns("confirm"), "Bestätigen", style = "minimal", color = "success"), + actionBttn(ns("delete"), "Löschen", style = "minimal", color = "danger"), + splitLayout(cellWidths = c("50%", "50%"), + numericInput(ns("bid"), "ID:", value = record$id), + numericInput(ns("trans_id"), "Trans_id:", value = record$entry_id) + ), ), easyClose = TRUE )) # Aktion beim Bestätigen observeEvent(input$confirm, ignoreInit = T, { - message("Eingabe im Modul ", id, ": ", input$user_name) - removeModal() + 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 + observeEvent(input$delete, ignoreInit = T, { + anz <- dbxSelect(conn, paste0("SELECT count(entry_id) FROM postings WHERE entry_id=", record$entry_id) ) %>% pull + if(anz>1){ + dbxDelete(conn, "postings", where = data.frame(id=record$id)) + removeModal() + return(reactive(input$delete)) + } else { + showNotification("Das ist der letzte Buchungsteil, er kann nicht gelöscht werden -> Transaktion löschen", type = "error") + } + }) + # }) } \ No newline at end of file diff --git a/R/projects/projects.R b/R/projects/projects.R index a46e282..eea3ac4 100644 --- a/R/projects/projects.R +++ b/R/projects/projects.R @@ -5,5 +5,5 @@ get_project_choices <- function(conn) { arrange(projektname) choices <- setNames(as.character(projekte$id), projekte$projektname) - c("-" = "", choices) + return(c("Kein Projekt" = 0, choices)) } diff --git a/db/development.sqlite b/db/development.sqlite index 64a6c2c40c0537d82753b0a3d7c164598a98dff1..2df833be00b35b4da8c890bdb52e2503e30669a3 100644 GIT binary patch delta 525 zcmZp8VB7G(c7imc< z39dvgSmt%X#wu~*3O^Wq0>rB>oRyCHlEX!Gn zSS*;oGjC!pVAf=M&a{EahVd+86{9A@I|c}_Xq;=n!N4RbsHv*Tus66MH7_NV$34hBYPL1R@_Ij7XjlA^?PKga2TiG0G7mEt5=%p2zhPQP%SQE~IEfOQ<3 zn<6V&ShO1Fs!Ug$!6>plsE%=cqC9&%g9$?=1OF!eG=4e08+;S^y!e=S_wc;rS;7;` zBQaSmL4LA(f)RHmP!R|^-7}edFN;#tVxC*!Xra^6%s?;dkH{;(NxoYqOxkGCpz5M`=O~Oq_~}j8HFf0BOGslP4yK zNaSfgO2HzzbTVVEsJPanB%mB4n#QG*4b#OWE*U;bK-0($G<5~YRGtb4%NUKXhx%ij y9>q=HsLmwZ-Zh^Ih?#+y1&CRJm<@>8ftUk`If0l9h`E872Z(vMcg^Q3y8r;k%9D=( delta 188 zcmZp8VB7G(c7ik`-$WT_M!v>`tqF|F@`Xwn_|5sY@@4Q@@&4xB$J@#4xmhA$AOG~4 ziHsuKU)3{;C#W(oFjz2DGVpKWPve*4yTLbs&x?vW6A&{4F$)m00x=s9 bvjZ^)5OV@C7Z7s;F%J;)Ztt4US9SpaH^V^= diff --git a/global.R b/global.R index cba5b65..1f3c2c1 100644 --- a/global.R +++ b/global.R @@ -19,5 +19,4 @@ options(shiny.error = browser) conn <- dbConnect(RSQLite::SQLite(), "db/development.sqlite") sourceDirectory("R/") -dbReadTable(conn, "projects") %>% str -dbGetQuery(conn, "PRAGMA table_info(postings);") +