Repository: pharmaverse/sdtm.oak
Pull request #112: supp domain generation
Author: login: ShiyuC
Created: 2025-03-11T20:51:35Z | Merged: 2025-05-16T18:02:44Z

Close #111 

- [x] Place Closes #<insert_issue_number> into the beginning of your Pull z
Request Title (Use Edit button in top-right if you need to update)
- [x] Code is formatted according to the 
[tidyverse style guide](https://style.tidyverse.org/). Run 
`styler::style_file()` to style R and Rmd files
- [x] Updated relevant unit tests or have written new unit tests, which should
consider realistic data scenarios and edge cases, e.g. empty datasets, errors,
boundary cases etc. - See 
[Unit Test Guide](https://pharmaverse.github.io/admiraldev/articles/unit_test_guidance.html#tests-should-be-robust-to-cover-realistic-data-scenarios)
- [x] If you removed/replaced any function and/or function parameters, did you 
fully follow the 
[deprecation guidance](https://pharmaverse.github.io/admiraldev/articles/programming_strategy.html#deprecation)?
- [x] Update to all relevant roxygen headers and examples, including keywords
and families. Refer to the 
[categorization of functions](https://pharmaverse.github.io/admiraldev/articles/programming_strategy.html#categorization-of-functions) to tag appropriate keyword/family.
- [x] Run `devtools::document()` so all `.Rd` files in the `man` folder and the
`NAMESPACE` file in the project root are updated appropriately
- [x] Address any updates needed for vignettes and/or templates
- [x] Update `NEWS.md` if the changes pertain to a user-facing function (i.e. it
has an `@export` tag) or documentation aimed at users (rather than developers)
- [x] Build oak site `pkgdown::build_site()` and check that all affected
examples are displayed correctly and that all new functions occur on the "[Reference](https://pharmaverse.github.io/admiral/reference/index.html)" page. 
- [x] Address or fix all lintr warnings and errors - `lintr::lint_package()`
- [x] Run `R CMD check` locally and address all errors and warnings - `devtools::check()`
- [x] Link the issue in the Development Section on the right hand side.
- [x] Address all merge conflicts and resolve appropriately
- [x] Pat yourself on the back for a job well done! Much love to your accomplishment!


Linked issue #111: Feature Request:  Split to SUPP-- domain functionality
### Feature Idea

Create function to derive SUPP-- domain from the SDTM output

- Users to provide list of SUPP variables and their QORIG
- `pivot_longer` to shape the data frame
- Columns to include in the output:
      "STUDYID" - inherit from SDTM output
      "RDOMAIN" - inherit from DOMAIN variable
      "USUBJID" - inherit from SDTM output
      "IDVAR" - user input, default to SEQ
      "IDVARVAL" - values from IDVAR
      "QNAM" - user input, SUPP variable names
      "QVAL" - SUPP variable values
      "QORIG" - user input
      "QEVAL" - user input, default to NA


### Relevant Input

_No response_

### Relevant Output

_No response_

### Reproducible Example/Pseudo Code

_No response_

Diff:
diff --git a/NAMESPACE b/NAMESPACE
index 13951835..23b89b19 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -19,6 +19,7 @@ export(derive_study_day)
 export(domain_example)
 export(fmt_cmp)
 export(generate_oak_id_vars)
+export(generate_sdtm_supp)
 export(hardcode_ct)
 export(hardcode_no_ct)
 export(oak_cal_ref_dates)
diff --git a/R/generate_sdtm_supp.R b/R/generate_sdtm_supp.R
new file mode 100644
index 00000000..044e386c
--- /dev/null
+++ b/R/generate_sdtm_supp.R
@@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#'
+#' dm_suppdm <-
+#'   generate_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+generate_sdtm_supp <- function(sdtm_dataset,
+                               idvar = NULL,
+                               supp_qual_info,
+                               qnam_var,
+                               label_var,
+                               orig_var) {
+  admiraldev::assert_character_scalar(qnam_var)
+  admiraldev::assert_character_scalar(label_var)
+  admiraldev::assert_character_scalar(orig_var)
+
+  admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+  # Create vectors for later use
+  domain <- unique(sdtm_dataset$DOMAIN)
+
+  assertthat::assert_that(identical(length(domain), 1L),
+    msg = "There are multiple domain names in the SDTM dataset"
+  )
+
+  # Add dummy SEQ variable for DM domain.
+  # We are removing DMSEQ later in the code.
+  if (identical(domain, "DM") && is.null(idvar)) {
+    sdtm_dataset$DMSEQ <- NA_integer_
+  }
+
+  # The default setting is to use xxSEQ variable for IDVAR
+  idvar <- if (is.null(idvar)) {
+    paste0(domain, "SEQ")
+  }
+
+  admiraldev::assert_character_scalar(idvar)
+
+  # Each supplemental variable should only be mapped to one unique label
+  supp_qual_info <- supp_qual_info |>
+    dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+  supp_cols <- supp_qual_info |>
+    dplyr::select(dplyr::all_of(qnam_var)) |>
+    dplyr::pull()
+
+  admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+    idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+  )))
+
+  supp <- sdtm_dataset |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(supp_cols),
+      names_to = "QNAM",
+      values_to = "QVAL",
+      values_transform = as.character
+    ) |>
+    # Exclude the records where QVAL is null
+    dplyr::filter(!is.na(QVAL)) |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(idvar),
+      names_to = "IDVAR",
+      names_transform = function(names_values) {
+        # Replace DMSEQ with NA
+        names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+      },
+      values_to = "IDVARVAL"
+    ) |>
+    dplyr::left_join(supp_qual_info, by = c("QNAM" = qnam_var)) |>
+    dplyr::mutate(
+      RDOMAIN = DOMAIN,
+      QORIG = Origin,
+      QLABEL = Label,
+      QEVAL = NA_character_
+    ) |>
+    dplyr::select(
+      STUDYID,
+      RDOMAIN,
+      USUBJID,
+      IDVAR,
+      IDVARVAL,
+      QNAM,
+      QLABEL,
+      QVAL,
+      QORIG,
+      QEVAL
+    )
+
+  # Assign labels to SUPPQUAL
+  labels <-
+    c(
+      "Study Identifier",
+      "Related Domain Abbreviation",
+      "Unique Subject Identifier",
+      "Identifying Variable",
+      "Identifying Variable Value",
+      "Qualifier Variable Name",
+      "Qualifier Variable Label",
+      "Data Value",
+      "Origin",
+      "Evaluator"
+    )
+
+  for (v in seq_len(length(labels))) {
+    attr(supp[[v]], "label") <- labels[v]
+  }
+
+  sdtm_output <- sdtm_dataset |>
+    dplyr::select(-dplyr::all_of(supp_cols), -dplyr::any_of("DMSEQ"))
+
+  domain <- toupper(domain)
+  supp_domain <- paste0("SUPP", domain)
+
+  final <- rlang::list2(
+    {{ domain }} := sdtm_output,
+    {{ supp_domain }} := supp
+  )
+
+  cli::cli_alert_info("QEVAL should be manually programmed in supplemental domain.")
+
+  return(final)
+}
diff --git a/R/globals.R b/R/globals.R
index 3b1f54ba..2ec8b39f 100644
--- a/R/globals.R
+++ b/R/globals.R
@@ -2,5 +2,7 @@ utils::globalVariables(c(
   "USUBJID", "VISIT", "dom_dt", "dom_tm", "ref_dt",
   "ref_tm", "datetime", "date_time", "year", "month",
   "day", "hour", "minute", "dataset_name", "date_var",
-  "dformat", "tformat", "sdtm_var_name", "patient_number"
+  "dformat", "tformat", "sdtm_var_name", "patient_number",
+  "DOMAIN", "IDVAR", "IDVARVAL", "Label", "Origin", "QEVAL", "QLABEL",
+  "QNAM", "QORIG", "QVAL", "RDOMAIN", "STUDYID"
 ))
diff --git a/_pkgdown.yml b/_pkgdown.yml
index 83020855..94d9d524 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -58,6 +58,10 @@ reference:
   contents:
   - "%.>%"
 
+- title: Supplemental Qualifiers
+  contents:
+  - generate_sdtm_supp
+
 - title: Calculation of minimum/maximum ISO8601 dates
   contents:
   - cal_min_max_date
diff --git a/data-raw/sdtm_domain_examples.R b/data-raw/sdtm_domain_examples.R
index 4c58ea1d..1ecea719 100644
--- a/data-raw/sdtm_domain_examples.R
+++ b/data-raw/sdtm_domain_examples.R
@@ -26,7 +26,15 @@ apsc <- tibble::tribble(
   "ABC123", "ABC123-212", "JOBCLAS",  "APSC",  "SPOUSE",  "CAREGIVERSTUDY"
 )
 
+suppdm <- pharmaversesdtm::suppdm |>
+  dplyr::select(USUBJID, QNAM, QVAL) |>
+  tidyr::pivot_wider(names_from = QNAM, values_from = QVAL)
+
+dm <- dplyr::left_join(pharmaversesdtm::dm, suppdm) |>
+  dplyr::relocate(COMPLT16, COMPLT24, COMPLT8, EFFICACY, ITT, SAFETY, .after = DTHFL)
+
 readr::write_rds(x = pharmaversesdtm::ae, file = file.path(path, "ae.rds"), compress = "xz")
 readr::write_rds(x = pharmaversesdtm::cm, file = file.path(path, "cm.rds"), compress = "xz")
 readr::write_rds(x = vs, file = file.path(path, "vs.rds"), compress = "xz")
 readr::write_rds(x = apsc, file = file.path(path, "apsc.rds"), compress = "xz")
+readr::write_rds(x = dm, file = file.path(path, "dm.rds"), compress = "xz")
diff --git a/inst/domain/dm.rds b/inst/domain/dm.rds
new file mode 100644
index 00000000..c3bcc99f
Binary files /dev/null and b/inst/domain/dm.rds differ
diff --git a/inst/spec/suppqual_spec.csv b/inst/spec/suppqual_spec.csv
new file mode 100644
index 00000000..4a7770cc
--- /dev/null
+++ b/inst/spec/suppqual_spec.csv
@@ -0,0 +1,7 @@
+Order,Dataset,Variable,Label,Length,Origin,Role
+1,DM,COMPLT16,Completers of Week 16 Population Flag,1,DERIVED,Record Qualifier
+2,DM,COMPLT24,Completers of Week 16 Population Flag,1,DERIVED,Record Qualifier
+3,DM,COMPLT8,Completers of Week 16 Population Flag,1,DERIVED,Record Qualifier
+4,DM,EFFICACY,Efficacy Population Flag,1,DERIVED,Record Qualifier
+5,DM,ITT,Intent to Treat Population Flag,1,DERIVED,Record Qualifier
+6,DM,SAFETY,Safety Population Flag,1,DERIVED,Record Qualifier
diff --git a/man/generate_sdtm_supp.Rd b/man/generate_sdtm_supp.Rd
new file mode 100644
index 00000000..02a94bb7
--- /dev/null
+++ b/man/generate_sdtm_supp.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/generate_sdtm_supp.R
+\name{generate_sdtm_supp}
+\alias{generate_sdtm_supp}
+\title{Function to generate final SDTM domain and supplemental domain SUPP--}
+\usage{
+generate_sdtm_supp(
+  sdtm_dataset,
+  idvar = NULL,
+  supp_qual_info,
+  qnam_var,
+  label_var,
+  orig_var
+)
+}
+\arguments{
+\item{sdtm_dataset}{SDTM output used to split supplemental domains.}
+
+\item{idvar}{Variable name for IDVAR variable.}
+
+\item{supp_qual_info}{User-defined data frame of specifications for suppquals
+which contains \code{qnam_var}, \code{label_var} and \code{orig_var}.}
+
+\item{qnam_var}{Variable name in user-defined \code{supp_qual_info} for QNAM variable.}
+
+\item{label_var}{Variable name in user-defined \code{supp_qual_info} for QLABEL variable.}
+
+\item{orig_var}{Variable name in user-defined \code{supp_qual_info} for QORIG variable.}
+}
+\value{
+List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+}
+\description{
+Function to generate final SDTM domain and supplemental domain SUPP--
+}
+\examples{
+dm <- read_domain_example("dm")
+supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+
+dm_suppdm <-
+  generate_sdtm_supp(
+    dm,
+    idvar = NULL,
+    supp_qual_info = supp_qual_info,
+    qnam_var = "Variable",
+    label_var = "Label",
+    orig_var = "Origin"
+  )
+}
diff --git a/renv.lock b/renv.lock
index cd6da0f0..8db7dd43 100644
--- a/renv.lock
+++ b/renv.lock
@@ -70,7 +70,7 @@
     },
     "R.utils": {
       "Package": "R.utils",
-      "Version": "2.12.3",
+      "Version": "2.13.0",
       "Source": "Repository",
       "Repository": "CRAN",
       "Requirements": [
@@ -81,7 +81,7 @@
         "tools",
         "utils"
       ],
-      "Hash": "3dc2829b790254bfba21e60965787651"
+      "Hash": "d32373d88da809f8974d5307481862b0"
     },
     "R6": {
       "Package": "R6",
diff --git a/renv/profiles/4.2/renv.lock b/renv/profiles/4.2/renv.lock
index 210a2de0..07fd324e 100644
--- a/renv/profiles/4.2/renv.lock
+++ b/renv/profiles/4.2/renv.lock
@@ -70,7 +70,7 @@
     },
     "R.utils": {
       "Package": "R.utils",
-      "Version": "2.12.3",
+      "Version": "2.13.0",
       "Source": "Repository",
       "Repository": "CRAN",
       "Requirements": [
@@ -81,7 +81,7 @@
         "tools",
         "utils"
       ],
-      "Hash": "3dc2829b790254bfba21e60965787651"
+      "Hash": "d32373d88da809f8974d5307481862b0"
     },
     "R6": {
       "Package": "R6",
diff --git a/renv/profiles/4.3/renv.lock b/renv/profiles/4.3/renv.lock
index cd6da0f0..8db7dd43 100644
--- a/renv/profiles/4.3/renv.lock
+++ b/renv/profiles/4.3/renv.lock
@@ -70,7 +70,7 @@
     },
     "R.utils": {
       "Package": "R.utils",
-      "Version": "2.12.3",
+      "Version": "2.13.0",
       "Source": "Repository",
       "Repository": "CRAN",
       "Requirements": [
@@ -81,7 +81,7 @@
         "tools",
         "utils"
       ],
-      "Hash": "3dc2829b790254bfba21e60965787651"
+      "Hash": "d32373d88da809f8974d5307481862b0"
     },
     "R6": {
       "Package": "R6",
diff --git a/tests/testthat/test-generate_sdtm_supp.R b/tests/testthat/test-generate_sdtm_supp.R
new file mode 100644
index 00000000..a9c8e429
--- /dev/null
+++ b/tests/testthat/test-generate_sdtm_supp.R
@@ -0,0 +1,115 @@
+dm <- read_domain_example("dm")[1L:5L, ]
+supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+
+test_that("`generate_sdtm_supp` works as expected", {
+  dm_suppdm <-
+    generate_sdtm_supp(
+      dm,
+      idvar = NULL,
+      supp_qual_info = supp_qual_info,
+      qnam = "Variable",
+      label_var = "Label",
+      orig_var = "Origin"
+    )
+
+  expected_dm_output <- dm |> dplyr::select(-dplyr::all_of((supp_qual_info$Variable)))
+
+  expect_identical(dm_suppdm$DM, expected_dm_output, ignore_attr = TRUE)
+
+  # nolint start
+  expected_suppdm_output <- tibble::tribble(
+    ~STUDYID,       ~RDOMAIN,      ~USUBJID, ~IDVAR, ~IDVARVAL,      ~QNAM,                                 ~QLABEL, ~QVAL,    ~QORIG, ~QEVAL,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA, "COMPLT16", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA, "COMPLT24", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA,  "COMPLT8", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA, "EFFICACY",              "Efficacy Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA,      "ITT",       "Intent to Treat Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1015",     NA,        NA,   "SAFETY",                "Safety Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1023",     NA,        NA, "EFFICACY",              "Efficacy Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1023",     NA,        NA,      "ITT",       "Intent to Treat Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1023",     NA,        NA,   "SAFETY",                "Safety Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA, "COMPLT16", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA, "COMPLT24", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA,  "COMPLT8", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA, "EFFICACY",              "Efficacy Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA,      "ITT",       "Intent to Treat Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1028",     NA,        NA,   "SAFETY",                "Safety Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1033",     NA,        NA, "EFFICACY",              "Efficacy Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1033",     NA,        NA,      "ITT",       "Intent to Treat Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1033",     NA,        NA,   "SAFETY",                "Safety Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA, "COMPLT16", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA, "COMPLT24", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA,  "COMPLT8", "Completers of Week 16 Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA, "EFFICACY",              "Efficacy Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA,      "ITT",       "Intent to Treat Population Flag",   "Y", "DERIVED",     NA,
+    "CDISCPILOT01",     "DM", "01-701-1034",     NA,        NA,   "SAFETY",                "Safety Population Flag",   "Y", "DERIVED",     NA
+  ) |>
+    dplyr::mutate(dplyr::across(c("IDVAR", "QEVAL"), as.character),
+      IDVARVAL = as.integer(IDVARVAL)
+    )
+  # nolint end
+
+  expect_identical(dm_suppdm$SUPPDM, expected_suppdm_output, ignore_attr = TRUE)
+})
+
+test_that("`generate_sdtm_supp` input validation works", {
+  expect_error(
+    generate_sdtm_supp(
+      dm,
+      idvar = 123L,
+      supp_qual_info = supp_qual_info,
+      qnam = "Variable",
+      label_var = "Label",
+      orig_var = "Origin"
+    ),
+    "Argument `idvar` must be a scalar"
+  )
+
+  expect_error(
+    generate_sdtm_supp(
+      dm,
+      idvar = NULL,
+      supp_qual_info = "abc",
+      qnam = "Variable",
+      label_var = "Label",
+      orig_var = "Origin"
+    ),
+    "Argument `supp_qual_info` must be class"
+  )
+
+  expect_error(
+    generate_sdtm_supp(
+      dm,
+      idvar = NULL,
+      supp_qual_info = supp_qual_info,
+      qnam = "Var",
+      label_var = "Label",
+      orig_var = "Origin"
+    ),
+    "Required variable `Var`"
+  )
+
+  expect_error(
+    generate_sdtm_supp(
+      dm,
+      idvar = NULL,
+      supp_qual_info = supp_qual_info,
+      qnam = "Variable",
+      label_var = c("label", "qlabel"),
+      orig_var = "Origin"
+    ),
+    "Argument `label_var` must be a scalar"
+  )
+
+  expect_error(
+    generate_sdtm_supp(
+      dm |> dplyr::select(-COMPLT16),
+      idvar = NULL,
+      supp_qual_info = supp_qual_info,
+      qnam = "Variable",
+      label_var = "Label",
+      orig_var = "Origin"
+    ),
+    "Required variable `COMPLT16` is missing"
+  )
+})


Reviews:
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T16:30:41Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T15:48:25Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T15:49:08Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T16:05:50Z
user: login: rammprasad
body: Minor comments.
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T05:22:32Z
user: login: edgar-manukyan
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T18:15:53Z
user: login: rammprasad
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T21:53:03Z
user: login: rammprasad
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T22:02:34Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T23:10:19Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T23:27:23Z
user: login: edgar-manukyan
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T13:56:50Z
user: login: edgar-manukyan
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T13:58:02Z
user: login: edgar-manukyan
body: @ShiyuC, thanks for the updates. Approved. Just left two comments, more like questions for my own understanding. 🙏 
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-15T13:58:38Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T15:41:55Z
user: login: ShiyuC
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T15:47:48Z
user: login: rammprasad
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-16T18:01:03Z

Review comments:
diff_hunk: @@ -0,0 +1,113 @@
+#' Function to generate supplemental domains SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name used to for variable.
+#' @param spec Data frame of specifications..
path: R/gen_supp.R
user: login: ShiyuC
body: Try to incorporate `xportr_spec`; Let the user define the input of label and origin
created_at: 2025-03-12T16:28:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,113 @@
+#' Function to generate supplemental domains SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name used to for variable.
+#' @param spec Data frame of specifications..
+#' @param eval Character string of the evaluator.
+#'
+#' @return Supplemental domains.
path: R/gen_supp.R
user: login: ShiyuC
body: Return a list of data frames - 1. sdtm with suppquals dropped; 2. supp-- domain
created_at: 2025-03-12T16:29:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,113 @@
+#' Function to generate supplemental domains SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name used to for variable.
+#' @param spec Data frame of specifications..
+#' @param eval Character string of the evaluator.
+#'
+#' @return Supplemental domains.
+#' @export
+#'
+#' @examples
+#' path <- here::here("inst")
+#' dm <- readRDS(paste0(path, "/domain/dm.rds"))
+#' spec <- read.csv(paste0(path, "/spec/spec.csv"))
+#' suppdm <- gen_supp(dm, idvar = NULL, spec = spec, eval = "CLINICAL STUDY SPONSOR")
+gen_supp <-
+  function(sdtm_dataset = NULL,
+           idvar = NULL,
+           spec = NULL,
+           eval = NA_character_ ### Should this be 1 single character value or a vector?
path: R/gen_supp.R
user: login: ShiyuC
body: Check with SMEs - if it's not a single value across the entire supp- domain, then users need to manually program it.
created_at: 2025-03-12T16:30:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,113 @@
+#' Function to generate supplemental domains SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name used to for variable.
+#' @param spec Data frame of specifications..
path: R/gen_supp.R
user: login: ShiyuC
body: Used the naming convention from xportr to create spec example
created_at: 2025-03-26T15:48:25Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,113 @@
+#' Function to generate supplemental domains SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name used to for variable.
+#' @param spec Data frame of specifications..
+#' @param eval Character string of the evaluator.
+#'
+#' @return Supplemental domains.
+#' @export
+#'
+#' @examples
+#' path <- here::here("inst")
+#' dm <- readRDS(paste0(path, "/domain/dm.rds"))
+#' spec <- read.csv(paste0(path, "/spec/spec.csv"))
+#' suppdm <- gen_supp(dm, idvar = NULL, spec = spec, eval = "CLINICAL STUDY SPONSOR")
+gen_supp <-
+  function(sdtm_dataset = NULL,
+           idvar = NULL,
+           spec = NULL,
+           eval = NA_character_ ### Should this be 1 single character value or a vector?
path: R/gen_supp.R
user: login: ShiyuC
body: SME confirmed the QEVAL values can vary within one single supp domain
created_at: 2025-03-26T15:49:08Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,145 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param spec User-defined data frame of specifications which should contain
+#' `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `spec` for QNAM variable.
+#' @param label_var Variable name in user-defined `spec` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `spec` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' path <- here::here("inst")
path: R/gen_sdtm_supp.R
user: login: ShiyuC
body: The here package won't work for the users. Switch to system.file
created_at: 2025-03-26T16:05:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param spec User-defined data frame of specifications which should contain
+#' `qnam_var`, `label_var` and `orig_var`.
path: R/gen_sdtm_supp.R
user: login: rammprasad
body: Can we change the name of the parameter to `supp_qual_info`
created_at: 2025-05-14T05:21:05Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: Shall we name our functions consistently? We have a function `generate_oak_id_vars()` that generates oak_id_vars. Now we have a function to generate final SDTM domain. It sounds to me that we should consider `generate_sdtm_supp` name. What do you think?
created_at: 2025-05-14T17:05:22Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion
#'
#' final <-
```
created_at: 2025-05-14T17:15:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: The whole body of the function is indented by four spaces in comparison to other functions in the packages with two spaces.

![image](https://github.com/user-attachments/assets/9d44ff46-7e9e-4731-b5b6-2c24d995d256)

created_at: 2025-05-14T17:47:31Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion

    assertthat::assert_that(identical(length(domain), 1L),
```
created_at: 2025-05-14T17:52:03Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion
    # We are removing DMSEQ later in the code.
```
created_at: 2025-05-14T17:53:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
+    }
+
+    # The default setting is to use xxSEQ variable for IDVAR
+    idvar <- if (is.null(idvar)) {
+      paste0(domain, "SEQ")
+    }
+    admiraldev::assert_character_scalar(idvar)
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion

    admiraldev::assert_character_scalar(idvar)
```
created_at: 2025-05-14T17:54:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
+    }
+
+    # The default setting is to use xxSEQ variable for IDVAR
+    idvar <- if (is.null(idvar)) {
+      paste0(domain, "SEQ")
+    }
+    admiraldev::assert_character_scalar(idvar)
+
+    # Each supplemental variable should only be mapped to one unique label
+    supp_qual_info <- supp_qual_info |>
+      dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+    supp_cols <- supp_qual_info |>
+      dplyr::select(dplyr::all_of(qnam_var)) |>
+      dplyr::pull()
+
+    admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+      idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+    )))
+
+    supp <- sdtm_dataset |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(supp_cols),
+        names_to = "QNAM",
+        values_to = "QVAL",
+        values_transform = as.character
+      ) |>
+      # Exclude the records where QVAL is null
+      dplyr::filter(!is.na(QVAL)) |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(idvar),
+        names_to = "IDVAR",
+        names_transform = function(names_values) {
+          # Replace DMSEQ with NA
+          names_values <- gsub("^DMSEQ$", NA_character_, names_values)
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion
          gsub("^DMSEQ$", NA_character_, names_values)
```
created_at: 2025-05-14T18:02:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: Why do we assign DMSEQ integer NA and they change to character NA?
created_at: 2025-05-14T18:05:58Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
+    }
+
+    # The default setting is to use xxSEQ variable for IDVAR
+    idvar <- if (is.null(idvar)) {
+      paste0(domain, "SEQ")
+    }
+    admiraldev::assert_character_scalar(idvar)
+
+    # Each supplemental variable should only be mapped to one unique label
+    supp_qual_info <- supp_qual_info |>
+      dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+    supp_cols <- supp_qual_info |>
+      dplyr::select(dplyr::all_of(qnam_var)) |>
+      dplyr::pull()
+
+    admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+      idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+    )))
+
+    supp <- sdtm_dataset |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(supp_cols),
+        names_to = "QNAM",
+        values_to = "QVAL",
+        values_transform = as.character
+      ) |>
+      # Exclude the records where QVAL is null
+      dplyr::filter(!is.na(QVAL)) |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(idvar),
+        names_to = "IDVAR",
+        names_transform = function(names_values) {
+          # Replace DMSEQ with NA
+          names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+        },
+        values_to = "IDVARVAL"
+      ) |>
+      dplyr::left_join(supp_qual_info, by = c("QNAM" = qnam_var)) |>
+      dplyr::mutate(
+        RDOMAIN = DOMAIN,
+        QORIG = Origin,
+        QLABEL = Label,
+        QEVAL = NA_character_
+      ) |>
+      dplyr::select(
+        STUDYID,
+        RDOMAIN,
+        USUBJID,
+        IDVAR,
+        IDVARVAL,
+        QNAM,
+        QLABEL,
+        QVAL,
+        QORIG,
+        QEVAL
+      )
+
+    # Assign labels to SUPPQUAL
+    labels <-
+      c(
+        labels <-
+          c(
+            "Study Identifier",
+            "Related Domain Abbreviation",
+            "Unique Subject Identifier",
+            "Identifying Variable",
+            "Identifying Variable Value",
+            "Qualifier Variable Name",
+            "Qualifier Variable Label",
+            "Data Value",
+            "Origin",
+            "Evaluator"
+          )
+      )
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion
    labels <- c(
      "Study Identifier",
      "Related Domain Abbreviation",
      "Unique Subject Identifier",
      "Identifying Variable",
      "Identifying Variable Value",
      "Qualifier Variable Name",
      "Qualifier Variable Label",
      "Data Value",
      "Origin",
      "Evaluator"
    )
```

- Somehow there were two assignments.
- @rammprasad, do we want these to be configurable or they never change?
created_at: 2025-05-14T18:13:14Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
+    }
+
+    # The default setting is to use xxSEQ variable for IDVAR
+    idvar <- if (is.null(idvar)) {
+      paste0(domain, "SEQ")
+    }
+    admiraldev::assert_character_scalar(idvar)
+
+    # Each supplemental variable should only be mapped to one unique label
+    supp_qual_info <- supp_qual_info |>
+      dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+    supp_cols <- supp_qual_info |>
+      dplyr::select(dplyr::all_of(qnam_var)) |>
+      dplyr::pull()
+
+    admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+      idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+    )))
+
+    supp <- sdtm_dataset |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(supp_cols),
+        names_to = "QNAM",
+        values_to = "QVAL",
+        values_transform = as.character
+      ) |>
+      # Exclude the records where QVAL is null
+      dplyr::filter(!is.na(QVAL)) |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(idvar),
+        names_to = "IDVAR",
+        names_transform = function(names_values) {
+          # Replace DMSEQ with NA
+          names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+        },
+        values_to = "IDVARVAL"
+      ) |>
+      dplyr::left_join(supp_qual_info, by = c("QNAM" = qnam_var)) |>
+      dplyr::mutate(
+        RDOMAIN = DOMAIN,
+        QORIG = Origin,
+        QLABEL = Label,
+        QEVAL = NA_character_
+      ) |>
+      dplyr::select(
+        STUDYID,
+        RDOMAIN,
+        USUBJID,
+        IDVAR,
+        IDVARVAL,
+        QNAM,
+        QLABEL,
+        QVAL,
+        QORIG,
+        QEVAL
+      )
+
+    # Assign labels to SUPPQUAL
+    labels <-
+      c(
+        labels <-
+          c(
+            "Study Identifier",
+            "Related Domain Abbreviation",
+            "Unique Subject Identifier",
+            "Identifying Variable",
+            "Identifying Variable Value",
+            "Qualifier Variable Name",
+            "Qualifier Variable Label",
+            "Data Value",
+            "Origin",
+            "Evaluator"
+          )
+      )
+
+    for (v in seq_len(length(labels))) {
+      attr(supp[[v]], "label") <- labels[v]
+    }
+
+    sdtm_output <- sdtm_dataset |>
+      dplyr::select(-dplyr::all_of(supp_cols), -dplyr::any_of("DMSEQ"))
+
+    domain <- toupper(domain)
+    supp_domain <- paste0("SUPP", domain)
+    final <- rlang::list2(
path: R/gen_sdtm_supp.R
user: login: edgar-manukyan
body: ```suggestion

    final <- rlang::list2(
```
created_at: 2025-05-14T18:13:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
path: R/gen_sdtm_supp.R
user: login: rammprasad
body: Good idea, I am fine to rename the function.
created_at: 2025-05-14T21:53:03Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
+    }
+
+    # The default setting is to use xxSEQ variable for IDVAR
+    idvar <- if (is.null(idvar)) {
+      paste0(domain, "SEQ")
+    }
+    admiraldev::assert_character_scalar(idvar)
+
+    # Each supplemental variable should only be mapped to one unique label
+    supp_qual_info <- supp_qual_info |>
+      dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+    supp_cols <- supp_qual_info |>
+      dplyr::select(dplyr::all_of(qnam_var)) |>
+      dplyr::pull()
+
+    admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+      idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+    )))
+
+    supp <- sdtm_dataset |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(supp_cols),
+        names_to = "QNAM",
+        values_to = "QVAL",
+        values_transform = as.character
+      ) |>
+      # Exclude the records where QVAL is null
+      dplyr::filter(!is.na(QVAL)) |>
+      tidyr::pivot_longer(
+        cols = dplyr::all_of(idvar),
+        names_to = "IDVAR",
+        names_transform = function(names_values) {
+          # Replace DMSEQ with NA
+          names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+        },
+        values_to = "IDVARVAL"
+      ) |>
+      dplyr::left_join(supp_qual_info, by = c("QNAM" = qnam_var)) |>
+      dplyr::mutate(
+        RDOMAIN = DOMAIN,
+        QORIG = Origin,
+        QLABEL = Label,
+        QEVAL = NA_character_
+      ) |>
+      dplyr::select(
+        STUDYID,
+        RDOMAIN,
+        USUBJID,
+        IDVAR,
+        IDVARVAL,
+        QNAM,
+        QLABEL,
+        QVAL,
+        QORIG,
+        QEVAL
+      )
+
+    # Assign labels to SUPPQUAL
+    labels <-
+      c(
+        labels <-
+          c(
+            "Study Identifier",
+            "Related Domain Abbreviation",
+            "Unique Subject Identifier",
+            "Identifying Variable",
+            "Identifying Variable Value",
+            "Qualifier Variable Name",
+            "Qualifier Variable Label",
+            "Data Value",
+            "Origin",
+            "Evaluator"
+          )
+      )
path: R/gen_sdtm_supp.R
user: login: rammprasad
body: This will never change. It is based on the CDISC IG. If they change the Implementation guide, we have to update the package. I am happy to leave it like this.
created_at: 2025-05-14T21:55:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
path: R/gen_sdtm_supp.R
user: login: rammprasad
body: Can we rename the object to be something meaningful? `dm_suppdm`
created_at: 2025-05-14T22:02:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
+    admiraldev::assert_character_scalar(label_var)
+    admiraldev::assert_character_scalar(orig_var)
+
+    admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+    # Create vectors for later use
+    domain <- unique(sdtm_dataset$DOMAIN)
+    assertthat::assert_that(identical(length(domain), 1L),
+      msg = "There are multiple domain names in the SDTM dataset"
+    )
+
+    # Add dummy SEQ variable for DM domain.
+    # The DMSEQ will be removed later.
+    if (identical(domain, "DM") && is.null(idvar)) {
+      sdtm_dataset$DMSEQ <- NA_integer_
path: R/gen_sdtm_supp.R
user: login: ShiyuC
body: From my understanding, the `names_transform` in `pivot_longer` doesn't change the values under `DMSEQ` to be character NA, it will just change the "DMSEQ" value itself into `NA` under the `IDVAR` column because there is no such SDTM variable called "DMSEQ".
In short, after `pivot_longer`, for DMSEQ, `NA_character` goes under `IDVAR`, `NA_integer` goes under `IDVARVAL`
created_at: 2025-05-14T23:10:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,142 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#' final <-
+#'   gen_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+gen_sdtm_supp <-
+  function(sdtm_dataset,
+           idvar = NULL,
+           supp_qual_info,
+           qnam_var,
+           label_var,
+           orig_var) {
+    admiraldev::assert_character_scalar(qnam_var)
path: R/gen_sdtm_supp.R
user: login: ShiyuC
body: Updated
created_at: 2025-05-14T23:27:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,143 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#'
+#' dm_suppdm <-
+#'   generate_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+generate_sdtm_supp <- function(sdtm_dataset,
+                               idvar = NULL,
+                               supp_qual_info,
+                               qnam_var,
+                               label_var,
+                               orig_var) {
+  admiraldev::assert_character_scalar(qnam_var)
+  admiraldev::assert_character_scalar(label_var)
+  admiraldev::assert_character_scalar(orig_var)
+
+  admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+  # Create vectors for later use
+  domain <- unique(sdtm_dataset$DOMAIN)
+
+  assertthat::assert_that(identical(length(domain), 1L),
+    msg = "There are multiple domain names in the SDTM dataset"
+  )
+
+  # Add dummy SEQ variable for DM domain.
+  # We are removing DMSEQ later in the code.
+  if (identical(domain, "DM") && is.null(idvar)) {
+    sdtm_dataset$DMSEQ <- NA_integer_
+  }
+
+  # The default setting is to use xxSEQ variable for IDVAR
+  idvar <- if (is.null(idvar)) {
+    paste0(domain, "SEQ")
+  }
+
+  admiraldev::assert_character_scalar(idvar)
+
+  # Each supplemental variable should only be mapped to one unique label
+  supp_qual_info <- supp_qual_info |>
+    dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+  supp_cols <- supp_qual_info |>
+    dplyr::select(dplyr::all_of(qnam_var)) |>
+    dplyr::pull()
+
+  admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+    idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+  )))
+
+  supp <- sdtm_dataset |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(supp_cols),
+      names_to = "QNAM",
+      values_to = "QVAL",
+      values_transform = as.character
+    ) |>
+    # Exclude the records where QVAL is null
+    dplyr::filter(!is.na(QVAL)) |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(idvar),
+      names_to = "IDVAR",
+      names_transform = function(names_values) {
+        # Replace DMSEQ with NA
+        names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+        names_values
path: R/generate_sdtm_supp.R
user: login: edgar-manukyan
body: I do not think we need to assign the result of gsub, it will just return itself.
created_at: 2025-05-15T13:56:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,143 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#'
+#' dm_suppdm <-
+#'   generate_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+generate_sdtm_supp <- function(sdtm_dataset,
+                               idvar = NULL,
+                               supp_qual_info,
+                               qnam_var,
+                               label_var,
+                               orig_var) {
+  admiraldev::assert_character_scalar(qnam_var)
+  admiraldev::assert_character_scalar(label_var)
+  admiraldev::assert_character_scalar(orig_var)
+
+  admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+  # Create vectors for later use
+  domain <- unique(sdtm_dataset$DOMAIN)
+
+  assertthat::assert_that(identical(length(domain), 1L),
+    msg = "There are multiple domain names in the SDTM dataset"
+  )
+
+  # Add dummy SEQ variable for DM domain.
+  # We are removing DMSEQ later in the code.
+  if (identical(domain, "DM") && is.null(idvar)) {
+    sdtm_dataset$DMSEQ <- NA_integer_
path: R/generate_sdtm_supp.R
user: login: edgar-manukyan
body: What happens if we just assign char NA here and to do not change it to char again later?
created_at: 2025-05-15T13:58:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,143 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#'
+#' dm_suppdm <-
+#'   generate_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+generate_sdtm_supp <- function(sdtm_dataset,
+                               idvar = NULL,
+                               supp_qual_info,
+                               qnam_var,
+                               label_var,
+                               orig_var) {
+  admiraldev::assert_character_scalar(qnam_var)
+  admiraldev::assert_character_scalar(label_var)
+  admiraldev::assert_character_scalar(orig_var)
+
+  admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+  # Create vectors for later use
+  domain <- unique(sdtm_dataset$DOMAIN)
+
+  assertthat::assert_that(identical(length(domain), 1L),
+    msg = "There are multiple domain names in the SDTM dataset"
+  )
+
+  # Add dummy SEQ variable for DM domain.
+  # We are removing DMSEQ later in the code.
+  if (identical(domain, "DM") && is.null(idvar)) {
+    sdtm_dataset$DMSEQ <- NA_integer_
path: R/generate_sdtm_supp.R
user: login: ShiyuC
body: @edgar-manukyan , the logic is inherited from roak but let me try to explain it better. 
For other domains like LB, for example, when creating SUPPLB, this is what we want to do:
![image](https://github.com/user-attachments/assets/81d5a81d-a4d9-4735-8979-d7f9bbf589c6)

For DM, there is no such variable called DMSEQ, so we created a dummy variable. This is what we are expecting to do:
![image](https://github.com/user-attachments/assets/4020c2d1-7020-4317-8172-85b1809357f0)

IDVAR is a character variable while IDVARVAL is a numeric variable. Please let me know if this makes sense.
created_at: 2025-05-15T15:41:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,143 @@
+#' Function to generate final SDTM domain and supplemental domain SUPP--
+#'
+#' @param sdtm_dataset SDTM output used to split supplemental domains.
+#' @param idvar Variable name for IDVAR variable.
+#' @param supp_qual_info User-defined data frame of specifications for suppquals
+#' which contains `qnam_var`, `label_var` and `orig_var`.
+#' @param qnam_var Variable name in user-defined `supp_qual_info` for QNAM variable.
+#' @param label_var Variable name in user-defined `supp_qual_info` for QLABEL variable.
+#' @param orig_var Variable name in user-defined `supp_qual_info` for QORIG variable.
+#'
+#' @return List of SDTM domain with suppquals dropped and corresponding supplemental domain.
+#' @export
+#'
+#' @examples
+#' dm <- read_domain_example("dm")
+#' supp_qual_info <- read.csv(system.file("spec/suppqual_spec.csv", package = "sdtm.oak"))
+#'
+#' dm_suppdm <-
+#'   generate_sdtm_supp(
+#'     dm,
+#'     idvar = NULL,
+#'     supp_qual_info = supp_qual_info,
+#'     qnam_var = "Variable",
+#'     label_var = "Label",
+#'     orig_var = "Origin"
+#'   )
+generate_sdtm_supp <- function(sdtm_dataset,
+                               idvar = NULL,
+                               supp_qual_info,
+                               qnam_var,
+                               label_var,
+                               orig_var) {
+  admiraldev::assert_character_scalar(qnam_var)
+  admiraldev::assert_character_scalar(label_var)
+  admiraldev::assert_character_scalar(orig_var)
+
+  admiraldev::assert_data_frame(supp_qual_info, required_vars = rlang::syms(c(qnam_var, label_var, orig_var)))
+
+  # Create vectors for later use
+  domain <- unique(sdtm_dataset$DOMAIN)
+
+  assertthat::assert_that(identical(length(domain), 1L),
+    msg = "There are multiple domain names in the SDTM dataset"
+  )
+
+  # Add dummy SEQ variable for DM domain.
+  # We are removing DMSEQ later in the code.
+  if (identical(domain, "DM") && is.null(idvar)) {
+    sdtm_dataset$DMSEQ <- NA_integer_
+  }
+
+  # The default setting is to use xxSEQ variable for IDVAR
+  idvar <- if (is.null(idvar)) {
+    paste0(domain, "SEQ")
+  }
+
+  admiraldev::assert_character_scalar(idvar)
+
+  # Each supplemental variable should only be mapped to one unique label
+  supp_qual_info <- supp_qual_info |>
+    dplyr::distinct(dplyr::across(dplyr::all_of(c(qnam_var, label_var, orig_var))), .keep_all = TRUE)
+
+  supp_cols <- supp_qual_info |>
+    dplyr::select(dplyr::all_of(qnam_var)) |>
+    dplyr::pull()
+
+  admiraldev::assert_data_frame(sdtm_dataset, required_vars = rlang::syms(c(
+    idvar, supp_cols, "STUDYID", "DOMAIN", "USUBJID"
+  )))
+
+  supp <- sdtm_dataset |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(supp_cols),
+      names_to = "QNAM",
+      values_to = "QVAL",
+      values_transform = as.character
+    ) |>
+    # Exclude the records where QVAL is null
+    dplyr::filter(!is.na(QVAL)) |>
+    tidyr::pivot_longer(
+      cols = dplyr::all_of(idvar),
+      names_to = "IDVAR",
+      names_transform = function(names_values) {
+        # Replace DMSEQ with NA
+        names_values <- gsub("^DMSEQ$", NA_character_, names_values)
+        names_values
path: R/generate_sdtm_supp.R
user: login: ShiyuC
body: Removed the return
created_at: 2025-05-15T15:47:48Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-11T20:55:27Z
body: ![Code Coverage](https://img.shields.io/badge/Code%20Coverage-94%25-success?style=flat)

Package | Line Rate | Health
-------- | --------- | ------
sdtm.oak | 94% | ✔
**Summary** | **94%** (1127 / 1198) | ✔

<!-- Sticky Pull Request Commentcode-coverage -->
author_association: NONE
user: login: rammprasad
created_at: 2025-05-14T05:18:20Z
body: Looks good to me @ShiyuC - Can you merge main to FB? 
author_association: COLLABORATOR
user: login: ShiyuC
created_at: 2025-05-14T16:48:40Z
body: @edgar-manukyan Can I request your review of this PR? Thanks!
author_association: COLLABORATOR
user: login: edgar-manukyan
created_at: 2025-05-14T18:19:18Z
body: > @edgar-manukyan Can I request your review of this PR? Thanks!

Nice job @ShiyuC 💯 💯 💯 I left few stylistic comments, suggestions.
author_association: COLLABORATOR
user: login: ShiyuC
created_at: 2025-05-15T00:06:38Z
body: @edgar-manukyan @rammprasad the PR is updated. Please conduct another review when you get a chance. 😺 
author_association: COLLABORATOR