diff --git a/.gitignore b/.gitignore index ee8b1bf..4a1dbe0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ inst/doc *_.new.png config.yml +.venv/ diff --git a/DESCRIPTION b/DESCRIPTION index c4c15cb..8e5d08e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -13,26 +13,83 @@ Description: Provides a Shiny dashboard and API client for interactingwith License: file LICENSE URL: https://github.com/noclocks/gmhdatahub BugReports: https://github.com/noclocks/gmhdatahub/issues +Depends: + R (>= 4.1) Imports: + bsicons, bslib, + cli, + dplyr, fontawesome, + golem, htmltools, + httr2, + jsonlite, + logger, pkgload, + purrr, rlang (>= 1.1.0), - shiny + sass, + shiny, + shinyjs, + shinyWidgets, + stringr, + waiter Suggests: httptest2, + kableExtra, knitr, rmarkdown, shinytest2, spelling, - testthat (>= 3.0.0) + testthat (>= 3.0.0), + tibble, + tidyr +Remotes: + rstudio/bslib, + r-lib/httr2, + rstudio/sass VignetteBuilder: knitr -Config/testthat/edition: 3 Encoding: UTF-8 Language: en-US Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 -Depends: - R (>= 2.10) +Config/testthat/edition: 3 +Config/tests/needs: + testthat (>= 3.0.0), + spelling, + httptest2, + shinytest2 +Config/coverage/needs: + covr, + covrpage +Config/pkgdown/needs: + pkgdown, + testdown, + gitdown, + covrpage +Config/database/needs: + DBI, + pool, + dbplyr, + dplyr, + RPostgres, + config +Config/api/needs: + httr2, + jsonlite, + plumber, + R6, + config +Config/shiny/needs: + shiny, + shinyjs, + shinyWidgets, + waiter, + bslib, + bsicons, + fontawesome, + sass, + golem +LazyData: true diff --git a/NAMESPACE b/NAMESPACE index 697f103..c8fb269 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,29 +1,115 @@ # Generated by roxygen2: do not edit by hand +export(add_external_resources) +export(compile_styles) +export(entrata_req_auth) +export(entrata_req_body) +export(entrata_req_endpoint) +export(entrata_req_error) +export(entrata_req_log) +export(entrata_req_perform) +export(entrata_request) +export(entrata_resp_abort) +export(entrata_resp_body_json) +export(entrata_resp_check_status) +export(entrata_resp_status) +export(entrata_resp_status_desc) export(footer_client_section) export(footer_copyright_section) export(footer_logo_section) export(footer_top_section) +export(get_entrata_config) +export(get_entrata_report_info) +export(get_entrata_reports_list) +export(get_latest_report_version) +export(icon_text) +export(is_boolean_string) +export(is_integer_string) +export(is_integer_string_multi) export(mod_footer_server) export(mod_footer_ui) +export(mod_home_server) +export(mod_home_ui) +export(mod_properties_ui) export(mod_sidebar_server) export(mod_sidebar_ui) +export(pkg_sys) +export(pkg_sys_assets) +export(pkg_sys_config) +export(pkg_sys_examples) +export(pkg_sys_templates) +export(validate_entrata_config) +export(validate_entrata_endpoint_method_params) +export(validate_entrata_method_version) +export(validate_entrata_request) +export(validate_entrata_request_endpoint) +export(validate_entrata_request_endpoint_method) export(validate_image) importFrom(bsicons,bs_icon) importFrom(bslib,accordion) importFrom(bslib,accordion_panel) +importFrom(bslib,card) +importFrom(bslib,card_body) importFrom(bslib,card_footer) +importFrom(bslib,card_title) +importFrom(bslib,layout_column_wrap) importFrom(bslib,layout_columns) importFrom(bslib,sidebar) +importFrom(bslib,value_box) +importFrom(cli,cli_abort) +importFrom(cli,cli_alert_danger) +importFrom(cli,cli_alert_info) +importFrom(cli,cli_alert_success) +importFrom(cli,cli_alert_warning) +importFrom(config,get) +importFrom(dplyr,filter) +importFrom(dplyr,left_join) +importFrom(dplyr,pull) +importFrom(dplyr,select) importFrom(fontawesome,fa) +importFrom(glue,glue) importFrom(htmltools,HTML) +importFrom(htmltools,tagList) importFrom(htmltools,tags) +importFrom(httr2,req_auth_basic) +importFrom(httr2,req_body_json) +importFrom(httr2,req_dry_run) +importFrom(httr2,req_error) +importFrom(httr2,req_headers) +importFrom(httr2,req_method) +importFrom(httr2,req_perform) +importFrom(httr2,req_url_path_append) +importFrom(httr2,req_user_agent) +importFrom(httr2,request) +importFrom(httr2,resp_body_json) +importFrom(logger,log_info) +importFrom(purrr,list_rbind) +importFrom(purrr,map) +importFrom(purrr,pluck) +importFrom(purrr,pluck_exists) +importFrom(purrr,set_names) importFrom(rlang,.data) importFrom(rlang,.env) +importFrom(rlang,arg_match) +importFrom(rlang,caller_arg) +importFrom(rlang,caller_env) +importFrom(sass,output_template) +importFrom(sass,sass) +importFrom(sass,sass_file) +importFrom(sass,sass_options) importFrom(shiny,NS) importFrom(shiny,icon) importFrom(shiny,includeCSS) importFrom(shiny,moduleServer) importFrom(shiny,reactive) importFrom(shiny,req) +importFrom(shiny,textOutput) +importFrom(shiny,uiOutput) importFrom(shinyWidgets,pickerInput) +importFrom(tibblify,tib_chr) +importFrom(tibblify,tib_df) +importFrom(tibblify,tib_int) +importFrom(tibblify,tib_lgl) +importFrom(tibblify,tib_row) +importFrom(tibblify,tspec_df) +importFrom(yaml,read_yaml) diff --git a/R/app_ui.R b/R/app_ui.R index 10ccf75..694a923 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -7,30 +7,6 @@ # # ------------------------------------------------------------------------ - -# internal ---------------------------------------------------------------- - -add_external_resources <- function() { - shiny::addResourcePath( - "www", - system.file("www", package = "gmhdatahub") - ) - - htmltools::tags$head( - htmltools::tags$link( - rel = "shortcut icon", - type = "image/x-icon", - href = "www/favicon.ico" - ), - golem::bundle_resources( - path = system.file("www", package = "gmhdatahub"), - app_title = "gmhdatahub" - ), - shinyjs::useShinyjs(), - waiter::use_waiter() - ) -} - # UI ---------------------------------------------------------------------- app_ui <- function(req) { @@ -50,20 +26,20 @@ app_ui <- function(req) { bslib::nav_panel( title = "Home", value = "home", - icon = shiny::icon("home")#, - # mod_home_ui("app") + icon = shiny::icon("home"), + mod_home_ui("app") ), bslib::nav_panel( title = "Data", value = "data", - icon = shiny::icon("database")#, - # mod_data_ui("app") + icon = shiny::icon("database"), + mod_data_ui("app") ), bslib::nav_panel( title = "Analysis", value = "analysis", - icon = shiny::icon("chart-line")#, - # mod_analysis_ui("app") + icon = shiny::icon("chart-line"), + mod_analysis_ui("app") ), bslib::nav_spacer(), bslib::nav_menu( diff --git a/R/assets.R b/R/assets.R new file mode 100644 index 0000000..03d053b --- /dev/null +++ b/R/assets.R @@ -0,0 +1,116 @@ + +# ------------------------------------------------------------------------ +# +# Title : Assets +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + + +# add external resources -------------------------------------------------- + +#' Add External Resources +#' +#' @description +#' Add external resources to the shiny app. +#' +#' This function performs the following: +#' +#' - Adds this package's installed `www` folder to the shiny app resource paths +#' via [shiny::addResourcePath()]. +#' +#' +#' @return NULL +#' @export +add_external_resources <- function() { + + shiny::addResourcePath("www", pkg_sys("www")) + + htmltools::tags$head( + htmltools::tags$link( + rel = "shortcut icon", + type = "image/x-icon", + href = "www/favicon.ico" + ), + golem::bundle_resources( + path = system.file("www", package = "gmhdatahub"), + app_title = "gmhdatahub" + ), + shinyjs::useShinyjs(), + waiter::use_waiter() + ) +} + + +# compile SASS ------------------------------------------------------------ + +#' Compile Styles +#' +#' @description +#' Compile SASS files to CSS. +#' +#' @param path The path to the `styles` folder. Default is `pkg_sys("www", "styles")`. +#' This folder must contain a `scss` folder with a `index.scss` file. +#' +#' @return The path to the compiled CSS file. +#' +#' @export +#' +#' @examples +#' compile_styles() +#' +#' @importFrom sass sass sass_file sass_options output_template +#' @importFrom cli cli_alert_danger cli_alert_success +compile_styles <- function( + path = pkg_sys("www", "styles"), + source_map = TRUE, + cache = FALSE +) { + + # paths + scss_dir <- file.path(path, "scss") + css_dir <- file.path(path, "css") + + # create css directory if it doesn't exist + if (!dir.exists(css_dir)) { + dir.create(css_dir) + } + + # output template + sass_output_template <- sass::output_template( + basename = "styles", + dirname = "css", + fileext = ".min.css", + path = path + ) + + # main scss file + scss_main <- file.path(scss_dir, "index.scss") + output_file <- file.path(css_dir, "styles.min.css") + + # compile scss to css + tryCatch({ + sass::sass( + sass::sass_file(scss_main), + output = sass_output_template(suffix = ""), + options = sass::sass_options( + output_style = "compressed", + include_path = list.files( + scss_dir, + full.names = TRUE + ), + source_map_embed = source_map + ), + cache = cache + ) + }, error = function(e) { + cli::cli_alert_danger("Error compiling SASS: {e$message}") + }) + + cli::cli_alert_success("SASS compiled successfully: {.field {output_file}}") + + # return the path to the compiled css file + return(output_file) + +} diff --git a/R/config.R b/R/config.R new file mode 100644 index 0000000..afbaa28 --- /dev/null +++ b/R/config.R @@ -0,0 +1,256 @@ + +# ------------------------------------------------------------------------ +# +# Title : Configuration +# By : Jimmy Briggs +# Date : 2024-11-12 +# +# ------------------------------------------------------------------------ + +# entrata ----------------------------------------------------------------- + +# notes: +# must contain base_url, username, password +# optional fields: user_agent, timeout, request_id, default_request_id, debug, +# headers, error handler, verbosity, redaction, retry, retry_count, retry_delay, +# retry_backoff, transient_codes, error_codes, progress, logging, +# caching, etc. + +#' Get Entrata API Configuration +#' +#' @description +#' This function retrieves the Entrata configuration from the specified configuration +#' file and returns the configuration as a list. You can optionally specify a key +#' to retrieve a specific configuration value. +#' +#' @details +#' The Entrata configuration is expected to be stored in a YAML configuration file +#' under the `entrata` key. The configuration file should contain the following +#' fields: +#' +#' - `base_url` - The base URL for the Entrata API. +#' - `username` - The username to use for authenticating with the Entrata API. +#' - `password` - The password to use for authenticating with the Entrata API. +#' +#' For example, in this package's used `config.yml` file, there is the following +#' `"entrata"` specific (default) configuration: +#' +#' ```yaml +#' default: +#' entrata: +#' base_url: "https://gmhcommunities.entrata.com" +#' username: "" +#' password: "" +#' ``` +#' +#' @param key A character string representing the configuration key to retrieve. +#' Defaults to `NULL` which returns the full `entrata` specific configuration +#' object as a list. +#' @inheritParams config::get +#' +#' @return A list, or vector (if `key` is specified), corresponding to the +#' contents of the `entrata` configuration key's values (i.e. `base_url`, +#' `username`, and `password`). +#' +#' @export +#' +#' @family Configuration +#' @family Entrata +#' +#' @seealso [config::get()] - the primary workhorse for retrieving configuration +#' values from configuration files. +#' @seealso [validate_entrata_config()] - a function that validates the +#' Entrata configuration to ensure that all required fields are present +#' and valid. +#' +#' @importFrom cli cli_abort +#' @importFrom config get +#' @importFrom rlang arg_match +get_entrata_config <- function( + key = NULL, + file = Sys.getenv("R_CONFIG_FILE", "config.yml"), + config = Sys.getenv("R_CONFIG_ACTIVE", "default") +) { + + # normalize path to config file + file <- normalizePath(file, mustWork = FALSE) + + # ensure config file exists + if (!file.exists(file)) { + cli::cli_abort( + c( + "Provided configuration file: {.field {basename(file)}} not found ", + "under path: {.path {dirname(file)}}. Please ensure the file exists." + ) + ) + } + + # attempt to read the configuration file + cfg <- tryCatch({ + config::get( + value = "entrata", + file = file, + config = config + ) + }, error = function(e) { + cli::cli_abort( + c( + "Error reading configuration file {.field {basename(file)}}.", + "Ensure the file contains an {.code {entrata}} configuration block for ", + " the {.field {config}} configuration.", + "Error: {.error_message {e}}" + ) + ) + }) + + keys <- names(cfg) + + if (!is.null(key)) { + key <- rlang::arg_match(key, keys) + return(cfg[[key]]) + } + + return(cfg) + +} + +# validate ---------------------------------------------------------------- + +#' Validate Entrata Configuration +#' +#' @description +#' This function validates the Entrata configuration to ensure that all +#' required configuration values are present and that they are of the correct +#' type. +#' +#' If the configuration is invalid, an error will be thrown in the caller +#' function's caller environment. +#' +#' @details +#' The following validations are performed on the Entrata configuration: +#' +#' 1. The Entrata configuration must contain the following keys: +#' `username`, `password`, and `base_url`. +#' 2. All required keys must not be empty or `NULL`. +#' 3. The `base_url` key must be a valid `entrata.com` domain URL. +#' +#' To validate the credentials provided in the configuration use the +#' [entrata_status()] function which pings the API to check the status. +#' +#' @param cfg A list containing the Entrata configuration values or a character +#' string representing the path to the configuration file. +#' @inheritParams rlang::args_error_context +#' +#' @return Will throw an error if the configuration is invalid, otherwise +#' will invisibly return the validated `cfg`. +#' +#' @family Configuration +#' @family Validation +#' @family Entrata +#' +#' @seealso [get_entrata_config()] - a function that retrieves the Entrata +#' configuration from a configuration file. +#' +#' @export +#' +#' @importFrom rlang caller_env caller_arg +#' @importFrom cli cli_abort +#' @importFrom yaml read_yaml +#' @importFrom purrr pluck +validate_entrata_config <- function( + cfg, + arg = rlang::caller_arg(cfg), + call = rlang::caller_env() +) { + + # copy provided cfg + cfg_orig <- cfg + + # check if list or file path, and read if necessary + if (!is.list(cfg) && file.exists(cfg)) { + + # read whole yaml + cfg <- yaml::read_yaml(cfg) + + # ensure default key is present + if (!("default" %in% names(cfg))) { + + # throw error condition + cli::cli_abort( + c( + "Invalid Configuration Provided: {.arg {arg}}", + "Configuration is missing required {.field default} configuration." + ), + call = call + ) + + } + + # extract default config values + default_cfg <- purrr::pluck(cfg, "default") + + # ensure entrata key is present + if (!("entrata" %in% names(default_cfg))) { + cli::cli_abort( + c( + "Invalid Configuration Provided: {.arg {arg}}", + "Configuration is missing required {.field entrata} field." + ), + call = call + ) + } + + # replace cfg with entrata values from the file used + cfg <- default_cfg$entrata + } + + # if cfg has default, go one level deeper + if ("default" %in% names(cfg)) { + cfg <- purrr::pluck(cfg, "default") + } + + # if cfg has entrata, go one level deeper + if ("entrata" %in% names(cfg)) { + cfg <- purrr::pluck(cfg, "entrata") + } + + # validations ------------------------------------------------------------- + + # validate list + if (!is.list(cfg)) { + cli::cli_abort( + c( + "Invalid Configuration Provided: {.arg {arg}}. ", + "Configuration must be a list." + ), + call = call + ) + } + + # validate required fields + req_fields <- c("username", "password", "base_url") + cfg_fields <- names(cfg) + missing_fields <- req_fields[!req_fields %in% cfg_fields] + num_missing_fields <- length(missing_fields) + + if (num_missing_fields > 0) { + # error message + msg <- c( + "Invalid Configuration Provided: {.arg {arg}}. ", + "Provided configuration is missing required ", + if (num_missing_fields == 1) { + paste0("{.field ", missing_fields, "}") + } else { + paste0("fields: ", paste0("{.field ", missing_fields, "}", collapse = ", ")) + } + ) + + # throw error + cli::cli_abort(msg, call = call) + } + + # return original cfg invisibly + invisible(cfg_orig) + +} + diff --git a/R/mod_dashboard_cards.R b/R/entrata_api.R similarity index 100% rename from R/mod_dashboard_cards.R rename to R/entrata_api.R diff --git a/R/entrata_arcodes.R b/R/entrata_arcodes.R new file mode 100644 index 0000000..cb34b96 --- /dev/null +++ b/R/entrata_arcodes.R @@ -0,0 +1,114 @@ +entrata_req_arcodes <- function(property_id = NULL, request_id = NULL, ...) { + + # property_id (is provided) can only be a single integer value for /arcodes + if (!is.null(property_id)) { + property_id <- as.integer(property_id) + if (length(property_id) != 1) { + cli::cli_abort("{.arg property_id} must be a single integer value.") + } + } + + # body params ------------------------------------------------------------- + method_params <- list( + propertyId = property_id + ) |> + purrr::compact() + + # build request ----------------------------------------------------------- + req <- entrata_request() |> + entrata_req_endpoint("arcodes") |> + entrata_req_method("getArCodes") |> + entrata_req_method_params(method_params) |> + entrata_req_id(request_id) + + # perform request into response ------------------------------------------- + resp <- entrata_req_perform(req, ...) + + # parse response ---------------------------------------------------------- + entrata_resp_parse_arcodes(resp) + +} + +entrata_resp_parse_arcodes <- function(resp) { + + check_response(resp) + + resp_body <- httr2::resp_body_json(resp) + arcodes <- purrr::pluck(resp_body, "response", "result", "arcodes", "arcode") + + purrr::map_dfr( + arcodes, + .parse_arcode_to_tibble + ) + +} + +entrata_req_validate_arcodes <- function(req) { + + check_request(req) + + schema <- get_request_schema("arcodes", "getArCodes") + + validation <- jsonvalidate::json_validate( + json = httr2::req_body_json(req), + schema = schema, + engine = "ajv", + verbose = TRUE, + greedy = TRUE, + error = FALSE + ) + + if (!validation) { + cli::cli_abort("Request validation failed.") + } + + return(invisible(req)) + +} + +entrata_resp_validate_arcodes <- function(resp) { + + check_response(resp) + + resp_body <- httr2::resp_body_json(resp) |> + jsonlite::toJSON(auto_unbox = TRUE) + + schema <- get_response_schema("arcodes", "getArCodes") + + validation <- jsonvalidate::json_validate( + json = resp_body, + schema = schema, + engine = "ajv", + verbose = TRUE, + greedy = TRUE, + error = FALSE + ) + + if (!validation) { + cli::cli_abort("Response validation failed.") + } + + return(invisible(resp)) + +} + + + +.parse_arcode_to_tibble <- function(arcode) { + arcode |> + tibble::as_tibble() |> + dplyr::select( + id, + code, + name, + code_type = codeType, + charge_usage = chargeUsage, + associated_ledger = associatedLedger, + debit_gl_account_id = debitGlAccountId, + credit_gl_account_id = creditGlAccountId, + display_as = displayAs, + is_disabled = isDisabled, + is_entrata_disabled = isEntrataDisabled, + is_taxable = isTaxable + ) +} diff --git a/R/entrata_pipeline.R b/R/entrata_pipeline.R new file mode 100644 index 0000000..2ae31c7 --- /dev/null +++ b/R/entrata_pipeline.R @@ -0,0 +1,33 @@ + +# ------------------------------------------------------------------------ +# +# Title : Entrata API Data Pipeline +# By : Jimmy Briggs +# Date : 2024-11-12 +# +# ------------------------------------------------------------------------ + + +# investment partner/portfolio mapping ------------------------------------ + +# investment_partners_mapping <- readr::read_csv("data-raw/investment_partners.csv") + +map_property_to_investment_partner <- function(property_name) { + investment_partners_mapping |> + dplyr::filter(.data$property_name == .env$property_name) |> + dplyr::pull(.data$investment_partner) +} + + +# manual bed counts ------------------------------------------------------- + +# model_beds_tbl <- investment_partners_mapping |> +# dplyr::mutate(model_beds = 0) |> +# dplyr::arrange(.data$property_name) +# +# model_beds_tbl$model_beds[1] <- 4 + +# get main summary table -------------------------------------------------- + +# pre_lease_summary_data <- entrata_pre_lease_report() + diff --git a/R/entrata_pre_lease_report.R b/R/entrata_pre_lease_report.R new file mode 100644 index 0000000..db905a4 --- /dev/null +++ b/R/entrata_pre_lease_report.R @@ -0,0 +1,17 @@ + +# ------------------------------------------------------------------------ +# +# Title : Pre-Lease Report +# By : Jimmy Briggs +# Date : 2024-11-12 +# +# ------------------------------------------------------------------------ + + +# global report_version --------------------------------------------------- +pre_lease_report_version <- "3.2" + + + +# utilities --------------------------------------------------------------- + diff --git a/R/entrata_reports.R b/R/entrata_reports.R new file mode 100644 index 0000000..6beebf1 --- /dev/null +++ b/R/entrata_reports.R @@ -0,0 +1,205 @@ +# report version ---------------------------------------------------------- + +#' Get Latest Report Version from Entrata +#' +#' @description +#' This function retrieves the latest version of a specified report from Entrata. +#' It's useful when you need to ensure you're working with the most up-to-date +#' version of a particular report. +#' +#' @param report_name A character string representing the name of the report. +#' +#' @return A character string representing the latest version of the report. +#' +#' @export +#' +#' @examples +#' \dontrun{ +#' # Get the latest version of the "pre_lease" report +#' latest_version <- get_latest_report_version("pre_lease") +#' print(latest_version) +#' } +#' +#' @seealso +#' \code{\link{get_entrata_reports_list}} for getting a list of all available reports +#' \code{\link{get_entrata_report_info}} for getting detailed information about a specific report +#' +#' @importFrom dplyr filter pull +#' @importFrom rlang .data .env +get_latest_report_version <- function(report_name) { + + validate_entrata_report_name(report_name) + + latest_report_version <- get_entrata_reports_list(latest_only = TRUE) |> + dplyr::filter( + .data$report_name == {{ report_name }} + ) |> + dplyr::pull("report_version") + + return(latest_report_version) + +} + +# reports list ------------------------------------------------------------ + +#' Get Entrata Reports List +#' +#' @description +#' This function retrieves a list of reports available in the +#' Entrata system, optionally filtering to only the latest version of each report. +#' +#' @param latest_only Logical, if TRUE (default), returns only the latest version +#' of each report. +#' +#' @return A tibble containing report information including report name, ID, +#' system name, and version. +#' +#' @export +#' +#' @importFrom dplyr filter left_join select +#' @importFrom tibblify tspec_df tib_int tib_chr tib_row tib_df tib_lgl +#' @importFrom purrr pluck set_names list_rbind +#' @importFrom httr2 req_perform resp_body_json +#' @importFrom rlang .data .env +get_entrata_reports_list <- function(latest_only = TRUE) { + req <- entrata(endpoint = "reports", method = "getReportList") + res <- httr2::req_perform(req) + res_content <- res |> + httr2::resp_body_json() + + reports_specs <- list( + "getReportList" = list( + main = tibblify::tspec_df( + tibblify::tib_int("id"), + tibblify::tib_chr("reportName"), + tibblify::tib_chr("systemName"), + tibblify::tib_row( + "reportVersions", + tibblify::tib_df( + "reportVersion", + tibblify::tib_chr("version"), + tibblify::tib_lgl("isLatest"), + tibblify::tib_chr("titleAddendum", required = FALSE), + tibblify::tib_chr("expiryDate", required = FALSE), + ) + ) + ), + versions = tibblify::tspec_row( + tibblify::tib_chr("version"), + tibblify::tib_lgl("isLatest"), + tibblify::tib_chr("titleAddendum", required = FALSE), + tibblify::tib_chr("expiryDate", required = FALSE) + ) + ) + ) + + res_data <- res_content |> + purrr::pluck("response", "result", "reports", "report") |> + tibblify::tibblify(reports_specs$getReportList$main) + + report_names <- res_data$reportName + + res_data_report_versions <- purrr::pluck( + res_data, + "reportVersions", + "reportVersion" + ) |> + rlang::set_names(report_names) |> + purrr::list_rbind(names_to = "report_name") + + res_data_merged <- dplyr::select( + res_data, + "report_id" = "id", + "report_name" = "reportName", + "system_name" = "systemName", + -c("reportVersions") + ) |> + dplyr::left_join( + res_data_report_versions, + by = "report_name" + ) |> + dplyr::select( + "report_id", + "report_name", + "system_name", + "report_version" = "version", + "is_latest" = "isLatest", + -c("titleAddendum", "expiryDate") + ) + + if (!latest_only) { + return(res_data_merged) + } + + res_data_merged |> + dplyr::filter( + .data$is_latest == TRUE + ) |> + dplyr::select( + -c("is_latest") + ) +} + +# report info ------------------------------------------------------------- + +#' Get Entrata Report Info +#' +#' @description +#' This function retrieves detailed information for a specified +#' report from Entrata, including filters and descriptions. +#' +#' @param report_name A character string representing the name of the report. +#' @param report_version A character string representing the version of the report. +#' Defaults to "latest". +#' +#' @return A list containing report name, description, and filters. +#' +#' @export +#' +#' @importFrom dplyr filter pull +#' @importFrom rlang .data .env +#' @importFrom purrr pluck map list_rbind +#' @importFrom httr2 req_perform resp_body_json +get_entrata_report_info <- function(report_name, report_version = "latest") { + + validate_entrata_report_name(report_name) + + if (report_version == "latest") { + latest_report_version <- mem_get_entrata_reports_list(latest_only = TRUE) |> + dplyr::filter( + "report_name" == {{ report_name }} + ) |> + dplyr::pull("report_version") + } + + req <- entrata( + endpoint = "reports", + method = "getReportInfo", + method_params = list( + reportName = report_name, + reportVersion = latest_report_version + ) + ) + + res <- httr2::req_perform(req) + + res_content <- res |> + httr2::resp_body_json() |> + purrr::pluck("response", "result", "reports", "report", 1) + + res_report_name <- res_content |> purrr::pluck("name") + res_report_description <- res_content |> purrr::pluck("description") + res_report_filters <- res_content |> + purrr::pluck("filters", "filter") |> + purrr::map(tibble::as_tibble) |> + purrr::list_rbind() + + res_report_info <- list( + report_name = res_report_name, + report_description = res_report_description, + report_filters = res_report_filters + ) + + return(res_report_info) + +} diff --git a/R/entrata_req_body.R b/R/entrata_req_body.R index e69de29..caa72b6 100644 --- a/R/entrata_req_body.R +++ b/R/entrata_req_body.R @@ -0,0 +1,22 @@ + +# ------------------------------------------------------------------------ +# +# Title : Endpoint Request Body +# By : Jimmy Briggs +# Date : 2024-11-10 +# +# ------------------------------------------------------------------------ + +entrata_req_body <- function( + req, + request_id = 15, + method_name = NULL, + method_version = NULL, + method_params = NULL +) { + + check_request(req) + + + +} diff --git a/R/entrata_request.R b/R/entrata_request.R index 6349a21..b364178 100644 --- a/R/entrata_request.R +++ b/R/entrata_request.R @@ -27,7 +27,7 @@ #' send the HTTP request to. Must be one of the valid [entrata_endpoints()]. #' If left `NULL` will default to the base Entrata API URL: #' `https://gmhcommunities.entrata.com/api/v1/`. -#' @param method Character string specifying the **Entrata** endpoint method +#' @param method_name Character string specifying the **Entrata** endpoint method #' (not the HTTP method) to use for the request. Must be one of the valid #' [entrata_methods()] for the provided `endpoint` value. If left `NULL`, #' a default method will be determined based on the `endpoint` value. @@ -38,11 +38,260 @@ #' values (typically default version is `"r1"`). #' @param method_params List of parameters to include in the request body's #' "method" object. This is where the actual API method parameters are +#' specified. The parameters must be in the correct format for the method +#' being called. If left `NULL`, the method will be called with no parameters. +#' @param request_id An integer or string to use for the request ID. +#' By default this will first check the global option +#' `entrata.default_request_id` and then fall back to `15L`. +#' @param config A list of configuration options for the Entrata API. +#' This should include the base URL, username, and password and +#' can also include the user agent, default request ID, retry logic, +#' rate limit handling, error handling, caching options, logging options, +#' and more. +#' @param ... Additional arguments to pass to the request object. #' +#' @return An httr2 request object with the Entrata API request configuration. #' +#' @export #' +#' @importFrom httr2 request req_method req_auth_basic req_headers req_user_agent req_body_json +#' @importFrom config get +#' @importFrom cli cli_alert_danger #' +#' +#' +#' + + +entrata_request <- function( + endpoint, + body_method = list( + name = NULL, + version = NULL, + params = list(NULL) + ), + options = list( + request_id = getOption("entrata.default_request_id", 15L), + user_agent = getOption("entrata.user_agent", "entrata-r/0.1.0"), + verbosity = getOption("entrata.verbosity", "info"), + debug = getOption("entrata.debug", FALSE), + log = getOption("entrata.log", NULL), + retry = getOption("entrata.retry", 3L), + timeout = getOption("entrata.timeout", 30L), + progress = getOption("entrata.progress", FALSE), + cache = getOption("entrata.cache", FALSE), + cache_path = getOption("entrata.cache_path", ":memory:") + ), + config = get_entrata_config(), + ... +) { + + # ensure config + + + base_url <- config$base_url + user_agent <- config$user_agent + username <- config$username + password <- config$password + + req <- httr2::request(base_url) |> + httr2::req_method("POST") |> + httr2::req_auth_basic( + username = username, + password = password + ) |> + httr2::req_headers( + `Content-Type` = "application/json; charset=utf-8", + `Accept` = "application/json", + ) |> + httr2::req_user_agent(user_agent) |> + httr2::req_body_json( + list( + auth = list( + type = "bsic" + ), + requestId = request_id, + method = list( + name = method_name, + version = method_version, + params = method_params + ) + ) + ) + + return(req) + + +} + + +# request modifiers ------------------------------------------------------- + +#' Entrata Request Modifiers +#' +#' @name entrata_request_modifiers +#' +#' @description +#' These functions are used to modify the Entrata request object before +#' sending the request to the API. These functions are used to set the +#' endpoint path, Entrata internal endpoint method (name, version, and params), +#' additional headers, authentication, request body, error handling, logging, +#' and more. +NULL + +#' Set Basic Authentication for Entrata Request +#' +#' @description +#' Adds basic authentication (username and password) to the Entrata request. +#' +#' @param req An httr2 request object +#' @param username Username for authentication +#' @param password Password for authentication +#' +#' @return The modified request object with authentication headers. +#' +#' @export +#' +#' @importFrom httr2 req_auth_basic +entrata_req_auth <- function(req, username = NULL, password = NULL) { + + check_request(req) + + username <- username %||% getOption("entrata.username") %||% + Sys.getenv("ENTRATA_USERNAME") %||% config::get("entrata")$username + + password <- password %||% getOption("entrata.password") %||% + Sys.getenv("ENTRATA_PASSWORD") %||% config::get("entrata")$password + + req |> httr2::req_auth_basic(username, password) +} + +#' Set Request Body for Entrata API Request +#' +#' @description +#' Configures the request body with specific values for the request. +#' +#' @param req An httr2 request object +#' @param id Request ID +#' @param method The endpoint method name +#' @param version The endpoint method version +#' @param params List of parameters for the method +#' +#' @return Modified request object with the configured body +#' +#' @export +entrata_req_body <- function(req, id = NULL, method = NULL, version = "r1", params = list()) { + + check_request(req) + req_body <- list( + auth = list( + type = "basic" + ), + requestId = id %||% getOption("entrata.default_request_id", 15L), + method = list( + name = method, + version = version, + params = params + ) + ) |> + purrr::compact() + + req |> + httr2::req_body_json(req_body) + +} + +#' Set Endpoint Path for Entrata Request +#' +#' @description +#' Appends an endpoint path to the request URL. +#' +#' @param req An httr2 request object +#' @param endpoint The API endpoint to set +#' +#' @return Modified request object with the endpoint URL path appended +#' +#' @export +#' +#' @importFrom httr2 req_url_path_append +entrata_req_endpoint <- function(req, endpoint) { + + check_request(req) + + pre_endpoint <- req_get_endpoint(req) + + if (is.null(pre_endpoint) || pre_endpoint == "") { + out <- req |> + httr2::req_url_path_append(endpoint) + } else { + out <- req + } + + return(out) + +} + +#' Set Error Handling for Entrata Request +#' +#' @description Configures error handling for the request, using custom error functions. +#' @param req An httr2 request object +#' @param is_error Function to check if response contains an error +#' @param error_body Function to parse error body in case of an error +#' @return Modified request with error handling +#' @export +#' @importFrom httr2 req_error +entrata_req_error <- function(req, is_error = entrata_resp_is_error, error_body = entrata_resp_body) { + req |> httr2::req_error(is_error = is_error, body = error_body) +} + +#' Log Entrata Request Details +#' +#' @description Logs request information according to the configured logger. +#' @param req An httr2 request object +#' @param logger Optional logger to use +#' @return The original request object +#' @export +#' @importFrom logger log_info +entrata_req_log <- function(req, logger = entrata_req_logger) { + log_info(logger, "Request ID: {req$body$requestId}") + log_info(logger, "Endpoint: {req$url}") + log_info(logger, "Method: {req$method}") + invisible(req) +} + +#' Perform Entrata API Request +#' +#' @description Executes a prepared Entrata request with custom options. +#' @param req An httr2 request object +#' @param cache Logical indicating if response should be cached +#' @param cache_path Path to cache the request +#' @param save Logical indicating if request should be saved +#' @param save_path Path to save request data +#' @param verbosity Verbosity level of output +#' @param debug Logical for debugging request +#' @param logger Logger object +#' @param mock Mock request response if needed +#' @param error_call Call environment for error reporting +#' @param ... Additional arguments passed to req_perform +#' @return The response object +#' @export +#' @importFrom httr2 req_perform req_dry_run +entrata_req_perform <- function( + req, cache = FALSE, cache_path = ":memory:", save = FALSE, save_path = NULL, + verbosity = NULL, debug = FALSE, logger = NULL, mock = NULL, + error_call = rlang::caller_env(), ... +) { + # Caching, saving, and debugging logic + if (debug) req <- httr2::req_dry_run(req) + + response <- httr2::req_perform(req, ...) + + # Additional post-processing, like logging and error handling, can be added here + entrata_req_log(req, logger = logger) + + response +} # perform ----------------------------------------------------------------- @@ -80,3 +329,11 @@ entrata_req_perform <- function( return(resp) } + + + +req_get_endpoint <- function(req) { + check_request(req) + req_url <- purrr::pluck(req, "url") + gsub(paste0("^", "https://gmhcommunities.entrata.com/api/v1/"), "", req_url) +} diff --git a/R/entrata_response.R b/R/entrata_response.R new file mode 100644 index 0000000..d8a13ee --- /dev/null +++ b/R/entrata_response.R @@ -0,0 +1,252 @@ + +# ------------------------------------------------------------------------ +# +# Title : Entrata Response +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + + +# entrata_response -------------------------------------------------------- + + +# entrata_resp_body_json -------------------------------------------------- + +#' Entrata Response Body JSON +#' +#' @description +#' This function extracts the JSON response body from an Entrata API response. +#' +#' @details +#' This function is used to extract the JSON response body from an Entrata API +#' response object. The function will check the response object for the expected +#' structure and return the response body as a list containing the request ID, +#' status code, and result object. +#' +#' @param resp The Entrata API response object. Must be a valid HTTP response. +#' +#' @return A list containing the request ID, status code, and result object. +#' +#' @export +#' +#' @importFrom httr2 resp_body_json +#' @importFrom purrr pluck_exists pluck +#' @importFrom cli cli_alert_danger +entrata_resp_body_json <- function(resp) { + + check_response(resp) + httr2::resp_check_status(resp) + httr2::resp_check_content_type(resp) + + if (!httr2::resp_check_content_type()) + + resp_body <- httr2::resp_body_json(resp) + + if (!purrr::pluck_exists(resp_body, "response")) { + cli::cli_alert_danger( + c( + "The Entrata API response does not contain the expected 'response' object.", + "The response body may be malformed or incomplete." + ) + ) + return(resp) + } + + # parse request id, status code and body response/result + resp_req_id <- purrr::pluck(resp_body, "response", "requestId") + resp_status <- purrr::pluck(resp_body, "response", "code") + resp_result <- purrr::pluck(resp_body, "response", "result") + + # return response body JSON + return(list( + request_id = resp_req_id, + status = resp_status, + result = resp_result + )) + +} + +# entrata_resp_is_error --------------------------------------------------- + +entrata_resp_is_error <- function(resp) { + + check_response(resp) + + resp_body <- httr2::resp_body_json(resp) + + if (purrr::pluck_exists(resp_body, "response", "error")) { + return(TRUE) + } + + return(FALSE) + +} + + +# entrata_resp_body_error ------------------------------------------------- + +entrata_resp_body_error <- function(resp, ...) { + + check_response(resp) + + if (!entrata_resp_is_error(resp)) { + cli::cli_alert_info( + c( + "The Entrata API response does not contain an error object." + ) + ) + return(NULL) + } + + resp_body <- httr2::resp_body_json(resp) + err <- purrr::pluck(resp_body, "response", "error") + err_code <- purrr::pluck(err, "code") + err_msg <- purrr::pluck(err, "message") + + cli::cli_bullets( + c( + "i" = "HTTP Error Status Code: {err_code}", + "i" = "HTTP Error Message: {err_msg}" + ) + ) + + return(err) + +} + +# entrata_resp_status ----------------------------------------------------- + +#' Entrata API Response Status Helpers +#' +#' @description +#' Helper functions for working with the Entrata API response status codes, +#' descriptions, and errors. +#' +#' - `entrata_resp_status()` retrieves the integer `HTTP` status code from an +#' Entrata API response. +#' - `entrata_resp_status_desc()` retrieves a brief textual description of the +#' `HTTP` status code from an Entrata API response. +#' - `entrata_resp_is_error()` determines if the response is an error, i.e. +#' it returns `TRUE` if the status code is greater than or equal to `400`. +#' - `entrata_resp_check_status()` checks the status of an Entrata API response +#' by turning HTTP/Entrata specific errors into R errors. +#' - `entrata_resp_abort()` aborts the response if the status is an error. +#' +#' Note that these functions are mostly for internal use but are exported +#' for clarity and consistency. +#' +#' @details +#' These functions are used to help with the processing of Entrata API +#' responses. +#' +#' The Entrata API is unique in that all endpoints utilize `POST` `HTTP` methods +#' and the API will always return a `200` status code, regardless of the success +#' or failure of the request. +#' +#' This makes the usage of the default `httr2` functions like [httr2::resp_check_status()] +#' or [httr2::resp_is_error()] useless as they rely on the `HTTP` status code to +#' determine if a request was successful or not. +#' +#' To mitigate this, we must inspect the response body to determine if the request +#' was successful or not. If the response body contains an error message, we can +#' assume that the request was not successful. +#' +#' @section Functions: +#' +#' - `entrata_resp_status()` - Extract the status code from an Entrata API response. +#' - `entrata_resp_status_desc()` - Extract the status description from an Entrata API response. +#' - `entrata_resp_is_error()` - Determine if the response is an error. +#' - `entrata_resp_check_status()` - Check the status of an Entrata API response. +#' - `entrata_resp_abort()` - Abort the requested response using the response object. +#' +#' @seealso [httr2::resp_status()] +#' +#' @param resp [httr2::response()] object +#' @param info Additional information to include in the error message. +#' @param error_call The calling environment for the error. Defaults to the +#' caller environment. +#' @inheritParams httr2::resp_status +#' @inheritParams rlang::args_error_context +#' +#' @return +#' - `entrata_resp_status()` - The status code of the response. +#' - `entrata_resp_status_desc()` - The status description of the response. +#' - `entrata_resp_is_error()` - Logical value indicating whether the response is an error. +#' - `entrata_resp_check_status()` - Invisibly returns the response if the status is not an error. +#' - `entrata_resp_abort()` - Aborts the response if the status is an error. +#' +#' @export +#' +#' @importFrom httr2 resp_body_json +#' @importFrom purrr pluck_exists pluck +entrata_resp_status <- function(resp) { + + resp_body <- httr2::resp_body_json(resp) + + if (purrr::pluck_exists(resp_body, "response", "error")) { + status_code <- purrr::pluck(resp_body, "response", "error", "code") |> + as.integer() + } else { + status_code <- purrr::pluck(resp_body, "response", "code") |> + as.integer() + } + + status_code + +} + +#' @rdname entrata_resp_status +#' @export +entrata_resp_status_desc <- function(resp) { + + status <- entrata_resp_status(resp) + + if (status %in% http_statuses) { + http_statuses[[as.character(status)]] + } else { + NA_character_ + } + +} + +#' @rdname entrata_resp_status +#' @export +#' @importFrom rlang caller_env +#' @importFrom glue glue +entrata_resp_abort <- function(resp, req, info = NULL, call = rlang::caller_env()) { + + status <- entrata_resp_status(resp) + desc <- entrata_resp_status_desc(resp) + message <- glue::glue("HTTP {status} {desc}.") + + rlang::abort( + c(message, info), + status = status, + resp = resp, + class = c( + glue::glue("entrata_http_{status}"), + glue::glue("httr2_http_{status}"), + "httr2_http", + "httr2_error" + ), + request = req, + call = call + ) + +} + +#' @rdname entrata_resp_status +#' @export +entrata_resp_check_status <- function(resp, info = NULL, error_call = rlang::caller_env()) { + + if (!entrata_resp_is_error(resp)) { + invisible(resp) + } else { + entrata_resp_abort(resp, httr2:::req_info(resp), info, error_call) + } +} + +# entrata_resp_is_transient ----------------------------------------------- + + diff --git a/R/entrata_weekly_report.R b/R/entrata_weekly_report.R new file mode 100644 index 0000000..c0da9fd --- /dev/null +++ b/R/entrata_weekly_report.R @@ -0,0 +1,257 @@ +get_weekly_period_start_date = function(end_date = lubridate::today()) { + hold <- lubridate::today() - lubridate::days(7) + out <- format(hold, "%m/%d/%Y") |> as.character() + out +} + +entrata_reports_pre_lease_weekly <- function( + config = config::get()$entrata, + req_id_reports = 15, + req_id_queue = 15, + report_name = "lease_execution_(applicant)", + report_version = "1.8", + property_ids = NULL, + ... +) { + + property_group_ids <- property_ids + + if (is.null(property_group_ids)) { + property_group_ids <- c( + "1161867", + "641240", + "739084", + "1197886", + "1143679", + "739079", + "518044", + "676055", + "952515", + "518041", + "518046", + "1197887", + "1132027", + "577897", + "1161871", + "739085", + "518042", + "833617", + "1311849", + "739080", + "739076", + "1115679" + ) + } + + default_req_body <- list( + auth = list(type = "basic"), + requestId = 15, + method = list( + name = "getReportData", + version = "r3", + params = list( + reportName = "lease_execution_(applicant)", + reportVersion = "1.8", # get_latest_report_version("lease_execution_(applicant)"), + filters = list( + property_group_ids = property_group_ids, + period = list( + daterange = list( + "daterange-start" = as.Date(get_weekly_period_start_date(), format = "%m/%d/%Y"), + "daterange-end" = as.Date(format(lubridate::today(), "%m/%d/%Y"), format = '%m/%d/%Y') + ), + "period_type" = "daterange" + ), + results_based_on = "activity", + lease_type = c("1", "3"), + summarize_by = "lease_type", + group_by = "property", + consolidate_by = "no_consolidation", + arrange_by_property = "0", + subtotals = "0" + ) + ) + ) + ) + + req <- httr2::request(paste0(config$base_url)) |> + httr2::req_auth_basic(config$username, config$password) |> + httr2::req_body_json(default_req_body) |> + httr2::req_headers("Content-Type" = "application/json") |> + httr2::req_method("POST") |> + httr2::req_url_path_append("reports") + + req + + resp <- httr2::req_perform(req) + + queue_id <- httr2::resp_body_json(resp) |> + purrr::pluck("response", "result", "queueId") + + cli::cli_alert_info( + c( + "The report data has been successfully queued for processing.", + "The queue ID is: {.field {queue_id}}" + ) + ) + + req_body_queue <- list( + auth = list(type = "basic"), + requestId = 15, + method = list( + name = "getResponse", + version = "r1", + params = list(queueId = queue_id, serviceName = "getReportData") + ) + ) + + req_queue <- httr2::request(config$base_url) |> + httr2::req_auth_basic(config$username, config$password) |> + httr2::req_body_json(req_body_queue) |> + httr2::req_headers("Content-Type" = "application/json") |> + httr2::req_method("POST") |> + httr2::req_url_path_append("queue") |> + httr2::req_retry( + max_tries = 10, + backoff = ~ lubridate::seconds(2 ^ (.x - 1)), + is_transient = \(resp) { + !is.null(httr2::resp_body_json(resp)$response$error) + } + ) + + req_queue + + resp_queue <- httr2::req_perform(req_queue) + + resp_data_queue <- httr2::resp_body_json(resp_queue) |> + purrr::pluck("response", "result", "reportData") + + resp_data_queue_parsed <- resp_data_queue |> + jsonlite::toJSON(auto_unbox = TRUE, pretty = TRUE) |> + jsonlite::fromJSON(flatten = TRUE) |> + tibble::as_tibble() |> + dplyr::select("property_name", "lease_type", "signed") |> + tidyr::pivot_wider(names_from = lease_type, values_from = signed) |> + dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(., 0))) |> + dplyr::rename(new_leases = `New Lease`, new_renewals = Renewal) |> + dplyr::mutate(new_total = new_leases + new_renewals) + + return(resp_data_queue_parsed) + +} + + # results_based_on <- c("activity", "moved_in", "current_status")[[1]] + # period <- list( + # daterange = list(`daterange-start` = "m/d/Y", `daterange-end` = "m/d/Y"), + # date = "m/d/Y", + # # "today,yesterday,currentwk,lastwk,currentcm,priorcm,currentcq,priorcq,currentcyr,priorcyr,daterange,date" + # period_type = c( + # "today", + # "yesterday", + # "currentwk", + # "lastwk", + # "currentcm", + # "priorcm", + # "currentcq", + # "priorcq", + # "currentcyr", + # "priorcyr", + # "daterange", + # "date" + # ) + # ) + # + # # not being used by pat? + # applicant <- c(1, 4, 2) + # + # # pat uses c('1', '3')? + # lease_type <- c(1, 3, 5) + # + # # pat using 'lease_type'? + # summarize_by <- c("property", "lease_type", "do_not_summarize") + # + # # pat using 'property'? + # group_by <- c("property", "lease_type", "building_units", "do_not_group") + # + # # pat not using? + # lease_terms <- list(dependencies = c("property_group_ids", "lease_occupancy_types")) + # + # consolidate_by <- c( + # "no_consolidation", + # "consolidate_all_properties", + # "consolidate_by_property_groups" + # ) + # arrange_by_property <- c("0", "1") + # subtotals <- c("0", "1") + + # { + # "response": { + # "requestId": "15", + # "code": 200, + # "result": { + # "reports": { + # "report": [ + # { + # "name": "lease_execution_(applicant)", + # "description": "The purpose of the Lease Execution (Applicant) report is to be able to track lease signatures based on applicant types.", + # "filters": { + # "lease_occupancy_types": [], + # "property_group_ids": [ + # 1161867, + # 641240, + # 739084, + # 1197886, + # 1143679, + # 739079, + # 518044, + # 676055, + # 952515, + # 518041, + # 518046, + # 1197887, + # 1132027, + # 577897, + # 1161871, + # 739085, + # 518042, + # 833617, + # 1311849, + # 739080, + # 739076, + # 1115679 + # ], + # "results_based_on": "activity,moved_in,current_status", + # "period": { + # "daterange": { + # "daterange-start": "m/d/Y", + # "daterange-end": "m/d/Y" + # }, + # "date": "m/d/Y", + # "period_type": "today,yesterday,currentwk,lastwk,currentcm,priorcm,currentcq,priorcq,currentcyr,priorcyr,daterange,date" + # }, + # "applicant": [ + # 1, + # 4, + # 2 + # ], + # "lease_type": [ + # 1, + # 3, + # 5 + # ], + # "summarize_by": "property,lease_type,do_not_summarize", + # "group_by": "property,lease_type,building_units,do_not_group", + # "lease_terms": { + # "dependencies": "property_group_ids,lease_occupancy_types" + # }, + # "consolidate_by": "no_consolidation,consolidate_all_properties,consolidate_by_property_groups", + # "arrange_by_property": "0,1", + # "subtotals": "0,1" + # } + # } + # ] + # } + # } + # } + # } + + diff --git a/R/inputs.R b/R/inputs.R index 7ed11dd..e1ee8c7 100644 --- a/R/inputs.R +++ b/R/inputs.R @@ -10,33 +10,48 @@ # properties -------------------------------------------------------------- -input_gmh_properties <- function( +# input_gmh_properties <- function( +# id, +# label = "Select Property:", +# choices = metadata$app_choices$properties, +# selected = metadata$app_choices$properties, +# multiple = TRUE, +# options = metadata$app_defaults$picker_options, +# width = "auto", +# +# shinyWidgets::pickerInput( +# ns("properties"), +# label = icon_text("building", "Select Properties"), +# choices = .app_choices$properties, +# multiple = TRUE, +# options = +# ) +# +# } + + +# reports ----------------------------------------------------------------- + +input_gmh_reports <- function( id, - label = "Select Property:", - choices = metadata$app_choices$properties, - selected = metadata$app_choices$properties, + label = "Select Report:", + choices = metadata$app_choices$reports, + selected = metadata$app_choices$reports, multiple = TRUE, options = metadata$app_defaults$picker_options, - width = "auto", - - + width = "auto" +) { shinyWidgets::pickerInput( inputId = id, - label = "Select " + label = label, + choices = choices, + selected = selected, + multiple = multiple, + options = options, + width = width ) - - shinyWidgets::pickerInput( - ns("properties"), - label = icon_text("building", "Select Properties"), - choices = .app_choices$properties, - multiple = TRUE, - options = - ) - } - - # password ---------------------------------------------------------------- diff --git a/R/mod_footer.R b/R/mod_footer.R index 117ea7a..4e81596 100644 --- a/R/mod_footer.R +++ b/R/mod_footer.R @@ -8,45 +8,7 @@ # ------------------------------------------------------------------------ -# internal ---------------------------------------------------------------- - -#' @keywords internal -#' @noRd -.app_info <- list( - name = "GMH Data Hub", - version = "1.0", - logo = "www/img/logos/app-logo.svg", - symbol = "www/img/icons/app-icon.webp", - repo_url = "https://github.com/noclocks/gmhdatahub", - docs_url = "https://docs.noclocks.dev/gmhdatahub" -) - -#' @keywords internal -#' @noRd -.client_info <- list( - name = "GMH Communities", - url = "https://gmhcommunities.com", - logo = "www/img/logos/gmh-logo.svg", - symbol = "www/img/icons/gmh-icon.png" -) - -#' @keywords internal -#' @noRd -.developer_info <- list( - name = "No Clocks, LLC", - url = "https://noclocks.dev", - logo = "www/img/logos/noclocks-logo.svg", - symbol = "www/img/icons/noclocks-icon-circular.png" -) - -#' @keywords internal -#' @noRd -.entrata_info <- list( - name = "Entrata", - url = "https://gmhcommunities.entrata.com/api/v1/documentation", - logo = "www/img/logos/entrata-logo.png", - symbol = NULL -) + # topic ------------------------------------------------------------------- @@ -55,7 +17,7 @@ #' @name mod_footer #' #' @description -#' A Shiny module for creating the footer of the GMH Leasing Dashboard. +#' A Shiny module for creating the footer of the GMH Data Hub's Leasing Dashboard. #' #' Composed of the `ui`, `server`, and helper functions: #' @@ -134,9 +96,9 @@ mod_footer_ui <- function( id = NULL, align = "center", class = "footer", - app_info = .app_info, - client_info = .client_info, - developer_info = .developer_info, + app_info = gmhdatahub::app_info, + client_info = client_info, + developer_info = developer_info, copyright_holder = "No Clocks, LLC", year = format(Sys.Date(), "%Y"), ... diff --git a/R/mod_home.R b/R/mod_home.R new file mode 100644 index 0000000..e788c60 --- /dev/null +++ b/R/mod_home.R @@ -0,0 +1,157 @@ + +# ------------------------------------------------------------------------ +# +# Title : Home (Page) Shiny Module +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + + +# topic ------------------------------------------------------------------- + +#' Home (Page) Shiny Module +#' +#' @name mod_home +#' +#' @description +#' A Shiny module for creating the home page tab of the GMH Data Hub's Leasing +#' Dashboard. +#' +#' This module includes the UI and Server functions: +#' - `mod_home_ui()` +#' - `mod_home_server()` +#' +#' @param id The module id. +#' +#' @return +#' - `mod_home_ui()`: The UI HTML wrapped in a [htmltools::tagList()]. +#' - `mod_home_server()`: A shiny server function. +NULL + +# UI ---------------------------------------------------------------------- + +#' @rdname mod_home +#' @export +#' @importFrom htmltools tags tagList +#' @importFrom bslib card card_body card_title layout_columns layout_column_wrap +#' @importFrom bslib value_box +#' @importFrom bsicons bs_icon +#' @importFrom shiny NS textOutput uiOutput +mod_home_ui <- function(id, ...) { + + ns <- shiny::NS(id) + + # value boxes ------------------------------------------------------------- + htmltools::tagList( + bslib::layout_column_wrap( + width = 1/3, + heights_equal = "all", + bslib::value_box( + id = ns("properties_value_box"), + title = "Properties", + value = shiny::textOutput(ns("properties_value_box"), inline = TRUE), + shiny::uiOutput(ns("properties_value_box_details")), + showcase = bsicons::bs_icon("building-check"), + showcase_layout = "left center", + full_screen = TRUE, + theme = "info", + height = NULL, + max_height = NULL, + min_height = NULL, + fill = TRUE, + class = NULL + ), + bslib::value_box( + id = ns("leases_value_box"), + title = "Leases", + value = shiny::textOutput(ns("leases_value_box"), inline = TRUE), + shiny::uiOutput(ns("leases_value_box_details")), + showcase = bsicons::bs_icon("file-earmark-text-fill"), + showcase_layout = "left center", + full_screen = TRUE, + theme = "success", + height = NULL, + max_height = NULL, + min_height = NULL, + fill = TRUE, + class = NULL + ), + bslib::value_box( + id = ns("rate_value_box"), + title = "Occupancy Rate", + value = shiny::textOutput(ns("rate_value_box"), inline = TRUE), + shiny::uiOutput(ns("rate_value_box_details")), + showcase = bsicons::bs_icon("house-check-fill"), + showcase_layout = "left center", + full_screen = TRUE, + theme = "primary", + height = NULL, + max_height = NULL, + min_height = NULL, + fill = TRUE, + class = NULL + ) + ), + bslib::layout_columns( + bslib::card( + bslib::card_header(bs_icon("graph-up"), "Key Metrics"), + bslib::card_body( + "This is where you would display additional metrics or charts." + ), + full_screen = TRUE + ), + bslib::card( + bslib::card_header(bs_icon("clock-history"), "Recent Activity"), + bslib::card_body( + "This section could show recent updates or activities." + ), + full_screen = TRUE + ) + ), + bslib::layout_columns( + bslib::card( + bslib::card_header(bs_icon("calendar2-check"), "Upcoming Events"), + bslib::card_body( + "This section could show upcoming events or important dates." + ), + full_screen = TRUE + ), + bslib::card( + bslib::card_header(bs_icon("chat-dots"), "Messages"), + bslib::card_body( + "This section could show recent messages or notifications." + ), + full_screen = TRUE + ) + ) + ) + +} + + +# Server ------------------------------------------------------------------ + +#' @rdname mod_home +#' @export +#' +mod_home_server <- function(id, filters, data, user) { + shiny::server <- function(input, output, session) { + + ns <- session$ns + + # reactive values ------------------------------------------------------- + properties <- shiny::reactive({ + shiny::req(input$properties) + shiny::req(input$leases) + shiny::req(input$rate) + + list( + properties = input$properties, + leases = input$leases, + rate = input$rate + ) + }) + + } +} diff --git a/R/mod_properties.R b/R/mod_properties.R new file mode 100644 index 0000000..a675fef --- /dev/null +++ b/R/mod_properties.R @@ -0,0 +1,52 @@ + +# ------------------------------------------------------------------------ +# +# Title : Properties Shiny Module +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + +# topic ------------------------------------------------------------------- + +#' Properties Shiny Module +#' +#' @name mod_properties +#' +#' @description +#' This is the shiny module for the properties page/tab in the shiny app. +#' +#' It includes the UI and server functions: +#' - `mod_properties_ui()` +#' - `mod_properties_server()` +#' +#' The module includes the following children modules for its major functional +#' areas: +#' - [mod_property_tbl] - For listing/displaying all properties. +#' - [mod_property_map] - For displaying a map of all properties. +#' - [mod_property_details] - For displaying the details of a single property. +#' +#' @param id The module id. +#' @param ... Additional parameters. +#' +#' @return +#' - `mod_properties_ui()`: Shiny UI. +#' - `mod_properties_server()`: Shiny Server. +NULL + +# UI ---------------------------------------------------------------------- + +#' @rdname mod_properties +#' @export +mod_properties_ui <- function(id, ...) { + + ns <- shiny::NS(id) + + shiny::tagList( + mod_title_ui(id), + mod_property_tbl_ui(ns("property_tbl")), + mod_property_map_ui(ns("property_map")), + mod_property_details_ui(ns("property_details")) + ) + +} diff --git a/R/mod_sidebar.R b/R/mod_sidebar.R index dadab38..48ebfdb 100644 --- a/R/mod_sidebar.R +++ b/R/mod_sidebar.R @@ -27,7 +27,7 @@ #' @return #' - `mod_sidebar_ui()`: A shiny UI function. #' - `mod_sidebar_server()`: A shiny server function. - +NULL # UI ---------------------------------------------------------------------- @@ -59,7 +59,7 @@ mod_sidebar_ui <- function(id, ...) { shinyWidgets::pickerInput( ns("properties"), label = icon_text("building", "Select Properties"), - choices = .app_choices$properties, + choices = app_choices$properties, multiple = TRUE, options = list( `actions-box` = TRUE, diff --git a/R/mod_summary.R b/R/mod_summary.R new file mode 100644 index 0000000..f35cea6 --- /dev/null +++ b/R/mod_summary.R @@ -0,0 +1,225 @@ +mod_summary_ui <- function(id) { + +} + +mod_summary_server <- function(id) { + shiny::moduleServer( + id, + function(input, output, session) { + + ns <- session$ns + + summary_data <- shiny::reactive({ + #empty_summary_table() + demo_summary_tbl() + }) + + output$summary_table <- DT::renderDT({ + shiny::req(summary_data()) + + dat <- split_summary_table(summary_data()) + + DT::datatable( + data = dat$tbl_1, + options = list( + dom = 't', # Hide pagination/search bar + paging = FALSE, # Display full table without pagination + ordering = FALSE, # Disable column sorting + scrollX = TRUE, # Enable horizontal scrolling + autoWidth = TRUE, # Adjust column widths + columnDefs = list( + list(targets = 0, visible = FALSE), # Hide `property_id` + list(className = "highlight", targets = "_all") # Apply highlight to all cells + ) + ), + rownames = FALSE + ) |> + # Custom cell formatting for specific columns + DT::formatStyle( + columns = c("prelease_percent", "prior_prelease_percent"), + backgroundColor = DT::styleInterval(90, c("lightcoral", "lightgreen")), + fontWeight = 'bold' + ) |> + DT::formatStyle( + columns = "yoy_variance_2", + color = DT::styleInterval(0, c("red", "green")), + fontWeight = 'bold' + ) + }) + }) +} + + +# utils ------------------------------------------------------------------- + +empty_summary_table <- function() { + tibble::tibble( + property_id = integer(), + property_name = character(), + leases_count = integer(), + total_beds = integer(), + model_beds = integer(), + current_occupied = integer(), + current_occupency = double(), + total_new = integer(), + total_renewals = integer(), + total_leases = integer(), + prelease_percent = double(), + prior_total_new = integer(), + prior_total_renewals = integer(), + prior_total_leases = integer(), + prior_prelease_percent = double(), + yoy_variance_1 = integer(), + yoy_variance_2 = double(), + weekly_new_leases = integer(), + weekly_new_renewals = integer(), + weekly_new_total = integer(), + weekly_new_pct_gained = double(), + beds_left_to_lease = integer(), + beds_leased_this_week = integer(), + weekly_velocity_needed_90 = double(), + weekly_velocity_needed_95 = double(), + weekly_velocity_needed_100 = double() + ) +} + +demo_summary_tbl <- function() { + + readr::read_csv( + pkg_sys("extdata", "csv", "summary.csv") + ) + +} + +prep_summary_table_data <- function(tbl) { + tbl |> + dplyr::transmute( + property_id = as.integer(property_id), + property_name = as.character(property_name), + # Leasing summary section + leases_count = as.integer(units), # Assuming 'units' is total leased units + total_beds = as.integer(rentable_unit_count), # Total beds + model_beds = as.integer(rentable_unit_count), # Model beds, assuming similar to rentable units + current_occupied = as.integer(preleased_count), # Occupied units count + current_occupency = as.double(preleased_percent),# Occupancy percentage + # Prelease activity + total_new = as.integer(preleased_new_count), # New preleases count + total_renewals = as.integer(preleased_renewal_count), # Renewal preleases count + total_leases = as.integer(preleased_new_count + preleased_renewal_count), # Calculated + prelease_percent = as.double(preleased_percent), # Prelease percent + # Prior year same store + prior_total_new = as.integer(preleased_count_prior), # Prior new preleases + prior_total_renewals = as.integer(preleased_renewal_count_prior), # Prior renewals + prior_total_leases = as.integer(preleased_count_prior + preleased_renewal_count_prior), # Calculated + prior_prelease_percent = as.double(preleased_percent_prior), # Prior prelease percent + # Year-over-Year variance + yoy_variance_1 = as.integer(variance), # Count change + yoy_variance_2 = as.double(preleased_percent - preleased_percent_prior), # Percent change calculated + # Preleasing activity - prior seven days + weekly_new_leases = as.integer(0), # Placeholder, as no direct data was available + weekly_new_renewals = as.integer(0), # Placeholder + weekly_new_total = as.integer(0), # Placeholder + weekly_new_pct_gained = as.double(0), # Placeholder + # Weekly velocity needed + beds_left_to_lease = as.integer(available_count), # Beds available for leasing + beds_leased_this_week = as.integer(0), # Placeholder for leased this week + # Calculated weekly velocities + weekly_velocity_needed_90 = (total_beds * 0.90 - current_occupied) / weeks_remaining, + weekly_velocity_needed_95 = (total_beds * 0.95 - current_occupied) / weeks_remaining, + weekly_velocity_needed_100 = (total_beds * 1.00 - current_occupied) / weeks_remaining + ) |> + dplyr::mutate( + weekly_velocity_needed_90 = ifelse(weekly_velocity_needed_90 < 0, 0, weekly_velocity_needed_90), + weekly_velocity_needed_95 = ifelse(weekly_velocity_needed_95 < 0, 0, weekly_velocity_needed_95), + weekly_velocity_needed_100 = ifelse(weekly_velocity_needed_100 < 0, 0, weekly_velocity_needed_100) + ) +} + +split_summary_table <- function(tbl) { + + main_1 <- dplyr::select( + tbl, + property_name, + leases_count, + total_beds, + model_beds, + current_occupied, + current_occupency + ) + + main_2 <- dplyr::select( + tbl, + total_new, + total_renewals, + total_leases, + prelease_percent, + prior_total_new, + prior_total_renewals + ) + + prior_year <- dplyr::select( + tbl, + prior_new, + prior_total_leases, + prior_prelease_percent + ) + + yoy_variance <- dplyr::select( + tbl, + prior_total_leases, + prior_prelease_percent, + yoy_variance_1, + yoy_variance_2 + ) + + prior_seven_days <- dplyr::select( + tbl, + weekly_new_leases, + weekly_new_renewals, + weekly_new_total, + weekly_new_pct_gained + ) + + weekly_velocity <- dplyr::select( + tbl, + beds_left_to_lease, + beds_leased_this_week, + weekly_velocity_needed_90, + weekly_velocity_needed_95, + weekly_velocity_needed_100 + ) + + return(list(tbl_1 = tbl_1, tbl_2 = tbl_2, tbl_3 = tbl_3)) + +} + +get_pre_lease_period_start_date <- function() { + today <- lubridate::today() + if (month(today) >= 9) { + make_date(year(today) + 1, 9, 1) + } else { + make_date(year(today), 9, 1) + } %>% + format("%m/%d/%Y") +} + +get_leasing_season_end_date <- function(as_of = lubridate::today()) { + + requireNamespace("lubridate") + + dplyr::case_when( + lubridate::month(as_of) >= 9 ~ lubridate::make_date(lubridate::year(as_of) + 1, 8, 1), + lubridate::month(as_of) < 9 ~ lubridate::make_date(lubridate::year(as_of), 8, 1) + ) + +} + +get_weeks_left_to_lease <- function(leasing_season_end_date = get_leasing_season_end_date()) { + + leasing_season_end_date %--% lubridate::today() |> + lubridate::as.duration() |> + as.numeric("weeks") |> + floor() * -1 + +} + diff --git a/R/sysdata.rda b/R/sysdata.rda index 1779975..0427100 100644 Binary files a/R/sysdata.rda and b/R/sysdata.rda differ diff --git a/R/utils.R b/R/utils.R index 9690da5..98a6488 100644 --- a/R/utils.R +++ b/R/utils.R @@ -7,6 +7,72 @@ # # ------------------------------------------------------------------------ +#' Package System File +#' +#' @name pkg_sys +#' +#' @description +#' This function is a wrapper for the `system.file` function. It is used to +#' retrieve the path to a file within the package directory. +#' +#' @param ... A character vector of subdirectories and file name. +#' +#' @return A character string of the file path. +#' +#' @export +#' +#' @examples +#' pkg_sys("www", "styles", "css", "styles.min.css") +#' pkg_sys("config", "config.yml") +#' pkg_sys("extdata") +pkg_sys <- function(...) { + system.file(..., package = "gmhdatahub") +} + +#' @rdname pkg_sys +#' @export +pkg_sys_assets <- function(...) { + pkg_sys("www", ...) +} + +#' @rdname pkg_sys +#' @export +pkg_sys_config <- function(...) { + pkg_sys("config", ...) +} + +#' @rdname pkg_sys +#' @export +pkg_sys_templates <- function(...) { + pkg_sys("templates", ...) +} + +#' @rdname pkg_sys +#' @export +pkg_sys_examples <- function(...) { + pkg_sys("examples", ...) +} + +#' Icon Text +#' +#' @description +#' This function is used to create a simple icon and text element. +#' +#' @param icon The icon to display. This can be a character string or an icon +#' object. +#' @param text The text to display next to the icon. +#' @param .function The function to use to create the icon. Default is `shiny::icon`. +#' +#' @return A `tagList` object containing the icon and text. +#' +#' @export +#' +#' @examples +#' icon_text("user", "User") +#' icon_text(shiny::icon("user"), "User") +#' +#' @importFrom shiny icon +#' @importFrom htmltools tagList tags icon_text <- function(icon, text, .function = shiny::icon) { if (is.character(icon)) i <- .function(icon) else i <- icon t <- paste0(" ", text) diff --git a/R/validation.R b/R/validation.R index 4000fec..ba1e1b5 100644 --- a/R/validation.R +++ b/R/validation.R @@ -382,3 +382,321 @@ check_request <- function( ) } + +#' Is Boolean String +#' +#' @description +#' Checks if provided string represents a boolean (used by Entrata API). +#' +#' @param str Character string to check. Typically, with the Entrata API, "boolean" +#' values are represented as quoted integers (`"0"` or `"1"`) representing +#' `FALSE` and `TRUE`, respectively. +#' +#' @return `TRUE` if the string is a boolean string, `FALSE` otherwise. +#' +#' @export +#' +#' @examples +#' is_boolean_string("0") +is_boolean_string <- function(str) { + str %in% c(as.character(as.integer(TRUE)), as.character(as.integer(FALSE))) +} + +#' Is Integer String +#' +#' @description +#' Validate a string can be parsed into an integer. +#' +#' @param str Character string to check. Typically, with the Entrata API, "integer" +#' parameters are actually represented as strings in the request payload. +#' @param arg For internal use only, used to capture the name of the argument. +#' +#' @return `TRUE` if the string is parseable to an integer, `FALSE` otherwise. +#' +#' @export +#' +#' @importFrom rlang caller_arg +#' +#' @examples +#' is_integer_string("1") +#' [1] TRUE +#' +#' is_integer_string("a") +#' [1] FALSE +is_integer_string <- function(str, arg = rlang::caller_arg(str)) { + + int <- NA + + tryCatch({ + int <- suppressWarnings(as.integer(str)) + }, error = function(e) { + return(FALSE) + }) + + if (is.na(int)) { return(FALSE) } else { return(TRUE) } + +} + +#' @describeIn is_integer_string Is Integer String (Multi) +#' +#' @description +#' Validate a string with comma separated integers can be parsed into individual integers. +#' +#' @param str Character string to check. Typically, with the Entrata API, "multiple" +#' values are represented as comma separated integer strings. +#' @param arg For internal use only, used to capture the name of the argument. +#' +#' @export +#' +#' @examples +#' is_integer_string_multi("1,2,3") +#' [1] TRUE +#' is_integer_string_multi("1,2,3,") +#' [1] FALSE +#' is_integer_string_multi("1,2,a,b") +#' [1] FALSE +is_integer_string_multi <- function( + str, + arg = rlang::caller_arg(str) +) { + + # verify a single string with comma separated integers can be parsed + # into individual integers + int <- NA + + # if ends with a comma, fail + if (grepl(",$", str)) { + cli::cli_alert_warning("{.arg {str}} ends with a comma.") + return(FALSE) + } + + tryCatch({ + int <- suppressWarnings(as.integer(unlist(strsplit(str, ",")))) + }, error = function(e) { + return(FALSE) + }) + + if (any(is.na(int))) { return(FALSE) } else { return(TRUE) } + +} + +# get_validation_function <- function( +# endpoint, +# method, +# param, +# call = rlang::caller_env(), +# arg_endpoint = rlang::caller_arg(endpoint), +# arg_method = rlang::caller_arg(method), +# arg_param = rlang::caller_arg(param) +# ) { +# +# hold <- entrata_api_request_endpoint_method_parameters |> +# dplyr::filter(endpoint == endpoint, +# method == method, +# parameter == param) +# +# if (nrow(hold) == 0) { +# cli::cli_abort( +# c( +# "No parameter {.arg arg_param} found for the {.arg arg_method} method in the {.arg arg_endpoint} endpoint." +# ), +# call = call +# ) +# } +# +# param_type <- hold$type[[1]] +# param_multi <- hold$multiple[[1]] +# +# dplyr::case_when( +# param_multi ~ switch( +# param_type, +# "integer" = is_integer_string_multi, +# "string" = is_string, +# "date" = function(x) inherits(x, "Date"), +# "boolean" = is.logical, +# "boolean_string" = is_boolean_string, +# "string_list" = is.character, +# "integer_list" = is_integer_string_multi, +# stop("Unknown parameter type: ", param_type) +# ), +# TRUE ~ switch( +# param_type, +# "integer" = is_integer_string, +# "string" = is.character, +# "date" = function(x) inherits(x, "Date"), +# "boolean" = is.logical, +# "boolean_string" = is_boolean_string, +# "string_list" = is.character, +# "integer_list" = is_integer_string_multi, +# stop("Unknown parameter type: ", param_type) +# ) +# ) +# +# switch( +# param_type, +# "integer" = is_integer_string, +# "string" = is.character, +# "date" = function(x) inherits(x, "Date"), +# "boolean" = is.logical, +# "boolean_string" = is_boolean_string, +# "string_list" = is.character, +# "integer_list" = is_integer_string_multi, +# stop("Unknown parameter type: ", param_type) +# ) +# +# switch( +# type, +# "integer" = is_integer_string, +# "string" = is.character, +# "date" = function(x) inherits(x, "Date"), +# "boolean" = is.logical, +# "boolean_string" = is_boolean_string, +# "string_list" = is.character, +# "integer_list" = is_integer_string_multi, +# stop("Unknown parameter type: ", type) +# ) +# +# +# if (param_info$type == "integer" && !is.integer(param_value)) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be an integer." +# ), +# call = call +# ) +# } else if (param_info$type == "string" && !is.character(param_value)) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be a string." +# ), +# call = call +# ) +# } else if (param_info$type == "date" && !inherits(param_value, "Date")) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be a Date object." +# ), +# call = call +# ) +# } else if (param_info$type == "boolean" && !is.logical(param_value)) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be a logical value." +# ), +# call = call +# ) +# } else if (param_info$type == "boolean_string" && !is_boolean_string(param_value)) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be a boolean string." +# ), +# call = call +# ) +# } +# if (!is.null(param_info$multiple) && param_info$multiple && length(param_value) > 1 && !is.vector(param_value)) { +# cli::cli_abort( +# c( +# "Parameter {.field {param_name}} should be a vector for multiple values." +# ), +# call = call +# ) +# +# +# } + +#' #' @rdname entrata_request_validation +#' #' @export +#' #' @importFrom cli cli_abort +#' #' @importFrom rlang caller_arg caller_env +#' validate_entrata_request_method_params <- function( +#' endpoint, +#' method, +#' method_params, +#' arg_endpoint = rlang::caller_arg(endpoint), +#' arg_method = rlang::caller_arg(method), +#' arg_method_params = rlang::caller_arg(method_params), +#' call = rlang::caller_env() +#' ) { +#' +#' expected_params <- entrata_api_request_parameters[[endpoint]][[method]] +#' +#' if (is.null(expected_params)) { +#' cli::cli_alert_info( +#' c( +#' "No parameters are expected for the {.field {method}} method." +#' ) +#' ) +#' } else { +#' for (param_name in names(method_params)) { +#' if (!param_name %in% names(expected_params)) { +#' cli::cli_alert_warning( +#' c( +#' "Unexpected parameter: {.field {param_name}}" +#' ) +#' ) +#' } else { +#' param_info <- expected_params[[param_name]] +#' param_value <- method_params[[param_name]] +#' +#' if (param_info$required && is.null(param_value)) { +#' cli::cli_abort( +#' c( +#' "Required parameter is missing: {.field {param_name}}", +#' "The {.field {param_name}} parameter is required for the {.field {method}} method.", +#' "Please provide a value for the {.field {param_name}} parameter." +#' ), +#' call = call +#' ) +#' } +#' +#' if (!is.null(param_value)) { +#' if (param_info$type == "integer" && !is.integer(param_value)) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be an integer." +#' ), +#' call = call +#' ) +#' } else if (param_info$type == "string" && !is.character(param_value)) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be a string." +#' ), +#' call = call +#' ) +#' } else if (param_info$type == "date" && !inherits(param_value, "Date")) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be a Date object." +#' ), +#' call = call +#' ) +#' } else if (param_info$type == "boolean" && !is.logical(param_value)) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be a logical value." +#' ), +#' call = call +#' ) +#' } else if (param_info$type == "boolean_string" && !is_boolean_string(param_value)) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be a boolean string." +#' ), +#' call = call +#' ) +#' } +#' if (!is.null(param_info$multiple) && param_info$multiple && length(param_value) > 1 && !is.vector(param_value)) { +#' cli::cli_abort( +#' c( +#' "Parameter {.field {param_name}} should be a vector for multiple values." +#' ), +#' call = call +#' ) +#' } +#' } +#' } +#' } +#' } +#' } + diff --git a/data-raw/R/utils_brand.R b/data-raw/R/utils_brand.R new file mode 100644 index 0000000..7b4ab9c --- /dev/null +++ b/data-raw/R/utils_brand.R @@ -0,0 +1,249 @@ +#' Fetch a Brand using the Brandfetch API +#' +#' @description +#' This function fetches a brand using the +#' [Brandfetch Brand API](https://docs.brandfetch.com/reference/brand-api). +#' +#' @param domain The domain of the brand to fetch +#' @param brandfetch_api_key The API key for the Brandfetch API +#' @param ... Additional arguments +#' +#' @importFrom httr2 request req_url_path_append req_method req_auth_bearer_token req_headers req_perform resp_body_json +#' @importFrom tibblify tib_chr tib_lgl tib_dbl tib_unspecified tib_df tib_row +#' @importFrom purrr pluck +#' @importFrom tidyr unnest +#' @importFrom rlang abort +#' @importFrom tibble tibble +#' +#' @return A tibble with the brand information +#' @export +fetch_brand <- function( + domain, + brandfetch_api_key = config::get("tools")$brandfetch_api_key, + ... +) { + + base_url <- "https://api.brandfetch.io/v2/brands" + + if (is.null(brandfetch_api_key)) { + brandfetch_api_key <- config::get("brandfetch_api_key") + } + + if (is.null(brandfetch_api_key)) { + rlang::abort("No Brandfetch API key found") + } + + req <- httr2::request( + base_url = base_url + ) |> + httr2::req_url_path_append( + domain + ) |> + httr2::req_method("GET") |> + httr2::req_auth_bearer_token(brandfetch_api_key) |> + httr2::req_headers( + `Accept` = "application/json", + `Content-Type` = "application/json" + ) + + res <- req |> httr2::req_perform() + if (res$status_code != 200) { + rlang::abort("Brandfetch API request failed") + } + + content <- res |> + httr2::resp_body_json() + + spec <- tibblify::tspec_object( + tibblify::tib_chr("id"), + tibblify::tib_chr("name"), + tibblify::tib_chr("domain"), + tibblify::tib_lgl("claimed"), + tibblify::tib_chr("description"), + tibblify::tib_chr("longDescription"), + tibblify::tib_dbl("qualityScore"), + tibblify::tib_unspecified("images"), + + tibblify::tib_df( + "links", + tibblify::tib_chr("name"), + tibblify::tib_chr("url") + ), + + tibblify::tib_df( + "logos", + tibblify::tib_chr("theme"), + tibblify::tib_df( + "formats", + tibblify::tib_chr("src"), + tibblify::tib_unspecified("background"), + tibblify::tib_chr("format"), + tibblify::tib_int("height"), + tibblify::tib_int("width"), + tibblify::tib_int("size"), + ), + tibblify::tib_unspecified("tags"), + tibblify::tib_chr("type") + ), + + tibblify::tib_df( + "colors", + tibblify::tib_chr("hex"), + tibblify::tib_chr("type"), + tibblify::tib_int("brightness"), + ), + + tibblify::tib_df( + "fonts", + tibblify::tib_chr("name"), + tibblify::tib_chr("type"), + tibblify::tib_chr("origin"), + tibblify::tib_chr("originId"), + tibblify::tib_unspecified("weights"), + ), + + tibblify::tib_row( + "company", + tibblify::tib_unspecified("employees"), + tibblify::tib_unspecified("foundedYear"), + tibblify::tib_unspecified("kind"), + tibblify::tib_unspecified("location"), + tibblify::tib_df( + "industries", + tibblify::tib_unspecified("id", required = FALSE), + tibblify::tib_unspecified("parent"), + tibblify::tib_dbl("score", required = FALSE), + tibblify::tib_chr("name", required = FALSE), + tibblify::tib_chr("emoji", required = FALSE), + tibblify::tib_chr("slug", required = FALSE) + ) + ) + ) + + out <- tibblify::tibblify(content, spec, unspecified = "drop") + out$logos <- out$logos |> tidyr::unnest("formats") + out$industries <- out$company |> purrr::pluck("industries") + out$company <- NULL + + brand <- out + + brand_logos <- brand$logos |> + dplyr::mutate( + file = purrr::pmap_chr( + list( + brand_name = brand$name, + type = type, + format = format, + height = height, + width = width + ), + get_logo_file_name + ) + ) + + return(out) + +} + +download_brand_logos <- function( + brand, + path = "inst/www/images/gmh", + ... +) { + + if (!fs::dir_exists(path)) { + fs::dir_create(path) + } + + brand_logos <- brand$logos |> + dplyr::mutate( + file = purrr::pmap_chr( + list( + brand_name = brand$name, + type = type, + format = format, + height = height, + width = width + ), + get_logo_file_name + ) + ) + + brand_logos |> + purrr::pwalk( + download_logo, + src = brand$logos$src, + name = brand$name, + path = path, + ... + ) + + return( + invisible(TRUE) + ) + +} + +download_logo <- function( + src, + file, + name, + path = "inst/www/images/gmh", + type = c("icon", "logo"), + format = c("png", "svg", "jpeg"), + height, + width, + ... +) { + + type <- match.arg(type) + format <- match.arg(format) + height <- as.integer(height) + width <- as.integer(width) + src <- src |> stringr::str_replace_all(" ", "%20") + brand_name_clean <- stringr::str_to_lower(name) |> stringr::str_replace_all(" ", "_") + size <- paste0(as.character(height), "x", as.character(width)) + + if (!fs::dir_exists(path)) { + fs::dir_create(path) + } + + file_path <- fs::path(path, file) + + download.file( + src, + destfile = file_path, + method = "curl" + ) + + return( + invisible(TRUE) + ) + +} + +get_logo_file_name <- function( + brand_name, + type, + format, + height, + width, + ... +) { + + brand_name_clean <- stringr::str_to_lower(brand_name) |> stringr::str_replace_all(" ", "_") + size <- "" + if (!is.na(height) && !is.na(width) && format != "svg") { + size <- paste0("-", as.character(height), "x", as.character(width)) + } + + paste0( + brand_name_clean, + "-", + type, + size, + ".", + format + ) + +} diff --git a/data-raw/R/utils_cache.R b/data-raw/R/utils_cache.R new file mode 100644 index 0000000..320ee45 --- /dev/null +++ b/data-raw/R/utils_cache.R @@ -0,0 +1,94 @@ +require(qs2) + + + +#' Caching Utility Functions +#' +#' @name caching +#' +#' @description +#' Quick caching utility read/write functions utilizing the \code{qs} package. +#' +#' @seealso [qs2::qs_read()] and [qs2::qs_save()] +#' +#' @return invisibly returns object passed to the function. +#' +#' @examples +#' \dontrun{ +#' mydata <- mtcars +#' write_cache(mydata) # will save to 'cache/mydata'. +#' write_cache(mydata, "mydata-v2", cache_dir = "data/temp") # will save to 'data/temp/mydata-v2' +#' +#' # read back in +#' read_cache(mydata) +#' } +NULL + + +#' Write Cache +#' +#' @rdname caching +#' +#' @param x object to cache +#' @param name name to store object with +#' @param cache_dir path to cache directory +#' @param overwrite logical (default = TRUE) +#' +#' @return x +#' @export +#' @importFrom fs dir_exists dir_create path +#' @importFrom qs2 qs_save +#' @importFrom usethis ui_info ui_path +write_cache <- function(x, + name = NULL, + cache_dir = "data-raw/cache", + overwrite = TRUE) { + + if (!fs::dir_exists(cache_dir)) fs::dir_create(cache_dir) + if (is.null(name)) name <- deparse(substitute(x)) + qs_file <- fs::path(cache_dir, name) + + if (file.exists(qs_file)) { + usethis::ui_info("File: {usethis::ui_path(basename(qs_file))}, already + exists in cache; copying to prior and overwriting.") + fs::dir_create(fs::path(cache_dir, "prior")) + file.copy(qs_file, + fs::path(cache_dir, "prior", basename(qs_file)), + overwrite = TRUE) + } + + usethis::ui_info("Caching {usethis::ui_path(basename(qs_file))}, + in {usethis::ui_path(cache_dir)}") + + qs2::qs_save(x, qs_file) + return(invisible(x)) + +} + +#' Read Cache +#' +#' @rdname caching +#' +#' @param name name of object to read in. +#' @param cache_dir path to cache directory. +#' +#' @return invisibly attaches object to parent global environment +#' @export +#' @importFrom fs path file_exists +#' @importFrom qs2 qs_read +read_cache <- function(x, + name = NULL, + cache_dir = "data-raw/cache") { + + if (is.null(name)) name <- deparse(substitute(x)) + qs_file <- fs::path(cache_dir, name) + if (!fs::file_exists(qs_file)) { + stop("File not found in ", cache_dir) + } + out <- list(qs2::qs_read(qs_file)) + if (is.null(name)) name <- deparse(substitute(x)) + names(out) <- name + list2env(out, envir = .GlobalEnv) # avoid assign by using list2env + return(invisible(x)) + +} diff --git a/data-raw/R/utils_datadocs.R b/data-raw/R/utils_datadocs.R new file mode 100644 index 0000000..09b0fd9 --- /dev/null +++ b/data-raw/R/utils_datadocs.R @@ -0,0 +1,73 @@ +document_dataset <- function( + data_obj, + name = "DATASET_NAME", + description = "DATASET_DESCRIPTION", + source = "DATASET_SOURCE", + col_types = purrr::map_chr(data_obj, typeof), + col_descs = rep("COLUMN_DESCRIPTION", length(names(data_obj))), + file = fs::path("R", "data.R"), + append = TRUE, + overwrite = FALSE, + ... +) { + + col_names <- names(data_obj) + + if (missing(col_types) || is.null(col_types)) { + col_types <- purrr::map_chr(data_obj, typeof) + } + + if (missing(col_descs) || is.null(col_descs)) { + col_descs <- rep("COLUMN_DESCRIPTION", length(col_names)) + } + + stopifnot( + length(col_types) == length(col_names), + length(col_descs) == length(col_names) + ) + + col_roxys <- glue::glue( + .open = "[[", + .close = "]]", + "#' \\item{\\code{[[col_names]]}}{[[col_types]]. [[col_descs]].}" + ) |> + paste(collapse = "\n") + + # cat(col_roxys) + + dims <- paste0( + nrow(data_obj), + " rows and ", + ncol(data_obj), + " columns" + ) + + pre <- glue::glue( + .sep = "\n", + "#' {name}", + "#'", + "#' @description", + "#' {description}", + "#'", + "#' @source", + "#' {source}", + "#'", + "#' @format A data.frame with {dims}:" + ) + + skeleton <- paste0( + pre, + "\n", + "#' \\describe{\n", + col_roxys, + "\n", + "#'}\n", + '"', name, '"\n' + ) + + cat(skeleton, + file = file, + append = append, + sep = "\n") + +} diff --git a/data-raw/R/utils_excel.R b/data-raw/R/utils_excel.R new file mode 100644 index 0000000..a6bac37 --- /dev/null +++ b/data-raw/R/utils_excel.R @@ -0,0 +1,63 @@ +#' Excel Utility Functions +#' +#' @description +#' Functions for working with and munging data originating from Excel. +#' +#' @name excel +NULL + + +#' Create Excel Ranges +#' +#' @description +#' Helper function to create ranges for Excel sheets based on filter patterns +#' and column offsets. +#' +#' @param cells `data.frame` of raw Excel cells created via [tidyxl::xlsx_cells()]. +#' Must contain (at least) the columns `sheet`, `row`, `col`, `data_type` +#' and `character`. +#' @param filter_pattern `character` pattern to filter cells by. +#' @param start_offset `integer` offset to start the range from. +#' @param stop_col `integer` or `character` column to stop the range at. +#' +#' @return `data.frame` of ranges for each sheet. +#' @export +#' +#' @importFrom dplyr group_by slice ungroup mutate select filter +#' @importFrom stringr str_detect +#' @importFrom purrr map +#' @importFrom tidyr unite +#' @importFrom readxl excel_sheets read_excel +create_ranges <- function( + cells, + filter_pattern, + start_offset, + stop_col +) { + + # validate inputs + stopifnot(exprs = { + is.data.frame(cells) + all( + c("sheet", "row", "col", "data_type", "character") %in% colnames(cells) + ) + is.character(filter_pattern) + is.integer(start_offset) + is.character(stop_col) || is.integer(stop_col) + }) |> try() + + # create ranges + cells |> + dplyr::filter( + stringr::str_detect(.data$character, .env$filter_pattern) + ) |> + dplyr::group_by(.data$sheet) |> + dplyr::slice(1) |> # get first row of each sheet + dplyr::mutate( + start_cell = paste0("A", .env$start_offset), + stop_cell = paste0(.env$stop_col, .data$row - 1) + ) |> + dplyr::ungroup() %>% + dplyr::mutate(range = paste0(.data$start_cell, ":", .data$stop_cell)) |> + dplyr::select(.data$sheet, .data$range) +} diff --git a/data-raw/assets.R b/data-raw/assets.R new file mode 100644 index 0000000..fb702c6 --- /dev/null +++ b/data-raw/assets.R @@ -0,0 +1,147 @@ + +# ------------------------------------------------------------------------ +# +# Title : Asset Registry +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + +files <- fs::dir_ls("inst/www", recurse = TRUE, type = "file") + +img_files <- fs::dir_ls("inst/www/img", recurse = TRUE, type = "file") +style_files <- fs::dir_ls("inst/www/styles", recurse = TRUE, type = "file") +js_files <- fs::dir_ls("inst/www/scripts", recurse = TRUE, type = "file") +font_files <- fs::dir_ls("inst/www/fonts", recurse = TRUE, type = "file") + +registry <- list( + brands = list( + gmh = list( + logos = list( + primary = list( + default = "gmh/logos/logo.svg", + dark = "gmh/logos/logo-dark.svg", + light = "gmh/logos/logo-light.svg" + ), + divisions = list( + communities = "gmh/logos/communities/gmh-communities-logo.svg", + go = "gmh/logos/go/gmh-go-logo.svg", + innovative = "gmh/logos/innovative-living/gmh-innovative-living-logo.svg", + residential = "gmh/logos/residential-living/gmh-residential-living-logo.svg", + student = "gmh/logos/student-living/gmh-student-living-logo.svg" + ) + ) + ), + noclocks = list( + logos = list( + primary = list( + default = "noclocks/logos/logo.svg", + dark = "noclocks/logos/logo-dark.svg", + light = "noclocks/logos/logo-light.svg" + ) + ) + ), + entrata = list( + logos = list( + primary = list( + default = "entrata/logos/logo.svg", + dark = "entrata/logos/logo-dark.svg", + light = "entrata/logos/logo-light.svg" + ) + ) + ), + properties = list( + # Use standardized property keys + academy_65 = list( + logos = list( + default = "properties/academy-65/academy65-logo.webp", + black = "properties/academy-65/academy65-logo-black.webp" + ) + ) + ), + + shared = list( + app = list( + icons = "shared/app/icons/app-icon.webp", + logos = "shared/app/logos/app-logo.svg" + ), + favicons = list( + android = "shared/favicons/android/android-chrome-{size}.png", + apple = "shared/favicons/apple/apple-touch-icon-{size}.png", + favicon = "shared/favicons/favicon.ico" + ) + ) + ) + images = list( + entrata = list( + banner = "img/entrata/entrata-banner.jpeg", + logo = list( + dark = "img/entrata/entrata-logo-dark.png", + light = "img/entrata/entrata-logo-light.png", + square = "img/entrata/entrata-logo-square-red.jpg", + white = "img/entrata/entrata-logo-white.svg", + default = "img/entrata/entrata.png" + ) + ), + icons = list( + app = "img/icons/app-icon.webp", + gmh = "img/icons/gmh-icon.png", + noclocks = "img/icons/noclocks-icon-circular.png" + ), + logos = list( + app = "img/logos/app-logo.svg", + entrata = "img/logos/entrata-logo.png", + gmh = "img/logos/gmh-logo.svg", + noclocks = "img/logos/noclocks-logo.svg" + ), + placeholders = list( + default = "img/placeholders/default-image.png" + ) + ), + scripts = list( + main = "scripts/index.js", + modules = list( + config = "scripts/js/config.js", + cookies = "scripts/js/cookies.js", + gmaps = "scripts/js/gmaps.js", + idle = "scripts/js/idle.js", + iframe = "scripts/js/iframe.js", + init = "scripts/js/init.js", + redirect = "scripts/js/redirect.js" + ) + ), + styles = list( + css = "styles/css/styles.min.css", + scss = list( + elements = list( + buttons = "styles/scss/elements/_buttons.scss", + cards = "styles/scss/elements/_cards.scss", + selectize = "styles/scss/elements/_selectize.scss", + tables = "styles/scss/elements/_tables.scss" + ), + layout = list( + footer = "styles/scss/layout/_footer.scss", + navbar = "styles/scss/layout/_navbar.scss", + page = "styles/scss/layout/_page.scss", + sidebar = "styles/scss/layout/_sidebar.scss", + tabs = "styles/scss/layout/_tabs.scss" + ), + theme = list( + colors = "styles/scss/theme/_colors.scss", + company = "styles/scss/theme/_company.scss", + logos = "styles/scss/theme/_logos.scss", + social = "styles/scss/theme/_social.scss", + spacing = "styles/scss/theme/_spacing.scss", + typography = "styles/scss/theme/_typography.scss" + ), + utility = list( + gmaps = "styles/scss/utility/_gmaps.scss", + hover = "styles/scss/utility/_hover.scss", + settings = "styles/scss/utility/_settings.scss", + utils = "styles/scss/utility/_utils.scss" + ), + main = "styles/scss/index.scss" + ) + ) +) + diff --git a/data-raw/brand.R b/data-raw/brand.R new file mode 100644 index 0000000..530dc20 --- /dev/null +++ b/data-raw/brand.R @@ -0,0 +1,16 @@ +source("data-raw/R/utils_brand.R") +source("data-raw/R/utils_cache.R") + +gmh_brand <- fetch_brand( + domain = "gmhcommunities.com" +) + +write_cache(gmh_brand) +download_brand_logos(gmh_brand) + +noclocks_brand <- fetch_brand( + domain = "noclocks.dev" +) + + +usethis::use_data(brand, overwrite = TRUE) diff --git a/R/mod_header.R b/data-raw/exported.R similarity index 100% rename from R/mod_header.R rename to data-raw/exported.R diff --git a/data-raw/internal.R b/data-raw/internal.R new file mode 100644 index 0000000..f27ffa6 --- /dev/null +++ b/data-raw/internal.R @@ -0,0 +1,86 @@ + +# ------------------------------------------------------------------------ +# +# Title : Internal Package Data +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + + +# entrata ----------------------------------------------------------------- + +# entrata <- list( +# endpoints = entrata_endpoints, +# methods = entrata_methods, +# params = entrata_parameters, +# defaults = list( +# endpoint = entrata_default_endpoint, +# methods = entrata_default_methods, +# version = entrata_default_version, +# req_body = entrata_default_req_body, +# resp_body = entrata_default_resp_body, +# req_id = 15 +# ), +# schemas = + +# app_info ---------------------------------------------------------------- + +app_info <- list( + name = "GMH Data Hub", + version = "1.0", + logo = "www/img/logos/app-logo.svg", + symbol = "www/img/icons/app-icon.webp", + repo_url = "https://github.com/noclocks/gmhdatahub", + docs_url = "https://docs.noclocks.dev/gmhdatahub" +) + +# client information ------------------------------------------------------ + +client_info <- list( + name = "GMH Communities", + url = "https://gmhcommunities.com", + logo = "www/img/logos/gmh-logo.svg", + symbol = "www/img/icons/gmh-icon.png" +) + +# noclocks_info ----------------------------------------------------------- + +developer_info <- list( + name = "No Clocks, LLC", + url = "https://noclocks.dev", + logo = "www/img/logos/noclocks-logo.svg", + symbol = "www/img/icons/noclocks-icon-circular.png" +) + +# entrata_info ------------------------------------------------------------ + +entrata_info <- list( + name = "Entrata", + url = "https://gmhcommunities.entrata.com/api/v1/documentation", + logo = "www/img/logos/entrata-logo.png", + symbol = NULL +) + +# input_choices ------------------------------------------------------------- + +app_choices <- list( + portfolios = c("All", "CBRE"), + properties = c() +) + +usethis::use_data( + entrata_params_tbl, + entrata_methods_tbl, + entrata_used_methods_tbl, + entrata_default_methods_tbl, + entrata_method_versions, + entrata_endpoints, + app_info, + client_info, + developer_info, + entrata_info, + app_choices, + internal = TRUE, + overwrite = TRUE +) diff --git a/data-raw/metadata.R b/data-raw/metadata.R new file mode 100644 index 0000000..f80c91f --- /dev/null +++ b/data-raw/metadata.R @@ -0,0 +1,31 @@ + +# ------------------------------------------------------------------------ +# +# Title : Metadata +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + + +# application metadata ---------------------------------------------------- + +app_metadata <- list( + ui = list( + labels = list( + title = "App Title", + sidebar = "App Sidebar", + inputs = "Custom Shiny Inputs" + ), + input_choices = list( + properties = c("Property 1", "Property 2", "Property 3"), + reports = c("Report 1", "Report 2", "Report 3") + ) + ), + validation = list( + required_fields = c("name", "email"), + numeric_ranges = list( + age = c(0, 120) + ) + ) +) diff --git a/data-raw/src/entrata.R b/data-raw/src/entrata.R index 2d92078..4919c45 100644 --- a/data-raw/src/entrata.R +++ b/data-raw/src/entrata.R @@ -11,7 +11,7 @@ # sources ----------------------------------------------------------------- entrata_path <- "data-raw/src/entrata" -entrata_scripts <- fs::dir_ls(entrata_path) +entrata_scripts <- fs::dir_ls(entrata_path, type = "file", glob = "*.R") purrr::walk(entrata_scripts, source) # data -------------------------------------------------------------------- @@ -102,3 +102,46 @@ entrata_params_tbl <- entrata_parameters |> dplyr::desc(required), parameter ) + + +# req_validate_params <- function(req, ...) { +# +# check_request(req) +# +# # extract method object from request body +# req_method <- req$body$data$method +# +# # method name, version, and params +# req_method_name <- req_method$name +# req_method_version <- req_method$version +# req_method_params <- req_method$params +# +# # get values to validate with +# valid_method_params <- entrata_params_tbl |> +# dplyr::filter( +# .data$method == .env$req_method_name +# ) +# +# validated_params <- vector("list", length(valid_method_params)) +# +# for (i in seq_len(nrow(valid_method_params))) { +# param_name <- valid_method_params$parameter[i] +# param_type <- valid_method_params$type[i] +# param_required <- valid_method_params$required[i] +# param_multiple <- valid_method_params$multiple[i] +# +# # check if parameter exists in the request +# if (!param_name %in% names(req_method_params)) { +# if (param_required) { +# cli::cli_abort( +# "Missing required request body parameter for {.field {param_name}}." +# ) +# } else { +# next +# } +# } +# +# param_value <- req_method_params[[param_name]] +# if (!is.null(param_value)) { +# +# } diff --git a/data-raw/src/entrata/schemas.R b/data-raw/src/entrata/schemas.R index e69de29..ff062c0 100644 --- a/data-raw/src/entrata/schemas.R +++ b/data-raw/src/entrata/schemas.R @@ -0,0 +1,136 @@ + +# ------------------------------------------------------------------------ +# +# Title : Entrata API Schemas +# By : Jimmy Briggs +# Date : 2024-11-10 +# +# ------------------------------------------------------------------------ + +schemas_dir <- "data-raw/src/entrata/schemas" +fs::dir_create(schemas_dir) + +# endpoints --------------------------------------------------------------- + +entrata_endpoints_schema <- list( + type = "object", + properties = list( + endpoint = list( + type = "string", + enum = entrata_endpoints + ) + ), + required = "endpoint" +) + +jsonlite::write_json( + entrata_endpoints_schema, + file.path(schemas_dir, "entrata_endpoints.schema.json"), + auto_unbox = TRUE, + pretty = TRUE, + force = TRUE +) + +# methods ----------------------------------------------------------------- + +entrata_methods_schema <- list( + type = "object", + properties = list( + endpoint = list( + type = "string", + enum = unique(entrata_methods_tbl$endpoint) + ), + method = list( + type = "string", + enum = unique(entrata_methods_tbl$method) + ) + ), + required = c("endpoint", "method") +) + +jsonlite::write_json( + entrata_methods_schema, + file.path(schemas_dir, "entrata_methods.schema.json"), + auto_unbox = TRUE, + pretty = TRUE, + force = TRUE +) + +# versions ---------------------------------------------------------------- + +entrata_versions_schema <- list( + type = "object", + properties = list( + method = list( + type = "string", + enum = unique(entrata_methods_tbl$method) + ), + version = list( + type = "string", + enum = unique(entrata_methods_tbl$version) + ) + ), + required = c("method", "version") +) + +jsonlite::write_json( + entrata_versions_schema, + file.path(schemas_dir, "entrata_versions.schema.json"), + auto_unbox = TRUE, + pretty = TRUE, + force = TRUE +) + +# parameters -------------------------------------------------------------- + +entrata_parameters_schema <- list( + type = "object", + properties = list( + method = list( + type = "string", + enum = unique(entrata_methods_tbl$method) + ), + version = list( + type = "string", + enum = unique(entrata_methods_tbl$version) + ), + params = list( + type = "string", + enum = unique(entrata_params_tbl$parameter) + ) + ), + required = c("method", "version", "parameter") +) + +jsonlite::write_json( + entrata_parameters_schema, + file.path(schemas_dir, "entrata_parameters.schema.json"), + auto_unbox = TRUE, + pretty = TRUE, + force = TRUE +) + + +# base request ------------------------------------------------------------ + +# entrata_req_body_schema <- list( +# # auth object (required): type is always set to basic (const) +# auth = list( +# type = "basic" +# ), +# # requestId (optional but recommended): a unique identifier for the request; +# # - the API docs always default to a value of 15 +# # - from experimenting, this value seems like it can be anything (string or integer or null) +# requestId = c("string", "integer", "null"), +# # method object (required if the endpoint method requires a body); +# # has fields name (string, required), version (enum: r1, r2, or r3), +# # and params (object, optional, specific to the method): +# method = list( +# name = "string", +# version = c("r1", "r2", "r3"), +# params = list( +# # method-specific parameters +# ) +# ) +# +# ) diff --git a/R/mod_navigation.R b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.headers.json similarity index 100% rename from R/mod_navigation.R rename to data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.headers.json diff --git a/R/mod_reports.R b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.json similarity index 100% rename from R/mod_reports.R rename to data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.json diff --git a/data-raw/dataprep.R b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.schema.json similarity index 100% rename from data-raw/dataprep.R rename to data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.request.schema.json diff --git a/dev/app/app_deployment.R b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.headers.json similarity index 100% rename from dev/app/app_deployment.R rename to data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.headers.json diff --git a/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.json b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.json new file mode 100644 index 0000000..582c5ed --- /dev/null +++ b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.json @@ -0,0 +1,4940 @@ +{ + "response": { + "requestId": "15", + "code": 200, + "result": { + "arcodes": { + "arcode": [ + { + "id": 149947, + "code": 3, + "name": "Parking Permit Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Parking Permit Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149914, + "code": 3, + "name": "Settlement Offer", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Settlement Offer", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149881, + "code": 3, + "name": "Monthly Utility Bundle", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235730, + "displayAs": "Monthly Utility Bundle", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149848, + "code": 7, + "name": "Deferred Rent July 2026", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent July 2026", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149847, + "code": 7, + "name": "Deferred Rent June 2026", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent June 2026", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149846, + "code": 7, + "name": "Deferred Rent May 2026", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent May 2026", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149813, + "code": 3, + "name": "Monthly Utility Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235730, + "displayAs": "Monthly Utility Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149780, + "code": 3, + "name": "Resio Deposits", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240289, + "displayAs": "Resio Deposits", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149779, + "code": 3, + "name": "Resio Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240285, + "displayAs": "Resio Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149778, + "code": 3, + "name": "Resio NSF Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240286, + "displayAs": "Resio NSF Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149777, + "code": 3, + "name": "Resio Payment", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240287, + "displayAs": "Resio Payment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149744, + "code": 3, + "name": "NIL Monthly Concessions", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "NIL Monthly Concessions", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149711, + "code": 3, + "name": "Guarantor Waiver Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Guarantor Waiver Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149678, + "code": 3, + "name": "Guest Suite Income", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "chargeTiming": "Reservation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Guest Suite Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149645, + "code": 2, + "name": "Furniture Package - Amenity", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Furniture Package", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149612, + "code": 3, + "name": "Best Deal Guarantee Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Best Deal Guarantee Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149611, + "code": 3, + "name": "Best Deal Guarantee Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Best Deal Guarantee Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149545, + "code": 3, + "name": "Renewal Item Giveaway Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Renewal Item Giveaway Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149544, + "code": 3, + "name": "Renewal Item Giveaway", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Renewal Item Giveaway", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149543, + "code": 3, + "name": "New Item Giveaway Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "New Item Giveaway Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149542, + "code": 3, + "name": "New Item Giveaway", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "New Item Giveaway", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149509, + "code": 2, + "name": "Custom Closet Upgrade", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Custom Closet Upgrade", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149476, + "code": 3, + "name": "Corner Room Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Corner Room Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149443, + "code": 3, + "name": "My Credit Lift", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "My Credit Lift", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149410, + "code": 3, + "name": "Community Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Community Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149377, + "code": 3, + "name": "Credit Score", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Credit Score", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149376, + "code": 1, + "name": "Collections Payment", + "codeType": "Payment", + "chargeUsage": "Base", + "chargeTiming": "Collections Payment", + "associatedLedger": "Resident", + "debitGlAccountId": 235695, + "creditGlAccountId": 235694, + "displayAs": "Collections Payment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149375, + "code": 2, + "name": "Amenity Rent", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Amenity Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149342, + "code": 7, + "name": "Deferred Rent July 2025", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent July 2025", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149341, + "code": 7, + "name": "Deferred Rent June 2025", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent June 2025", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149340, + "code": 7, + "name": "Deferred Rent May 2025", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent May 2025", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149307, + "code": 3, + "name": "Offsite Parking Credit", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Offsite Parking Credit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149274, + "code": 3, + "name": "One-Time Courtesy - Balcony View Premium", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "One-Time Courtesy - Balcony View Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149273, + "code": 3, + "name": "One-Time Courtesy - Pool View Premium Waive", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "One-Time Courtesy - Pool View Premium Waive", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149240, + "code": 2, + "name": "Multi-Bed Space Rent Offset", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Multi-Bed Space Rent Offset", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149239, + "code": 2, + "name": "Multi-Bed Space Rent", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Multi-Bed Space Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149206, + "code": 3, + "name": "Spray Tan Fee Waived", + "codeType": "Other Income", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Spray Tan Fee Waived", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149173, + "code": 3, + "name": "Restoration Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239334, + "displayAs": "Restoration Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149140, + "code": 3, + "name": "ProCollect Collection Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235746, + "displayAs": "ProCollect Collection Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149107, + "code": 2, + "name": "Bluebird View - Amenity", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Bluebird View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149074, + "code": 3, + "name": "Skyline Level Premium - Amenity", + "codeType": "Other Income", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Skyline Level Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149073, + "code": 3, + "name": "Penthouse Level Premium - Amenity", + "codeType": "Other Income", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Penthouse Level Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149072, + "code": 3, + "name": "Mid Level Premium - Amenity", + "codeType": "Other Income", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Mid Level Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149071, + "code": 3, + "name": "Aerial Level Premium - Amenity", + "codeType": "Other Income", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Aerial Level Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149038, + "code": 7, + "name": "Deferred Rent - April 2024", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - April 2024", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149037, + "code": 7, + "name": "Deferred Rent - May 2024", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - May 2024", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149035, + "code": 3, + "name": "One-Time Courtesy Parking Waiver", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "One-Time Courtesy Parking Waiver", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149034, + "code": 3, + "name": "TAMU Parking - AddOns", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "TAMU Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149033, + "code": 3, + "name": "TAMU Parking", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "TAMU Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149032, + "code": 3, + "name": "TAMU Offset Credit", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "TAMU Offset Credit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149031, + "code": 3, + "name": "Mid-Level Unit Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Mid-Level Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149030, + "code": 3, + "name": "Skyline Unit Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Skyline Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149029, + "code": 3, + "name": "Aerial Unit Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Aerial Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149028, + "code": 3, + "name": "Penthouse Unit Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Penthouse Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149025, + "code": 3, + "name": "LEAP Guarantor Waiver Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "LEAP Guarantor Waiver Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149023, + "code": 3, + "name": "Group Lease Utilities", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235730, + "displayAs": "Group Lease Utilities", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149022, + "code": 3, + "name": "Group Lease Damage and Repairs", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 239334, + "displayAs": "Group Lease Damage and Repairs", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149017, + "code": 7, + "name": "Deferred Rent - June 2024", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - June 2024", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 149015, + "code": 7, + "name": "Deferred Rent - July 2024", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - July 2024", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149014, + "code": 3, + "name": "Group Immediate Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group Immediate Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149013, + "code": 3, + "name": "Group Immediate Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group Immediate Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149012, + "code": 3, + "name": "Group Renewal Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group Renewal Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149011, + "code": 3, + "name": "Group Renewal Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group Renewal Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149010, + "code": 3, + "name": "Group New Lease Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group New Lease Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149009, + "code": 3, + "name": "Group New Lease Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group New Lease Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149008, + "code": 3, + "name": "Renewal One-Time Concession", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Renewal One-Time Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149007, + "code": 3, + "name": "Renewal Monthly Concession", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Renewal Monthly Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149006, + "code": 3, + "name": "New Lease One-Time Concession", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "New Lease One-Time Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149005, + "code": 3, + "name": "New Lease Monthly Concession", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "New Lease Monthly Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149004, + "code": 3, + "name": "Referral Renewal Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Referral Renewal Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149003, + "code": 3, + "name": "Referral Renewal Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Referral Renewal Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149002, + "code": 3, + "name": "Referral New Lease Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Referral New Lease Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149001, + "code": 3, + "name": "Referral New Lease Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Referral New Lease Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149000, + "code": 3, + "name": "One-Time Giveaway Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "One-Time Giveaway Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148999, + "code": 3, + "name": "One-Time Giveaway", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "One-Time Giveaway", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148998, + "code": 3, + "name": "Immediate Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Immediate Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148997, + "code": 3, + "name": "Immediate Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Immediate Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148996, + "code": 3, + "name": "Renewal Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Renewal Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148995, + "code": 3, + "name": "Renewal Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Renewal Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148994, + "code": 3, + "name": "New Lease Gift Card Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "New Lease Gift Card Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148993, + "code": 3, + "name": "New Lease Gift Card", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "New Lease Gift Card", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148982, + "code": 3, + "name": "Parking Remote Replacement", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Parking Remote Replacement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148978, + "code": 3, + "name": "Lease Violations - Inspections", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238898, + "displayAs": "Lease Violations", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148973, + "code": 3, + "name": "EV Charging", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "EV Charging", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148972, + "code": 3, + "name": "Paint/Wall Repairs - Inspections", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Paint/Wall Repairs", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148971, + "code": 3, + "name": "Carpet/Flooring Replacement - Inspections", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238900, + "displayAs": "Carpet/Flooring Replacement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148969, + "code": 3, + "name": "Spray Tan Charge", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "chargeTiming": "Reservation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Spray Tan Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148968, + "code": 2, + "name": "Unit Premium - Corner View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Corner View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148967, + "code": 2, + "name": "Unit Premium - Top Floor", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Top Floor", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148966, + "code": 2, + "name": "Unit Premium - Vaulted Ceiling", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Vaulted Ceiling", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148965, + "code": 2, + "name": "Unit Premium - First Floor", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - First Floor", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148964, + "code": 2, + "name": "Unit Premium - Sq Footage Adjustment", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Sq Footage Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148963, + "code": 2, + "name": "Unit Sized Premium - Third Floor", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Sized Premium - Third Floor", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148962, + "code": 2, + "name": "Unit Premium - Medium Sized Unit", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Medium Sized Unit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148961, + "code": 2, + "name": "Unit Premium - Terrace", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Terrace", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148960, + "code": 2, + "name": "Unit Premium - Fourth Floor", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Fourth Floor", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148959, + "code": 2, + "name": "Unit Premium - East Location Discount", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - East Location Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148958, + "code": 2, + "name": "Unit Premium - Balcony/deck", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Balcony/deck", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148957, + "code": 2, + "name": "Unit Premium - Water View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Water View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148956, + "code": 2, + "name": "Unit Premium - Smaller Style Discount", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Smaller Style Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148955, + "code": 2, + "name": "Unit Premium - Pool/Location/View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Pool/Location/View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148954, + "code": 2, + "name": "Unit Premium - Larger Size Unit", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Larger Size Unit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148953, + "code": 2, + "name": "Unit Premium - Den/Study", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Den/Study", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148952, + "code": 2, + "name": "Unit Premium - Loft", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Loft", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148951, + "code": 2, + "name": "Unit Premium - Porch", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Porch", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148950, + "code": 2, + "name": "Unit Premium - Park View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Park View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148949, + "code": 2, + "name": "Unit Premium - View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148948, + "code": 2, + "name": "Unit Premium - Patio", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium - Patio", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148947, + "code": 3, + "name": "Pool Pass", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Pool Pass", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148946, + "code": 3, + "name": "Package Delivery", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Package Delivery", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148945, + "code": 3, + "name": "Mingle Room", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240283, + "displayAs": "Mingle Room", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148944, + "code": 3, + "name": "Lease Modification Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235738, + "displayAs": "Lease Modification Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148943, + "code": 3, + "name": "Holding Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Holding Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148942, + "code": 3, + "name": "Effortless Move Out", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Effortless Move Out", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148941, + "code": 7, + "name": "Deposit Refund", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Deposit Refund", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148940, + "code": 7, + "name": "Deposit Forfeit", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Deposit Forfeit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148939, + "code": 2, + "name": "Corporate Housing", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Corporate Housing", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148938, + "code": 5, + "name": "Capital Reimbursement", + "codeType": "Asset", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240282, + "displayAs": "Reimbursement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148937, + "code": 3, + "name": "Discount, Preferred Employer", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Preferred Employer Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148936, + "code": 3, + "name": "Discount, Other", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Discount, Other", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148935, + "code": 2, + "name": "Corner View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Corner View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148934, + "code": 2, + "name": "Vaulted Ceiling", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Vaulted Ceiling", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148932, + "code": 3, + "name": "Guest Parking", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Guest Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148931, + "code": 7, + "name": "Deferred Rent - May 2023", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - May 2023", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148930, + "code": 7, + "name": "Deferred Rent - April 2023", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - April 2023", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148929, + "code": 7, + "name": "Deferred Rent - January 2023", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - January 2023", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148928, + "code": 3, + "name": "Short Term Premium - 10-11 Month Leases", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235740, + "displayAs": "Short Term Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148925, + "code": 3, + "name": "Terrace", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Terrace", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148924, + "code": 3, + "name": "Downtown Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Downtown Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148923, + "code": 3, + "name": "Campus Premium", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Campus Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148922, + "code": 3, + "name": "Pet Fees - General", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Pet Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148921, + "code": 3, + "name": "Key/Fob Replacements - Add-Ons", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Key/Fob Replacements", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148920, + "code": 3, + "name": "Damage and Repairs", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239334, + "displayAs": "Damage and Repairs", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148919, + "code": 2, + "name": "Balcony Unit Premium", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Balcony Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148918, + "code": 3, + "name": "Utility Admin Fee - Add-Ons", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Utility Admin Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148917, + "code": 3, + "name": "Unit Premium - Add-Ons", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148916, + "code": 2, + "name": "Top Floor Premium - Add On", + "codeType": "Rent", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Top Floor Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148915, + "code": 2, + "name": "Premium View - Amenity", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Premium View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148914, + "code": 2, + "name": "Premium View - Add On", + "codeType": "Rent", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Premium View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148913, + "code": 3, + "name": "Amenity View - Add-Ons", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Amenity View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148912, + "code": 3, + "name": "Additional Rent - Mitigated Risk Add-Ons", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Additional Rent - Mitigated Risk", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148911, + "code": 2, + "name": "Unit Premium", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Unit Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148910, + "code": 2, + "name": "Premium View", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Premium View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148909, + "code": 3, + "name": "Additional Rent - Mitigated Risk", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Additional Rent - Mitigated Risk", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148908, + "code": 3, + "name": "Telecom Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Telecom Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148906, + "code": 7, + "name": "Deferred Rent July 2023", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent July 2023", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148983, + "code": 3, + "name": "Parking Sticker Replacement", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Parking Sticker Replacement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148905, + "code": 7, + "name": "Deferred Rent June 2023", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent June 2023", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148902, + "code": 3, + "name": "Landlord Administered Protection Program", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Landlord Administered Protection Program", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148901, + "code": 3, + "name": "Lock Off Bed", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235684, + "displayAs": "Lock Off Bed", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148899, + "code": 3, + "name": "Retail Reimbursement - Taxes", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239938, + "displayAs": "Retail Reimbursement - Taxes", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148898, + "code": 3, + "name": "Retail Reimbursement - CAM", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239939, + "displayAs": "Retail Reimbursement - CAM", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148897, + "code": 3, + "name": "Retail Concessions", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Retail Concessions", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148896, + "code": 3, + "name": "Retail Parking Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Retail Parking Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148890, + "code": 7, + "name": "Deferred Rent May 2022", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148889, + "code": 7, + "name": "Security Deposit - Application Complete", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Security Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148887, + "code": 3, + "name": "Short Term Premium", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235740, + "displayAs": "Short Term Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148886, + "code": 3, + "name": "Innovation Package", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Innovation Package", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148885, + "code": 3, + "name": "Application Fee - Prequalification", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235668, + "displayAs": "Application Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148867, + "code": 1, + "name": "ACH Bank Draft Received", + "codeType": "Payment", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235695, + "creditGlAccountId": 235694, + "displayAs": "ACH Bank Draft Received", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148864, + "code": 2, + "name": "Premium Terrace", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Premium Terrace", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148851, + "code": 7, + "name": "Deferred Rent - August 2022", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - August 2022", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148837, + "code": 3, + "name": "Utility Default Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Utility Default Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148834, + "code": 3, + "name": "Landlord Liability Protection Plan - Base Use", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Landlord Liability Protection Plan", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148833, + "code": 3, + "name": "Landlord Personal Property Protection Program - Base Use", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Landlord Personal Property Protection Program", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148830, + "code": 3, + "name": "Retail Reimbursements - Ins.", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239939, + "displayAs": "Retail Reimbursements - Ins.", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148829, + "code": 3, + "name": "Real Estate Taxes", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239938, + "displayAs": "Real Estate Taxes", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148827, + "code": 3, + "name": "Utility - Late Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Utility - Late Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148826, + "code": 3, + "name": "Utility - Credit Reporting Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Utility - Credit Reporting Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148825, + "code": 3, + "name": "Utility - Card Storage Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Utility - Card Storage Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148824, + "code": 7, + "name": "Deferred Rent - May 2021", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - May 2021", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148823, + "code": 7, + "name": "Deferred Rent - December 2021", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent - December 2021", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148822, + "code": 3, + "name": "Common Area Maintenance - CAM", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235734, + "displayAs": "Common Area Maintenance - CAM", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148821, + "code": 7, + "name": "Deferred Rent June 2021", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent June 2021", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148819, + "code": 3, + "name": "Group Lease Keys", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Group Lease Keys", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148815, + "code": 7, + "name": "Deferred Rent July 2021", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent July 2021", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148786, + "code": 3, + "name": "Leasing Special - Waived Admin Fees", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Leasing Special - Waived Admin Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148785, + "code": 3, + "name": "Administration Fees - Lease Complete", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Administration Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148784, + "code": 7, + "name": "Deferred Rent June 2022", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent June 2022", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148783, + "code": 7, + "name": "Deferred Rent July 2022", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239891, + "displayAs": "Deferred Rent July 2022", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148755, + "code": 3, + "name": "Application Fee - Pre-Qualification 1", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235668, + "displayAs": "Application Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148752, + "code": 3, + "name": "Green Fee - Lease Approval", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235736, + "displayAs": "Green Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148751, + "code": 3, + "name": "Group Lease Parking", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Group Lease Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148750, + "code": 3, + "name": "Trash Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 239334, + "displayAs": "Trash Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148749, + "code": 7, + "name": "Group Lease Security Deposit", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Group Lease Security Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148748, + "code": 1, + "name": "Group Lease Payments", + "codeType": "Payment", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235695, + "creditGlAccountId": 235694, + "displayAs": "Group Lease Payments", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148746, + "code": 2, + "name": "Group Lease Rent", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Group Lease Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148710, + "code": 8, + "name": "Group Refund Payable", + "codeType": "Refund", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235696, + "displayAs": "This charge code is used to refund from the default Group ledger.", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148709, + "code": 4, + "name": "COVID-19 Expenses", + "codeType": "Expense", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238991, + "displayAs": "Move Out Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148705, + "code": 3, + "name": "Best Deal Guarantee", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Best Deal Guarantee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148675, + "code": 2, + "name": "Short Term Premium - Special", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Short Term Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148674, + "code": 3, + "name": "Resident-Utility Tax", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Resident Utiltiy Tax", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148667, + "code": 3, + "name": "Floor Plan Upgrade", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Floor Plan Upgrade", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148666, + "code": 3, + "name": "Special-Waived Admin Fee", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Waived Admin Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148664, + "code": 7, + "name": "Special-Waived Deposit", + "codeType": "Deposit", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Waived Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148662, + "code": 3, + "name": "Campustown Payment Adjustment", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Campustown Payment Transfer", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148660, + "code": 3, + "name": "Violation-Trash Fee", + "codeType": "Other Income", + "chargeUsage": "Lease Violation", + "chargeTiming": "Lease Violation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238898, + "displayAs": "Violation- Trash Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148659, + "code": 3, + "name": "Violation- Pet Fee", + "codeType": "Other Income", + "chargeUsage": "Lease Violation", + "chargeTiming": "Lease Violation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238898, + "displayAs": "Violation- Pet Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148658, + "code": 3, + "name": "Special-Admin Fees", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Waived Admin Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148657, + "code": 9, + "name": "Deposit Interest", + "codeType": "Other Liability", + "chargeUsage": "Base", + "chargeTiming": "Deposit Interest", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235689, + "displayAs": "Deposit Interest", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148656, + "code": 7, + "name": "Deposit", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148654, + "code": 3, + "name": "Motorcycle Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Motorcycle Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148651, + "code": 3, + "name": "Landlord Personal Property Protection Program", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Landlord Personal Property Protection Program", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148650, + "code": 3, + "name": "Landlord Liability Protection Plan", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238899, + "displayAs": "Landlord Liability Protection Plan", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148649, + "code": 3, + "name": "Property Transfer", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Property Transfer", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148646, + "code": 3, + "name": "RR Payment Collected", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235690, + "displayAs": "RR Payment Collected", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148645, + "code": 2, + "name": "Private Bath", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Private Bath", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148644, + "code": 2, + "name": "Walk-In Closet", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Walk-in Clost", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148643, + "code": 3, + "name": "UBC Unit Adjustment", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "UBC Unit Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148642, + "code": 3, + "name": "Palomar Parking-Chorro Resident", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Palomar Parking-Chorro Resident", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148639, + "code": 2, + "name": "Small Bedroom", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Small Bedroom", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148638, + "code": 3, + "name": "Unit Repairs", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Unit Repairs", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148631, + "code": 3, + "name": "Furniture Package", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Furniture Package", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148630, + "code": 3, + "name": "Refund-Resident Payment", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Refund-Resident Payment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148628, + "code": 2, + "name": "Commercial Rent Income", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Commercial Rent Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148626, + "code": 3, + "name": "Rentable Item Promotion", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Rentable Item Promotion", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148625, + "code": 3, + "name": "Special-Rental Installment Promotion", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Rental Installment Promotion", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148624, + "code": 3, + "name": "Adminstrative Fee-Lease Approval 1", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235668, + "displayAs": "Administrative Fee-Lease Approval", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148621, + "code": 3, + "name": "Furniture Promotion", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Furniture Discount Promotion", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148618, + "code": 3, + "name": "Courtesy Officer Credit", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Courtesy Officer Credit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148615, + "code": 3, + "name": "Special- Waived Admin Fee", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Waived Administrative Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148604, + "code": 2, + "name": "Relet Adjustment", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Relet Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148603, + "code": 7, + "name": "Pet Deposit", + "codeType": "Deposit", + "chargeUsage": "Pet", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Pet Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148601, + "code": 2, + "name": "Renewal Incentive", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Renewal Incentive", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148600, + "code": 2, + "name": "Standard Bedroom", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Standard Bedroom", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148599, + "code": 2, + "name": "Standard Shower", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Standard Shower", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148598, + "code": 3, + "name": "Special-Waived Move In Fees", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Waived Move In Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148558, + "code": 2, + "name": "Garage", + "codeType": "Rent", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Garage Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148557, + "code": 2, + "name": "River View", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "River View", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148556, + "code": 3, + "name": "Administrative Fee-Application Complete", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "One-Time Administrative Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148554, + "code": 2, + "name": "View Discount", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "View Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148553, + "code": 2, + "name": "Master Bed Space", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Master Bed Space", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148551, + "code": 2, + "name": "Prospect Tier One", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "New Lease Special", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148550, + "code": 2, + "name": "Renewal Tier One", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Renewal Special", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148547, + "code": 9, + "name": "FMO Adjustment", + "codeType": "Other Liability", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235689, + "displayAs": "Financial Move Out Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148515, + "code": 3, + "name": "Management Approved Floor Plan Adjustment", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Management Approved Floor Plan Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148514, + "code": 3, + "name": "Hold Over Violation Fee", + "codeType": "Other Income", + "chargeUsage": "Lease Violation", + "chargeTiming": "Lease Violation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238898, + "displayAs": "Hold Over Violation Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148513, + "code": 3, + "name": "Management Approved Holdover Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Management Approved Hold Over Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148512, + "code": 2, + "name": "Balcony Discount", + "codeType": "Rent", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Balcony Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148511, + "code": 2, + "name": "Location Discount", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Location Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148510, + "code": 2, + "name": "Juliette Balcony", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Juliette Balcony", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148504, + "code": 3, + "name": "Refer A Friend", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Refer A Friend", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148503, + "code": 3, + "name": "Refund Other Fee(s)", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Refund Ofther Fee(s)", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148501, + "code": 3, + "name": "Early Move In Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235736, + "displayAs": "Early Move In Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148496, + "code": 3, + "name": "Reverse Late Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Late Fee", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235673, + "displayAs": "Reverse Late Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148488, + "code": 3, + "name": "Resident Referral", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Resident Referral", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148487, + "code": 3, + "name": "Utility Allowance Credit", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Utility Allowance", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148482, + "code": 3, + "name": "Gift Incentive", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Gift Incentive", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148479, + "code": 3, + "name": "Green Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235736, + "displayAs": "Green Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148475, + "code": 2, + "name": "Upgraded Appliances", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Upgraded Appliances", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148473, + "code": 2, + "name": "Granite Kitchen Countertops", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Granite Kitchen Countertops", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148472, + "code": 2, + "name": "1st Floor", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "1st Floor", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148471, + "code": 3, + "name": "Accelerated Rent-Other Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Early Termination", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Accelerated Rent-Other Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148468, + "code": 2, + "name": "Terrace Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Terrace Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148467, + "code": 2, + "name": "Upgraded Unit Two Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Upgraded Unit Two Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148466, + "code": 2, + "name": "Upgraded Unit One Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Upgraded Unit On Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148465, + "code": 3, + "name": "Guest Suite Rental", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Guest Suite Rental", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148464, + "code": 2, + "name": "W/D Side by Side", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "W/D Side by Side", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148463, + "code": 2, + "name": "W/D Stack", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "W/D Stack", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148461, + "code": 3, + "name": "Beginning Ledger Balance", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235690, + "displayAs": "Begining Ledger Balance", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148460, + "code": 3, + "name": "Vacant Electric", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235727, + "displayAs": "Vacant Electric", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148454, + "code": 3, + "name": "Cares Team", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Cares Team Rental Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148453, + "code": 3, + "name": "Pet Rent", + "codeType": "Other Income", + "chargeUsage": "Pet", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235739, + "displayAs": "Pet Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148450, + "code": 3, + "name": "Valet Trash Service", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235732, + "displayAs": "Valet Trash Service", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148449, + "code": 3, + "name": "Pest Control", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235727, + "displayAs": "Pest Control", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148445, + "code": 3, + "name": "Group Lease Special", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "Group Lease Special", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148418, + "code": 3, + "name": "Annual Admin Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Annual Admin Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148413, + "code": 7, + "name": "Remote Deposit", + "codeType": "Deposit", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Remote Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147881, + "code": 2, + "name": "Base Rent", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Base Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148110, + "code": 3, + "name": "Short Term Premium - Add Ons", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235740, + "displayAs": "Short Term Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148188, + "code": 2, + "name": "Floor Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Floor Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148230, + "code": 2, + "name": "Floor Plan Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Floor Plan Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148260, + "code": 2, + "name": "Master Bed Space Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Master Bed Space Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148261, + "code": 2, + "name": "Skyline View Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Skyline View Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148254, + "code": 2, + "name": "Top Floor Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Top Floor Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148258, + "code": 2, + "name": "Pool View Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Pool View Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148259, + "code": 2, + "name": "Courtyard View Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Courtyard View Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148255, + "code": 2, + "name": "Location Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Location Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148189, + "code": 2, + "name": "Balcony", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "FP Premium For Balcony", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148253, + "code": 2, + "name": "Balcony Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Balcony Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148257, + "code": 2, + "name": "Oversized Living Room", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Deluxe Living Room Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148252, + "code": 2, + "name": "Large Bedroom", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Bluff Bed Space", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148251, + "code": 2, + "name": "Extra Large Bedroom", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Cambria Bed Space", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148256, + "code": 2, + "name": "Deluxe Shower Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Deluxe Shower Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148406, + "code": 2, + "name": "Window Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Window Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148405, + "code": 2, + "name": "Window Shared Premium", + "codeType": "Rent", + "chargeUsage": "Amenity", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Window Shared Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148407, + "code": 3, + "name": "Accounting Correction", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Accounting Correction", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148404, + "code": 7, + "name": "Deferred Rent", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Deferred Rent", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148403, + "code": 3, + "name": "Common Area Electric", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235730, + "displayAs": "Common Area Electric", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148328, + "code": 3, + "name": "Prelease Garage Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Prelease Garage Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148250, + "code": 3, + "name": "Waived Transfer Fee", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238896, + "displayAs": "*Waived Transfer Fee*", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148249, + "code": 3, + "name": "Leasing Special- Waived Application Fee", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235668, + "displayAs": "Leasing Special- Waived Application Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147886, + "code": 1, + "name": "Payment", + "codeType": "Payment", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235695, + "creditGlAccountId": 235694, + "displayAs": "Payment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148089, + "code": 3, + "name": "Employee Rent Credit", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235674, + "displayAs": "Employee Rent Credit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148090, + "code": 3, + "name": "Employee Discount", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235674, + "displayAs": "Employee Discount", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148135, + "code": 3, + "name": "Model / Office", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235725, + "displayAs": "Model / Office", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148091, + "code": 3, + "name": "Bad Debt Loss", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Bad Debt Write Off", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235745, + "displayAs": "Bad Debt Loss", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 147898, + "code": 3, + "name": "Application Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235668, + "displayAs": "Application Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147887, + "code": 3, + "name": "Late Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Late Fee", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235673, + "displayAs": "Late Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148134, + "code": 3, + "name": "Garage Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Garage parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147893, + "code": 3, + "name": "Covered Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Covered Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147894, + "code": 3, + "name": "Relet / Lease Termination Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Early Termination", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 240246, + "displayAs": "Lease Transfer Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147895, + "code": 3, + "name": "Return Item Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Return Item Fee", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235679, + "displayAs": "Return Item Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147896, + "code": 3, + "name": "Paint/Wall Repairs", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Paint/Wall Repairs", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147897, + "code": 3, + "name": "Transfer Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235738, + "displayAs": "Transfer Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147888, + "code": 3, + "name": "Miscellaneous Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Miscellaneous Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147892, + "code": 8, + "name": "Refund Payable", + "codeType": "Refund", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235696, + "displayAs": "Refund Payable", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 147884, + "code": 7, + "name": "Security Deposit", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Security Deposit", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148097, + "code": 3, + "name": "Lot Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Lot Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148098, + "code": 3, + "name": "Utility Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235727, + "displayAs": "Utility Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148099, + "code": 3, + "name": "Resident Online Payment Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235728, + "displayAs": "Resident Online Payment Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148100, + "code": 3, + "name": "Resident - Cable / Internet", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235729, + "displayAs": "Resident - Cable / Internet", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148101, + "code": 3, + "name": "Resident - Electric", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235730, + "displayAs": "Resident - Electric", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148102, + "code": 3, + "name": "Resident - Gas", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235731, + "displayAs": "Resident - Gas", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148103, + "code": 3, + "name": "Resident - Trash", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235732, + "displayAs": "Resident - Trash", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148104, + "code": 3, + "name": "Resident - Water / Sewer", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235733, + "displayAs": "Resident - Water / Sewer", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148105, + "code": 3, + "name": "Retail CAM Charges", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235734, + "displayAs": "Retail CAM Charges", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148106, + "code": 3, + "name": "Lease Processing / Other Admin Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235735, + "displayAs": "Lease Processing / Other Admin Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148107, + "code": 3, + "name": "Move In Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235736, + "displayAs": "Move In Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148109, + "code": 3, + "name": "Pet Fees", + "codeType": "Other Income", + "chargeUsage": "Pet", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235739, + "displayAs": "Pet Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148111, + "code": 3, + "name": "Amenity Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235736, + "displayAs": "Amenity Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148112, + "code": 3, + "name": "Other Premium Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Other Premium Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148113, + "code": 3, + "name": "Lockout Fees", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235743, + "displayAs": "Lockout Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148114, + "code": 3, + "name": "Interest Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235744, + "displayAs": "Interest Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148115, + "code": 3, + "name": "Bad Debt Recovery", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235746, + "displayAs": "Bad Debt Recovery", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148116, + "code": 3, + "name": "BYL Collection Fee", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235746, + "displayAs": "BYL Collection Fee", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148117, + "code": 3, + "name": "Vending Income", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235747, + "displayAs": "Vending Income", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148118, + "code": 3, + "name": "Storage Fees", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235748, + "displayAs": "Storage Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148119, + "code": 3, + "name": "Furniture Replacement", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235749, + "displayAs": "Furniture Replacement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148120, + "code": 3, + "name": "Rental Concession", + "codeType": "Other Income", + "chargeUsage": "Special", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235750, + "displayAs": "Rental Concession", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148121, + "code": 3, + "name": "Legal Fee Reimbursements", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235751, + "displayAs": "Legal Fee Reimbursements", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148122, + "code": 3, + "name": "Violation - Other", + "codeType": "Other Income", + "chargeUsage": "Lease Violation", + "chargeTiming": "Lease Violation", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238898, + "displayAs": "Violation - Other", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148123, + "code": 3, + "name": "Cleaning Fees", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Cleaning Fees", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148125, + "code": 3, + "name": "Key/Fob Replacements", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235752, + "displayAs": "Key/Fob Replacements", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 148124, + "code": 3, + "name": "Carpet/Flooring Replacement", + "codeType": "Other Income", + "chargeUsage": "Maintenance", + "chargeTiming": "Work Order Fees", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 238900, + "displayAs": "Carpet/Flooring Replacement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148096, + "code": 3, + "name": "Uncovered Garage Parking", + "codeType": "Other Income", + "chargeUsage": "Add Ons", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235726, + "displayAs": "Uncovered Garage Parking", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147899, + "code": 3, + "name": "Rental Income - Commercial", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235671, + "displayAs": "Rental Income - Commercial", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148108, + "code": 3, + "name": "Double Occupancy Premium", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235737, + "displayAs": "Double Occupancy Premium", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148136, + "code": 3, + "name": "Month to Month Charges", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Month To Month Begin", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235742, + "displayAs": "Month to Month Charges", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147905, + "code": 6, + "name": "Equity Draw Request", + "codeType": "Equity", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235691, + "creditGlAccountId": 235687, + "displayAs": "Equity Draw Request", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147901, + "code": 9, + "name": "Investor Loan Request", + "codeType": "Other Liability", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235691, + "creditGlAccountId": 235700, + "displayAs": "Investor Loan Request", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147885, + "code": 2, + "name": "Utility Allowance", + "codeType": "Rent", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235678, + "displayAs": "Utility Allowance", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147966, + "code": 3, + "name": "Repayment Agreement", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "Repayment Agreement", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147964, + "code": 3, + "name": "HUDWRITEOFF", + "codeType": "Other Income", + "chargeUsage": "Base", + "chargeTiming": "Bad Debt Write Off", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235676, + "displayAs": "HUDOVERPMTWRITEOFF", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": false + }, + { + "id": 147889, + "code": 3, + "name": "Beginning Balance", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235690, + "displayAs": "Beginning Balance", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147890, + "code": 3, + "name": "Beginning Deposit Adjustment", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235690, + "displayAs": "Beginning Deposit Adjustment", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 147891, + "code": 7, + "name": "Beginning Deposit Held", + "codeType": "Deposit", + "chargeUsage": "Base", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235680, + "displayAs": "Beginning Deposit Held", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 149578, + "code": 3, + "name": "Group Balance Transfer", + "codeType": "Other Income", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235693, + "creditGlAccountId": 235690, + "displayAs": "Group Balance Transfer", + "isDisabled": false, + "isEntrataDisabled": false, + "isTaxable": true + }, + { + "id": 148747, + "code": 1, + "name": "Group Lease Payment", + "codeType": "Payment", + "chargeUsage": "Base", + "associatedLedger": "Group", + "debitGlAccountId": 235695, + "creditGlAccountId": 235694, + "displayAs": "Group Lease Payment", + "isDisabled": false, + "isEntrataDisabled": true, + "isTaxable": false + }, + { + "id": 147900, + "code": 9, + "name": "Tax", + "codeType": "Other Liability", + "chargeUsage": "Base", + "chargeTiming": "Tax", + "associatedLedger": "Resident", + "debitGlAccountId": 235693, + "creditGlAccountId": 235685, + "displayAs": "Tax", + "isDisabled": false, + "isEntrataDisabled": true, + "isTaxable": true + } + ] + } + } + } +} diff --git a/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.schema.json b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.schema.json new file mode 100644 index 0000000..9ce88cf --- /dev/null +++ b/data-raw/src/entrata/schemas/arcodes/arcodes.getArCodes.response.schema.json @@ -0,0 +1,62 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "response": { + "type": "object", + "properties": { + "requestId": { "type": "string" }, + "code": { "type": "integer" }, + "result": { + "type": "object", + "properties": { + "arcodes": { + "type": "object", + "properties": { + "arcode": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "code": { "type": "integer" }, + "name": { "type": "string" }, + "codeType": { "type": "string" }, + "chargeUsage": { "type": "string" }, + "associatedLedger": { "type": "string" }, + "debitGlAccountId": { "type": "integer" }, + "creditGlAccountId": { "type": "integer" }, + "displayAs": { "type": "string" }, + "isDisabled": { "type": "boolean" }, + "isEntrataDisabled": { "type": "boolean" }, + "isTaxable": { "type": "boolean" }, + "chargeTiming": { "type": "string", "nullable": true } + }, + "required": [ + "id", + "code", + "name", + "codeType", + "chargeUsage", + "associatedLedger", + "debitGlAccountId", + "creditGlAccountId", + "displayAs", + "isDisabled", + "isEntrataDisabled", + "isTaxable" + ] + } + } + }, + "required": ["arcode"] + } + }, + "required": ["arcodes"] + } + }, + "required": ["requestId", "code", "result"] + } + }, + "required": ["response"] +} diff --git a/data-raw/src/entrata/schemas/entrata_endpoints.schema.json b/data-raw/src/entrata/schemas/entrata_endpoints.schema.json index 9e81ae8..2f4b8e2 100644 --- a/data-raw/src/entrata/schemas/entrata_endpoints.schema.json +++ b/data-raw/src/entrata/schemas/entrata_endpoints.schema.json @@ -1,30 +1,10 @@ { - "type": "object", - "properties": { - "endpoint": { - "type": "string", - "enum": [ - "status", - "applications", - "arcodes", - "arpayments", - "artransactions", - "communications", - "customers", - "financial", - "leads", - "leases", - "leasingcenter", - "maintenance", - "pricing", - "properties", - "pricing", - "propertyunits", - "queue", - "reports", - "vendors" - ] - } - }, - "required": ["endpoint"] + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "enum": ["status", "applications", "arcodes", "arpayments", "artransactions", "communications", "customers", "financial", "leads", "leases", "leasingcenter", "maintenance", "pricing", "properties", "pricing", "propertyunits", "queue", "reports", "vendors"] + } + }, + "required": "endpoint" } diff --git a/data-raw/src/entrata/schemas/entrata_parameters.schema.json b/data-raw/src/entrata/schemas/entrata_parameters.schema.json new file mode 100644 index 0000000..57389a5 --- /dev/null +++ b/data-raw/src/entrata/schemas/entrata_parameters.schema.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["getStatus", "getCompanyApplications", "sendApplicantGeneralDetails", "sendApplication", "sendApplicationAddOns", "sendApplicationEmployers", "sendApplicationPets", "sendApplicationVehicles", "updateApplication", "getArCodes", "getArPayments", "getArInvoices", "getLeaseArTransactions", "getMitsLeaseArTransactions", "sendLeaseArTransactionReversals", "sendLeaseArTransactions", "getMarketingPreferencePickList", "getMarketingPreferences", "getCustomers", "getCustomerTestimonials", "getTestimonialPickLists", "searchCustomers", "sendCustomerTestimonials", "updateCustomers", "updateCustomerTestimonials", "updatePropertyResponse", "getApCodes", "getBankAccounts", "getBudgetActuals", "getBudgets", "getFinancialPickList", "getGlTransactions", "getGlTrees", "getJobCategories", "getJobCostBudgets", "getJobs", "getTransactionTagLists", "markGlTransactionsExported", "sendBudgets", "sendJournalEntries", "updateBudgets", "applyQuote", "generateQuotes", "getLeadEvents", "getLeadPickLists", "getLeads", "getMitsLeads", "getQuotes", "sendLeads", "sendMitsLeads", "updateLeads", "cancelLease", "getEvictedLeases", "getExpiringLeases", "getLeaseDetails", "getLeaseDocuments", "getLeaseDocumentsList", "getLeasePickList", "getLeases", "getMitsCollections", "getMitsLeases", "getParcelAlerts", "getRentersInsurancePolicies", "moveInLease", "moveOutLease", "onNoticeLease", "sendLeaseActivities", "sendLeaseDocuments", "sendLeases", "sendRentersInsurancePolicies", "sendRoommateGroups", "sendScheduledCharges", "updateLease", "updateScheduledCharges", "getCallLogs", "getLeasingCenterPickLists", "getInspections", "getInspectionTemplates", "getWorkOrderPickLists", "getWorkOrders", "sendWorkOrders", "updateWorkOrders", "getPricingPicklists", "insertPricing", "sendBudgetedRent", "getAmenityReservations", "getCalendarAvailability", "getFloorPlans", "getPetTypes", "getPhoneNumber", "getProperties", "getPropertyAddOns", "getPropertyAnnouncements", "getPropertyPickLists", "getRentableItems", "getReservableAmenities", "getWebsites", "sendFloorplans", "sendRentableItems", "getAmenities", "getMitsPropertyUnits", "getPropertyUnits", "getSpecials", "getUnitsAvailabilityAndPricing", "getUnitTypes", "sendAmenities", "sendPropertyUnits", "updateAmenities", "getResponse", "getDependentFilter", "getReportData", "getReportInfo", "getReportList", "getInvoices", "getPoReceivingRecords", "getPurchaseOrders", "getTaxFormData", "getVendorLocations", "getVendorPickLists", "getVendors", "markInvoicesExported", "sendInvoices", "sendPurchaseOrders", "sendVendors", "updateInvoices", "updateVendors", "voidApPayments"] + }, + "version": { + "type": "string", + "enum": ["r1", "r2", "r3"] + }, + "params": { + "type": "string", + "enum": ["propertyId", "companyIdentificationTypeIds", "customerIds", "isAgreedToTermsOnly", "leaseStatusTypeIds", "accountingMethod", "budgetId", "glTreeId", "postMonthFrom", "postMonthTo", "budgetStatusTypeId", "glBookTypeIds", "budgetIds", "budgetStatusTypeIds", "fiscalYears", "leaseId", "includeAddOns", "includeCharge", "addedOnFromDate", "documentIds", "externalLeaseId", "fileTypesCode", "showDeletedFile", "applicationId", "buildingName", "customerId", "includeArTransactions", "includeLeaseHistory", "includeOtherIncomeLeases", "leaseExpiringDateFrom", "leaseExpiringDateTo", "leaseIds", "moveInDateFrom", "moveInDateTo", "moveOutDateFrom", "moveOutDateTo", "residentFriendlyMode", "scheduledArCodeIds", "unitNumber", "includeDisabledFloorPlans", "propertyFloorPlanIds", "usePropertyPreferences", "propertyIds", "propertyLookupCode", "showAllStatus", "addOnIds", "announcementIds", "rentableItemIds", "availableUnitsOnly", "includeDisabledUnits", "queueId", "serviceName", "filters", "reportName", "reportVersion", "dependentFilter", ""] + } + }, + "required": ["method", "version", "parameter"] +} diff --git a/data-raw/src/entrata/schemas/entrata_versions.schema.json b/data-raw/src/entrata/schemas/entrata_versions.schema.json index 9e0e7db..178ef22 100644 --- a/data-raw/src/entrata/schemas/entrata_versions.schema.json +++ b/data-raw/src/entrata/schemas/entrata_versions.schema.json @@ -1,149 +1,14 @@ { - "type": "object", - "properties": { - "method": { - "type": "string", - "enum": [ - "getStatus", - "getCompanyApplications", - "sendApplicantGeneralDetails", - "sendApplication", - "sendApplicationAddOns", - "sendApplicationEmployers", - "sendApplicationPets", - "sendApplicationVehicles", - "updateApplication", - "getArCodes", - "getArPayments", - "getArInvoices", - "getLeaseArTransactions", - "getMitsLeaseArTransactions", - "sendLeaseArTransactionReversals", - "sendLeaseArTransactions", - "getMarketingPreferencePickList", - "getMarketingPreferences", - "getCustomers", - "getCustomerTestimonials", - "getTestimonialPickLists", - "searchCustomers", - "sendCustomerTestimonials", - "updateCustomers", - "updateCustomerTestimonials", - "updatePropertyResponse", - "getApCodes", - "getBankAccounts", - "getBudgetActuals", - "getBudgets", - "getFinancialPickList", - "getGlTransactions", - "getGlTrees", - "getJobCategories", - "getJobCostBudgets", - "getJobs", - "getTransactionTagLists", - "markGlTransactionsExported", - "sendBudgets", - "sendJournalEntries", - "updateBudgets", - "applyQuote", - "generateQuotes", - "getLeadEvents", - "getLeadPickLists", - "getLeads", - "getMitsLeads", - "getQuotes", - "sendLeads", - "sendMitsLeads", - "updateLeads", - "cancelLease", - "getEvictedLeases", - "getExpiringLeases", - "getLeaseDetails", - "getLeaseDocuments", - "getLeaseDocumentsList", - "getLeasePickList", - "getLeases", - "getMitsCollections", - "getMitsLeases", - "getParcelAlerts", - "getRentersInsurancePolicies", - "moveInLease", - "moveOutLease", - "onNoticeLease", - "sendLeaseActivities", - "sendLeaseDocuments", - "sendLeases", - "sendRentersInsurancePolicies", - "sendRoommateGroups", - "sendScheduledCharges", - "updateLease", - "updateScheduledCharges", - "getCallLogs", - "getLeasingCenterPickLists", - "getInspections", - "getInspectionTemplates", - "getWorkOrderPickLists", - "getWorkOrders", - "sendWorkOrders", - "updateWorkOrders", - "getPricingPicklists", - "insertPricing", - "sendBudgetedRent", - "getAmenityReservations", - "getCalendarAvailability", - "getFloorPlans", - "getPetTypes", - "getPhoneNumber", - "getProperties", - "getPropertyAddOns", - "getPropertyAnnouncements", - "getPropertyPickLists", - "getRentableItems", - "getReservableAmenities", - "getWebsites", - "sendFloorplans", - "sendRentableItems", - "getAmenities", - "getMitsPropertyUnits", - "getPropertyUnits", - "getSpecials", - "getUnitsAvailabilityAndPricing", - "getUnitTypes", - "sendAmenities", - "sendPropertyUnits", - "updateAmenities", - "getResponse", - "getDependentFilter", - "getReportData", - "getReportInfo", - "getReportList", - "getInvoices", - "getPoReceivingRecords", - "getPurchaseOrders", - "getTaxFormData", - "getVendorLocations", - "getVendorPickLists", - "getVendors", - "markInvoicesExported", - "sendInvoices", - "sendPurchaseOrders", - "sendVendors", - "updateInvoices", - "updateVendors", - "voidApPayments" - ] - }, - "version": { - "type": "string", - "enum": [ - "r1", - "r2", - "r3" - ] - } + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": ["getStatus", "getCompanyApplications", "sendApplicantGeneralDetails", "sendApplication", "sendApplicationAddOns", "sendApplicationEmployers", "sendApplicationPets", "sendApplicationVehicles", "updateApplication", "getArCodes", "getArPayments", "getArInvoices", "getLeaseArTransactions", "getMitsLeaseArTransactions", "sendLeaseArTransactionReversals", "sendLeaseArTransactions", "getMarketingPreferencePickList", "getMarketingPreferences", "getCustomers", "getCustomerTestimonials", "getTestimonialPickLists", "searchCustomers", "sendCustomerTestimonials", "updateCustomers", "updateCustomerTestimonials", "updatePropertyResponse", "getApCodes", "getBankAccounts", "getBudgetActuals", "getBudgets", "getFinancialPickList", "getGlTransactions", "getGlTrees", "getJobCategories", "getJobCostBudgets", "getJobs", "getTransactionTagLists", "markGlTransactionsExported", "sendBudgets", "sendJournalEntries", "updateBudgets", "applyQuote", "generateQuotes", "getLeadEvents", "getLeadPickLists", "getLeads", "getMitsLeads", "getQuotes", "sendLeads", "sendMitsLeads", "updateLeads", "cancelLease", "getEvictedLeases", "getExpiringLeases", "getLeaseDetails", "getLeaseDocuments", "getLeaseDocumentsList", "getLeasePickList", "getLeases", "getMitsCollections", "getMitsLeases", "getParcelAlerts", "getRentersInsurancePolicies", "moveInLease", "moveOutLease", "onNoticeLease", "sendLeaseActivities", "sendLeaseDocuments", "sendLeases", "sendRentersInsurancePolicies", "sendRoommateGroups", "sendScheduledCharges", "updateLease", "updateScheduledCharges", "getCallLogs", "getLeasingCenterPickLists", "getInspections", "getInspectionTemplates", "getWorkOrderPickLists", "getWorkOrders", "sendWorkOrders", "updateWorkOrders", "getPricingPicklists", "insertPricing", "sendBudgetedRent", "getAmenityReservations", "getCalendarAvailability", "getFloorPlans", "getPetTypes", "getPhoneNumber", "getProperties", "getPropertyAddOns", "getPropertyAnnouncements", "getPropertyPickLists", "getRentableItems", "getReservableAmenities", "getWebsites", "sendFloorplans", "sendRentableItems", "getAmenities", "getMitsPropertyUnits", "getPropertyUnits", "getSpecials", "getUnitsAvailabilityAndPricing", "getUnitTypes", "sendAmenities", "sendPropertyUnits", "updateAmenities", "getResponse", "getDependentFilter", "getReportData", "getReportInfo", "getReportList", "getInvoices", "getPoReceivingRecords", "getPurchaseOrders", "getTaxFormData", "getVendorLocations", "getVendorPickLists", "getVendors", "markInvoicesExported", "sendInvoices", "sendPurchaseOrders", "sendVendors", "updateInvoices", "updateVendors", "voidApPayments"] }, - "required": [ - "method", - "version" - ] + "version": { + "type": "string", + "enum": ["r1", "r2", "r3"] + } + }, + "required": ["method", "version"] } diff --git a/data-raw/src/entrata/versions.R b/data-raw/src/entrata/versions.R index a727ee7..9e48d42 100644 --- a/data-raw/src/entrata/versions.R +++ b/data-raw/src/entrata/versions.R @@ -9,13 +9,43 @@ # all endpoint method versions are "r1" except for the following: -r2_methods <- c( +entrata_r2_methods <- c( "getLeases", "getLeaseDetails", "getReportInfo", "getDependentFilter" ) -r3_methods <- c( +entrata_r3_methods <- c( "getReportData" ) + + +# merge ------------------------------------------------------------------- + +if (!exists("entrata_methods")) { source("data-raw/src/entrata/methods.R") } + +# entrata_methods is a nested list where the first level object names are +# the endpoints and they contain a nested list of methods for that endpoint. +# we want to add the version to each method in each endpoint using the +# above lists (r1 by default, r2 for the methods in entrata_r2_methods, etc.) + +entrata_method_versions <- purrr::map2( + names(entrata_methods), + entrata_methods, + function(endpoint, endpoint_methods) { + endpoint_methods <- purrr::map(endpoint_methods, function(method) { + if (method %in% entrata_r2_methods) { + version <- "r2" + } else if (method %in% entrata_r3_methods) { + version <- "r3" + } else { + version <- "r1" + } + return(list(method = method, version = version)) + }) + return(endpoint_methods) + } +) + +names(entrata_method_versions) <- names(entrata_methods) diff --git a/data-raw/src/goals.R b/data-raw/src/goals.R new file mode 100644 index 0000000..f1ff496 --- /dev/null +++ b/data-raw/src/goals.R @@ -0,0 +1,37 @@ + +# ------------------------------------------------------------------------ +# +# Title : Goals +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + +goal_applies_to <- c( + "portfolio", + "property" +) + +goal_status + +goal_types <- c( + "pre_lease_percent", + "renewed_leases_percent", + "signed_leases_count", + "renewed_leases_count", + "rent_growth", + "occupancy", + "weekly_signed_leases", + "weekly_renewed_leases", + "weekly_lease_applications", + "other" + +) + +goals_table_names <- c( + "goal_id", + "goal_type", + "goal_name", + "goal_description", + +) diff --git a/data-raw/src/internal.R b/data-raw/src/internal.R deleted file mode 100644 index b5dbb6a..0000000 --- a/data-raw/src/internal.R +++ /dev/null @@ -1,3 +0,0 @@ -## code to prepare `internal` dataset goes here - -usethis::use_data(internal, overwrite = TRUE) diff --git a/data-raw/src/metadata.R b/data-raw/src/metadata.R index df2732f..94c748f 100644 --- a/data-raw/src/metadata.R +++ b/data-raw/src/metadata.R @@ -7,6 +7,57 @@ # # ------------------------------------------------------------------------ +metadata <- list( + labels = list( + title = "GMH Data Hub", + subtitle = "Data Analysis and Reporting" + ), + validation = list( + required_fields = c("properties", "reports"), + numeric_ranges = list( + age = c(0, 120), + weight = c(0, 1000), + score = c(0, 100) + ) + ), + defaults = list( + page_size = 10, + chart_height = 400, + table_height = 400 + ) +) + +app_metadata <- list( + # App configuration + config = list( + app_name = "My Shiny App", + version = "1.0.0", + description = "App description", + authors = c("Author 1", "Author 2") + ), + + # UI elements metadata + ui_elements = list( + labels = list( + title = "App Title", + subtitle = "Subtitle" + ), + input_choices = list( + colors = c("Red", "Blue", "Green"), + sizes = c("Small", "Medium", "Large") + ) + ), + + # Validation rules + validation = list( + required_fields = c("name", "email"), + numeric_ranges = list( + age = c(0, 120), + score = c(0, 100) + ) + ) +) + source("data-raw/src/properties.R") # dictionary -------------------------------------------------------------- @@ -15,26 +66,47 @@ dictionary <- list() # gmh_info ---------------------------------------------------------------- -gmh_info <- list() +client_info <- list( + name = "GMH Communities", + url = "https://gmhcommunities.com", + logo = "www/img/logos/gmh-logo.svg", + symbol = "www/img/icons/gmh-icon.png" +) # noclocks_info ----------------------------------------------------------- -noclocks_info <- list() +developer_info <- list( + name = "No Clocks, LLC", + url = "https://noclocks.dev", + logo = "www/img/logos/noclocks-logo.svg", + symbol = "www/img/icons/noclocks-icon-circular.png" +) # entrata_info ------------------------------------------------------------ -entrata_info <- list() +entrata_info <- list( + name = "Entrata", + url = "https://gmhcommunities.entrata.com/api/v1/documentation", + logo = "www/img/logos/entrata-logo.png", + symbol = NULL +) # app_info ---------------------------------------------------------------- -app_info <- list() +app_info <- list( + name = "GMH Data Hub", + version = "1.0", + logo = "www/img/logos/app-logo.svg", + symbol = "www/img/icons/app-icon.webp", + repo_url = "https://github.com/noclocks/gmhdatahub", + docs_url = "https://docs.noclocks.dev/gmhdatahub" +) # input_choices ------------------------------------------------------------- -input_choices <- list( - portfolios = c('GMH', '', 'Entrata'), - properties = tibble::deframe(properties), # names = ids, values = property names - +app_choices <- list( + portfolios = c(), + properties = c() #tibble::deframe(properties) # names = ids, values = property names ) @@ -42,12 +114,12 @@ input_choices <- list( app_defaults <- list( picker_options = list( - `actions-box` = TRUE, - `live-search` = TRUE, - `live-search-normalize` = TRUE, - `live-search-placeholder` = 'Search...', - `selected-text-format` = 'count > 3', - `count-selected-text` = 'Properties Selected' + "actions-box" = TRUE, + "live-search" = TRUE, + "live-search-normalize" = TRUE, + "live-search-placeholder" = "Search...", + "selected-text-format" = "count > 3", + "count-selected-text" = "Properties Selected" ) ) @@ -55,13 +127,28 @@ app_defaults <- list( # output ------------------------------------------------------------------ metadata <- list( - dictionary = dictionary, - gmh_info = gmh_info, - noclocks_info = noclocks_info, + # dictionary = dictionary, + client_info = client_info, + developer_info = developer_info, entrata_info = entrata_info, app_info = app_info, app_choices = app_choices, app_defaults = app_defaults ) -usethis::use_data(metadata, internal = TRUE, overwrite = TRUE) +# fs::file_delete("R/sysdata.rda") +# save(metadata, file = "R/sysdata.rda") +usethis::use_data( + client_info, + developer_info, + entrata_info, + app_info, + app_choices, + app_defaults, + internal = TRUE, + overwrite = TRUE, + compress = "bzip2", + version = 3, + ascii = FALSE +) + diff --git a/data-raw/src/portfolios.R b/data-raw/src/portfolios.R index 8b3195a..cf14c34 100644 --- a/data-raw/src/portfolios.R +++ b/data-raw/src/portfolios.R @@ -7,6 +7,27 @@ # # ------------------------------------------------------------------------ +portfolio_names <- c( + "CRG", + "Medistar", + "ASC", + "Principal", + "CBRE", + "All GMH Properties" +) + +portfolio_types <- c( + "Equity Partner", + "Owner", + "Equity Partner", + "Equity Partner", + "Equity Partner", + "Property Type" +) + + + + source("data-raw/src/properties.R") portfolios <- tibble::tribble( @@ -59,3 +80,48 @@ portfolios <- tibble::tribble( property_id, property_name ) + +portfolio_assignments <- tibble::tibble( + portfolio = rep( + c("AGC", "CBRE", "CRG", "Medistar", "Principal", "GMH"), + c(10L, 2L, 1L, 1L, 4L, 19L) + ), + property_id = c( + 739085, 739085, 739079, 739080, 739084, 641240, 676055, 535270, 676054, + 833617, 1143679, 952515, 1197887, 0, 518044, 518041, 518042, 518046, 1311849, + 0, 1197887, 1143679, 739085, 739085, 739079, 739080, 739084, 641240, 676055, + 518044, 952515, 518041, 535270, 518042, 676054, 518046, 833617 + ), + property_name = c( + "Campustown 1008 S. 4th", "1047 Commonwealth Avenue", + "Campustown 307 E. Daniel", "Campustown 501 S. 6th", "Campustown 908 S. 1st", + "Academy 65", "Academy Lincoln", "The Academy Chorro", "The Academy Palomar", + "The Dean Campustown", "Torre", "SOVA", "The Dean Reno", "Life Tower", + "Shortbread Lofts", "The Academy at Frisco", "The Academy on Charles", + "The Rise at Northgate", "The Venue at North Campus", "Life Tower", + "The Dean Reno", "Torre", "Campustown 1008 S. 4th", + "1047 Commonwealth Avenue", "Campustown 307 E. Daniel", + "Campustown 501 S. 6th", "Campustown 908 S. 1st", "Academy 65", + "Academy Lincoln", "Shortbread Lofts", "SOVA", "The Academy at Frisco", + "The Academy Chorro", "The Academy on Charles", "The Academy Palomar", + "The Rise at Northgate", "The Dean Campustown" + ), +) |> + structure( + spec = list( + cols = list( + portfolio = list() |> + structure(class = c("collector_character", "collector")), + property_id = list() |> + structure(class = c("collector_double", "collector")), + property_name = list() |> + structure(class = c("collector_character", "collector")) + ), + default = list() |> + structure(class = c("collector_guess", "collector")), + delim = "," + ) |> + structure(class = "col_spec"), + problems = constructive::.xptr("000000802B74F0C0"), + class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame") + ) diff --git a/data-raw/src/properties.R b/data-raw/src/properties.R index 92d6178..f56b9c9 100644 --- a/data-raw/src/properties.R +++ b/data-raw/src/properties.R @@ -7,9 +7,38 @@ # # ------------------------------------------------------------------------ +property_ids <- c( + +) + +property_names <- c( + +) + +entrata_property_names <- c( + +) + +name_diffs <- tibble::tibble( + gmh_property_name = c( + "Campustown 1008 S. 4th", + "Campustown 307 E. Daniel", + "Campustown 501 S. 6th", + "Campustown 908 S. 1st", + "The Venue at North Campus" + ), + entrata_property_name = c( + "1008 S. 4th", + "307 E. Daniel", + "501 S. 6th", + "908 S. 1st", + "Venue at North Campus" + ) +) + properties <- tibble::tribble( - ~property_id, ~property_name_entrata, property_name_gmh, - 739076L, "1008 S. 4th", "" + ~property_id, ~property_name_entrata, + 739076L, "1008 S. 4th", 739085L, "1047 Commonwealth Avenue", 739079L, "307 E. Daniel", 739080L, "501 S. 6th", diff --git a/data-raw/working/assignments.csv b/data-raw/working/assignments.csv new file mode 100644 index 0000000..385c724 --- /dev/null +++ b/data-raw/working/assignments.csv @@ -0,0 +1,38 @@ +"","portfolio","property_id","property_name" +"1","AGC",739085,"Campustown 1008 S. 4th" +"2","AGC",739085,"1047 Commonwealth Avenue" +"3","AGC",739079,"Campustown 307 E. Daniel" +"4","AGC",739080,"Campustown 501 S. 6th" +"5","AGC",739084,"Campustown 908 S. 1st" +"6","AGC",641240,"Academy 65" +"7","AGC",676055,"Academy Lincoln" +"8","AGC",535270,"The Academy Chorro" +"9","AGC",676054,"The Academy Palomar" +"10","AGC",833617,"The Dean Campustown" +"11","CBRE",1143679,"Torre" +"12","CBRE",952515,"SOVA" +"13","CRG",1197887,"The Dean Reno" +"14","Medistar",0,"Life Tower" +"15","Principal",518044,"Shortbread Lofts" +"16","Principal",518041,"The Academy at Frisco" +"17","Principal",518042,"The Academy on Charles" +"18","Principal",518046,"The Rise at Northgate" +"19","GMH",1311849,"The Venue at North Campus" +"20","GMH",0,"Life Tower" +"21","GMH",1197887,"The Dean Reno" +"22","GMH",1143679,"Torre" +"23","GMH",739085,"Campustown 1008 S. 4th" +"24","GMH",739085,"1047 Commonwealth Avenue" +"25","GMH",739079,"Campustown 307 E. Daniel" +"26","GMH",739080,"Campustown 501 S. 6th" +"27","GMH",739084,"Campustown 908 S. 1st" +"28","GMH",641240,"Academy 65" +"29","GMH",676055,"Academy Lincoln" +"30","GMH",518044,"Shortbread Lofts" +"31","GMH",952515,"SOVA" +"32","GMH",518041,"The Academy at Frisco" +"33","GMH",535270,"The Academy Chorro" +"34","GMH",518042,"The Academy on Charles" +"35","GMH",676054,"The Academy Palomar" +"36","GMH",518046,"The Rise at Northgate" +"37","GMH",833617,"The Dean Campustown" diff --git a/data-raw/working/charge_codes.csv b/data-raw/working/charge_codes.csv new file mode 100644 index 0000000..c89ea5b --- /dev/null +++ b/data-raw/working/charge_codes.csv @@ -0,0 +1,34 @@ +"","charge_code_id","charge_code","charge_type","charge_frequency","related_charge_code_id","charge_usage" +"1",148134,"Garage Parking","other","Monthly",148134,NA +"2",147881,"Base Rent","Base Rent","Monthly",147881,NA +"3",148902,"GMH Communities Covered","other","Monthly",148902,NA +"4",148096,"Uncovered Garage Parking","other","Monthly",148096,NA +"5",149017,"Deferred Rent - June 2024","Security Deposit","One-Time",149017,NA +"6",149015,"Deferred Rent - July 2024","Security Deposit","One-Time",149015,NA +"7",149009,"Group New Lease Gift Card","other","Monthly",149009,NA +"8",149010,"Group New Lease Gift Card Adjustment","other","Monthly",149010,NA +"9",149011,"Group Renewal Gift Card","other","Monthly",149011,NA +"10",149012,"Group Renewal Gift Card Adjustment","other","Monthly",149012,NA +"11",148135,"Model / Office","other","Monthly",148135,NA +"12",149011,"Group Renewal Gift Card","other","One-Time",149011,NA +"13",149012,"Group Renewal Gift Card Adjustment","other","One-Time",149012,NA +"14",148097,"Lot Parking","other","Monthly",148097,NA +"15",148453,"Pet Rent","other","Monthly",148453,NA +"16",149017,"Deferred Rent - June 2024","Security Deposit","Monthly",149017,NA +"17",149015,"Deferred Rent - July 2024","Security Deposit","Monthly",149015,NA +"18",148656,"Deposit","Security Deposit","One-Time",148656,NA +"19",147884,"Security Deposit","Security Deposit","One-Time",147884,NA +"20",147893,"Covered Parking","other","Monthly",147893,NA +"21",148820,"Leasing Special - New","other","Monthly",148820,"Concession" +"22",148111,"Amenity Fee","other","Monthly",148111,NA +"23",147897,"Transfer Fees","other","One-Time",147897,NA +"24",148995,"Renewal Gift Card","other","Monthly",148995,"Concession" +"25",148996,"Renewal Gift Card Adjustment","other","Monthly",148996,NA +"26",148993,"New Lease Gift Card","other","Monthly",148993,NA +"27",148994,"New Lease Gift Card Adjustment","other","Monthly",148994,NA +"28",148253,"Balcony Premium","Base Rent","Monthly",148253,NA +"29",148554,"View Discount","Base Rent","Monthly",148554,NA +"30",148511,"Location Discount","Base Rent","Monthly",148511,NA +"31",148258,"Pool View Premium","Base Rent","Monthly",148258,NA +"32",148656,"Deposit","Security Deposit","Monthly",148656,NA +"33",148109,"Pet Fees","other","One-Time",148109,NA diff --git a/data-raw/working/investment_partners.csv b/data-raw/working/investment_partners.csv new file mode 100644 index 0000000..b1f06f3 --- /dev/null +++ b/data-raw/working/investment_partners.csv @@ -0,0 +1,27 @@ +property_name,investment_partner +Torre,CBRE +SOVA,CBRE +Venue at North Campus,CBRE +1047 Commonwealth Avenue,AGC +307 E. Daniel,AGC +501 S. 6th,AGC +908 S. 1st,AGC +1008 S. 4th,AGC +Academy 65,AGC +The Academy on Charles,JHU +Academy Chorro,AGC +The Academy at Frisco,AEW +Academy Lincoln,AGC +Academy Palomar,AGC +ANOVA uCity Square,CBRE +The Caswell at Runnymeade,AEW +Central Station,NA +Courts at Spring Mill Station,Principal +The Dean Campustown,AGC +The Dean Reno,CRG and Canyon +Life Tower,Medistar Student Housing LLC +The Pendleton,CBRE +The Rise at Northgate,AEW +Shortbread Lofts,Principal +Station Nine,Principal +Yards at Malvern,AEW diff --git a/data-raw/working/portfolios.csv b/data-raw/working/portfolios.csv new file mode 100644 index 0000000..0206c34 --- /dev/null +++ b/data-raw/working/portfolios.csv @@ -0,0 +1,7 @@ +"","id","name","type","full_name","description","website","logo_url","icon_url" +"1",1,"All GMH Properties","Property Type","All Properties","All Properties","https://gmhcommunities.com","https://cdn.brandfetch.io/gmhcommunities.com/logo","https://cdn.brandfetch.io/gmhcommunities.com/icon" +"2",2,"AGC","Equity Partner","AGC Equity Partners","AGC Equity Partners is a global alternative asset investment firm operating from offices in London and the Middle East. AGC Equity Partners invests across alternative assets, including real estate, infrastructure, technology, growth, private equity, among others.","https://agcequitypartners.com/","https://agcequitypartners.com/wp-content/uploads/2024/03/AGC_Logo_Inline_Mar24-1.png","https://cdn.brandfetch.io/agcequitypartners.com/logo" +"3",3,"CBRE","Equity Partner","CBRE Investment Management","As a leading real assets investment management firm, we strive to realize potential in investments and people in innovative ways, every day. We do so by creating sustainable investment solutions of tomorrow so our clients, people and communities thrive.","https://www.cbre.com","https://cdn.brandfetch.io/cbre.com/logo","https://cdn.brandfetch.io/cbre.com/icon" +"4",4,"CRG","Equity Partner","CRG Real Estate Solutions","CRG is a recognized leader in development and investment throughout North America.","https://www.realcrg.com","https://cdn.brandfetch.io/realcrg.com/logo","https://cdn.brandfetch.io/realcrg.com/icon" +"5",5,"Medistar","Owner","Medistar Corporation","Medistar Corporation, a privately held real estate investment and development firm, boasts a remarkable 50-year history of innovation. With an unwavering focus on execution and a proven history of outstanding performance, Medistar stands as a testament to enduring excellence.","https://www.medistarcorp.com/","https://cdn.brandfetch.io/medistarcorp.com/logo","https://cdn.brandfetch.io/medistarcorp.com/icon" +"6",6,"Principal","Equity Partner","Principal Asset Management","Principal Asset Management","https://www.principalam.com/us/investment-teams/principal-real-estate","https://asset.brandfetch.io/id8-eJ8GSN/idLtuKTQo1.png","https://asset.brandfetch.io/id8-eJ8GSN/idPVfmaU8b.svg" diff --git a/data-raw/working/properties.csv b/data-raw/working/properties.csv new file mode 100644 index 0000000..9ffdc2c --- /dev/null +++ b/data-raw/working/properties.csv @@ -0,0 +1,73 @@ +"","file","property_name","entrata_property_name","property_address","number_of_floorplans","property_units","property_beds","number_of_signed_renewals_current_term","number_of_signed_new_leases_current_term","number_of_signed_leases_current_term","current_pre_lease","current_pre_lease_approved_only","benchmark_pre_lease_goal","current_term_weekly_goal","number_of_applications_completed_this_week","number_of_approved_leases_current_term","number_of_current_term_pricing_tiers","number_of_current_term_weekly_stats","number_of_delinquent_accounts","number_of_floorplans_tier_mismatches","number_of_leads_previous_week","number_of_leads_this_week","number_of_leases_approved_via_guarantor_current_term","number_of_leases_approved_via_international_student_criteria_current_term","number_of_leases_approved_via_self_approval_current_term","number_of_leases_approved_via_third_party_product_current_term","number_of_leases_pending_0_7_days_current_term","number_of_leases_pending_15_30_days_current_term","number_of_leases_pending_30_days","number_of_leases_pending_8_14_days_current_term","number_of_leases_pending_current_term","number_of_model_bed_leases_current_term","number_of_new_leases_last_term_ytd","number_of_renewals_last_term_ytd","number_of_residents_with_rents","number_of_signed_leases_last_term","number_of_signed_leases_last_term_ytd","number_of_tours_given_this_week","number_of_unapproved_leases_current_term","number_of_unvalidated_leases_39","number_of_unvalidated_leases_40","number_of_weekly_stats","add_benchmark","add_floorplan","add_lease","add_monthly_collection","add_occupancy_projection","add_portfolio_assignment","add_special","add_weekly_stat","applications_total_calls","applications_total_calls_reporting_week","applications_total_emails","applications_total_emails_reporting_week","applications_total_online","applications_total_online_reporting_week","applications_total_open_calls","applications_total_open_emails","applications_total_open_online","applications_total_open_others","applications_total_open_visit_tours","applications_total_others","applications_total_others_reporting_week","applications_total_visit_tours","applications_total_visit_tours_reporting_week","average_base_installment_rate_last_term","average_base_installment_rate_last_term_ytd","average_base_installment_rate_trending","average_base_installment_rent_current_term","average_budgeted_installment_rate","average_captured_effective_rate","average_days_pending","average_effective_installment_rate_last_term","average_effective_installment_rate_last_term_ytd","beds_remaining","benchmark_concession_budget","benchmark_concession_gauge","benchmark_concession_variance","benchmark_concessions_percentage","benchmark_gift_card_budget","benchmark_gift_card_gauge","benchmark_gift_card_percentage","benchmark_gift_card_variance","benchmark_other_incentive_budget","benchmark_other_incentive_gauge","benchmark_other_incentive_percentage","benchmark_other_incentive_variance","benchmark_pre_lease_goal_count","benchmark_renewal_goal","benchmark_rent_growth_goal","benchmarks","charge_for_location_premium","charge_for_parking_premium","charge_for_view_premium","city_state","cost_basis","cost_basis_bed","cost_basis_sf","cost_basis_unit","create_excel_wpo","create_pdf_wpo","create_pdf_wpo_no_stream","create_xl_sheet","create_xl_sheet_stream_back","create_xl_sheet2","current_date","current_leases","current_occupancy","current_pre_lease_vacancy_loss","current_term_number_of_signed_leases_vs_last_term","current_term_goal_pre_lease","current_term_goals","current_term_pre_lease_vs_last_term","current_term_pre_lease_vs_prior_term_num","current_week_end","current_week_number","current_week_start","current_weekly_stat","date_acquired","date_cancelled","date_created","date_modified","day_friday_new_leases","day_friday_renewals","day_friday_total_leases","day_monday_new_leases","day_monday_renewals","day_monday_total_leases","day_saturday_new_leases","day_saturday_renewals","day_saturday_total_leases","day_sunday_new_leases","day_sunday_renewals","day_sunday_total_leases","day_thursday_new_leases","day_thursday_renewals","day_thursday_total_leases","day_today_new_leases","day_today_renewals","day_today_total_leases","day_tuesday_new_leases","day_tuesday_renewals","day_tuesday_total_leases","day_wednesday_new_leases","day_wednesday_renewals","day_wednesday_total_leases","delinquencies2","effective_rate_growth_ytd_num","effective_rate_growth_ytd_vs_last_year_final_num","entrata_id","entrata_property_datas","equity_partner","equity_partner_name","floorplans","gain_loss_to_lease","gain_loss_to_lease_num","generate_pdf_report","gift_card_gauge","goals_number_of_signed_leases_vs_goal","goals_current_term_pre_lease_vs_goal","hybrid_future_leases","installment_rate_growth_trending_vs_budget","installment_rate_growth_trending_vs_budget_num","installment_rate_growth_trending_vs_last_term","installment_rate_growth_trending_vs_last_term_num","installment_rate_growth_ytd","installment_rate_growth_ytd_num","installment_rate_growth_ytd_vs_last_year_final_num","last_modified_by","last_term_corresponding_date","last_term_current_week_ending_date","last_term_current_weekly_stat","last_term_pre_lease_ytd","leads","leads_calls_today_1","leads_calls_today_2","leads_calls_today_3","leads_calls_today_4","leads_calls_today_5","leads_calls_today_6","leads_calls_today_7","leads_emails_today_1","leads_emails_today_2","leads_emails_today_3","leads_emails_today_4","leads_emails_today_5","leads_emails_today_6","leads_emails_today_7","leads_online_today_1","leads_online_today_2","leads_online_today_3","leads_online_today_4","leads_online_today_5","leads_online_today_6","leads_online_today_7","leads_others_today_1","leads_others_today_2","leads_others_today_3","leads_others_today_4","leads_others_today_5","leads_others_today_6","leads_others_today_7","leads_total_approved_applications","leads_total_calls","leads_total_calls_reporting_week","leads_total_completed_applications","leads_total_completed_guest_cards","leads_total_emails","leads_total_emails_reporting_week","leads_total_online","leads_total_online_reporting_week","leads_total_open_calls","leads_total_open_emails","leads_total_open_online","leads_total_open_others","leads_total_open_visit_tours","leads_total_others","leads_total_others_reporting_week","leads_total_partially_completed_applications","leads_total_started_applications","leads_total_started_leases","leads_total_visit_tours","leads_total_visit_tours_reporting_week","leads_visit_tours_today_1","leads_visit_tours_today_2","leads_visit_tours_today_3","leads_visit_tours_today_4","leads_visit_tours_today_5","leads_visit_tours_today_6","leads_visit_tours_today_7","leases","leasing_season_ending_week_number","leasing_season_week_ending_date","leasing_type","record_id_number","link_owner","live","model_beds","month_0_total_number_of_current_lease_ends","month_0_total_number_of_current_lease_ends_with_renewal","month_0_total_budgeted_occupancy","month_0_total_budgeted_occupied_beds","month_0_total_leases_needed_to_meet_budget","month_0_total_projected_move_ins","month_0_total_projected_move_outs","month_0_total_projected_occupancy","month_0_total_projected_renewal_goal","month_0_total_projected_renewals","month_0_total_running_projection_occupancy","month_0_total_running_projection_occupancy_through_last_month","month_0_total_starting_occupancy","month_1_total_number_of_current_lease_ends","month_1_total_number_of_current_lease_ends_with_renewal","month_1_total_budgeted_occupancy","month_1_total_budgeted_occupied_beds","month_1_total_leases_needed_to_meet_budget","month_1_total_projected_move_ins","month_1_total_projected_move_outs","month_1_total_projected_occupancy","month_1_total_projected_renewal_goal","month_1_total_projected_renewals","month_1_total_running_projection_occupancy","month_1_total_running_projection_occupancy_through_last_month","month_1_total_starting_occupancy","month_10_total_number_of_current_lease_ends","month_10_total_number_of_current_lease_ends_with_renewal","month_10_total_budgeted_occupancy","month_10_total_budgeted_occupied_beds","month_10_total_leases_needed_to_meet_budget","month_10_total_projected_move_ins","month_10_total_projected_move_outs","month_10_total_projected_occupancy","month_10_total_projected_renewal_goal","month_10_total_projected_renewals","month_10_total_running_projection_occupancy","month_10_total_running_projection_occupancy_through_last_month","month_10_total_starting_occupancy","month_11_total_number_of_current_lease_ends","month_11_total_number_of_current_lease_ends_with_renewal","month_11_total_budgeted_occupancy","month_11_total_budgeted_occupied_beds","month_11_total_leases_needed_to_meet_budget","month_11_total_projected_move_ins","month_11_total_projected_move_outs","month_11_total_projected_occupancy","month_11_total_projected_renewal_goal","month_11_total_projected_renewals","month_11_total_running_projection_occupancy","month_11_total_running_projection_occupancy_through_last_month","month_11_total_starting_occupancy","month_12_total_number_of_current_lease_ends","month_12_total_number_of_current_lease_ends_with_renewal","month_12_total_budgeted_occupancy","month_12_total_budgeted_occupied_beds","month_12_total_leases_needed_to_meet_budget","month_12_total_projected_move_ins","month_12_total_projected_move_outs","month_12_total_projected_occupancy","month_12_total_projected_renewal_goal","month_12_total_projected_renewals","month_12_total_running_projection_occupancy","month_12_total_running_projection_occupancy_through_last_month","month_12_total_starting_occupancy","month_2_total_number_of_current_lease_ends","month_2_total_number_of_current_lease_ends_with_renewal","month_2_total_budgeted_occupancy","month_2_total_budgeted_occupied_beds","month_2_total_leases_needed_to_meet_budget","month_2_total_projected_move_ins","month_2_total_projected_move_outs","month_2_total_projected_occupancy","month_2_total_projected_renewal_goal","month_2_total_projected_renewals","month_2_total_running_projection_occupancy","month_2_total_running_projection_occupancy_through_last_month","month_2_total_starting_occupancy","month_3_total_number_of_current_lease_ends","month_3_total_number_of_current_lease_ends_with_renewal","month_3_total_budgeted_occupancy","month_3_total_budgeted_occupied_beds","month_3_total_leases_needed_to_meet_budget","month_3_total_projected_move_ins","month_3_total_projected_move_outs","month_3_total_projected_occupancy","month_3_total_projected_renewal_goal","month_3_total_projected_renewals","month_3_total_running_projection_occupancy","month_3_total_running_projection_occupancy_through_last_month","month_3_total_starting_occupancy","month_4_total_number_of_current_lease_ends","month_4_total_number_of_current_lease_ends_with_renewal","month_4_total_budgeted_occupancy","month_4_total_budgeted_occupied_beds","month_4_total_leases_needed_to_meet_budget","month_4_total_projected_move_ins","month_4_total_projected_move_outs","month_4_total_projected_occupancy","month_4_total_projected_renewal_goal","month_4_total_projected_renewals","month_4_total_running_projection_occupancy","month_4_total_running_projection_occupancy_through_last_month","month_4_total_starting_occupancy","month_5_total_number_of_current_lease_ends","month_5_total_number_of_current_lease_ends_with_renewal","month_5_total_budgeted_occupancy","month_5_total_budgeted_occupied_beds","month_5_total_leases_needed_to_meet_budget","month_5_total_projected_move_ins","month_5_total_projected_move_outs","month_5_total_projected_occupancy","month_5_total_projected_renewal_goal","month_5_total_projected_renewals","month_5_total_running_projection_occupancy","month_5_total_running_projection_occupancy_through_last_month","month_5_total_starting_occupancy","month_6_total_number_of_current_lease_ends","month_6_total_number_of_current_lease_ends_with_renewal","month_6_total_budgeted_occupancy","month_6_total_budgeted_occupied_beds","month_6_total_leases_needed_to_meet_budget","month_6_total_projected_move_ins","month_6_total_projected_move_outs","month_6_total_projected_occupancy","month_6_total_projected_renewal_goal","month_6_total_projected_renewals","month_6_total_running_projection_occupancy","month_6_total_running_projection_occupancy_through_last_month","month_6_total_starting_occupancy","month_7_total_number_of_current_lease_ends","month_7_total_number_of_current_lease_ends_with_renewal","month_7_total_budgeted_occupancy","month_7_total_budgeted_occupied_beds","month_7_total_leases_needed_to_meet_budget","month_7_total_projected_move_ins","month_7_total_projected_move_outs","month_7_total_projected_occupancy","month_7_total_projected_renewal_goal","month_7_total_projected_renewals","month_7_total_running_projection_occupancy","month_7_total_running_projection_occupancy_through_last_month","month_7_total_starting_occupancy","month_8_total_number_of_current_lease_ends","month_8_total_number_of_current_lease_ends_with_renewal","month_8_total_budgeted_occupancy","month_8_total_budgeted_occupied_beds","month_8_total_leases_needed_to_meet_budget","month_8_total_projected_move_ins","month_8_total_projected_move_outs","month_8_total_projected_occupancy","month_8_total_projected_renewal_goal","month_8_total_projected_renewals","month_8_total_running_projection_occupancy","month_8_total_running_projection_occupancy_through_last_month","month_8_total_starting_occupancy","month_9_total_number_of_current_lease_ends","month_9_total_number_of_current_lease_ends_with_renewal","month_9_total_budgeted_occupancy","month_9_total_budgeted_occupied_beds","month_9_total_leases_needed_to_meet_budget","month_9_total_projected_move_ins","month_9_total_projected_move_outs","month_9_total_projected_occupancy","month_9_total_projected_renewal_goal","month_9_total_projected_renewals","month_9_total_running_projection_occupancy","month_9_total_running_projection_occupancy_through_last_month","month_9_total_starting_occupancy","monthly_collections","new_create_excel_wpo","occupancy_projections","parking_spaces","pending_pre_lease","percentage_of_billings_paid","portfolio_assignments","pre_lease_gained_previous_7_days","prior_2_week_end","prior_4_week_end","prior_term_leases_signed_this_week","prior_term_new_leases_signed_this_week","prior_term_renewals_signed_this_week","property_address_city","property_address_country","property_address_postal_code","property_address_state_region","property_address_street_1","property_address_street_2","prior_week_end","property_access","property_logo","property_manager","regional_access","regional_manager","related_formatted_output","renewal_percentage","rent_roll_rents","signed_leases_new_lease_percentage","signed_leases_renewal_percentage","specials","sqft_residential","sqft_retail","sqft_total","today_1","today_1_day_name","today_1_new_leases","today_1_renewals","today_2","today_2_day_name","today_2_new_leases","today_2_renewals","today_3","today_3_day_name","today_3_new_leases","today_3_renewals","today_4","today_4_day_name","today_4_new_leases","today_4_renewals","today_5","today_5_day_name","today_5_new_leases","today_5_renewals","today_6","today_6_day_name","today_6_new_leases","today_6_renewals","today_7","today_7_day_name","today_7_new_leases","today_7_renewals","total_beds","total_billings_collected","total_budget_installment_amount","total_budgeted_installment_amount_with_premiums","total_budgeted_premiums","total_captured_effective_installments","total_captured_effective_installments_last_term","total_captured_effective_installments_last_term_ytd","total_captured_installments","total_captured_installments_last_term","total_captured_installments_last_term_ytd","total_captured_pre_lease_rents","total_captured_premiums","x_dnu_total_committed_gift_card_amount","total_committed_other_incentive_amount","specials_total_committed_rent_concessions","total_entrata_beds","total_excluded_beds","total_model_beds","total_occupied_beds","total_rate_sheet_beds","total_remaining_potential_installments","total_remaining_premiums","total_scheduled_billings","total_trending_installments","total_unpaid_billings","trending_total_installments_with_premiums","upload_historical_pre_lease","upload_prior_term_new_leases","upload_prior_term_renewals","vintage_reno","week_number_of_leases_signed_previous_7_days","week_number_of_leases_signed_this_week","week_number_of_new_leases_signed_previous_7_days","week_number_of_new_leases_signed_this_week","week_number_of_renewals_signed_previous_7_days","week_number_of_renewals_signed_this_week","weekly_leases_needed_to_achieve_100_percent_at_at_custom_season_end","weekly_leases_needed_to_achieve_100_percent_at_week_52","weekly_leases_needed_to_achieve_90_percent_at_custom_season_end","weekly_leases_needed_to_achieve_90_percent_at_week_52","weekly_leases_needed_to_achieve_95_percent_at_at_custom_season_end","weekly_leases_needed_to_achieve_95_percent_at_week_52","weekly_leases_needed_to_achieve_goal_at_custom_season_end","weekly_pre_lease_gained","weekly_stats","x_current_term","x_day_1_of_week_monday","x_day_2_of_week_tuesday","x_day_3_of_week_wednesday","x_day_4_of_week_thursday","x_day_5_of_week_friday","x_day_6_of_week_saturday","x_day_7_of_week_sunday","xl_doc_date","xl_doc_date_email","xl_doc_date2","xl_document","xl_document2","x_last_term","x_last_term_ytd_date","x_monthly_collection_key","x_month_year","x_next_term","x_projected_occupancy_month_0","x_projected_occupancy_month_1","x_projected_occupancy_month_10","x_projected_occupancy_month_11","x_projected_occupancy_month_12","x_projected_occupancy_month_2","x_projected_occupancy_month_3","x_projected_occupancy_month_4","x_projected_occupancy_month_5","x_projected_occupancy_month_6","x_projected_occupancy_month_7","x_projected_occupancy_month_8","x_projected_occupancy_month_9","x_query_entrata_beds","x_query_entrata_leases","x_query_occupied_beds","x_system_average_days_pending","x_system_case_builder","x_system_last_term_current_week_ending_date_text","x_system_total_excluded_beds","x_system_wpo_delivery_email","x_weekly_stat_key","z_dynamic_gift_card_amount","total_concessions_committed","entrata_occupancy_mismatch","entrata_bed_cout_mismatch","entrata_lease_count_mismatch","total_gift_card_amount_committed","z_total_z_manual_effective_total","z_total_effective_rate_total_beds","z_total_rent_rate_total_beds","z_total_z_manual_rent_total","z_manual_ly_effective","z_manual_ly_rate","report_sort_order","property_type","client_id","control_id","entrata_floorplan_type","related_generation","leasing_portfolio","week_number_4_weeks_ago" +"1","data-raw/working/GMH/CSV/Properties.csv","1047 Commonwealth Avenue","1047 Commonwealth Avenue","1047 Commonwealth Avenue, Boston, Massachusetts 02215",12,183,183,76,84,160,"87.431693989071%","87.431693989071%",NA,0,0,160,0,56,0,11,NA,0,160,0,0,0,0,0,0,0,0,0,99,82,180,181,181,0,0,162,162,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=2&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=2&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=2&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$2621.6298342541","$2621.6298342541",NA,"$2817.80625","$1999.6612021858","$2817.80625",NA,"$2621.6298342541","$2621.6298342541",23,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,2,"no","no","no","Boston, Massachusetts","$75,639,102.76","$346,968.3612844","$1,188.5839083566","$413,328.43038251","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=2&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=1047 Commonwealth Avenue - WPO - 09-03-2024&dbid=bq5hz7i53&msid=2&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=1047 Commonwealth Avenue - WPO - 09-03-2024&dbid=bq5hz7i53&msid=2&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=2&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",2,"98.360655737705%",NA,"
-21
","100%",183,"
-11.5%
","87.431693989071%","09-05-2024",53,"09-02-2024","PID - 2: 2024 - 2025: 09-05-2024","04-29-2019",NA,"10-18-2020 04:20 PM","07-23-2024 04:33 PM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,"21.648513044142%","7.4829944785729%",739085,2,"AGC","AGC",2,"
$134,097
","$134,097","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=2&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","1047 Commonwealth Avenue","
-23
","
-12.6%
",2,"
%
",NA,"N/A",NA,"N/A","21.648513044142%","7.4829944785729%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 2: 2023 - 2024: 08-31-2023","98.907103825137%",2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,48,"08-01-2024","Student",2,"Bailey Tech Group QB <61083822.deca>","no",2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,2,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=2&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",2,41,"0%",NA,2,"0%","08-22-2024","08-08-2024",1,1,0,"Boston","United States","02215","Massachusetts","1047 Commonwealth Avenue",NA,"08-29-2024","Katie Lutz <63066649.dqqy>;Theresa Hill <63070222.crgu>",NA,NA,NA,NA,1,"42.222222222222%",2,"52.5%","41.530054644809%",2,63638,2890,66528,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,183,"$0","$365,938","$365,938","$0","$450,849","$474,515","$474,515","$450,849","$474,515",474515,"$316,752","$0","$0","$0","$0",183,0,0,180,183,"$49,186","$0","$0",NA,NA,"$500,035","0%",0,0,2020,0,0,0,0,0,0,0,0,0,0,0,0,32,"0%",2,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","01-24-2024 11:20 AM","12-01-2023 07:01 AM","07-23-2024 04:33 PM","1047 Commonwealth Avenue - WPO - 01-23-2024_2.pdf","XL Document_2.xlsx","2023 - 2024",NA,"2: September - 2024","September - 2024","2025 - 2026","2: September 2024","2: October 2024","2: July 2025","2: August 2025","2: September 2025","2: November 2024","2: December 2024","2: January 2025","2: February 2025","2: March 2025","2: April 2025","2: May 2025","2: June 2025",183,0,180,NA,"""1047 Commonwealth Avenue"", 2,","08-31-2023",0,NA,"PID - 2: 2024 - 2025: 09-08-2024","$2080","$0","no","no","yes","$0",368343.16,159,159,368343.16,"$2,316.350754717","$2,316.350754717",1,"Active Property",7,"gmh - 2","Standard",NA,"Student Housing Portfolio",49 +"2","data-raw/working/GMH/CSV/Properties.csv","Academy 65","Academy 65","1325 65th Street, Sacramento, California 95819",14,79,309,144,121,265,"85.760517799353%","80.582524271845%",NA,0,0,249,0,56,26,10,NA,0,249,0,0,0,0,0,1,0,1,4,140,133,202,274,273,0,1,257,257,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=6&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=6&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=6&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1001.0766423358","$1002.0146520147",NA,"$993.22641509434","$411.6504854369","$993.22641509434",44,"$1001.0766423358","$1002.0146520147",44,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,6,"no","no","no","Sacramento, California","$38,408,655.14","$125,930.01685246","$468.33540793308","$426,762.83488889","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=6&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Academy 65 - WPO - 09-03-2024&dbid=bq5hz7i53&msid=6&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Academy 65 - WPO - 09-03-2024&dbid=bq5hz7i53&msid=6&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=6&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",6,"77.99352750809%",NA,"
-8
","100%",309,"
-2.6%
","85.760517799353%","09-05-2024",53,"09-02-2024","PID - 6: 2024 - 2025: 09-05-2024","03-15-2018",NA,"10-18-2020 04:20 PM","12-01-2023 07:01 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,"18.753551019823%","-0.78417844443062%",641240,6,"AGC","AGC",6,"
$131,245
","$131,245","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=6&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Academy 65","
-44
","
-14.2%
",6,"
%
",NA,"
%
",NA,"
-0.9%
","1.8049695435076%","-0.78417844443062%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 6: 2023 - 2024: 08-31-2023","88.349514563107%",6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,48,"08-01-2024","Student",6,"Bailey Tech Group QB <61083822.deca>","yes",6,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,6,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=6&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",6,46,"0.32362459546926%","90.42923170526%",6,"0%","08-22-2024","08-08-2024",10,10,0,"Sacramento","United States","95819","California","1325 65th Street",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Mari Enriquez <63066651.ega7>;Jodi Charter <63070224.dwk3>","Academy65_logo_black-01.jpg",NA,NA,NA,1,"59.751037344398%",6,"45.66037735849%","46.601941747573%",6,82011,2700,84711,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,309,"$176,869.63","$127,200","$129,000","$1,800","$263,205","$274,295","$273,550","$263,205","$274,295",273550,"$131,960","$0","$0","$0","$0",309,-4,4,241,309,"-$4760","$1800","$195,589",NA,"$18,719.37","$260,245","0%",0,0,2019,0,0,0,0,0,0,0,0,0,0,0,0,53,"0%",6,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","06-20-2023 12:34 PM","12-01-2023 07:01 AM","04-25-2023 03:58 AM","Academy 65 - WPO - 11-30-2023_6.pdf","XL Document_6.xlsx","2023 - 2024",NA,"6: September - 2024","September - 2024","2025 - 2026","6: September 2024","6: October 2024","6: July 2025","6: August 2025","6: September 2025","6: November 2024","6: December 2024","6: January 2025","6: February 2025","6: March 2025","6: April 2025","6: May 2025","6: June 2025",309,0,241,"44 days","""Academy 65"", 6,","08-31-2023",0,NA,"PID - 6: 2024 - 2025: 09-08-2024","$6920","$0","no","no","yes","$0",258440.24,309,309,301465.6,"$836.37618122977","$975.61682847896",6,"Active Property",7,"gmh - 6","Standard",NA,"Student Housing Portfolio",49 +"3","data-raw/working/GMH/CSV/Properties.csv","Academy Lincoln","Academy Lincoln","1850 P Street, Lincoln, Nebraska 68508",9,151,632,249,402,651,"103.00632911392%","103.00632911392%",NA,0,0,651,0,56,5,6,NA,0,651,0,0,0,0,0,0,0,0,4,442,168,623,610,610,0,0,670,670,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=7&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=7&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=7&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$687.87540983607","$687.87540983607",NA,"$707.24577572965","$688.63924050633","$707.24577572965",NA,"$687.87540983607","$687.87540983607",-19,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,7,"no","no","no","Lincoln, Nebraska","$51,713,773.46","$81,825.590917722","$254.05681820862","$284,141.61241758","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=7&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Academy Lincoln - WPO - 09-03-2024&dbid=bq5hz7i53&msid=7&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Academy Lincoln - WPO - 09-03-2024&dbid=bq5hz7i53&msid=7&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=7&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",7,"96.044303797468%",NA,"
41
","100%",632,"
6.5%
","103.00632911392%","09-05-2024",53,"09-02-2024","PID - 7: 2024 - 2025: 09-05-2024","12-21-2018",NA,"10-18-2020 04:20 PM","02-08-2024 09:45 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,"9.124640814683%","2.8159701039753%",676055,7,"AGC","AGC",7,"
$12,262
","$12,262","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=7&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Academy Lincoln","
19
","
3%
",7,"
%
",NA,"
%
",NA,"
2.8%
","5.6406616004238%","2.8159701039753%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 7: 2023 - 2024: 08-31-2023","96.518987341772%",7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,48,"08-01-2024","Student",7,"Bailey Tech Group QB <61083822.deca>","yes",7,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,7,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=7&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",7,358,"0%","99.782380808021%",7,"0%","08-22-2024","08-08-2024",6,6,0,"Lincoln","United States","68508","Nebraska","1850 P Street",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Bailey Sherman <63066644.b3ah>;Morgan Swartz <63070227.c5jy>","Academy Lincoln (blue and orange).jpg",NA,NA,NA,1,"41.021416803954%",7,"61.751152073733%","39.398734177215%",7,203552,0,203552,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,632,"$435,592.38","$435,220","$435,220","$0","$460,417","$419,604","$419,604","$460,417","$419,604",419604,"$448,155","$0","$0","$0","$0",632,0,0,607,632,"-$12,935","$0","$436,542.38",NA,"$950","$447,482","0%",0,0,2016,0,0,0,0,0,0,0,19,16,82,0,51,130,"0%",7,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","02-08-2024 09:45 AM","12-01-2023 07:01 AM","01-28-2022 10:27 AM","Academy Lincoln - WPO - 02-07-2024_7.pdf","XL Document_7.xlsx","2023 - 2024",NA,"7: September - 2024","September - 2024","2025 - 2026","7: September 2024","7: October 2024","7: July 2025","7: August 2025","7: September 2025","7: November 2024","7: December 2024","7: January 2025","7: February 2025","7: March 2025","7: April 2025","7: May 2025","7: June 2025",632,0,607,NA,"""Academy Lincoln"", 7,","08-31-2023",0,NA,"PID - 7: 2024 - 2025: 09-08-2024","$124,570","$0","no","no","yes","$0",409604.4,632,632,423112.96,"$648.1082278481","$669.48253164557",7,"Active Property",7,"gmh - 7","Standard",NA,"Student Housing Portfolio",49 +"4","data-raw/working/GMH/CSV/Properties.csv","ANOVA uCity Square","ANOVA uCity Square",NA,13,0,461,159,273,432,"93.709327548807%","93.275488069414%",NA,NA,0,430,0,0,0,12,NA,NA,430,0,0,0,0,0,2,0,2,2,209,195,0,409,404,0,2,438,438,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=20&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=20&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=20&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$2216.1173594132","$2212.8712871287",NA,"$2191.2083333333","$0","$2191.2083333333",74,"$2216.1173594132","$2212.8712871287",29,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,20,"no","no","no",",",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=20&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=ANOVA uCity Square - WPO - 09-03-2024&dbid=bq5hz7i53&msid=20&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=ANOVA uCity Square - WPO - 09-03-2024&dbid=bq5hz7i53&msid=20&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=20&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",20,"80.477223427332%",NA,"
28
",NA,NA,"
6.1%
",NA,"09-05-2024",NA,"09-02-2024",NA,NA,NA,"02-20-2022 06:24 PM","12-01-2023 07:01 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,NA,"-1.1239939967108%",1115679,20,NA,NA,20,"
$946,602
","$946,602","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=20&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","ANOVA uCity Square","
","
%
",20,"
%
",NA,"
%
",NA,"
-1%
",NA,"-1.1239939967108%","JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,"87.63557483731%",20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,48,NA,"Student",20,"JT Bailey <62477437.bhmt>","no",20,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,20,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=20&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",20,NA,"0.43383947939262%",NA,20,"0%","08-22-2024","08-08-2024",NA,NA,NA,NA,"United States",NA,NA,NA,NA,"08-29-2024",NA,NA,NA,NA,NA,NA,"42.857142857143%",20,"63.194444444444%","34.490238611714%",20,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,461,"$0","$0","$0","$0","$946,602","$906,392","$894,000","$946,602","$906,392",894000,"$0","$0",NA,NA,NA,461,0,0,371,0,"$0","$0",NA,NA,NA,"$946,602",NA,NA,NA,NA,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,"0%",20,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","06-20-2023 12:34 PM","12-01-2023 07:01 AM",NA,"ANOVA uCity Square - WPO - 11-30-2023_20.pdf",NA,"2023 - 2024",NA,"20: September - 2024","September - 2024","2025 - 2026","20: September 2024","20: October 2024","20: July 2025","20: August 2025","20: September 2025","20: November 2024","20: December 2024","20: January 2025","20: February 2025","20: March 2025","20: April 2025","20: May 2025","20: June 2025",461,0,371,"74 days","""ANOVA uCity Square"", 20,",NA,0,NA,"PID - 20: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",0,NA,NA,0,NA,NA,8,"Active Property",7,"gmh - 20","Standard",NA,"Innovative Living Portfolio",NA +"5","data-raw/working/GMH/CSV/Properties.csv","Campustown 1008 S. 4th","1008 S. 4th","1008 South Fourth Street, Champaign, Illinois 61820",15,66,158,56,108,164,"103.79746835443%","103.79746835443%",NA,0,0,164,0,56,0,14,NA,0,164,0,0,0,0,0,0,0,0,0,138,21,97,159,159,0,0,168,168,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=1&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=1&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=1&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$853.5283018868","$853.5283018868",NA,"$927.46951219512","$897.3417721519","$927.46951219512",NA,"$853.5283018868","$853.5283018868",-6,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,1,"no","no","no","Champaign, Illinois","$20,887,963.34","$132,202.29962025","$411.86141138891","$316,484.2930303","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=1&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 1008 S. 4th - WPO - 09-03-2024&dbid=bq5hz7i53&msid=1&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 1008 S. 4th - WPO - 09-03-2024&dbid=bq5hz7i53&msid=1&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=1&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",1,"96.20253164557%",NA,"
5
","100%",158,"
3.2%
","103.79746835443%","09-05-2024",53,"09-02-2024","PID - 1: 2024 - 2025: 09-05-2024","06-27-2019",NA,"10-18-2020 04:20 PM","12-01-2023 07:01 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,"26.372649769884%","8.6630062699593%",739076,1,"AGC","AGC",1,"
$4170
","$4170","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=1&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Campustown 1008 S. 4th","
6
","
3.8%
",1,"
%
",NA,"
%
",NA,"
8.7%
","3.3990711783457%","8.6630062699593%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 1: 2023 - 2024: 08-31-2023","100.6329113924%",1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,48,"08-01-2024","Student",1,"Bailey Tech Group QB <61083822.deca>","no",1,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,1,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=1&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",1,31,"0%","100%",1,"0%","08-22-2024","08-08-2024",1,1,0,"Champaign","United States","61820","Illinois","1008 South Fourth Street",NA,"08-29-2024","Cedric Jones <63070225.dz2p>",NA,NA,NA,NA,1,"36.842105263158%",1,"65.853658536585%","35.443037974684%",1,50716,0,50716,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,158,"$92,083.19","$141,780","$141,780","$0","$152,105","$135,711","$135,711","$152,105","$135,711",135711,"$147,935","$0","$0","$0","$0",158,0,0,152,158,"-$6155","$0","$92,083.19",NA,NA,"$145,950","0%",0,0,2016,0,0,0,0,0,0,0,6,4,22,0,14,33,"0%",1,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:32 PM","12-01-2023 07:01 AM","01-24-2022 12:42 PM","Campustown 1008 S 4th - WPO - 11-30-2023_1.pdf","XL Document_1.pdf","2023 - 2024",NA,"1: September - 2024","September - 2024","2025 - 2026","1: September 2024","1: October 2024","1: July 2025","1: August 2025","1: September 2025","1: November 2024","1: December 2024","1: January 2025","1: February 2025","1: March 2025","1: April 2025","1: May 2025","1: June 2025",158,0,152,NA,"""Campustown 1008 S. 4th"", 1,","08-31-2023",0,NA,"PID - 1: 2024 - 2025: 09-08-2024","$108,000","$0","no","no","yes","$0",115958.78,158,158,141722.92,"$733.91632911392","$896.98050632911",5,"Active Property",7,"gmh - 1","Standard",NA,"Student Housing Portfolio",49 +"6","data-raw/working/GMH/CSV/Properties.csv","Campustown 307 E. Daniel","307 E. Daniel","307 East Daniel Street, Champaign, Illinois 61820",2,10,40,16,23,39,"97.5%","97.5%",NA,0,0,39,0,56,0,1,NA,0,39,0,0,0,0,0,0,0,0,0,35,5,17,40,40,0,0,41,41,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=3&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=3&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=3&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$853.75","$832.375",NA,"$934.48717948718","$825","$934.48717948718",NA,"$853.75","$832.375",1,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,3,"no","no","no","Champaign, Illinois","$4,476,552.5","$111,913.8125","$290.68522727273","$447,655.25","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=3&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 307 E. Daniel - WPO - 09-03-2024&dbid=bq5hz7i53&msid=3&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 307 E. Daniel - WPO - 09-03-2024&dbid=bq5hz7i53&msid=3&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=3&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",3,"97.5%",NA,"
-1
","100%",40,"
-2.5%
","97.5%","09-05-2024",53,"09-02-2024","PID - 3: 2024 - 2025: 09-05-2024","06-27-2019",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,"21.414005935944%","9.4567706573563%",739079,3,"AGC","AGC",3,"
$4270
","$4270","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=3&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Campustown 307 E. Daniel","
-1
","
-2.5%
",3,"
%
",NA,"
%
",NA,"
12.3%
","13.271173271173%","9.4567706573563%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 3: 2023 - 2024: 08-31-2023","100%",3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,48,"08-01-2024","Student",3,"Bailey Tech Group QB <61083822.deca>","no",3,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,3,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=3&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",3,19,"0%","100%",3,"0%","08-22-2024","08-08-2024",0,0,0,"Champaign","United States","61820","Illinois","307 East Daniel Street",NA,"08-29-2024","Cedric Jones <63070225.dz2p>","The Academy Camputtown_main logo-01.jpg",NA,NA,NA,1,"41.025641025641%",3,"58.974358974359%","40%",3,15400,0,15400,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,40,"$14,485","$33,000","$33,000","$0","$36,445","$34,150","$33,295","$36,445","$34,150",33295,"$32,175","$0","$0","$0","$0",40,0,0,39,40,"$825","$0","$14,485",NA,NA,"$37,270","0%",0,0,2014,0,0,0,0,0,0,0,0,1,3,0,1,8,"0%",3,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:32 PM","12-01-2023 07:02 AM","02-17-2022 01:18 PM","Campustown 307 E Daniel - WPO - 11-30-2023_3.pdf","XL Document_3.xlsx","2023 - 2024",NA,"3: September - 2024","September - 2024","2025 - 2026","3: September 2024","3: October 2024","3: July 2025","3: August 2025","3: September 2025","3: November 2024","3: December 2024","3: January 2025","3: February 2025","3: March 2025","3: April 2025","3: May 2025","3: June 2025",40,0,39,NA,"""Campustown 307 E. Daniel"", 3,","08-31-2023",0,NA,"PID - 3: 2024 - 2025: 09-08-2024","$6000","$0","no","no","yes","$0",30786.8,40,40,33000,"$769.67","$825",2,"Active Property",7,"gmh - 3","Standard",NA,"Student Housing Portfolio",49 +"7","data-raw/working/GMH/CSV/Properties.csv","Campustown 501 S. 6th","501 S. 6th","501 South Sixth Street, Champaign, Illinois 61820",10,27,104,57,51,108,"103.84615384615%","103.84615384615%",NA,0,0,108,0,56,2,9,NA,0,108,0,0,0,0,0,0,0,0,0,77,27,33,104,104,0,0,110,110,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=4&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=4&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=4&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$740.50961538462","$740.50961538462",NA,"$798.24074074074","$838.84615384615","$798.24074074074",NA,"$740.50961538462","$740.50961538462",-4,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,4,"no","no","no","Champaign, Illinois","$11,761,647.45","$113,092.7639423","$251.99030423139","$435,616.57222222","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=4&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 501 S. 6th - WPO - 09-03-2024&dbid=bq5hz7i53&msid=4&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 501 S. 6th - WPO - 09-03-2024&dbid=bq5hz7i53&msid=4&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=4&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",4,"99.038461538462%",NA,"
4
","100%",104,"
3.8%
","103.84615384615%","09-05-2024",53,"09-02-2024","PID - 4: 2024 - 2025: 09-05-2024","06-27-2019",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,"34.726806208106%","7.7961344669563%",739080,4,"AGC","AGC",4,"
-$4420
","-$4420","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=4&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Campustown 501 S. 6th","
4
","
3.8%
",4,"
%
",NA,"
%
",NA,"
7.8%
","-5.1404666987804%","7.7961344669563%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 4: 2023 - 2024: 08-31-2023","100%",4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,48,"08-01-2024","Student",4,"Bailey Tech Group QB <61083822.deca>","no",4,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,4,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=4&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",4,41,"0%","96.43433029909%",4,"0%","08-22-2024","08-08-2024",0,0,0,"Champaign","United States","61820","Illinois","501 South Sixth Street",NA,"08-29-2024","Cedric Jones <63070225.dz2p>","The Academy Camputtown_main logo-01.jpg",NA,NA,NA,1,"55.339805825243%",4,"47.222222222222%","54.807692307692%",4,46675,0,46675,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,104,"$27,809.25","$87,240","$87,240","$0","$86,210","$77,013","$77,013","$86,210","$77,013",77013,"$90,630","$0","$0","$0","$0",104,0,0,103,104,"-$3390","$0","$28,837.5",NA,"$1,028.25","$82,820","0%",0,0,2012,0,0,0,0,0,0,0,4,3,14,0,9,22,"0%",4,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:33 PM","12-01-2023 07:02 AM","12-07-2021 10:22 AM","Campustown 501 S 6th - WPO - 11-30-2023_4.pdf","XL Document_4.pdf","2023 - 2024",NA,"4: September - 2024","September - 2024","2025 - 2026","4: September 2024","4: October 2024","4: July 2025","4: August 2025","4: September 2025","4: November 2024","4: December 2024","4: January 2025","4: February 2025","4: March 2025","4: April 2025","4: May 2025","4: June 2025",104,0,103,NA,"""Campustown 501 S. 6th"", 4,","08-31-2023",0,NA,"PID - 4: 2024 - 2025: 09-08-2024","$48,500","$0","no","no","yes","$0",60433.82,102,102,85832.76,"$592.48843137255","$841.49764705882",3,"Active Property",7,"gmh - 4","Standard",NA,"Student Housing Portfolio",49 +"8","data-raw/working/GMH/CSV/Properties.csv","Campustown 908 S. 1st","908 S. 1st","908 South First Street, Champaign, Illinois 61820",11,36,96,34,65,99,"103.125%","102.08333333333%",NA,0,0,98,0,56,0,8,NA,0,98,0,0,0,0,0,1,0,1,0,81,15,54,96,96,0,1,99,99,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=5&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=5&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=5&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$952.40625","$952.40625",NA,"$1025.5555555556","$950.41666666667","$1025.5555555556",112,"$952.40625","$952.40625",-3,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,5,"no","no","no","Champaign, Illinois","$12,566,037.8","$130,896.22708333","$360.36816174362","$184,794.67352941","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=5&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 908 S. 1st - WPO - 09-03-2024&dbid=bq5hz7i53&msid=5&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Campustown 908 S. 1st - WPO - 09-03-2024&dbid=bq5hz7i53&msid=5&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=5&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",5,"95.833333333333%",NA,"
3
","102.08333333333%",98,"
3.1%
","103.125%","09-05-2024",53,"09-02-2024","PID - 5: 2024 - 2025: 09-05-2024","06-27-2019",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,"31.187151334257%","7.6804730707674%",739084,5,"AGC","AGC",5,"
$6995
","$6995","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=5&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Campustown 908 S. 1st","
1
","
1%
",5,"
%
",NA,"
%
",NA,"
7.7%
","9.2663292787598%","7.6804730707674%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 5: 2023 - 2024: 08-31-2023","100%",5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,48,"08-01-2024","Student",5,"Bailey Tech Group QB <61083822.deca>","no",5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,5,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=5&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",5,24,"1.0416666666667%","100%",5,"0%","08-22-2024","08-08-2024",3,3,0,"Champaign","United States","61820","Illinois","908 South First Street",NA,"08-29-2024","Cedric Jones <63070225.dz2p>","The Academy Camputtown_main logo-01.jpg",NA,NA,NA,1,"36.95652173913%",5,"65.656565656566%","35.416666666667%",5,34870,0,34870,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,96,"$52,174.03","$91,240","$91,240","$0","$101,530","$91,431","$91,431","$101,530","$91,431",91431,"$94,535","$0","$0","$0","$0",96,0,0,92,96,"-$3295","$0","$52,174.03",NA,NA,"$98,235","0%",0,0,2016,0,0,0,0,0,0,0,3,3,13,0,8,20,"0%",5,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","10-11-2022 09:27 AM","12-01-2023 07:02 AM","01-18-2022 02:35 PM","Campustown 908 S 1st - WPO - 11-30-2023_5.pdf","XL Document_5.pdf","2023 - 2024",NA,"5: September - 2024","September - 2024","2025 - 2026","5: September 2024","5: October 2024","5: July 2025","5: August 2025","5: September 2025","5: November 2024","5: December 2024","5: January 2025","5: February 2025","5: March 2025","5: April 2025","5: May 2025","5: June 2025",96,0,92,"112 days","""Campustown 908 S. 1st"", 5,","08-31-2023",0,NA,"PID - 5: 2024 - 2025: 09-08-2024","$29,000","$0","no","no","yes","$0",75048,96,96,90104,"$781.75","$938.58333333333",4,"Active Property",7,"gmh - 5","Standard",NA,"Student Housing Portfolio",49 +"9","data-raw/working/GMH/CSV/Properties.csv","Everly on The Loop","Everly on The Loop","6105 Delmar Boulevard, Saint Louis, Missouri 63112",7,209,0,0,0,0,NA,NA,NA,NA,0,0,0,0,24,0,NA,NA,0,0,0,0,0,0,0,0,0,0,0,0,348,0,0,0,0,0,0,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=8&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=8&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=8&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,NA,NA,0,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,8,"no","no","no","Saint Louis, Missouri","$75,688,204.31","$176,841.59885514","$402.83253132152","$362,144.51822967","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=8&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Everly on The Loop - WPO - 09-03-2024&dbid=bq5hz7i53&msid=8&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Everly on The Loop - WPO - 09-03-2024&dbid=bq5hz7i53&msid=8&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=8&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",8,NA,NA,"
0
",NA,NA,NA,NA,"09-05-2024",NA,"09-02-2024",NA,"11-15-2019",NA,"10-18-2020 04:20 PM","07-18-2023 10:19 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,NA,NA,909419,8,"AGC",NA,8,"
$0
","$0","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=8&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Everly on The Loop","
","
%
",8,"
%
",NA,"
%
",NA,"
%
",NA,NA,"JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,NA,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,48,NA,"Student",8,"Bailey Tech Group QB <61083822.deca>","yes",8,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,8,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=8&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",8,209,NA,"99.194502260926%",8,NA,"08-22-2024","08-08-2024",NA,NA,NA,"Saint Louis","United States","63112","Missouri","6105 Delmar Boulevard",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Benjamin Williams <63066645.c8t4>","Everly_colored-Logo - Copy.jpg",NA,NA,NA,NA,NA,8,NA,NA,8,187890,4500,192390,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$416,652.56","$0","$14,430","$14,430","$0","$0","$0","$0","$0",0,"$0","$0","$0","$0","$0",0,-2,2,0,428,"$0","$14,430","$420,035.94",NA,"$3,383.38","$14,430",NA,NA,NA,2017,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,NA,8,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","05-04-2023 03:09 PM","05-30-2023 07:02 AM","02-02-2022 01:57 PM","Everly on The Loop - WPO - 05-29-2023_8.pdf","XL Document_8.pdf","2023 - 2024",NA,"8: September - 2024","September - 2024","2025 - 2026","8: September 2024","8: October 2024","8: July 2025","8: August 2025","8: September 2025","8: November 2024","8: December 2024","8: January 2025","8: February 2025","8: March 2025","8: April 2025","8: May 2025","8: June 2025",0,0,0,NA,"""Everly on The Loop"", 8,",NA,0,NA,"PID - 8: 2024 - 2025: 09-08-2024","$17,100","$0","no","no","no","$0",0,NA,NA,0,"$1,237.0754205607","$1,237.0754205607",9,"Previous Property",7,"gmh - 8","Standard",NA,"Student Housing Portfolio",NA +"10","data-raw/working/GMH/CSV/Properties.csv","Life Tower","Life Tower","6919 Main Street, Houston, Texas 77030",13,0,0,0,0,0,NA,NA,NA,0,0,0,0,56,0,0,NA,0,0,0,0,0,0,0,0,0,0,0,289,143,0,435,432,0,0,358,358,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=22&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=22&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=22&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1142.7034482759","$1141.1828703704",NA,NA,NA,NA,NA,"$1142.7034482759","$1141.1828703704",0,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,22,"no","no","no","Houston, Texas",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=22&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Life Tower - WPO - 09-03-2024&dbid=bq5hz7i53&msid=22&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Life Tower - WPO - 09-03-2024&dbid=bq5hz7i53&msid=22&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=22&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",22,NA,NA,"
-432
","100%",714,NA,NA,"09-05-2024",53,"09-02-2024","PID - 22: 2024 - 2025: 09-05-2024",NA,NA,"01-10-2023 06:25 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,NA,NA,1211481,22,NA,NA,22,"
$0
","$0","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=22&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Life Tower","
-714
","
%
",22,"
%
",NA,"
%
",NA,"
%
",NA,NA,"JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 22: 2023 - 2024: 08-31-2023",NA,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,48,"08-01-2024","Student",22,"JT Bailey <62477437.bhmt>","no",22,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,22,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=22&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",22,NA,NA,NA,22,NA,"08-22-2024","08-08-2024",2,2,0,"Houston","United States","77030","Texas","6919 Main Street",NA,"08-29-2024",NA,NA,NA,NA,NA,1,NA,22,NA,NA,22,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$0","$0","$3010","$3,010","$0","$497,076","$492,991","$0","$497,076",492991,"$0","$0",NA,NA,NA,0,0,0,0,0,"$0","$3010",NA,NA,NA,"$3010",NA,0,0,NA,0,0,0,0,0,0,0,0,0,0,0,0,0,NA,22,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","06-20-2023 11:54 AM","12-01-2023 07:02 AM",NA,"Life Tower - WPO - 11-30-2023_22.pdf",NA,"2023 - 2024",NA,"22: September - 2024","September - 2024","2025 - 2026","22: September 2024","22: October 2024","22: July 2025","22: August 2025","22: September 2025","22: November 2024","22: December 2024","22: January 2025","22: February 2025","22: March 2025","22: April 2025","22: May 2025","22: June 2025",0,0,0,NA,"""Life Tower"", 22,","08-31-2023",0,NA,"PID - 22: 2024 - 2025: 09-08-2024","$0","$0","no","no","no","$0",0,NA,NA,0,NA,NA,NA,"Active Property",7,"gmh - 22","Standard",NA,"Student Housing Portfolio",49 +"11","data-raw/working/GMH/CSV/Properties.csv","River House","River House","1 Point Street, Providence, Rhode Island 02903",26,0,0,0,0,0,NA,NA,NA,NA,0,0,0,0,5,0,NA,NA,0,0,0,0,0,0,0,0,0,0,0,0,234,0,0,0,0,0,0,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=9&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=9&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=9&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,NA,NA,0,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,9,"no","no","no","Providence, Rhode Island","$58,800,335.62","$217,779.02081481","$522.20546731794","$337,932.96333333","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=9&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=River House - WPO - 09-03-2024&dbid=bq5hz7i53&msid=9&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=River House - WPO - 09-03-2024&dbid=bq5hz7i53&msid=9&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=9&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",9,NA,NA,"
0
",NA,NA,NA,NA,"09-05-2024",NA,"09-02-2024",NA,"06-30-2017",NA,"10-18-2020 04:20 PM","07-29-2022 12:55 PM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,NA,NA,637523,9,"Wexford / IP",NA,9,"
$0
","$0","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=9&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","River House","
","
%
",9,"
%
",NA,"
%
",NA,"
%
",NA,NA,"JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,NA,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,48,NA,"Hybrid",9,"Bailey Tech Group QB <61083822.deca>","no",9,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,9,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=9&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",9,106,NA,"98.566485353943%",9,NA,"08-22-2024","08-08-2024",NA,NA,NA,"Providence","United States","02903","Rhode Island","1 Point Street",NA,"08-29-2024",NA,NA,NA,NA,NA,NA,NA,9,NA,NA,9,112600,0,112600,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$229,272.86","$0","$0","$0","$0","$0","$0","$0","$0",0,"$0","$0",NA,NA,NA,0,0,0,0,270,"$0","$0","$232,607.32",NA,"$3,334.46","$0",NA,NA,NA,2018,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,NA,9,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:33 PM","04-08-2022 01:33 PM","11-15-2021 09:08 PM","River House - WPO - 04-07-2022_9.pdf","XL Document_9.pdf","2023 - 2024",NA,"9: September - 2024","September - 2024","2025 - 2026","9: September 2024","9: October 2024","9: July 2025","9: August 2025","9: September 2025","9: November 2024","9: December 2024","9: January 2025","9: February 2025","9: March 2025","9: April 2025","9: May 2025","9: June 2025",0,0,0,NA,"""River House"", 9,",NA,0,NA,"PID - 9: 2024 - 2025: 09-08-2024","$500","$0","no","no","no","$0",0,NA,NA,0,NA,NA,10,"Previous Property",7,"gmh - 9","Standard",NA,NA,NA +"12","data-raw/working/GMH/CSV/Properties.csv","Shortbread Lofts","Shortbread Lofts","333 West Rosemary Street, Chapel Hill, North Carolina 27516",38,84,374,29,344,373,"99.732620320856%","99.732620320856%",NA,0,0,373,0,56,4,10,NA,0,373,0,0,0,0,0,0,0,0,3,330,21,394,354,351,0,0,379,379,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=10&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=10&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=10&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1068.7146892655","$1066.5811965812",NA,"$1160.4959785523","$1059.064171123","$1160.4959785523",NA,"$1068.7146892655","$1066.5811965812",1,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,10,"no","no","no","Chapel Hill, North Carolina","$39,549,600.33","$100,635.11534351","$358.46317583106","$465,289.41564706","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=10&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Shortbread Lofts - WPO - 09-03-2024&dbid=bq5hz7i53&msid=10&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Shortbread Lofts - WPO - 09-03-2024&dbid=bq5hz7i53&msid=10&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=10&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",10,"98.930481283422%",NA,"
22
","105.61497326203%",395,"
5.9%
","99.732620320856%","09-05-2024",53,"09-02-2024","PID - 10: 2024 - 2025: 09-05-2024","08-05-2015",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,"25.387463198283%","8.5880067157885%",518044,10,"Principal","Principal",10,"
$82,380
","$82,380","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=10&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Shortbread Lofts","
-22
","
-5.9%
",10,"
%
",NA,"
%
",NA,"
8.8%
","25.387463198283%","8.5880067157885%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 10: 2023 - 2024: 08-31-2023","93.85026737968%",10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,48,"08-01-2024","Student",10,"Bailey Tech Group QB <61083822.deca>","no",10,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,10,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=10&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",10,121,"0%","99.413796855449%",10,"0%","08-22-2024","08-08-2024",0,0,0,"Chapel Hill","United States","27516","North Carolina","333 West Rosemary Street",NA,"08-29-2024","Kristen Turner <63066650.bjcg>;Myranda Blankenship <63070223.f66r>","9619ee8e-9ec0-44ca-8d6b-47f20fceea68.jpg",NA,NA,NA,1,"7.3417721518987%",10,"92.225201072386%","7.7540106951872%",10,110330,0,110330,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,374,"$365,465","$396,090","$397,825","$1,735","$432,865","$378,325","$374,370","$432,865","$378,325",374370,"$350,485","$0","$0","$0","$0",374,-3,3,395,392,"$45,605","$1735","$367,620",NA,"$2,155","$480,205","0%",0,0,2014,0,0,0,0,0,0,0,0,7,36,0,18,75,"0%",10,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","07-26-2023 09:58 AM","12-01-2023 07:02 AM","01-24-2022 12:42 PM","Shortbread Lofts - WPO - 11-30-2023_10.pdf","XL Document_10.pdf","2023 - 2024",NA,"10: September - 2024","September - 2024","2025 - 2026","10: September 2024","10: October 2024","10: July 2025","10: August 2025","10: September 2025","10: November 2024","10: December 2024","10: January 2025","10: February 2025","10: March 2025","10: April 2025","10: May 2025","10: June 2025",374,0,370,NA,"""Shortbread Lofts"", 10,","08-31-2023",0,NA,"PID - 10: 2024 - 2025: 09-08-2024","$0","$0","yes","no","yes","$0",400522,374,374,400522,"$925.52791878173","$925.52791878173",11,"Active Property",7,"gmh - 10","Space Options",NA,"Student Housing Portfolio",49 +"13","data-raw/working/GMH/CSV/Properties.csv","SOVA","SOVA","3021 Hidden Forest Court, Marietta, Georgia 30066",10,248,816,462,491,953,"116.78921568627%","116.42156862745%",NA,0,0,950,0,56,47,7,NA,0,950,0,0,0,0,0,3,0,3,4,430,383,806,820,813,0,3,996,996,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=11&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=11&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=11&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$944.36585365854","$942.68142681427",NA,"$1004.7114375656","$815.93137254902","$1004.7114375656",229,"$944.36585365854","$942.68142681427",-137,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,11,"no","no","no","Marietta, Georgia","$82,239,687.36","$100,783.93058824","$255.73950593328","$331,611.64258065","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=11&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=SOVA - WPO - 09-03-2024&dbid=bq5hz7i53&msid=11&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=SOVA - WPO - 09-03-2024&dbid=bq5hz7i53&msid=11&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=11&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",11,"99.142156862745%",NA,"
140
","100%",816,"
17.2%
","116.78921568627%","09-05-2024",53,"09-02-2024","PID - 11: 2024 - 2025: 09-05-2024","12-30-2019",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,"21.812340357094%","6.3900641550373%",952515,11,"Sigfried","CBRE",11,"
$175,945
","$175,945","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=11&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","SOVA","
137
","
16.8%
",11,"
%
",NA,"
%
",NA,"
6.6%
","21.812340357094%","6.3900641550373%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 11: 2023 - 2024: 08-31-2023","99.632352941176%",11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,48,"08-01-2024","Student",11,"Bailey Tech Group QB <61083822.deca>","no",11,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,11,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=11&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",11,174,"0.36764705882353%","98.05661549892%",11,"0%","08-22-2024","08-08-2024",1,1,0,"Marietta","United States","30066","Georgia","3021 Hidden Forest Court",NA,"08-29-2024","Justin Huntley <63066648.ce6c>;Sarah Garcia <63070221.jj9w>;Shomari Watford <63070220.stxa>","Sova_Color.jpg",NA,NA,NA,1,"57.107540173053%",11,"51.521511017838%","56.617647058824%",11,321576,0,321576,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,816,"$632,748.23","$665,800","$672,770","$6,970","$957,490","$774,380","$766,400","$957,490","$774,380",766400,"$781,545","$0","$0","$0","$0",816,-4,4,809,816,"-$115,745","$6970","$645,288.67",NA,"$12,540.44","$848,715","0%",0,0,2019,0,0,0,0,0,0,0,137,44,219,0,178,191,"0%",11,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:34 PM","12-01-2023 07:02 AM","01-25-2022 03:07 PM","SOVA - WPO - 11-30-2023_11.pdf","XL Document_11.pdf","2023 - 2024",NA,"11: September - 2024","September - 2024","2025 - 2026","11: September 2024","11: October 2024","11: July 2025","11: August 2025","11: September 2025","11: November 2024","11: December 2024","11: January 2025","11: February 2025","11: March 2025","11: April 2025","11: May 2025","11: June 2025",816,0,809,"229 days","""SOVA"", 11,","08-31-2023",0,NA,"PID - 11: 2024 - 2025: 09-08-2024","$300","$0","no","no","yes","$0",673038.98,816,816,673038.98,"$824.80267156863","$824.80267156863",12,"Active Property",7,"gmh - 11","Standard",NA,"Student Housing Portfolio",49 +"14","data-raw/working/GMH/CSV/Properties.csv","Station Nine","Station Nine","2211 Hillsborough Road, Durham, North Carolina 27705",18,0,323,82,220,302,"93.498452012384%","93.498452012384%",NA,NA,0,302,0,0,1,15,NA,NA,302,0,0,0,0,0,0,0,0,1,186,80,240,268,266,0,0,310,310,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=12&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=12&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=12&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$2134.8097014925","$2137.015037594",NA,"$2138.655629139","$0","$2138.655629139",NA,"$2134.8097014925","$2137.015037594",21,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,12,"no","no","no","Durham, North Carolina","$84,711,487.23","$263,898.71411215","$271.76464981762","$263,898.71411215","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=12&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Station Nine - WPO - 09-03-2024&dbid=bq5hz7i53&msid=12&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Station Nine - WPO - 09-03-2024&dbid=bq5hz7i53&msid=12&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=12&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",12,"72.445820433437%",NA,"
36
",NA,NA,"
11.1%
",NA,"09-05-2024",NA,"09-02-2024",NA,"02-05-2018",NA,"10-18-2020 04:20 PM","12-01-2023 07:02 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,NA,"0.1801531838574%",577897,12,"Principal",NA,12,"
$645,874
","$645,874","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=12&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Station Nine","
","
%
",12,"
%
",NA,"
%
",NA,"
0.1%
",NA,"0.1801531838574%","JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,"82.35294117647%",12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,48,NA,"Hybrid",12,"Bailey Tech Group QB <61083822.deca>","no",12,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,12,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=12&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",12,540,"0%","99.866234944409%",12,"0%","08-22-2024","08-08-2024",NA,NA,NA,"Durham","United States","27705","North Carolina","2211 Hillsborough Road",NA,"08-29-2024",NA,NA,NA,NA,NA,NA,"35.042735042735%",12,"72.847682119205%","25.386996904025%",12,311709,0,311709,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,323,"$373,289.7","$0","$0","$0","$645,874","$572,129","$568,446","$645,874","$572,129",568446,"$0","$0","$0","$0","$0",323,0,0,234,0,"$0","$0","$373,789.7",NA,"$500","$645,874",NA,NA,NA,2019,0,0,0,0,0,0,NA,NA,NA,NA,NA,NA,NA,"0%",12,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","06-20-2023 11:05 AM","12-01-2023 07:02 AM","12-07-2021 09:10 AM","Station Nine - WPO - 11-30-2023_12.pdf","XL Document_12.pdf","2023 - 2024",NA,"12: September - 2024","September - 2024","2025 - 2026","12: September 2024","12: October 2024","12: July 2025","12: August 2025","12: September 2025","12: November 2024","12: December 2024","12: January 2025","12: February 2025","12: March 2025","12: April 2025","12: May 2025","12: June 2025",323,0,234,NA,"""Station Nine"", 12,",NA,0,NA,"PID - 12: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",0,NA,NA,0,NA,NA,13,"Active Property",7,"gmh - 12","Standard",NA,"Conventional Portfolio",NA +"15","data-raw/working/GMH/CSV/Properties.csv","The Academy at Frisco","The Academy at Frisco","413 North West Avenue, Fayetteville, Arkansas 72701",14,218,640,341,343,684,"106.875%","106.5625%",NA,0,0,682,0,56,19,12,NA,0,682,0,0,0,0,0,2,0,2,4,384,255,622,639,639,0,2,714,714,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=13&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=13&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=13&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$708.26291079812","$708.26291079812",NA,"$883.1812865497","$609.375","$883.1812865497",445,"$708.26291079812","$708.26291079812",-44,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,13,"no","no","no","Fayetteville, Arkansas","$52,358,998.2","$81,810.9346875","$222.5665276662","$239,082.18356164","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=13&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy at Frisco - WPO - 09-03-2024&dbid=bq5hz7i53&msid=13&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy at Frisco - WPO - 09-03-2024&dbid=bq5hz7i53&msid=13&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=13&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",13,"99.84375%",NA,"
45
","100%",640,"
7%
","106.875%","09-05-2024",53,"09-02-2024","PID - 13: 2024 - 2025: 09-05-2024","01-29-2015",NA,"10-18-2020 04:20 PM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,"47.41161836005%","24.69681428814%",518041,13,"Principal","Principal",13,"
$185,761
","$185,761","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=13&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Academy at Frisco","
44
","
6.9%
",13,"
%
",NA,"
%
",NA,"
24.7%
","47.41161836005%","24.69681428814%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 13: 2023 - 2024: 08-31-2023","99.84375%",13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,48,"08-01-2024","Student",13,"Bailey Tech Group QB <61083822.deca>","no",13,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,13,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=13&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",13,633,"0.3125%","99.46288554215%",13,"0%","08-22-2024","08-08-2024",2,2,0,"Fayetteville","United States","72701","Arkansas","413 North West Avenue",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Anthony Blok <63066643.d4k2>;Jessica Burrough <63070218.yq68>","Frisco-01-01.jpg",NA,NA,NA,1,"53.364632237872%",13,"50.14619883041%","53.28125%",13,235251,1235,236486,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,640,"$384,200.47","$390,000","$404,675","$14,675","$604,096","$452,580","$452,580","$604,096","$452,580",452580,"$418,335","$0","$0","$0","$0",640,-1,1,639,639,"-$28,335","$14,675","$386,275.21",NA,"$2,074.74","$590,436","0%",0,0,2014,0,0,0,0,0,0,0,44,22,108,0,76,137,"0%",13,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","06-20-2023 11:53 AM","12-01-2023 07:03 AM","01-24-2022 12:42 PM","The Academy at Frisco - WPO - 11-30-2023_13.pdf","XL Document_13.pdf","2023 - 2024",NA,"13: September - 2024","September - 2024","2025 - 2026","13: September 2024","13: October 2024","13: July 2025","13: August 2025","13: September 2025","13: November 2024","13: December 2024","13: January 2025","13: February 2025","13: March 2025","13: April 2025","13: May 2025","13: June 2025",640,0,639,"445 days","""The Academy at Frisco"", 13,","08-31-2023",0,NA,"PID - 13: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",383440.62,640,640,383440.62,"$599.12596875","$599.12596875",14,"Active Property",7,"gmh - 13","Standard",NA,"Student Housing Portfolio",49 +"16","data-raw/working/GMH/CSV/Properties.csv","The Academy Chorro","The Academy Chorro","22 Chorro Street, San Luis Obispo, California 93405",6,27,0,23,75,98,NA,NA,NA,0,0,97,0,56,2,0,NA,0,97,0,0,0,0,0,1,0,1,0,55,37,78,92,92,0,1,103,103,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=14&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=14&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=14&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1460.2173913043","$1460.2173913043",NA,"$1568.806122449",NA,"$1568.806122449",176,"$1460.2173913043","$1460.2173913043",-98,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,14,"no","no","no","San Luis Obispo, California","$15,087,764.45","$157,164.21302083","$520.93237751614","$580,298.6326923","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=14&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy Chorro - WPO - 09-03-2024&dbid=bq5hz7i53&msid=14&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy Chorro - WPO - 09-03-2024&dbid=bq5hz7i53&msid=14&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=14&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",14,NA,NA,"
6
","100%",96,NA,NA,"09-05-2024",53,"09-02-2024","PID - 14: 2024 - 2025: 09-05-2024","08-15-2017",NA,"10-18-2020 04:20 PM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,"18.480827840694%","7.4364770472727%",535270,14,"AGC","AGC",14,"
$25,629
","$25,629","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=14&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Academy Chorro","
2
","
%
",14,"
%
",NA,"
%
",NA,"
7.4%
","18.480827840694%","7.4364770472727%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 14: 2023 - 2024: 08-31-2023",NA,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,48,"08-01-2024","Student",14,"Bailey Tech Group QB <61083822.deca>","yes",14,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,14,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=14&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",14,33,NA,"99.902642288296%",14,NA,"08-22-2024","08-08-2024",0,0,0,"San Luis Obispo","United States","93405","California","22 Chorro Street",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Tiffany Browning <63066652.d942>","Chorro_logo_orange-01.jpg",NA,NA,NA,1,NA,14,"76.530612244898%",NA,14,28963,0,28963,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$102,614","$0","$1660","$1,660","$153,743","$134,340","$134,340","$153,743","$134,340",134340,"$128,114","$0","$0","$0","$0",0,-3,3,0,96,"-$128,114","$1660","$102,714",NA,"$100","$27,289",NA,0,0,2018,0,0,0,0,0,0,0,98,20,98,0,98,20,NA,14,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:34 PM","12-01-2023 07:03 AM","11-22-2021 11:08 AM","The Academy Chorro - WPO - 11-30-2023_14.pdf","XL Document_14.xlsx","2023 - 2024",NA,"14: September - 2024","September - 2024","2025 - 2026","14: September 2024","14: October 2024","14: July 2025","14: August 2025","14: September 2025","14: November 2024","14: December 2024","14: January 2025","14: February 2025","14: March 2025","14: April 2025","14: May 2025","14: June 2025",0,0,0,"176 days","""The Academy Chorro"", 14,","08-31-2023",0,NA,"PID - 14: 2024 - 2025: 09-08-2024","$23,000","$0","no","no","yes","$0",0,NA,NA,0,"$1,324.10125","$1,324.10125",15,"Active Property",7,"gmh - 14","Standard",NA,"Student Housing Portfolio",49 +"17","data-raw/working/GMH/CSV/Properties.csv","The Academy on Charles","The Academy on Charles","3700 North Charles Street, Baltimore, Maryland 21218",19,106,328,127,208,335,"102.13414634146%","102.13414634146%",NA,0,0,335,0,56,2,18,NA,0,335,0,0,0,0,0,0,0,0,4,216,112,310,328,328,0,0,337,337,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=15&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=15&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=15&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1390.6402439024","$1390.6402439024",NA,"$1481.1492537313","$1236.6615853659","$1481.1492537313",NA,"$1390.6402439024","$1390.6402439024",-7,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,15,"no","no","no","Baltimore, Maryland","$47,843,698.82","$149,511.5588125","$461.98121724185","$451,355.64924528","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=15&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy on Charles - WPO - 09-03-2024&dbid=bq5hz7i53&msid=15&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy on Charles - WPO - 09-03-2024&dbid=bq5hz7i53&msid=15&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=15&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",15,"100%",NA,"
7
","100%",328,"
2.1%
","102.13414634146%","09-05-2024",53,"09-02-2024","PID - 15: 2024 - 2025: 09-05-2024","11-04-2016",NA,"10-18-2020 04:20 PM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,"19.164171548196%","6.5084417214129%",518042,15,"Principal","Principal",15,"
$82,090
","$82,090","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=15&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Academy on Charles","
7
","
2.1%
",15,"
%
",NA,"
%
",NA,"
6.5%
","19.164171548196%","6.5084417214129%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 15: 2023 - 2024: 08-31-2023","100%",15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,48,"08-01-2024","Student",15,"Bailey Tech Group QB <61083822.deca>","no",15,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,15,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=15&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",15,93,"0%","99.277239926269%",15,"0%","08-22-2024","08-08-2024",0,0,0,"Baltimore","United States","21218","Maryland","3700 North Charles Street",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Brittney Longley <63066646.7vdd>;Janice Richards <63070219.tti2>","AcademyonCharlesLogo_Outlined-01.jpg",NA,NA,NA,1,"38.719512195122%",15,"62.089552238806%","38.719512195122%",15,103562,0,103562,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,328,"$366,403.8","$405,625","$407,345","$1,720","$496,185","$456,130","$456,130","$496,185","$456,130",456130,"$414,095","$0","$0","$0","$0",328,-4,4,328,328,"-$8470","$1720","$369,071.3",NA,"$2,667.5","$489,435","0%",0,0,2014,0,0,0,0,0,0,0,7,8,40,0,23,67,"0%",15,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","11-10-2022 09:47 AM","12-01-2023 07:03 AM","04-08-2022 12:59 PM","The Academy on Charles - WPO - 11-30-2023_15.pdf","XL Document_15.xlsx","2023 - 2024",NA,"15: September - 2024","September - 2024","2025 - 2026","15: September 2024","15: October 2024","15: July 2025","15: August 2025","15: September 2025","15: November 2024","15: December 2024","15: January 2025","15: February 2025","15: March 2025","15: April 2025","15: May 2025","15: June 2025",328,0,328,NA,"""The Academy on Charles"", 15,","08-31-2023",0,NA,"PID - 15: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",407084.46,328,328,407084.46,"$1,242.9484756098","$1,242.9484756098",16,"Active Property",7,"gmh - 15","Standard",NA,"Student Housing Portfolio",49 +"18","data-raw/working/GMH/CSV/Properties.csv","The Academy Palomar","The Academy Palomar","71 Palomar Avenue, San Luis Obispo, California 93405",6,32,0,38,93,131,NA,NA,NA,0,0,131,0,56,0,0,NA,0,131,0,0,0,0,0,0,0,0,0,90,35,116,125,125,0,0,142,142,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=16&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=16&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=16&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1443.04","$1443.04",NA,"$1556.7938931298",NA,"$1556.7938931298",NA,"$1443.04","$1443.04",-131,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,16,"no","no","no","San Luis Obispo, California","$19,733,814.85","$151,798.57576923","$571.51423006748","$597,994.38939394","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=16&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy Palomar - WPO - 09-03-2024&dbid=bq5hz7i53&msid=16&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Academy Palomar - WPO - 09-03-2024&dbid=bq5hz7i53&msid=16&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=16&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",16,NA,NA,"
6
","100%",129,NA,NA,"09-05-2024",53,"09-02-2024","PID - 16: 2024 - 2025: 09-05-2024","04-16-2018",NA,"10-18-2020 04:20 PM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,"18.768581593895%","7.8829341618923%",676054,16,"AGC","AGC",16,"
$32,918
","$32,918","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=16&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Academy Palomar","
2
","
%
",16,"
%
",NA,"
%
",NA,"
7.9%
","18.768581593895%","7.8829341618923%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 16: 2023 - 2024: 08-31-2023",NA,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,48,"08-01-2024","Student",16,"Bailey Tech Group QB <61083822.deca>","yes",16,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,16,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=16&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",16,63,NA,"100%",16,NA,"08-22-2024","08-08-2024",0,0,0,"San Luis Obispo","United States","93405","California","71 Palomar Avenue",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>; Tiffany Browning <63066652.d942>","AcademyPalomar_logo (color)-01.jpg",NA,NA,NA,1,NA,16,"70.992366412214%",NA,16,34529,0,34529,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$151,788","$0","$1920","$1,920","$203,940","$180,380","$180,380","$203,940","$180,380",180380,"$171,022","$0","$0","$0","$0",0,0,0,0,129,"-$171,022","$1920","$151,788",NA,NA,"$34,838",NA,0,0,2019,0,0,0,0,0,0,0,131,26,131,0,131,26,NA,16,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","04-08-2022 01:35 PM","12-01-2023 07:03 AM","11-15-2021 09:15 PM","The Academy Palomar - WPO - 11-30-2023_16.pdf","XL Document_16.pdf","2023 - 2024",NA,"16: September - 2024","September - 2024","2025 - 2026","16: September 2024","16: October 2024","16: July 2025","16: August 2025","16: September 2025","16: November 2024","16: December 2024","16: January 2025","16: February 2025","16: March 2025","16: April 2025","16: May 2025","16: June 2025",0,0,0,NA,"""The Academy Palomar"", 16,","08-31-2023",0,NA,"PID - 16: 2024 - 2025: 09-08-2024","$21,900","$0","no","no","yes","$0",0,NA,NA,0,"$1,310.7792248062","$1,310.7792248062",17,"Active Property",7,"gmh - 16","Standard",NA,"Student Housing Portfolio",49 +"19","data-raw/working/GMH/CSV/Properties.csv","The Caswell at Runnymeade","The Caswell at Runnymeade","1000 Bluebird View, Newtown Square, Pennsylvania 19073",17,249,0,18,164,182,NA,NA,NA,0,0,179,0,55,0,0,NA,0,179,0,0,0,0,0,3,0,3,0,0,0,0,0,0,0,3,182,182,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=24&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=24&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=24&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NA,NA,NA,"$2790.554945055",NA,"$2790.554945055",162,NA,NA,-182,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,24,"no","no","no","Newtown Square, Pennsylvania",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=24&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Caswell at Runnymeade - WPO - 09-03-2024&dbid=bq5hz7i53&msid=24&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Caswell at Runnymeade - WPO - 09-03-2024&dbid=bq5hz7i53&msid=24&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=24&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",24,"70.85020242915%",NA,"
182
","0%",0,NA,NA,"09-05-2024",52,"09-02-2024","PID - 24: 2024 - 2025: 09-05-2024",NA,NA,"02-02-2024 12:17 PM","02-02-2024 12:19 PM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,NA,NA,NA,24,NA,NA,24,"
$507,881
","$507,881","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=24&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Caswell at Runnymeade","
182
","
%
",24,"
%
",NA,"
%
",NA,"
%
",NA,NA,"JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,NA,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,48,"08-08-2024","Student",24,"JT Bailey <62477437.bhmt>","no",24,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,24,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=24&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",24,NA,NA,NA,24,NA,"08-22-2024","08-08-2024",NA,NA,NA,"Newtown Square","United States","19073","Pennsylvania","1000 Bluebird View",NA,"08-29-2024",NA,NA,NA,NA,NA,NA,NA,24,"90.10989010989%",NA,24,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,0,"$0","$0","$0","$0","$507,881","$0","$0","$507,881","$0",0,"$0","$0",NA,NA,NA,0,2,0,0,0,"$0","$0",NA,NA,NA,"$507,881",NA,NA,NA,NA,0,0,0,0,0,0,0,NA,46,NA,0,NA,46,NA,24,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024",NA,NA,NA,NA,NA,"2023 - 2024",NA,"24: September - 2024","September - 2024","2025 - 2026","24: September 2024","24: October 2024","24: July 2025","24: August 2025","24: September 2025","24: November 2024","24: December 2024","24: January 2025","24: February 2025","24: March 2025","24: April 2025","24: May 2025","24: June 2025",247,0,175,"162 days","""The Caswell at Runnymeade"", 24,",NA,2,NA,"PID - 24: 2024 - 2025: 09-08-2024","$0","$0","yes","yes","yes","$0",0,NA,NA,0,NA,NA,NA,"Active Property",7,"gmh - 24","Standard",NA,"Conventional Portfolio",48 +"20","data-raw/working/GMH/CSV/Properties.csv","The Dean Campustown","The Dean Campustown","708 South Sixth Street, Champaign, Illinois 61820",21,271,672,281,402,683,"101.6369047619%","88.988095238095%",NA,0,0,598,0,56,13,15,NA,0,598,0,0,0,0,0,1,0,1,4,459,209,322,669,668,0,1,627,627,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=18&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=18&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=18&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$1077.6233183857","$1077.7020958084",NA,"$1199.831625183","$943.33333333333","$1199.831625183",85,"$1077.6233183857","$1077.7020958084",-11,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,18,"no","no","no","Champaign, Illinois","$115,562,157.26","$171,967.49592262","$525.29208376516","$358,888.68714286","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=18&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Dean Campustown - WPO - 09-03-2024&dbid=bq5hz7i53&msid=18&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Dean Campustown - WPO - 09-03-2024&dbid=bq5hz7i53&msid=18&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=18&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",18,"96.279761904762%",NA,"
15
","100%",672,"
2.2%
","101.6369047619%","09-05-2024",53,"09-02-2024","PID - 18: 2024 - 2025: 09-05-2024","10-15-2020",NA,"10-18-2020 04:42 PM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,"48.60884921848%","11.34054030869%",833617,18,"AGC","AGC",18,"
$170,950
","$170,950","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=18&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Dean Campustown","
11
","
1.6%
",18,"
%
",NA,"
%
",NA,"
11.3%
","22.29362021607%","11.34054030869%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 18: 2023 - 2024: 08-31-2023","99.404761904762%",18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,48,"08-01-2024","Student",18,"Bailey Tech Group QB <61083822.deca>","no",18,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,18,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=18&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",18,72,"0.14880952380952%","96.373788697737%",18,"0%","08-22-2024","08-08-2024",2,2,0,"Champaign","United States","61820","Illinois","708 South Sixth Street",NA,"08-29-2024","Cedric Jones <63070225.dz2p>","TheDean-Final Logo- orange and teal- 01.jpg",NA,NA,NA,1,"43.431221020093%",18,"58.857979502196%","41.815476190476%",18,219996,20420,240416,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,672,"$326,078.43","$633,920","$642,320","$8,400","$819,485","$720,930","$719,905","$819,485","$720,930",719905,"$648,535","$0","$0","$0","$0",672,0,0,647,672,"-$14,615","$8400","$338,347.63",NA,"$12,269.2","$813,270","0%",0,0,2020,0,0,0,0,0,0,0,11,16,78,0,45,137,"0%",18,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","09-21-2023 04:43 PM","12-01-2023 07:03 AM","01-28-2022 03:19 PM","The Dean Campustown - WPO - 11-30-2023_18.pdf","XL Document_18.pdf","2023 - 2024",NA,"18: September - 2024","September - 2024","2025 - 2026","18: September 2024","18: October 2024","18: July 2025","18: August 2025","18: September 2025","18: November 2024","18: December 2024","18: January 2025","18: February 2025","18: March 2025","18: April 2025","18: May 2025","18: June 2025",672,0,647,"85 days","""The Dean Campustown"", 18,","08-31-2023",0,NA,"PID - 18: 2024 - 2025: 09-08-2024","$368,700","$0","no","no","yes","$0",542556.42,672,672,659304.1,"$807.375625","$981.10729166667",18,"Active Property",7,"gmh - 18","Standard",NA,"Student Housing Portfolio",49 +"21","data-raw/working/GMH/CSV/Properties.csv","The Dean Reno","The Dean Reno",NA,14,205,773,245,419,664,"85.899094437257%","85.252263906856%",NA,0,0,659,0,56,0,13,NA,0,659,0,0,0,0,0,5,0,5,6,495,0,0,500,495,0,5,690,690,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=21&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=21&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=21&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"$948.85","$945.11111111111",NA,"$956.4548192771","$894.94566623545","$956.4548192771",478,"$948.85","$945.11111111111",109,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,21,"no","no","no",",",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=21&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Dean Reno - WPO - 09-03-2024&dbid=bq5hz7i53&msid=21&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Dean Reno - WPO - 09-03-2024&dbid=bq5hz7i53&msid=21&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=21&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",21,"72.056921086675%",NA,"
169
","100%",773,"
21.9%
","85.899094437257%","09-05-2024",53,"09-02-2024","PID - 21: 2024 - 2025: 09-05-2024",NA,NA,"10-24-2022 10:26 AM","12-01-2023 07:03 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,NA,"0.8014775019348%",1197887,21,NA,"CRG",21,"
$33,478
","$33,478","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=21&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Dean Reno","
-109
","
-14.1%
",21,"
%
",NA,"
%
",NA,"
1.2%
",NA,"0.8014775019348%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 21: 2023 - 2024: 08-31-2023","64.036222509702%",21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,48,"08-01-2024","Student",21,"JT Bailey <62477437.bhmt>","no",21,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,21,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=21&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",21,NA,"0.64683053040104%",NA,21,"0%","08-22-2024","08-08-2024",7,7,0,NA,"United States",NA,NA,NA,NA,"08-29-2024","Aaron Doucet <63066642.d9eq>",NA,NA,NA,NA,1,"43.985637342908%",21,"63.102409638554%","31.69469598965%",21,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,773,"$0","$691,793","$691,793","$0","$635,086","$474,425","$467,830","$635,086","$474,425",467830,"$601,608","$0",NA,NA,NA,773,0,0,557,0,"$90,185","$0",NA,NA,NA,"$725,271","0%",0,0,NA,0,0,0,0,0,0,0,0,0,0,0,0,133,"0%",21,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","12-02-2022 08:15 AM","12-01-2023 07:03 AM",NA,"The Dean Reno - WPO - 11-30-2023_21.pdf",NA,"2023 - 2024",NA,"21: September - 2024","September - 2024","2025 - 2026","21: September 2024","21: October 2024","21: July 2025","21: August 2025","21: September 2025","21: November 2024","21: December 2024","21: January 2025","21: February 2025","21: March 2025","21: April 2025","21: May 2025","21: June 2025",773,0,557,"478 days","""The Dean Reno"", 21,","08-31-2023",0,NA,"PID - 21: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",0,NA,NA,0,NA,NA,NA,"Active Property",7,"gmh - 21","Standard",NA,"Student Housing Portfolio",49 +"22","data-raw/working/GMH/CSV/Properties.csv","The Rise at Northgate","The Rise at Northgate","717 University Drive, College Station, Texas 77840",42,165,465,273,203,476,"102.36559139785%","102.1505376344%",NA,0,0,475,0,56,2,15,NA,0,475,0,0,0,0,0,1,0,1,0,190,275,457,465,465,0,1,482,482,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=17&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=17&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=17&z=9mb",3,0,4,0,435,0,0,0,0,0,0,0,0,3,0,"$965.97849462366","$965.97849462366",NA,"$1087.037815126","$796.3440860215","$1087.037815126",259,"$965.97849462366","$965.97849462366",-11,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,17,"no","no","no","College Station, Texas","$59,008,196.28","$125,282.79464968","$304.81172112052","$341,087.83976879","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=17&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Rise at Northgate - WPO - 09-03-2024&dbid=bq5hz7i53&msid=17&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Rise at Northgate - WPO - 09-03-2024&dbid=bq5hz7i53&msid=17&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=17&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",17,"54.408602150538%",NA,"
11
","100%",465,"
2.4%
","102.36559139785%","09-05-2024",53,"09-02-2024","PID - 17: 2024 - 2025: 09-05-2024","11-05-2015",NA,"10-18-2020 04:20 PM","12-01-2023 07:04 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,"32.088294656285%","12.532299753687%",518046,17,"Principal","Principal",17,"
$133,880
","$133,880","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=17&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Rise at Northgate","
11
","
2.4%
",17,"
%
",NA,"
%
",NA,"
12.5%
","32.088294656285%","12.532299753687%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 17: 2023 - 2024: 08-31-2023","100%",17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,0,0,0,18,0,444,0,0,0,444,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,17,48,"08-01-2024","Student",17,"Bailey Tech Group QB <61083822.deca>","no",17,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,17,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=17&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",17,271,"0.21505376344086%","99.690902801084%",17,"0%","08-22-2024","08-08-2024",4,4,0,"College Station","United States","77840","Texas","717 University Drive",NA,"08-29-2024","Aaron Doucet <63066642.d9eq>;Garrett Cline <63070217.dkpm>","black box.png",NA,NA,NA,1,"59.09090909091%",17,"42.64705882353%","58.709677419355%",17,193589,0,193589,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,465,"$366,556.87","$370,300","$378,425","$8,125","$517,430","$449,180","$449,180","$517,430","$449,180",449180,"$383,550","$0","$0","$0","$0",465,0,0,462,465,"-$13,250","$8125","$367,693.4",NA,"$1,136.53","$512,305","0%",0,0,2013,0,0,0,0,0,0,0,11,12,58,0,34,95,"0%",17,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","10-02-2023 07:49 AM","12-01-2023 07:04 AM","10-02-2023 07:49 AM","The Rise at Northgate - WPO - 11-30-2023_17.pdf","XL Document_17.xlsx","2023 - 2024",NA,"17: September - 2024","September - 2024","2025 - 2026","17: September 2024","17: October 2024","17: July 2025","17: August 2025","17: September 2025","17: November 2024","17: December 2024","17: January 2025","17: February 2025","17: March 2025","17: April 2025","17: May 2025","17: June 2025",465,0,253,"259 days","""The Rise at Northgate"", 17,","08-31-2023",0,NA,"PID - 17: 2024 - 2025: 09-08-2024","$0","$0","yes","no","yes","$0",385446.33,465,465,385446.33,"$822.96301724138","$822.96301724138",19,"Active Property",7,"gmh - 17","Space Options",NA,"Student Housing Portfolio",49 +"23","data-raw/working/GMH/CSV/Properties.csv","The Venue at North Campus","Venue at North Campus","13702 North 42nd Street, Tampa, Florida 33613",7,0,734,353,340,693,"94.41416893733%","94.41416893733%",NA,0,0,693,0,56,0,6,NA,0,693,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,715,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=23&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=23&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=23&z=9mb",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NA,NA,NA,"$930.8152958153","$0","$930.8152958153",NA,NA,NA,41,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,23,"no","no","no","Tampa, Florida",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=23&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Venue at North Campus - WPO - 09-03-2024&dbid=bq5hz7i53&msid=23&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=The Venue at North Campus - WPO - 09-03-2024&dbid=bq5hz7i53&msid=23&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=23&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",23,"88.964577656676%",NA,"
693
","0%",0,"
94.4%
",NA,"09-05-2024",53,"09-02-2024","PID - 23: 2024 - 2025: 09-05-2024",NA,NA,"12-18-2023 03:52 PM","12-19-2023 12:22 PM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,NA,NA,NA,23,NA,NA,23,"
$645,055
","$645,055","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=23&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","The Venue at North Campus","
693
","
94.4%
",23,"
%
",NA,"
%
",NA,"
%
",NA,NA,"JT Bailey <62477437.bhmt>","09-05-2023",NA,NA,"0%",23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,48,"08-01-2024","Student",23,"JT Bailey <62477437.bhmt>","no",23,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,23,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=23&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",23,NA,"0%",NA,23,"0%","08-22-2024","08-08-2024",NA,NA,NA,"Tampa","United States","33613","Florida","13702 North 42nd Street",NA,"08-29-2024",NA,NA,NA,NA,NA,1,"54.05819295559%",23,"49.06204906205%","48.092643051771%",23,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,734,"$0","$0","$0","$0","$645,055","$0","$0","$645,055","$0",0,"$0","$0",NA,NA,NA,734,0,0,653,0,"$0","$0",NA,NA,NA,"$645,055",NA,NA,NA,NA,0,0,0,0,0,0,0,0,6,32,0,0,139,"0%",23,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024",NA,NA,NA,NA,NA,"2023 - 2024",NA,"23: September - 2024","September - 2024","2025 - 2026","23: September 2024","23: October 2024","23: July 2025","23: August 2025","23: September 2025","23: November 2024","23: December 2024","23: January 2025","23: February 2025","23: March 2025","23: April 2025","23: May 2025","23: June 2025",734,0,653,NA,"""The Venue at North Campus"", 23,",NA,0,NA,"PID - 23: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",0,NA,NA,0,NA,NA,NA,"Active Property",7,"gmh - 23","Standard",NA,"Student Housing Portfolio",49 +"24","data-raw/working/GMH/CSV/Properties.csv","Torre","Torre",NA,62,0,558,166,360,526,"94.26523297491%","89.78494623656%",NA,0,0,501,0,56,0,41,NA,0,501,0,0,0,0,0,0,0,0,6,362,146,0,509,508,0,0,526,525,0,"https://gmh.quickbase.com/db/bq5hz7i9f?a=API_GenAddRecordForm&_fid_12=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7i58?a=API_GenAddRecordForm&_fid_14=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7i6d?a=API_GenAddRecordForm&_fid_90=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7jgr?a=API_GenAddRecordForm&_fid_12=19&z=9mb","https://gmh.quickbase.com/db/bq8c8mj2g?a=API_GenAddRecordForm&_fid_10=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7i5z?a=API_GenAddRecordForm&_fid_6=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8r?a=API_GenAddRecordForm&_fid_12=19&z=9mb","https://gmh.quickbase.com/db/bq5hz7i8t?a=API_GenAddRecordForm&_fid_11=19&z=9mb",61,0,3,0,398,0,0,0,0,0,0,14,0,28,0,"$1276.9548133595","$1276.7224409449",NA,"$1332.0703422053","$0","$1332.0703422053",NA,"$1276.9548133595","$1276.7224409449",32,NA,NA,"$0",NA,NA,NA,NA,"$0",NA,NA,NA,"$0",NA,NA,NA,19,"no","no","no",",",NA,NA,NA,NA,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=19&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs5/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Torre - WPO - 09-03-2024&dbid=bq5hz7i53&msid=19&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=","https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=Torre - WPO - 09-03-2024&dbid=bq5hz7i53&msid=19&faid=117&xlddte=606&docfmt=pdf&stream=n&apptoken=","javascript:var wnd=window.open('https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_LP.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=19&faid=117&xlddte=118&docfmt=pdf&apptoken=c48jy9bp9vb7frmw395cuyxw','copy','top=240,left=320,width=500,height=350,location=no,menubar=no,toolbar=no'); + +var id=setInterval(function() {if (wnd.closed) {clearInterval(id);location.reload(true);}},1000);void(0);","Create XL Sheet (stream back)","Create XL Sheet","09-04-2024",19,"89.605734767025%",NA,"
18
","100%",558,"
3.2%
","94.26523297491%","09-05-2024",53,"09-02-2024","PID - 19: 2024 - 2025: 09-05-2024",NA,NA,"12-06-2021 02:10 PM","12-01-2023 07:04 AM",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,NA,"4.316169082036%",1143679,19,NA,"CBRE",19,"
$700,669
","$700,669","https://www.aws-juiced-client2.com/Juiced/XLDocs1/ExcelGen_UA.aspx?clientid=Q2097&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=1&fn=XL Document&dbid=bq5hz7i53&msid=19&faid=117&xlddte=118&docfmt=pdf&stream=y&apptoken=c48jy9bp9vb7frmw395cuyxw","Torre","
-32
","
-5.7%
",19,"
%
",NA,"
%
",NA,"
4.3%
",NA,"4.316169082036%","JT Bailey <62477437.bhmt>","09-05-2023","08-31-2023","PID - 19: 2023 - 2024: 08-31-2023","91.039426523297%",19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,389,0,0,3,14,0,451,0,3,0,451,0,0,17,0,0,0,0,127,0,0,0,0,0,0,0,0,19,48,"08-01-2024","Student",19,"JT Bailey <62477437.bhmt>","no",19,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,19,"https://www.aws-juiced-client2.com/Juiced/XLDocs3/ExcelGen_UA.aspx?clientid=Q2258&appid=bq5hz7i5b&tpdbid=bq5hz7i9i&tpid=5&fn=XL Document&dbid=bq5hz7i53&msid=19&faid=434&xlddte=435&docfmt=xlsx&stream=y&apptoken=",19,NA,"0%",NA,19,"0%","08-22-2024","08-08-2024",6,6,0,NA,"United States",NA,NA,NA,NA,"08-29-2024","Aaron Doucet <63066642.d9eq>",NA,NA,NA,NA,1,"33.2%",19,"68.441064638783%","29.749103942652%",19,NA,NA,NA,"09-03-2024","Tu",0,0,"09-02-2024","M",0,0,"09-01-2024","Su",0,0,"08-31-2024","Sa",0,0,"08-30-2024",FALSE,0,0,"08-29-2024","Th",0,0,"08-28-2024","W",0,0,558,"$0","$0","$0","$0","$700,669","$649,970","$648,575","$700,669","$649,970",648575,"$0","$0","$0","$0","$0",558,0,0,500,0,"$0","$0",NA,NA,NA,"$700,669","0%",0,0,NA,0,0,0,0,0,0,0,0,5,24,0,0,105,"0%",19,"2024 - 2025","08-30-2024","08-31-2024","09-01-2024","09-02-2024","09-03-2024","09-04-2024","09-05-2024","09-21-2023 04:16 PM","12-01-2023 07:04 AM","04-06-2022 12:35 PM","Torre - WPO - 11-30-2023_19.pdf","XL Document_19.xlsx","2023 - 2024",NA,"19: September - 2024","September - 2024","2025 - 2026","19: September 2024","19: October 2024","19: July 2025","19: August 2025","19: September 2025","19: November 2024","19: December 2024","19: January 2025","19: February 2025","19: March 2025","19: April 2025","19: May 2025","19: June 2025",558,0,500,NA,"""Torre"", 19,","08-31-2023",0,NA,"PID - 19: 2024 - 2025: 09-08-2024","$0","$0","no","no","yes","$0",0,NA,NA,0,NA,NA,20,"Active Property",7,"gmh - 19","Standard",NA,"Student Housing Portfolio",49 diff --git a/data/app_choices.rda b/data/app_choices.rda new file mode 100644 index 0000000..ba169f3 Binary files /dev/null and b/data/app_choices.rda differ diff --git a/data/app_info.rda b/data/app_info.rda new file mode 100644 index 0000000..b37d4c4 Binary files /dev/null and b/data/app_info.rda differ diff --git a/data/client_info.rda b/data/client_info.rda new file mode 100644 index 0000000..fcdf20f Binary files /dev/null and b/data/client_info.rda differ diff --git a/data/developer_info.rda b/data/developer_info.rda new file mode 100644 index 0000000..f415ff8 Binary files /dev/null and b/data/developer_info.rda differ diff --git a/data/entrata_default_methods_tbl.rda b/data/entrata_default_methods_tbl.rda new file mode 100644 index 0000000..c4b30dd Binary files /dev/null and b/data/entrata_default_methods_tbl.rda differ diff --git a/data/entrata_endpoints.rda b/data/entrata_endpoints.rda new file mode 100644 index 0000000..26fde85 Binary files /dev/null and b/data/entrata_endpoints.rda differ diff --git a/data/entrata_info.rda b/data/entrata_info.rda new file mode 100644 index 0000000..3a7e538 Binary files /dev/null and b/data/entrata_info.rda differ diff --git a/data/entrata_method_versions.rda b/data/entrata_method_versions.rda new file mode 100644 index 0000000..692b08f Binary files /dev/null and b/data/entrata_method_versions.rda differ diff --git a/data/entrata_methods_tbl.rda b/data/entrata_methods_tbl.rda new file mode 100644 index 0000000..aeafae4 Binary files /dev/null and b/data/entrata_methods_tbl.rda differ diff --git a/data/entrata_params_tbl.rda b/data/entrata_params_tbl.rda new file mode 100644 index 0000000..eec4220 Binary files /dev/null and b/data/entrata_params_tbl.rda differ diff --git a/data/entrata_used_methods_tbl.rda b/data/entrata_used_methods_tbl.rda new file mode 100644 index 0000000..85494ef Binary files /dev/null and b/data/entrata_used_methods_tbl.rda differ diff --git a/dev/app/app_docker.R b/dev/R/checks.R similarity index 100% rename from dev/app/app_docker.R rename to dev/R/checks.R diff --git a/dev/R/db_connect.R b/dev/R/db_connect.R index e69de29..a2cd191 100644 --- a/dev/R/db_connect.R +++ b/dev/R/db_connect.R @@ -0,0 +1,31 @@ + +# ------------------------------------------------------------------------ +# +# Title : Database Connection +# By : Jimmy Briggs +# Date : 2024-11-13 +# +# ------------------------------------------------------------------------ + +db_connect <- function(db_config, ...) { + + conn <- pool::dbPool( + drv = RPostgres::Postgres(), + dbname = db_config$dbname, + host = db_config$host, + port = db_config$port, + username = db_config$username, + password = db_config$password + ) + + return(conn) + +} + +debounced_db_query <- shiny::debounce(function(conn, qry, ...) { + + # query database + pool::dbGetQuery(conn, qry, ...) + +}, millis = 1000) + diff --git a/dev/R/entrata_api.R b/dev/R/entrata_api.R new file mode 100644 index 0000000..23fa83b --- /dev/null +++ b/dev/R/entrata_api.R @@ -0,0 +1,179 @@ + +# ------------------------------------------------------------------------ +# +# Title : Entrata API Client +# By : Jimmy Briggs +# Date : 2024-11-13 +# +# ------------------------------------------------------------------------ + +exponential_backoff <- function(num_requests) { + backoff <- 2^num_requests + jitter <- runif(1, 0, 1) + backoff <- backoff + jitter + return(min(backoff, 60)) +} + +retry_after <- function(resp) { + time <- as.numeric(httr2::resp_headers(resp, "X-RateLimit-Reset")) +} + +entrata_resp_parse_rate_limit_headers <- function(resp) { + + headers <- httr2::resp_headers( + resp, + filter = "x-ratelimit-limit|x-ratelimit-remaining|x-ratelimit-reset" + ) + + + + +} + +entrata_api <- function(entrata_config) { + + base_url <- entrata_config$base_url + username <- entrata_config$username + password <- entrata_config$password + + user_agent <- entrata_config$user_agent %||% "gmhdatahub/0.0.1" + + retry_policy <- list( + max_tries = 10, + max_seconds = 60, + retry_on_failure = TRUE, + is_transient = function(resp) { + status_transient <- httr2::resp_status(resp) %in% c(408, 429, 500:599) + headers_transient <- "x-ratelimit-remaining" %in% tolower(names(httr2::resp_headers(resp))) && + tolower(httr2::resp_headers(resp))$`x-ratelimit-remaining` == "0" + status_transient || headers_transient + }, + backoff = exponential_backoff + ) + + req <- httr2::request(base_url) |> + httr2::req_auth_basic(username, password) |> + httr2::req_user_agent(user_agent) |> + httr2::req_retry(!!!retry_policy) |> + httr2::req_throttle(rate = 25 / 60) |> + httr2::req_error(is_error = entrata_resp_is_error, body = entrata_resp_body_error) + + structure( + list( + req = req, + config = entrata_config + ), + class = c("entrata_request", "httr2_request") + ) + +} + +set_entrata_config <- function(api, ...) { + api$config <- modifyList(api$config, list(...)) + api +} + +entrata_error <- function(resp) { + cond <- structure( + list( + message = paste("Entrata API Request failed: ", resp$status), + resposne = resp + ), + class = c("entrata_error", "error", "condition") + ) + stop(cond) +} + +entrata_resp_error_body <- function(resp) { + entrata_error(resp) +} + +entrata_req_error <- function(req) { + req |> + httr2::req_error(is_error = entrata_resp_is_error, body = entrata_resp_error_body) +} + +# entrata_req_retry <- function(req, max_tries = 10, backoff = ) + +library(ratelimitr) + +entrata_rate_limited <- limit_rate( + entrata_request, + rate(n = 10, period = 60) +) + +library(memoise) + +cached_get_customers <- memoise(get_customers) + +library(logger) + +log_request <- function(req) { + log_info("Making request to {req$url}") +} + +req_before(\(req) log_request(req)) + +library(jsonvalidate) + +validate_customer_response <- function(json) { + schema <- '{ + "type": "object", + "properties": { + "id": {"type": "integer"}, + "name": {"type": "string"} + }, + "required": ["id", "name"] + }' + + json_validate(json, schema) +} + +entrata_status <- function(api, ...) { + api$req |> + httr2::req_url_path_append("status") |> + httr2::req_body_json( + list( + auth = list( + type = "basic" + ), + method = list( + name = "getStatus", + version = "r1", + params = list(NULL) + ) + ) + ) |> + httr2::req_perform() |> + httr2::resp_body_json() |> + purrr::pluck("response", "result") +} + +# access-control-allow-origin: * +# access-control-expose-headers: Link, X-Total-Count, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Content-Language + +entrata_req_retry <- function(req) { + req |> + httr2::req_retry( + max_tries = 5, + is_transient = function(resp) { + rate_info <- entrata_resp_parse_rate_limit_headers(resp) + httr2::resp_status(resp) == 429 || + all(sapply(rate_info$remaining, function(x) x == 0)) + }, + backoff = function(resp) { + rate_info <- entrata_resp_parse_rate_limit_headers(resp) + max(rate_info$reset$minute, rate_info$reset$hour, rate_info$reset$day, 1) + } + ) +} + +entrata_req_throttle <- function(req) { + req |> + httr2::req_throttle(rate = 25 / 60) # 25 requests per minute +} + +entrata_req_cache <- function(req) { + req |> + httr2::req_cache(path = "entrata_cache") +} diff --git a/dev/app/app_run.R b/dev/R/mod_dashboard_cards.R similarity index 100% rename from dev/app/app_run.R rename to dev/R/mod_dashboard_cards.R diff --git a/dev/pkg/pkg_build.R b/dev/R/mod_entrata.R similarity index 100% rename from dev/pkg/pkg_build.R rename to dev/R/mod_entrata.R diff --git a/dev/pkg/pkg_hex.R b/dev/R/mod_leasing.R similarity index 100% rename from dev/pkg/pkg_hex.R rename to dev/R/mod_leasing.R diff --git a/dev/R/mod_navigation.R b/dev/R/mod_navigation.R new file mode 100644 index 0000000..e69de29 diff --git a/dev/R/mod_valboxes.R b/dev/R/mod_valboxes.R new file mode 100644 index 0000000..e69de29 diff --git a/dev/pkg/pkg_assets.R b/dev/pkg_assets.R similarity index 100% rename from dev/pkg/pkg_assets.R rename to dev/pkg_assets.R diff --git a/dev/pkg/pkg_devt.R b/dev/pkg_devt.R similarity index 99% rename from dev/pkg/pkg_devt.R rename to dev/pkg_devt.R index 65ebb15..17e4e35 100644 --- a/dev/pkg/pkg_devt.R +++ b/dev/pkg_devt.R @@ -66,3 +66,6 @@ c( usethis::use_coverage() covr::codecov() covrpage::covrpage() + + + diff --git a/dev/pkg_docs.R b/dev/pkg_docs.R new file mode 100644 index 0000000..8b3026a --- /dev/null +++ b/dev/pkg_docs.R @@ -0,0 +1,20 @@ + +# ------------------------------------------------------------------------ +# +# Title : Package Documentation Development +# By : Jimmy Briggs +# Date : 2024-11-12 +# +# ------------------------------------------------------------------------ + +# vignettes --------------------------------------------------------------- + +usethis::use_vignette("gmhdatahub") + +usethis::use_vignette("workflow") + +c( + "entrata", + "properties" +) |> + purrr::walk(usethis::use_vignette) diff --git a/dev/pkg/pkg_init.R b/dev/pkg_init.R similarity index 100% rename from dev/pkg/pkg_init.R rename to dev/pkg_init.R diff --git a/dev/sandbox/custom_httr2_proxied_requests_with_mitmproxy.R b/dev/sandbox/custom_httr2_proxied_requests_with_mitmproxy.R new file mode 100644 index 0000000..c28f609 --- /dev/null +++ b/dev/sandbox/custom_httr2_proxied_requests_with_mitmproxy.R @@ -0,0 +1,241 @@ +require(httr2) +library(reticulate) + +fs::dir_create(".venv") +reticulate::use_virtualenv(fs::path(getwd(), ".venv")) +reticulate::py_install(c("mitmproxy", "mitmproxy2swagger")) + +mitmproxy <- reticulate::import("mitmproxy") +mitmdump <- reticulate::import("mitmproxy.tools.dump") +mitmproxy2swagger <- reticulate::import("mitmproxy2swagger") + +# Function to start mitmdump +start_mitmdump <- function(outfile) { + + options <- list( + listen_host = "127.0.0.1", + listen_port = 8080, + save_stream_file = outfile + ) + + master <- mitmdump$DumpMaster(options) + master$run() +} + +# Function to convert mitmdump output to OpenAPI spec +mitmdump_to_swagger <- function(input_file, output_file, api_prefix) { + # mitmproxy2swagger -i -o -p + mitmproxy2swagger$mitmproxy2swagger( + "-i", input_file, + "-o", output_file, + "-p", api_prefix + ) +} + +# Function to set up a proxy for httr2 requests +# setup_mitmproxy <- function(host = "127.0.0.1", port = 8080, config) { +# +# } + +Sys.setenv(CURL_CA_BUNDLE = "/path/to/mitmproxy-ca-cert.pem") + +proxy_url <- "http://localhost:8080" + +entrata_config <- config::get("entrata") + +base_req <- httr2::request(entrata_config$base_url) |> + httr2::req_auth_basic(entrata_config$username, entrata_config$password) |> + httr2::req_method("POST") |> + httr2::req_headers(`Content-Type` = "application/json") |> + httr2::req_user_agent("gmhdatahub/0.1.0 (https://github.com/noclocks/gmhdatahub)") |> + httr2::req_verbose( + header_req = TRUE, + header_resp = TRUE, + body_req = TRUE, + body_resp = TRUE, + info = TRUE, + redact_headers = TRUE + ) |> + httr2::req_progress() |> + httr2::req_body_json( + list( + auth = list( + type = "basic" + ), + requestId = 15, + method = list( + name = NULL, + version = "r1", + params = list(NULL) + ) + ) + ) |> + httr2::req_proxy( + url = "127.0.0.1", + port = 8080, + username = config$username, + password = config$password, + auth = "basic" + ) + +entrata_req_proxy_perform <- function(endpoint, body) { + + req <- base_req |> httr2::req_url_path_append(endpoint) |> + httr2::req_body_json(body) + + entrata_req_log(req) + req |> httr2::req_perform() + entrata_resp_log(resp) + resp +} + +entrata_req_log <- function(req) { + + logger::log_info("Request URL: {req$url}") + logger::log_info("Request Method: {req$method}") + logger::log_info("Request Headers: {req$headers}") + logger::log_info("Request Body: {req$body}") + +} + +entrata_resp_log <- function(resp) { + + logger::log_info("Response Status: {resp$status_code}") + logger::log_info("Response Headers: {resp$headers}") + logger::log_info("Response Body:\n{httr2::resp_body_string(resp)}") + +} + + + +out_file <- "data-raw/entrata_captured_traffic.flow" +future::future(start_mitmdump(out_file)) + +req_status <- httr2::request(entrata_config$base_url) |> + httr2::req_url_path_append("status") |> + httr2::req_auth_basic(entrata_config$username, entrata_config$password) |> + httr2::req_method("POST") |> + httr2::req_headers(`Content-Type` = "application/json") |> + httr2::req_user_agent("gmhdatahub/0.1.0 (https://github.com/noclocks/gmhdatahub)") |> + httr2::req_verbose( + header_req = TRUE, + header_resp = TRUE, + body_req = TRUE, + body_resp = TRUE, + info = TRUE, + redact_headers = TRUE + ) |> + httr2::req_progress() |> + httr2::req_body_json( + list( + auth = list( + type = "basic" + ), + requestId = 15, + method = list( + name = "getStatus", + version = "r1", + params = list(NULL) + ) + ) + ) |> + httr2::req_proxy( + url = "127.0.0.1", + port = 8080, + username = entrata_config$username, + password = entrata_config$password, + auth = "basic" + ) + +req + +resp_status <- req_status |> httr2::req_perform() + +mitmdump_to_swagger( + input_file = out_file, + output_file = "data-raw/entrata_apispec.yml", + api_prefix = entrata_config$base_url +) + + +req_properties <- httr2::request(entrata_config$base_url) |> + httr2::req_url_path_append("properties") |> + httr2::req_auth_basic(entrata_config$username, entrata_config$password) |> + httr2::req_method("POST") |> + httr2::req_headers(`Content-Type` = "application/json") |> + httr2::req_user_agent("gmhdatahub/0.1.0 (https://github.com/noclocks/gmhdatahub)") |> + httr2::req_verbose( + header_req = TRUE, + header_resp = TRUE, + body_req = TRUE, + body_resp = TRUE, + info = TRUE, + redact_headers = TRUE + ) |> + httr2::req_progress() |> + httr2::req_body_json( + list( + auth = list( + type = "basic" + ), + requestId = 15, + method = list( + name = "getProperties", + version = "r1", + params = list( + propertyId = "" + ) + ) + ) + ) |> + httr2::req_proxy( + url = "http://127.0.0.1", + port = 8080, + username = entrata_config$username, + password = entrata_config$password, + auth = "basic" + ) + +req + +resp_properties <- req_properties |> httr2::req_perform() +resp_properties_content <- resp_properties |> httr2::resp_body_json() +resp_properties_data <- purrr::pluck( + resp_properties_content, "response", "result", "PhysicalProperty", "Property" +) |> + parse_properties_response() + +# queue +req_queue |> httr2::req_proxy( + url = "http://127.0.0.1", + port = 8080, + username = entrata_config$username, + password = entrata_config$password, + auth = "basic" +) |> + httr2::req_perform() + +# reports +req |> httr2::req_proxy( + url = "http://127.0.0.1", + port = 8080, + username = entrata_config$username, + password = entrata_config$password, + auth = "basic" +) |> + httr2::req_perform() + +# arcodes +httr2::request(entrata_config$base_url) |> + httr2::req_url_path_append("arcodes") |> + httr2::req_auth_basic(entrata_config$username, entrata_config$password) |> + httr2::req_method("POST") |> + httr2::req_headers(`Content-Type` = "application/json") |> + httr2::req_proxy( + url = "http://127.0.0.1", + port = 8080, + username = entrata_config$username, + password = entrata_config$password, + auth = "basic" + ) |> + httr2::req_perform() diff --git a/dev/sandbox/mitmproxy/apispec.yml b/dev/sandbox/mitmproxy/apispec.yml new file mode 100644 index 0000000..59ff6de --- /dev/null +++ b/dev/sandbox/mitmproxy/apispec.yml @@ -0,0 +1,411 @@ +openapi: 3.0.0 +info: + title: .\traffic Mitmproxy2Swagger + version: 1.0.0 +servers: +- url: https://gmhcommunities.entrata.com/api/v1 + description: The default server +paths: + /status: + post: + summary: POST status + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + type: object + properties: + requestId: + type: string + code: + type: number + result: + type: object + properties: + status: + type: string + message: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + auth: + type: object + properties: + type: + type: string + requestId: + type: number + method: + type: object + properties: + name: + type: string + version: + type: string + params: + type: array + items: + type: object + /properties: + post: + summary: POST properties + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + type: object + properties: + requestId: + type: string + code: + type: number + result: + type: object + properties: + PhysicalProperty: + type: object + properties: + Property: + type: array + items: + type: object + properties: + PropertyID: + type: number + MarketingName: + type: string + Type: + type: string + webSite: + type: string + Address: + type: object + properties: + '@attributes': + type: object + properties: + AddressType: + type: string + Address: + type: string + City: + type: string + State: + type: string + PostalCode: + type: string + Country: + type: string + Email: + type: string + Addresses: + type: object + properties: + Address: + type: array + items: + type: object + properties: + AddressType: + type: string + Address: + type: string + City: + type: string + StateCode: + type: string + PostalCode: + type: string + Country: + type: string + PostMonths: + type: object + properties: + ArPostMonth: + type: string + ApPostMonth: + type: string + GlPostMonth: + type: string + PropertyHours: + type: object + properties: + OfficeHours: + type: object + properties: + OfficeHour: + type: array + items: + type: object + properties: + Day: + type: string + AvailabilityType: + type: string + OpenTime: + type: string + CloseTime: + type: string + IsDisabled: + type: number + IsFeaturedProperty: + type: number + SpaceOptions: + type: object + properties: + SpaceOption: + type: array + items: + type: object + properties: + Id: + type: string + Name: + type: string + LeaseTerms: + type: object + properties: + LeaseTerm: + type: array + items: + type: object + properties: + Id: + type: number + Name: + type: string + TermMonths: + type: number + IsProspect: + type: number + IsRenewal: + type: number + requestBody: + content: + application/json: + schema: + type: object + properties: + auth: + type: object + properties: + type: + type: string + requestId: + type: number + method: + type: object + properties: + name: + type: string + version: + type: string + params: + type: array + items: + type: object + /queue: + post: + summary: POST queue + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + type: object + properties: + requestId: + type: string + code: + type: number + result: + type: object + properties: + reportData: + type: array + items: + type: object + properties: + property: + type: string + property_name: + type: string + lease_type: + type: string + lead: + type: object + lead_id: + type: object + initial_contact_date: + type: object + leasing_agent: + type: object + lease_creation_date: + type: object + building_units: + type: object + applicant_type: + type: object + application_approved: + type: number + generated: + type: number + signed: + type: number + approved: + type: number + cancelled: + type: object + move_in: + type: number + reopened_on: + type: object + lease_approved_by: + type: object + queueStartedOn: + type: string + queueCompletedOn: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + auth: + type: object + properties: + type: + type: string + requestId: + type: number + method: + type: object + properties: + name: + type: string + version: + type: string + params: + type: object + properties: + queueId: + type: string + serviceName: + type: string + /reports: + post: + summary: POST reports + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + type: object + properties: + requestId: + type: string + code: + type: number + result: + type: object + properties: + queueId: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + auth: + type: object + properties: + type: + type: string + requestId: + type: number + method: + type: object + properties: + name: + type: string + version: + type: string + params: + type: object + properties: + reportName: + type: string + reportVersion: + type: string + filters: + type: object + properties: + property_group_ids: + type: array + items: + type: string + period: + type: object + properties: + daterange: + type: object + properties: + daterange-start: + type: string + daterange-end: + type: string + period_type: + type: string + results_based_on: + type: string + lease_type: + type: array + items: + type: string + summarize_by: + type: string + group_by: + type: string + consolidate_by: + type: string + arrange_by_property: + type: string + subtotals: + type: string + /arcodes: + post: + summary: POST arcodes + responses: + '200': + description: OK + content: {} +x-path-templates: +# Remove the ignore: prefix to generate an endpoint with its URL +# Lines that are closer to the top take precedence, the matching is greedy +- /propertyunits +- /leases +- ignore:/documentation diff --git a/dev/sandbox/mitmproxy/flows b/dev/sandbox/mitmproxy/flows new file mode 100644 index 0000000..f544c1a Binary files /dev/null and b/dev/sandbox/mitmproxy/flows differ diff --git a/dev/sandbox/mitmproxy/traffic b/dev/sandbox/mitmproxy/traffic new file mode 100644 index 0000000..cb46b89 Binary files /dev/null and b/dev/sandbox/mitmproxy/traffic differ diff --git a/dev/sandbox/mitmproxy/traffic.flow b/dev/sandbox/mitmproxy/traffic.flow new file mode 100644 index 0000000..329eeb5 --- /dev/null +++ b/dev/sandbox/mitmproxy/traffic.flow @@ -0,0 +1,33 @@ +POST /api/v1/status HTTP/1.1 +Host: gmhcommunities.entrata.com +User-Agent: gmhdatahub/0.1.0 (https://github.com/noclocks/gmhdatahub) +Accept: */* +Accept-Encoding: deflate, gzip +Authorization: Basic Z21oX2NvbW11bml0aWVzX3JlcG9ydGluZ18yNDE2QGdtaGNvbW11bml0aWVzOk52eigyWWZARzc= +Content-Type: application/json +Content-Length: 101 + +{"auth":{"type":"basic"},"requestId":15,"method":{"name":"getStatus","version":"r1","params":[null]}} + +HTTP/1.1 200 OK +Date: Wed, 13 Nov 2024 19:42:17 GMT +Content-Type: application/json;charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +vary: Authorization +access-control-allow-origin: * +access-control-expose-headers: Link, X-Total-Count, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Content-Language +x-ratelimit-limit: 8640/day;360/hour;6/minute +x-ratelimit-remaining: 8639/day;359/hour;5/minute +x-ratelimit-reset: 40662;1062;42 +x-read-only: 000 +CF-Cache-Status: DYNAMIC +Set-Cookie: __cf_bm=vC_f5xG9iUXpIDs0HuVV6QqMIKOvVxRnGBjGXYqurh4-1731526937-1.0.1.1-ijMMvQEmz9i6TQTKZXD_AoMZcCJ5xS84jNT.F2JgIj4pjABYL.ToePSx1dSskvA5HMm5XdOOUr2vFqoKlXhHaw; path=/; expires=Wed, 13-Nov-24 20:12:17 GMT; domain=.entrata.com; HttpOnly; Secure; SameSite=None +Server: cloudflare +CF-RAY: 8e213e7f1de7bffa-ATL +alt-svc: h3=":443"; ma=86400 + +7a +{"response":{"requestId":"15","code":200,"result":{"status":"Success","message":"API service is available and running."}}} +0 + diff --git a/dev/sandbox/properties_response_parsers.R b/dev/sandbox/properties_response_parsers.R new file mode 100644 index 0000000..85d3789 --- /dev/null +++ b/dev/sandbox/properties_response_parsers.R @@ -0,0 +1,515 @@ +parse_properties_response <- function(res_data) { + + # extract base properties tibble + property_tbl_init <- res_data |> + jsonlite::toJSON(auto_unbox = TRUE) |> + jsonlite::fromJSON(flatten = TRUE) |> + tibble::as_tibble() + + # extract base properties tibble + properties_tbl_base <- parse_property_base_data(property_tbl_init) + + # parse nested address data (primary/main property address + mailing sub-addresses): + property_addresses <- parse_property_address_data(property_tbl_init) + + # parse nested post months + property_post_months <- parse_property_post_months(property_tbl_init) + + # parse nested property hours (office/pool) + property_hours <- parse_property_hours(property_tbl_init) + + # parse nested space options + property_space_options <- parse_property_space_options(property_tbl_init) + + # parse nested lease terms + property_lease_term_windows <- parse_property_lease_term_windows(property_tbl_init) + + # parse nested phone data + property_phones <- parse_property_phones(property_tbl_init) + + # parse nested custom keys data + property_custom_keys <- parse_property_custom_keys(property_tbl_init) + + list( + property_tbl_base = properties_tbl_base, + property_addresses = property_addresses, + property_post_months = property_post_months, + property_hours = property_hours, + property_space_options = property_space_options, + property_lease_term_windows = property_lease_term_windows, + property_phones = property_phones, + property_custom_keys = property_custom_keys + ) + +} + +#' Entrata Property Parsers +#' +#' @name entrata_property_parsers +#' +#' @description +#' These functions parse the response data from the Entrata API `/properties` endpoint's +#' `getProperties` method into various tibbles containing the response's property-level +#' information and data. +#' +#' @details +#' These functions all use the `property_tbl_init` tibble as the initial data source +#' for parsing the various property data components. +#' +#' This tibble is generated from performing the following operations on the +#' extracted, nested JSON data from the response data: +#' +#' ```R +#' property_tbl_init <- res_data |> +#' jsonlite::toJSON(auto_unbox = TRUE) |> +#' jsonlite::fromJSON(flatten = TRUE) |> +#' tibble::as_tibble() +#' ``` +#' +#' which flattens the nested JSON data into a tibble ready to be parsed. +#' +#' @section Functions: +#' - `parse_property_base_data()` - Parse base property data +#' - `parse_property_address_data()` - Parse property address data +#' - `parse_property_post_months()` - Parse property post months +#' - `parse_property_hours()` - Parse property hours +#' - `parse_property_space_options()` - Parse property space options +#' - `parse_property_lease_term_windows()` - Parse property lease term windows +#' - `parse_property_phones()` - Parse property phone numbers +#' - `parse_property_custom_keys()` - Parse property custom keys +#' +#' @param property_tbl_init Initial property data tibble (see details). +#' +#' @seealso [parse_properties_response()] for the main parsing function. +#' +#' @return A tibble containing the parsed property data. +NULL + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr select rename +#' @importFrom purrr keep +#' @importFrom cli cli_alert_warning +#' @importFrom tidyselect all_of any_of +parse_property_base_data <- function(property_tbl_init) { + + # determine which columns are available to extract + expected_cols <- c( + "PropertyID", + "MarketingName", + "Type", + "webSite", + "ShortDescription", + "LongDescription", + "IsDisabled", + "IsFeaturedProperty", + "ParentPropertyID", + "YearBuilt" + ) + + select_cols <- intersect( + expected_cols, + colnames(property_tbl_init) + ) + + excluded_cols <- setdiff( + expected_cols, + colnames(property_tbl_init) + ) + + if (length(excluded_cols) > 0) { + cli::cli_alert_warning( + c( + "The following columns are not available in the property data: ", + "{.field {paste(excluded_cols, collapse = ', ')}}" + ) + ) + } + + rename_vec <- c( + "property_id" = "PropertyID", + "property_name" = "MarketingName", + "property_type" = "Type", + "property_website" = "webSite", + "property_short_description" = "ShortDescription", + "property_long_description" = "LongDescription", + "property_is_disabled" = "IsDisabled", + "property_is_featured" = "IsFeaturedProperty", + "parent_property_id" = "ParentPropertyID", + "property_year_built" = "YearBuilt" + ) |> + purrr::keep(~ .x %in% select_cols) + + property_tbl_init |> + dplyr::select(tidyselect::any_of(expected_cols)) |> + dplyr::rename(tidyselect::all_of(rename_vec)) + +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr select filter mutate left_join +#' @importFrom tidyr unnest +parse_property_address_data <- function(property_tbl_init) { + + property_addresses_init <- property_tbl_init |> + dplyr::select( + property_id = "PropertyID", + primary_address_street = "Address.Address", + primary_address_city = "Address.City", + primary_address_state = "Address.State", + primary_address_zip = "Address.PostalCode", + primary_address_country = "Address.Country", + primary_address_email = "Address.Email", + primary_address_type = "Address.@attributes.AddressType", + sub_addresses = "Addresses.Address" + ) |> + tidyr::unnest(cols = c("sub_addresses")) |> + tidyr::unnest(cols = c("Address")) |> + dplyr::select( + property_id, + primary_address_street:primary_address_type, + sub_address_type = "AddressType", + sub_address_street = "Address", + sub_address_city = "City", + sub_address_state = "StateCode", + sub_address_zip = "PostalCode", + sub_address_country = "Country" + ) + + property_mailing_addresses <- property_addresses_init |> + dplyr::filter( + .data$primary_address_type == "property", + .data$sub_address_type == "Mailing" + ) |> + dplyr::select( + "property_id", + mailing_address_street = sub_address_street, + mailing_address_city = sub_address_city, + mailing_address_state = sub_address_state, + mailing_address_zip = sub_address_zip, + mailing_address_country = sub_address_country + ) + + property_primary_addresses <- property_addresses_init |> + dplyr::filter( + .data$primary_address_type == "property", + .data$sub_address_type == "Primary" + ) |> + dplyr::select( + "property_id", + "primary_address_street", + "primary_address_city", + "primary_address_state", + "primary_address_zip", + "primary_address_country", + "primary_address_email" + ) + + property_primary_addresses |> + dplyr::left_join( + property_mailing_addresses, + by = "property_id" + ) |> + dplyr::mutate( + primary_address_full = ifelse( + is.na(primary_address_street), + NA_character_, + paste0( + .data$primary_address_street, + ", ", + .data$primary_address_city, + ", ", + .data$primary_address_state, + " ", + .data$primary_address_zip, + ", ", + .data$primary_address_country + ) + ), + mailing_address_full = ifelse( + is.na(.data$mailing_address_street), + NA_character_, + paste0( + .data$mailing_address_street, + ", ", + .data$mailing_address_city, + ", ", + .data$mailing_address_state, + " ", + .data$mailing_address_zip, + ", ", + .data$mailing_address_country + ) + ) + ) |> + dplyr::select( + "property_id", + "primary_address_full", + "primary_address_street", + "primary_address_city", + "primary_address_state", + "primary_address_zip", + "primary_address_country", + "primary_address_email", + "mailing_address_full", + "mailing_address_street", + "mailing_address_city", + "mailing_address_state", + "mailing_address_zip", + "mailing_address_country" + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dint date_ym is_date_ym +#' @importFrom dplyr mutate_if select mutate +#' @importFrom stringr str_sub +parse_property_post_months <- function(property_tbl_init) { + property_tbl_init |> + dplyr::select( + property_id = "PropertyID", + ar_post_month = "PostMonths.ArPostMonth", + ap_post_month = "PostMonths.ApPostMonth", + gl_post_month = "PostMonths.GlPostMonth" + ) |> + dplyr::mutate( + ar_post_month_year = as.integer(stringr::str_sub(.data$ar_post_month, 4, 7)), + ar_post_month_month = as.integer(stringr::str_sub(.data$ar_post_month, 1, 2)), + ap_post_month_year = as.integer(stringr::str_sub(.data$ap_post_month, 4, 7)), + ap_post_month_month = as.integer(stringr::str_sub(.data$ap_post_month, 1, 2)), + gl_post_month_year = as.integer(stringr::str_sub(.data$gl_post_month, 4, 7)), + gl_post_month_month = as.integer(stringr::str_sub(.data$gl_post_month, 1, 2)), + ar_post_month = dint::date_ym(.data$ar_post_month_year, .data$ar_post_month_month), + ap_post_month = dint::date_ym(.data$ap_post_month_year, .data$ap_post_month_month), + gl_post_month = dint::date_ym(.data$gl_post_month_year, .data$gl_post_month_month) + ) |> + dplyr::select( + property_id, + ar_post_month, + ap_post_month, + gl_post_month + ) |> + dplyr::mutate_if( + dint::is_date_ym, + dint:::format.date_ym, + format = "%Y-%m" + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr select mutate arrange left_join join_by +#' @importFrom tidyr unnest +parse_property_hours <- function(property_tbl_init) { + + property_office_hours <- property_tbl_init |> + dplyr::select( + "PropertyID", + office_hours = "PropertyHours.OfficeHours.OfficeHour" + ) |> + tidyr::unnest(cols = c("office_hours")) |> + dplyr::select( + property_id = "PropertyID", + office_hours_day = "Day", + office_hours_availability_type = "AvailabilityType", + office_hours_open_time = "OpenTime", + office_hours_close_time = "CloseTime" + ) |> + dplyr::mutate( + office_hours_interval = ifelse( + is.na(.data$office_hours_open_time) | is.na(.data$office_hours_close_time), + .data$office_hours_availability_type, + paste0( + .data$office_hours_open_time, + " - ", + .data$office_hours_close_time + ) + ) + ) |> + dplyr::select( + "property_id", + day_of_week = office_hours_day, + office_hours = office_hours_interval + ) + + property_pool_hours <- property_tbl_init |> + dplyr::select( + "PropertyID", + pool_hours = "PropertyHours.PoolHours.PoolHour" + ) |> + tidyr::unnest(cols = c("pool_hours")) |> + dplyr::select( + property_id = "PropertyID", + pool_hours_day = "Day", + pool_hours_open_time = "OpenTime", + pool_hours_close_time = "CloseTime" + ) |> + dplyr::mutate( + pool_hours_interval = ifelse( + is.na(.data$pool_hours_open_time) | is.na(.data$pool_hours_close_time), + NA_character_, + paste0( + .data$pool_hours_open_time, + " - ", + .data$pool_hours_close_time + ) + ) + ) |> + dplyr::select( + "property_id", + day_of_week = pool_hours_day, + pool_hours = pool_hours_interval + ) + + # merge into single property_hours table + property_office_hours |> + dplyr::left_join( + property_pool_hours, + by = dplyr::join_by( + "property_id", + "day_of_week" + ) + ) |> + dplyr::mutate( + day_of_week_num = match( + .data$day_of_week, + c( + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ) + ) + ) |> + dplyr::arrange( + .data$property_id, + .data$day_of_week_num + ) |> + dplyr::select( + "property_id", + "day_of_week", + "office_hours", + "pool_hours" + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr mutate select +#' @importFrom tidyr unnest +parse_property_space_options <- function(property_tbl_init) { + property_tbl_init |> + dplyr::select( + "PropertyID", + space_options = "SpaceOptions.SpaceOption" + ) |> + tidyr::unnest(cols = c("space_options")) |> + dplyr::select( + property_id = "PropertyID", + space_option_id = "Id", + space_option_name = "Name" + ) |> + dplyr::mutate( + space_option_id = as.integer(space_option_id) + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr mutate select +#' @importFrom lubridate mdy +#' @importFrom tidyr unnest +parse_property_lease_term_windows <- function(property_tbl_init) { + + property_tbl_init |> + dplyr::select( + "PropertyID", + lease_terms = "LeaseTerms.LeaseTerm" + ) |> + tidyr::unnest(cols = c("lease_terms")) |> + dplyr::select( + "PropertyID", + lease_term_id = "Id", + lease_term_name = "Name", + lease_term_months = "TermMonths", + lease_term_is_prospect = "IsProspect", + lease_term_is_renewal = "IsRenewal", + "LeaseStartWindows.LeaseStartWindow" + ) |> + tidyr::unnest(cols = c("LeaseStartWindows.LeaseStartWindow")) |> + dplyr::select( + property_id = "PropertyID", + "lease_term_id", + lease_term_window_id = "Id", + "lease_term_name", + "lease_term_months", + "lease_term_is_prospect", + "lease_term_is_renewal", + lease_term_window_start_date = "WindowStartDate", + lease_term_window_end_date = "WindowEndDate" + ) |> + dplyr::mutate( + lease_term_window_start_date = lubridate::mdy(lease_term_window_start_date), + lease_term_window_end_date = lubridate::mdy(lease_term_window_end_date) + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dialr phone get_type +#' @importFrom dplyr select mutate filter +parse_property_phones <- function(property_tbl_init) { + + property_tbl_init |> + dplyr::select( + property_id = "PropertyID", + phone_number = "Phone.PhoneNumber"#, + # phone_description = "Phone.PhoneDescription", + # phone_type = "Phone.@attributes.PhoneType" + ) |> + dplyr::filter( + !is.na(.data$phone_number) + ) |> + dplyr::mutate( + phone_number = dialr::phone(.data$phone_number, region = "US"), + phone_number_parsed = format(.data$phone_number), + phone_number_intl = format(.data$phone_number, format = "INTERNATIONAL", clean = FALSE), + phone_number_link = format(.data$phone_number, format = "RFC3966", clean = TRUE), + phone_number_link = paste0("tel:", .data$phone_number_link), + phone_number_link_html = paste0("", .data$phone_number_intl, ""), + phone_number_type = dialr::get_type(.data$phone_number) + ) |> + dplyr::select( + "property_id", + phone_number = phone_number_parsed, + "phone_number_intl", + "phone_number_link", + "phone_number_link_html", + "phone_number_type" + ) +} + +#' @rdname entrata_property_parsers +#' @export +#' @importFrom dplyr select +#' @importFrom tidyr unnest +parse_property_custom_keys <- function(property_tbl_init) { + + property_tbl_init |> + dplyr::select( + property_id = "PropertyID", + custom_keys = "CustomKeysData.CustomKeyData" + ) |> + tidyr::unnest(cols = c("custom_keys")) |> + dplyr::select( + "property_id", + key = 2, + value = 3 + ) + +} diff --git a/dev/sandbox/rate_limits_parsing_etc.R b/dev/sandbox/rate_limits_parsing_etc.R new file mode 100644 index 0000000..acdd545 --- /dev/null +++ b/dev/sandbox/rate_limits_parsing_etc.R @@ -0,0 +1,186 @@ +.get_rate_limit_headers <- function(resp) { + httr2::resp_headers( + resp, + filter = "x-ratelimit-limit|x-ratelimit-remaining|x-ratelimit-reset|expires" + ) +} + +.parse_limits_remaining <- function(header) { + limits <- strsplit(header, ";")[[1]] + lapply(limits, function(limit) { + parts <- strsplit(limit, "/")[[1]] + list(value = as.integer(parts[1]), period = ifelse(length(parts) > 1, parts[2], NA)) + }) +} + +entrata_resp_parse_rate_limit_headers <- function(resp) { + + headers <- .get_rate_limit_headers(resp) + + limit <- .parse_limits_remaining(headers$`x-ratelimit-limit`) + remaining <- .parse_limits_remaining(headers$`x-ratelimit-remaining`) + + reset <- as.integer(strsplit(headers$`x-ratelimit-reset`, ";")[[1]]) + + expires <- if (!is.null(headers$expires)) { + as.POSIXct(headers$expires, format = "%a, %d %b %Y %H:%M:%S", tz = "GMT") + } else { + NA + } + + list( + limit = list( + day = limit[[1]]$value, + hour = limit[[2]]$value, + minute = limit[[3]]$value + ), + remaining = list( + day = remaining[[1]]$value, + hour = remaining[[2]]$value, + minute = remaining[[3]]$value + ), + reset = list( + day = reset[1], + hour = reset[2], + minute = reset[3] + ), + expires = expires + ) +} + +# Assuming 'resp' is your httr2 response object +rate_limit_info <- entrata_resp_parse_rate_limit_headers(resp) + +# You can then access the parsed information like this: +print(rate_limit_info$limit$day) # Prints the daily limit +print(rate_limit_info$remaining$hour) # Prints the remaining hourly limit +print(rate_limit_info$reset$minute) # Prints the reset time for the minute limit +print(rate_limit_info$expires) # Prints the expiration time + +entrata_req_retry <- function(req) { + req |> + httr2::req_retry( + max_tries = 5, + is_transient = function(resp) { + rate_info <- entrata_resp_parse_rate_limit_headers(resp) + httr2::resp_status(resp) == 429 || + all(sapply(rate_info$remaining, function(x) x == 0)) + }, + backoff = function(resp) { + rate_info <- entrata_resp_parse_rate_limit_headers(resp) + max(rate_info$reset$minute, rate_info$reset$hour, rate_info$reset$day, 1) + } + ) +} + +entrata_req_throttle <- function(req) { + req |> + httr2::req_throttle(rate = 25 / 60) # 25 requests per minute +} + +entrata_req_cache <- function(req) { + req |> + httr2::req_cache(path = "entrata_cache") +} + +build_entrata_request <- function(base_url) { + httr2::request(base_url) |> + entrata_req_retry() |> + entrata_req_throttle() |> + entrata_req_cache() |> + httr2::req_headers( + Accept = "application/json", + `User-Agent` = "Your App Name (your@email.com)" + ) +} + +entrata_api_call <- function(endpoint, query = list()) { + build_entrata_request("https://api.entrata.com") |> + req_url_path(endpoint) |> + req_url_query(!!!query) |> + req_perform() +} + +# Example usage +response <- entrata_api_call("/properties", list(limit = 10)) + +req_get_endpoint <- function(req) { + check_request(req) + req_url <- purrr::pluck(req, "url") + gsub(paste0("^", "https://gmhcommunities.entrata.com/api/v1/"), "", req_url) +} + +entrata_req_hash <- function(req) { + endpoint <- req_get_endpoint(req) + body <- req$body$data + cache_key <- paste0(endpoint, digest::digest(body, algo = "md5"), sep = "_") + return(cache_key) +} + +library(digest) + +generate_cache_key <- function(endpoint, body) { + key <- paste(endpoint, digest::digest(body, algo = "md5"), sep = "_") + return(key) +} + +library(R6) + +EntrataCache <- R6::R6Class( + "EntrataCache", + public = list( + cache = list(), + set = function(key, value, expires) { + self$cache[[key]] <- list( + value = value, + expires = expires + ) + }, + get = function(key) { + entry <- self$cache[[key]] + if (!is.null(entry) && Sys.time() < entry$expires) { + return(entry$value) + } + return(NULL) + }, + clear = function(key) { + self$cache[[key]] <- NULL + } + ) +) + +entrata_cache <- EntrataCache$new() + + +entrata_api_call <- function(endpoint, body = list(), use_cache = TRUE) { + + cache_key <- generate_cache_key(endpoint, body) + + if (use_cache) { + cached_response <- entrata_cache$get(cache_key) + if (!is.null(cached_response)) { + return(cached_response) + } + } + + response <- build_entrata_request("https://api.entrata.com") |> + req_url_path(endpoint) |> + req_body_json(body) |> + req_method("POST") |> + req_perform() + + rate_limit_info <- entrata_resp_parse_rate_limit_headers(response) + + if (use_cache && !is.null(rate_limit_info$cache_control)) { + max_age <- as.numeric(sub(".*max-age=(\\d+).*", "\\1", rate_limit_info$cache_control)) + if (!is.na(max_age)) { + expires <- Sys.time() + max_age + entrata_cache$set(cache_key, response, expires) + } + } + + return(response) + +} + +response <- entrata_api_call("/properties", list(auth = list(type = "basic"), requestId = 15, method = list(version = "r1", name = "getProperties", params = list(NULL)))) diff --git a/dev/shiny_assistant_generated_app.R b/dev/sandbox/shiny/shiny_assistant_generated_app.R similarity index 100% rename from dev/shiny_assistant_generated_app.R rename to dev/sandbox/shiny/shiny_assistant_generated_app.R diff --git a/dev/sass.R b/dev/sass.R new file mode 100644 index 0000000..2358ffd --- /dev/null +++ b/dev/sass.R @@ -0,0 +1,40 @@ + +# ------------------------------------------------------------------------ +# +# Title : SASS Styles Compilation +# By : Jimmy Briggs +# Date : 2024-09-27 +# +# ------------------------------------------------------------------------ + +# libs -------------------------------------------------------------------- +require(sass) +require(cli) + +# vars -------------------------------------------------------------------- +input_scss <- "inst/www/styles/scss/index.scss" +output_css <- "inst/www/styles/styles.min.css" + +# options ----------------------------------------------------------------- +default_opts <- sass::sass_options_get() +sass::sass_options_set(output_style = "compressed") +on.exit(sass::sass_options_set(default_opts)) + +# compile ----------------------------------------------------------------- +output <- sass::sass( + input = sass::sass_file(input_scss), + options = sass::sass_options_get(), + output = output_css, + write_attachments = FALSE, + cache = NULL, + cache_key_extra = NULL +) + +cli::cli_bullets( + c( + "v" = "Successfully compiled SASS styles (SCSS -> CSS)!", + "i" = "Input: {.file {input_scss}}", + "i" = "Output: {.file {output_css}}", + "i" = "Access compiled styles via {.field gmhdatahub::pkg_sys_assets('styles/styles.min.css')}" + ) +) diff --git a/exec/README.md b/exec/README.md new file mode 100644 index 0000000..e69de29 diff --git a/inst/database/db_init.R b/inst/database/db_init.R new file mode 100644 index 0000000..e69de29 diff --git a/inst/database/tables/properties.sql b/inst/database/tables/properties.sql new file mode 100644 index 0000000..f73fb73 --- /dev/null +++ b/inst/database/tables/properties.sql @@ -0,0 +1,3 @@ +CREATE TABLE properties ( + id +) diff --git a/inst/dependencies.R b/inst/dependencies.R new file mode 100644 index 0000000..fe25559 --- /dev/null +++ b/inst/dependencies.R @@ -0,0 +1,15 @@ +# Remotes ---- +install.packages("remotes") +remotes::install_github('rstudio/bslib') +remotes::install_github('r-lib/httr2') +remotes::install_github('rstudio/sass') +# Attachments ---- +to_install <- c("bsicons", "cli", "dplyr", "fontawesome", "golem", "htmltools", "jsonlite", "logger", "pkgload", "purrr", "rlang", "shiny", "shinyjs", "shinyWidgets", "stringr", "waiter") + for (i in to_install) { + message(paste("looking for ", i)) + if (!requireNamespace(i, quietly = TRUE)) { + message(paste(" installing", i)) + install.packages(i) + } + } + diff --git a/inst/extdata/csv/summary.csv b/inst/extdata/csv/summary.csv new file mode 100644 index 0000000..7424108 --- /dev/null +++ b/inst/extdata/csv/summary.csv @@ -0,0 +1,21 @@ +property_id,property_name,property,property_subtotal,avg_sqft,avg_advertised_rate,units,excluded_unit_count,rentable_unit_count,avg_scheduled_rent,occupied_count,started_new_count_prior,started_new_count,started_renewal_count_prior,started_renewal_count,started_count_prior,started_count,started_percent,partially_completed_new_count_prior,partially_completed_new_count,partially_completed_renewal_count_prior,partially_completed_renewal_count,partially_completed_count_prior,partially_completed_count,partially_completed_percent,completed_new_count_prior,completed_new_count,completed_renewal_count_prior,completed_renewal_count,completed_count_prior,completed_count,completed_percent,approved_new_count_prior,approved_new_count,approved_renewal_count_prior,approved_renewal_count,approved_count_prior,approved_count,approved_percent,preleased_new_count_prior,preleased_new_count,preleased_renewal_count_prior,preleased_renewal_count,preleased_count_prior,preleased_count,preleased_percent_prior,preleased_percent,variance,available_count,scheduled_rent_total +739076,1008 S. 4th,1008 S. 4th,1008 S. 4th,321.0759493670886,0,158,0,158,0,155,0,0,0,0,0,0,0,24,4,1,0,25,4,0.02531645569620253,0,0,0,0,0,0,0,64,96,48,54,112,150,0.9493670886075949,0,0,0,0,0,0,0,0,0,158,0 +739085,1047 Commonwealth Avenue,1047 Commonwealth Avenue,1047 Commonwealth Avenue,347.5245901639344,0,183,0,183,0,163,0,0,1,6,1,6,0.03278688524590164,0,0,0,0,0,0,0,0,0,1,2,1,2,0.01092896174863388,4,3,35,11,39,14,0.07650273224043716,0,0,0,0,0,0,0,0,0,183,0 +739079,307 E. Daniel,307 E. Daniel,307 E. Daniel,385,0,40,0,40,0,40,0,0,1,1,1,1,0.025,6,1,0,0,6,1,0.025,0,0,0,0,0,0,0,14,25,14,9,28,34,0.85,0,0,0,0,0,0,0,0,0,40,0 +739080,501 S. 6th,501 S. 6th,501 S. 6th,448.75961538461536,0,104,0,104,0,104,0,1,0,0,0,1,0.009615384615384616,11,4,0,0,11,4,0.038461538461538464,1,0,0,0,1,0,0,28,77,48,17,76,94,0.9038461538461539,0,0,0,0,0,0,0,0,0,104,0 +739084,908 S. 1st,908 S. 1st,908 S. 1st,365.6979166666667,0,96,0,96,0,94,2,2,0,1,2,3,0.03125,5,1,1,0,6,1,0.010416666666666666,0,0,0,0,0,0,0,26,49,32,16,58,65,0.6770833333333334,0,0,0,0,0,0,0,0,0,96,0 +641240,Academy 65,Academy 65,Academy 65,274.62459546925567,0,309,0,309,0,304,0,0,1,5,1,5,0.016181229773462782,0,0,0,0,0,0,0,0,0,0,1,0,1,0.003236245954692557,69,0,33,52,102,52,0.16828478964401294,0,0,0,0,0,0,0,0,0,309,0 +676055,Academy Lincoln,Academy Lincoln,Academy Lincoln,322.4810126582278,0,632,0,632,0,623,13,14,1,22,14,36,0.056962025316455694,4,2,0,0,4,2,0.0031645569620253164,3,0,0,0,3,0,0,36,48,111,124,147,172,0.2721518987341772,0,0,0,0,0,0,0,0,0,632,0 +1115679,ANOVA uCity Square,ANOVA uCity Square,ANOVA uCity Square,555.0672451193059,0,461,0,461,0,441,2,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,34,41,11,20,45,61,0.13232104121475055,0,0,0,0,0,0,0,0,0,461,0 +1161867,Courts at Spring Mill Station,Courts at Spring Mill Station,Courts at Spring Mill Station,955.4300518134716,0,386,0,386,0,355,0,0,0,1,0,1,0.0025906735751295338,0,0,0,0,0,0,0,0,0,0,4,0,4,0.010362694300518135,30,28,43,58,73,86,0.22279792746113988,0,0,0,0,0,0,0,0,0,386,0 +518044,Shortbread Lofts,Shortbread Lofts,Shortbread Lofts,296.29411764705884,0,374,0,374,0,374,19,31,0,2,19,33,0.08823529411764706,36,27,1,0,37,27,0.07219251336898395,24,1,0,0,24,1,0.00267379679144385,159,254,20,23,179,277,0.7406417112299465,0,0,0,0,0,0,0,0,0,374,0 +952515,SOVA,SOVA,SOVA,394.1078431372549,0,816,0,816,0,805,5,1,1,1,6,2,0.0024509803921568627,2,1,0,0,2,1,0.0012254901960784314,5,1,4,2,9,3,0.003676470588235294,39,12,161,262,200,274,0.33578431372549017,0,0,0,0,0,0,0,0,0,816,0 +577897,Station Nine,Station Nine,Station Nine,965.0433436532508,0,323,0,323,0,305,1,0,0,1,1,1,0.0030959752321981426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,33,5,5,39,38,0.11764705882352941,0,0,0,0,0,0,0,0,0,323,0 +518041,The Academy at Frisco,The Academy at Frisco,The Academy at Frisco,367.2203125,0,640,0,640,0,635,2,23,0,3,2,26,0.040625,31,1,0,0,31,1,0.0015625,128,1,10,3,138,4,0.00625,76,243,305,248,381,491,0.7671875,0,0,0,0,0,0,0,0,0,640,0 +518042,The Academy on Charles,The Academy on Charles,The Academy on Charles,315.0701219512195,0,328,0,328,0,327,0,0,0,2,0,2,0.006097560975609756,0,2,0,0,0,2,0.006097560975609756,0,15,0,7,0,22,0.06707317073170732,0,31,0,48,0,79,0.24085365853658536,0,0,0,0,0,0,0,0,0,328,0 +1197886,The Caswell at Runnymeade,The Caswell at Runnymeade,The Caswell at Runnymeade,1270.5222672064776,0,249,2,247,0,206,2,5,0,1,2,6,0.024291497975708502,1,0,0,0,1,0,0,0,3,0,0,0,3,0.012145748987854251,53,50,0,40,53,90,0.3643724696356275,0,0,0,0,0,0,0,0,0,247,0 +833617,The Dean Campustown,The Dean Campustown,The Dean Campustown,178.5625,0,672,0,672,0,656,4,4,0,6,4,10,0.01488095238095238,12,4,6,3,18,7,0.010416666666666666,3,1,1,0,4,1,0.001488095238095238,169,179,203,194,372,373,0.5550595238095238,0,0,0,0,0,0,0,0,0,672,0 +1197887,The Dean Reno,The Dean Reno,The Dean Reno,305.6106080206986,0,773,0,773,0,635,7,15,10,57,17,72,0.09314359637774904,6,1,1,0,7,1,0.00129366106080207,4,1,3,8,7,9,0.01164294954721863,15,19,46,73,61,92,0.11901681759379043,0,0,0,0,0,0,0,0,0,773,0 +518046,The Rise at Northgate,The Rise at Northgate,The Rise at Northgate,376,0,465,0,465,0,465,1,4,0,1,1,5,0.010752688172043012,7,5,0,0,7,5,0.010752688172043012,12,2,0,0,12,2,0.004301075268817204,54,117,255,228,309,345,0.7419354838709677,0,0,0,0,0,0,0,0,0,465,0 +1143679,Torre,Torre,Torre,331.24014336917566,0,558,0,558,0,500,1,19,1,3,2,22,0.03942652329749104,7,4,6,1,13,5,0.008960573476702509,7,0,1,0,8,0,0,183,135,100,164,283,299,0.53584229390681,0,0,0,0,0,0,0,0,0,558,0 +1311849,Venue at North Campus,Venue at North Campus,Venue at North Campus,104.07356948228883,0,734,0,734,0,632,9,12,23,13,32,25,0.0340599455040872,3,0,7,0,10,0,0,1,0,4,0,5,0,0,29,14,33,93,62,107,0.14577656675749318,0,0,0,0,0,0,0,0,0,734,0 diff --git a/inst/www/animations/loading.svg b/inst/www/animations/loading.svg new file mode 100644 index 0000000..445575b --- /dev/null +++ b/inst/www/animations/loading.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/inst/www/content/about/about.qmd b/inst/www/content/about/about.qmd new file mode 100644 index 0000000..67bfbe5 --- /dev/null +++ b/inst/www/content/about/about.qmd @@ -0,0 +1,47 @@ +--- +format: markdown +--- + +# About GMH Leasing Dashboard + +The GMH Leasing Dashboard is a web application that provides a comprehensive overview of the leasing performance +of GMH Community's leasing properties and portfolios. + +The dashboard is designed to help GMH Leasing executives make data-driven decisions to optimize the performance of +their properties. + +## Features + +The Leasing Dashboard includes the following features: + +- **Dashboard**: A high-level overview of key performance indicators for the leasing portfolio. + +- **Reports**: Detailed reports on leasing performance, occupancy rates, and revenue. + +- **Properties**: Information on individual properties, including occupancy rates, leasing status, and revenue. + +## Technologies + +The GMH Leasing Dashboard is built using the following technologies: + +- **R Shiny**: A web application framework for R that allows developers to create interactive web applications. +- **HTML/CSS/JavaScript**: Front-end technologies for building web applications. +- **Bootstrap**: A front-end framework for building responsive web applications. +- **DataTables.js**: A JavaScript/jQuery library for creating interactive data tables. +- **Highcharts.js**: A JavaScript library for creating interactive charts and graphs. + +the infrastructure behind the application is built using the following technologies: + +- **Docker**: A containerization platform for building, shipping, and running applications. +- **Docker Compose**: A tool for defining and running multi-container Docker applications. +- **PostgreSQL**: A powerful, open-source object-relational database system. + +and is hosted on Google Cloud Platform using the following services: + +- **Google Cloud Run**: A fully managed platform that automatically scales your stateless containers. +- **Google Cloud Artifact Registry**: A private Docker container registry for storing and managing container images. +- **Google Cloud Storage**: A scalable object storage service for storing and serving large amounts of unstructured data. + +## Contact Us + +If you have any questions or feedback about the GMH Leasing Dashboard, please contact us at [support@noclocks.dev](mailto:support@noclocks.dev). diff --git a/inst/www/content/faq/faq.qmd b/inst/www/content/faq/faq.qmd new file mode 100644 index 0000000..c737c90 --- /dev/null +++ b/inst/www/content/faq/faq.qmd @@ -0,0 +1,36 @@ +--- +format: markdown +--- + +# Frequently Asked Questions (FAQ) + +## What is the GMH Leasing Dashboard? + +The GMH Leasing Dashboard is a web application that provides a comprehensive overview of the leasing performance +of GMH Community's leasing properties and portfolios. + +The dashboard is designed to help GMH Leasing executives make data-driven decisions to optimize the performance of +their properties. + +## How do I access the GMH Leasing Dashboard? + +The GMH Leasing Dashboard is accessible through a web browser. To access the dashboard, navigate to the URL provided +by your GMH Leasing administrator. + +## What features are included in the GMH Leasing Dashboard? + +The Leasing Dashboard includes the following features: + +- **Dashboard**: A high-level overview of key performance indicators for the leasing portfolio. +- **Reports**: Detailed reports on leasing performance, occupancy rates, and revenue. +- **Properties**: Information on individual properties, including occupancy rates, leasing status, and revenue. + +## How do I navigate the GMH Leasing Dashboard? + +The GMH Leasing Dashboard is designed to be user-friendly and intuitive. To navigate the dashboard, use the menu +options at the top of the screen to access different sections of the application. + +## How do I view reports in the GMH Leasing Dashboard? + +To view reports in the GMH Leasing Dashboard, navigate to the "Reports" section of the application. From there, you +can select the type of report you would like to view and customize the report parameters to suit your needs. diff --git a/inst/www/content/help/help.qmd b/inst/www/content/help/help.qmd new file mode 100644 index 0000000..268589a --- /dev/null +++ b/inst/www/content/help/help.qmd @@ -0,0 +1,5 @@ +--- +format: markdown +--- + +# Help diff --git a/inst/www/html/favicons.html b/inst/www/html/favicons.html new file mode 100644 index 0000000..78239af --- /dev/null +++ b/inst/www/html/favicons.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/html/html_code.html b/inst/www/html/html_code.html new file mode 100644 index 0000000..1852d6d --- /dev/null +++ b/inst/www/html/html_code.html @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/img/entrata/entrata-banner.jpeg b/inst/www/images/entrata/banners/entrata-banner.jpeg similarity index 100% rename from inst/www/img/entrata/entrata-banner.jpeg rename to inst/www/images/entrata/banners/entrata-banner.jpeg diff --git a/inst/www/images/entrata/logos/entrata-logo-dark.png b/inst/www/images/entrata/logos/entrata-logo-dark.png new file mode 100644 index 0000000..f36cc2e Binary files /dev/null and b/inst/www/images/entrata/logos/entrata-logo-dark.png differ diff --git a/inst/www/img/logos/entrata-logo.png b/inst/www/images/entrata/logos/entrata-logo-light.png similarity index 100% rename from inst/www/img/logos/entrata-logo.png rename to inst/www/images/entrata/logos/entrata-logo-light.png diff --git a/inst/www/images/entrata/logos/entrata-logo-square-red.jpg b/inst/www/images/entrata/logos/entrata-logo-square-red.jpg new file mode 100644 index 0000000..0d5a2fb Binary files /dev/null and b/inst/www/images/entrata/logos/entrata-logo-square-red.jpg differ diff --git a/inst/www/images/gmh/banners/gmh-communities-banner.jpeg b/inst/www/images/gmh/banners/gmh-communities-banner.jpeg new file mode 100644 index 0000000..45350c5 Binary files /dev/null and b/inst/www/images/gmh/banners/gmh-communities-banner.jpeg differ diff --git a/inst/www/images/gmh/banners/gmh-communities-banner.png b/inst/www/images/gmh/banners/gmh-communities-banner.png new file mode 100644 index 0000000..1541828 Binary files /dev/null and b/inst/www/images/gmh/banners/gmh-communities-banner.png differ diff --git a/inst/www/images/gmh/banners/gmh-our-locations-banner.png b/inst/www/images/gmh/banners/gmh-our-locations-banner.png new file mode 100644 index 0000000..9358740 Binary files /dev/null and b/inst/www/images/gmh/banners/gmh-our-locations-banner.png differ diff --git a/inst/www/images/gmh/icons/gmh-icon-150x150.png b/inst/www/images/gmh/icons/gmh-icon-150x150.png new file mode 100644 index 0000000..df66fbd Binary files /dev/null and b/inst/www/images/gmh/icons/gmh-icon-150x150.png differ diff --git a/inst/www/images/gmh/icons/gmh-icon-transparent-shadow.png b/inst/www/images/gmh/icons/gmh-icon-transparent-shadow.png new file mode 100644 index 0000000..c792b8a Binary files /dev/null and b/inst/www/images/gmh/icons/gmh-icon-transparent-shadow.png differ diff --git a/inst/www/images/gmh/icons/gmh-icon.ico b/inst/www/images/gmh/icons/gmh-icon.ico new file mode 100644 index 0000000..47070f4 Binary files /dev/null and b/inst/www/images/gmh/icons/gmh-icon.ico differ diff --git a/inst/www/img/icons/gmh-icon.png b/inst/www/images/gmh/icons/gmh-icon.png similarity index 100% rename from inst/www/img/icons/gmh-icon.png rename to inst/www/images/gmh/icons/gmh-icon.png diff --git a/inst/www/images/gmh/icons/gmh-white-box.png b/inst/www/images/gmh/icons/gmh-white-box.png new file mode 100644 index 0000000..cce46b9 Binary files /dev/null and b/inst/www/images/gmh/icons/gmh-white-box.png differ diff --git a/inst/www/img/icons/app-icon.webp b/inst/www/images/gmh/icons/gmh.webp similarity index 100% rename from inst/www/img/icons/app-icon.webp rename to inst/www/images/gmh/icons/gmh.webp diff --git a/inst/www/images/gmh/logos/communities/gmh-communities-logo.jpg b/inst/www/images/gmh/logos/communities/gmh-communities-logo.jpg new file mode 100644 index 0000000..e62a067 Binary files /dev/null and b/inst/www/images/gmh/logos/communities/gmh-communities-logo.jpg differ diff --git a/inst/www/images/gmh/logos/communities/gmh-communities-logo.png b/inst/www/images/gmh/logos/communities/gmh-communities-logo.png new file mode 100644 index 0000000..3cbcc76 Binary files /dev/null and b/inst/www/images/gmh/logos/communities/gmh-communities-logo.png differ diff --git a/inst/www/images/gmh/logos/communities/gmh-communities-logo.svg b/inst/www/images/gmh/logos/communities/gmh-communities-logo.svg new file mode 100644 index 0000000..c3c4dcd --- /dev/null +++ b/inst/www/images/gmh/logos/communities/gmh-communities-logo.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/gmh/logos/communities/gmh-communities-square.png b/inst/www/images/gmh/logos/communities/gmh-communities-square.png new file mode 100644 index 0000000..1713a84 Binary files /dev/null and b/inst/www/images/gmh/logos/communities/gmh-communities-square.png differ diff --git a/inst/www/images/gmh/logos/communities/gmh-communities.avif b/inst/www/images/gmh/logos/communities/gmh-communities.avif new file mode 100644 index 0000000..553d771 Binary files /dev/null and b/inst/www/images/gmh/logos/communities/gmh-communities.avif differ diff --git a/inst/www/images/gmh/logos/go/gmh-go-logo.svg b/inst/www/images/gmh/logos/go/gmh-go-logo.svg new file mode 100644 index 0000000..c40ec9b --- /dev/null +++ b/inst/www/images/gmh/logos/go/gmh-go-logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.jpg b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.jpg new file mode 100644 index 0000000..3e8f757 Binary files /dev/null and b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.jpg differ diff --git a/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.png b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.png new file mode 100644 index 0000000..9b616f4 Binary files /dev/null and b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.png differ diff --git a/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.svg b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.svg new file mode 100644 index 0000000..815af50 --- /dev/null +++ b/inst/www/images/gmh/logos/innovative-living/gmh-innovative-living-logo.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/gmh/logos/logo-darkmode.svg b/inst/www/images/gmh/logos/logo-darkmode.svg new file mode 100644 index 0000000..934a4bb --- /dev/null +++ b/inst/www/images/gmh/logos/logo-darkmode.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/gmh/logos/logo-white.svg b/inst/www/images/gmh/logos/logo-white.svg new file mode 100644 index 0000000..934a4bb --- /dev/null +++ b/inst/www/images/gmh/logos/logo-white.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/gmh/logos/logo.svg b/inst/www/images/gmh/logos/logo.svg new file mode 100644 index 0000000..c3c4dcd --- /dev/null +++ b/inst/www/images/gmh/logos/logo.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.jpg b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.jpg new file mode 100644 index 0000000..056af5e Binary files /dev/null and b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.jpg differ diff --git a/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.png b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.png new file mode 100644 index 0000000..65fc18f Binary files /dev/null and b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.png differ diff --git a/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.svg b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.svg new file mode 100644 index 0000000..c93b2c7 --- /dev/null +++ b/inst/www/images/gmh/logos/residential-living/gmh-residential-living-logo.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.jpg b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.jpg new file mode 100644 index 0000000..3d19a43 Binary files /dev/null and b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.jpg differ diff --git a/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.png b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.png new file mode 100644 index 0000000..d4d63ff Binary files /dev/null and b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.png differ diff --git a/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.svg b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.svg new file mode 100644 index 0000000..5f9ebce --- /dev/null +++ b/inst/www/images/gmh/logos/student-living/gmh-student-living-logo.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/noclocks/favicons/noclocks-favicon.ico b/inst/www/images/noclocks/favicons/noclocks-favicon.ico new file mode 100644 index 0000000..9c795ef Binary files /dev/null and b/inst/www/images/noclocks/favicons/noclocks-favicon.ico differ diff --git a/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).ico b/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).ico new file mode 100644 index 0000000..b44c009 Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).ico differ diff --git a/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).png b/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).png new file mode 100644 index 0000000..7a5c129 Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-icon-circular (Custom).png differ diff --git a/inst/www/images/noclocks/icons/noclocks-icon-circular-100x100.png b/inst/www/images/noclocks/icons/noclocks-icon-circular-100x100.png new file mode 100644 index 0000000..235fb45 Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-icon-circular-100x100.png differ diff --git a/inst/www/img/icons/noclocks-icon-circular.png b/inst/www/images/noclocks/icons/noclocks-icon-circular.png similarity index 100% rename from inst/www/img/icons/noclocks-icon-circular.png rename to inst/www/images/noclocks/icons/noclocks-icon-circular.png diff --git a/inst/www/images/noclocks/icons/noclocks-icon-light.png b/inst/www/images/noclocks/icons/noclocks-icon-light.png new file mode 100644 index 0000000..0bdf36c Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-icon-light.png differ diff --git a/inst/www/images/noclocks/icons/noclocks-icon.png b/inst/www/images/noclocks/icons/noclocks-icon.png new file mode 100644 index 0000000..0bdf36c Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-icon.png differ diff --git a/inst/www/images/noclocks/icons/noclocks-icon.svg b/inst/www/images/noclocks/icons/noclocks-icon.svg new file mode 100644 index 0000000..92465bc --- /dev/null +++ b/inst/www/images/noclocks/icons/noclocks-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/inst/www/images/noclocks/icons/noclocks-thumbnail.png b/inst/www/images/noclocks/icons/noclocks-thumbnail.png new file mode 100644 index 0000000..10c918d Binary files /dev/null and b/inst/www/images/noclocks/icons/noclocks-thumbnail.png differ diff --git a/inst/www/images/noclocks/logos/noclocks-logo-black.png b/inst/www/images/noclocks/logos/noclocks-logo-black.png new file mode 100644 index 0000000..fd7842b Binary files /dev/null and b/inst/www/images/noclocks/logos/noclocks-logo-black.png differ diff --git a/inst/www/images/noclocks/logos/noclocks-logo-circular-100x100.png b/inst/www/images/noclocks/logos/noclocks-logo-circular-100x100.png new file mode 100644 index 0000000..235fb45 Binary files /dev/null and b/inst/www/images/noclocks/logos/noclocks-logo-circular-100x100.png differ diff --git a/inst/www/images/noclocks/logos/noclocks-logo-white.png b/inst/www/images/noclocks/logos/noclocks-logo-white.png new file mode 100644 index 0000000..ba2969d Binary files /dev/null and b/inst/www/images/noclocks/logos/noclocks-logo-white.png differ diff --git a/inst/www/images/noclocks/logos/noclocks-logo-wordmark-white.png b/inst/www/images/noclocks/logos/noclocks-logo-wordmark-white.png new file mode 100644 index 0000000..ba2969d Binary files /dev/null and b/inst/www/images/noclocks/logos/noclocks-logo-wordmark-white.png differ diff --git a/inst/www/images/noclocks/team/jimmy-headshot.png b/inst/www/images/noclocks/team/jimmy-headshot.png new file mode 100644 index 0000000..0473766 Binary files /dev/null and b/inst/www/images/noclocks/team/jimmy-headshot.png differ diff --git a/inst/www/images/noclocks/team/patrick-headshot.png b/inst/www/images/noclocks/team/patrick-headshot.png new file mode 100644 index 0000000..dd7e60d Binary files /dev/null and b/inst/www/images/noclocks/team/patrick-headshot.png differ diff --git a/inst/www/images/portfolios/agc/AGC_Equity_Partners_Logo.png b/inst/www/images/portfolios/agc/AGC_Equity_Partners_Logo.png new file mode 100644 index 0000000..ce35c1e Binary files /dev/null and b/inst/www/images/portfolios/agc/AGC_Equity_Partners_Logo.png differ diff --git a/inst/www/images/properties/academy-65/Academy65-logo-black.webp b/inst/www/images/properties/academy-65/Academy65-logo-black.webp new file mode 100644 index 0000000..6bf1031 Binary files /dev/null and b/inst/www/images/properties/academy-65/Academy65-logo-black.webp differ diff --git a/inst/www/images/properties/academy-65/academy65-logo-black.jpg b/inst/www/images/properties/academy-65/academy65-logo-black.jpg new file mode 100644 index 0000000..ebfebf7 Binary files /dev/null and b/inst/www/images/properties/academy-65/academy65-logo-black.jpg differ diff --git a/inst/www/images/properties/academy-65/academy65-logo.jpg b/inst/www/images/properties/academy-65/academy65-logo.jpg new file mode 100644 index 0000000..ebfebf7 Binary files /dev/null and b/inst/www/images/properties/academy-65/academy65-logo.jpg differ diff --git a/inst/www/images/properties/academy-65/academy65-logo.webp b/inst/www/images/properties/academy-65/academy65-logo.webp new file mode 100644 index 0000000..6bf1031 Binary files /dev/null and b/inst/www/images/properties/academy-65/academy65-logo.webp differ diff --git a/inst/www/images/properties/academy-campustown/The Academy Campustown-1.png b/inst/www/images/properties/academy-campustown/The Academy Campustown-1.png new file mode 100644 index 0000000..db0992c Binary files /dev/null and b/inst/www/images/properties/academy-campustown/The Academy Campustown-1.png differ diff --git a/inst/www/images/properties/academy-campustown/The Academy Campustown.png b/inst/www/images/properties/academy-campustown/The Academy Campustown.png new file mode 100644 index 0000000..7d10d2e Binary files /dev/null and b/inst/www/images/properties/academy-campustown/The Academy Campustown.png differ diff --git a/inst/www/images/properties/academy-campustown/academy-campustown-logo.jpg b/inst/www/images/properties/academy-campustown/academy-campustown-logo.jpg new file mode 100644 index 0000000..e54df3f Binary files /dev/null and b/inst/www/images/properties/academy-campustown/academy-campustown-logo.jpg differ diff --git a/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-blue.svg b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-blue.svg new file mode 100644 index 0000000..d962581 --- /dev/null +++ b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-blue.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.png b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.png new file mode 100644 index 0000000..db0992c Binary files /dev/null and b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.png differ diff --git a/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.svg b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.svg new file mode 100644 index 0000000..55d3222 --- /dev/null +++ b/inst/www/images/properties/academy-campustown/the-academy-campustown-logo-white.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/properties/academy-campustown/the-academy-compustown-logo-blue.png b/inst/www/images/properties/academy-campustown/the-academy-compustown-logo-blue.png new file mode 100644 index 0000000..7d10d2e Binary files /dev/null and b/inst/www/images/properties/academy-campustown/the-academy-compustown-logo-blue.png differ diff --git a/inst/www/images/properties/academy-charles/The Academy on Charles.png b/inst/www/images/properties/academy-charles/The Academy on Charles.png new file mode 100644 index 0000000..c2a3cb5 Binary files /dev/null and b/inst/www/images/properties/academy-charles/The Academy on Charles.png differ diff --git a/inst/www/images/properties/academy-charles/academy-on-charles-logo.jpg b/inst/www/images/properties/academy-charles/academy-on-charles-logo.jpg new file mode 100644 index 0000000..d02d0b8 Binary files /dev/null and b/inst/www/images/properties/academy-charles/academy-on-charles-logo.jpg differ diff --git a/inst/www/images/properties/academy-charles/the-academy-on-charles-logo.png b/inst/www/images/properties/academy-charles/the-academy-on-charles-logo.png new file mode 100644 index 0000000..c2a3cb5 Binary files /dev/null and b/inst/www/images/properties/academy-charles/the-academy-on-charles-logo.png differ diff --git a/inst/www/images/properties/academy-chorro/academy-chorro-orange.jpg b/inst/www/images/properties/academy-chorro/academy-chorro-orange.jpg new file mode 100644 index 0000000..ab5d0b8 Binary files /dev/null and b/inst/www/images/properties/academy-chorro/academy-chorro-orange.jpg differ diff --git a/inst/www/images/properties/academy-frisco/academy-at-frisco-logo-lightgreen.jpg b/inst/www/images/properties/academy-frisco/academy-at-frisco-logo-lightgreen.jpg new file mode 100644 index 0000000..049e707 Binary files /dev/null and b/inst/www/images/properties/academy-frisco/academy-at-frisco-logo-lightgreen.jpg differ diff --git a/inst/www/images/properties/academy-lincoln/academy-lincoln-logo.jpg b/inst/www/images/properties/academy-lincoln/academy-lincoln-logo.jpg new file mode 100644 index 0000000..0ef9866 Binary files /dev/null and b/inst/www/images/properties/academy-lincoln/academy-lincoln-logo.jpg differ diff --git a/inst/www/images/properties/academy-palomar/academy-palomar-logo.jpg b/inst/www/images/properties/academy-palomar/academy-palomar-logo.jpg new file mode 100644 index 0000000..fc8faa9 Binary files /dev/null and b/inst/www/images/properties/academy-palomar/academy-palomar-logo.jpg differ diff --git a/inst/www/images/properties/anova-ucity-square/anova-ucity-square-logo.png b/inst/www/images/properties/anova-ucity-square/anova-ucity-square-logo.png new file mode 100644 index 0000000..99d91b6 Binary files /dev/null and b/inst/www/images/properties/anova-ucity-square/anova-ucity-square-logo.png differ diff --git a/inst/www/images/properties/dean-campustown/The Dean Campustown.png b/inst/www/images/properties/dean-campustown/The Dean Campustown.png new file mode 100644 index 0000000..884edda Binary files /dev/null and b/inst/www/images/properties/dean-campustown/The Dean Campustown.png differ diff --git a/inst/www/images/properties/dean-campustown/dean-logo.jpg b/inst/www/images/properties/dean-campustown/dean-logo.jpg new file mode 100644 index 0000000..33b6ec0 Binary files /dev/null and b/inst/www/images/properties/dean-campustown/dean-logo.jpg differ diff --git a/inst/www/images/properties/dean-campustown/the-dean-campustown-logo-white.svg b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo-white.svg new file mode 100644 index 0000000..d57eb1e --- /dev/null +++ b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo-white.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.png b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.png new file mode 100644 index 0000000..884edda Binary files /dev/null and b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.png differ diff --git a/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.svg b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.svg new file mode 100644 index 0000000..2e24e6b --- /dev/null +++ b/inst/www/images/properties/dean-campustown/the-dean-campustown-logo.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/properties/dean-campustown/the-dean-campustown.svg b/inst/www/images/properties/dean-campustown/the-dean-campustown.svg new file mode 100644 index 0000000..2e24e6b --- /dev/null +++ b/inst/www/images/properties/dean-campustown/the-dean-campustown.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/properties/gmh-communities-map.svg b/inst/www/images/properties/gmh-communities-map.svg new file mode 100644 index 0000000..ef3778c --- /dev/null +++ b/inst/www/images/properties/gmh-communities-map.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/properties/shortbread-lofts/Shortbread Lofts.png b/inst/www/images/properties/shortbread-lofts/Shortbread Lofts.png new file mode 100644 index 0000000..1c20c25 Binary files /dev/null and b/inst/www/images/properties/shortbread-lofts/Shortbread Lofts.png differ diff --git a/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.jpg b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.jpg new file mode 100644 index 0000000..a61891f Binary files /dev/null and b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.jpg differ diff --git a/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.png b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.png new file mode 100644 index 0000000..1c20c25 Binary files /dev/null and b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.png differ diff --git a/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.svg b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.svg new file mode 100644 index 0000000..39dfb3b --- /dev/null +++ b/inst/www/images/properties/shortbread-lofts/shortbread-lofts-logo.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/properties/sova/sova-logo.jpg b/inst/www/images/properties/sova/sova-logo.jpg new file mode 100644 index 0000000..fcb2d0f Binary files /dev/null and b/inst/www/images/properties/sova/sova-logo.jpg differ diff --git a/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.png b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.png new file mode 100644 index 0000000..9b3f711 Binary files /dev/null and b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.png differ diff --git a/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.webp b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.webp new file mode 100644 index 0000000..368910f Binary files /dev/null and b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth-logo.webp differ diff --git a/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.png b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.png new file mode 100644 index 0000000..c16a5cf Binary files /dev/null and b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.png differ diff --git a/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.webp b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.webp new file mode 100644 index 0000000..368910f Binary files /dev/null and b/inst/www/images/properties/ten47-commonwealth/ten47-commonwealth.webp differ diff --git a/inst/www/images/properties/venue-north-campus/Venue at North Campus.png b/inst/www/images/properties/venue-north-campus/Venue at North Campus.png new file mode 100644 index 0000000..0e6e460 Binary files /dev/null and b/inst/www/images/properties/venue-north-campus/Venue at North Campus.png differ diff --git a/inst/www/images/properties/venue-north-campus/venue-at-north-campus-logo.png b/inst/www/images/properties/venue-north-campus/venue-at-north-campus-logo.png new file mode 100644 index 0000000..0e6e460 Binary files /dev/null and b/inst/www/images/properties/venue-north-campus/venue-at-north-campus-logo.png differ diff --git a/inst/www/images/shared/app/icons/app-icon.webp b/inst/www/images/shared/app/icons/app-icon.webp new file mode 100644 index 0000000..8f2cdec Binary files /dev/null and b/inst/www/images/shared/app/icons/app-icon.webp differ diff --git a/inst/www/images/shared/app/icons/gmh-icon.png b/inst/www/images/shared/app/icons/gmh-icon.png new file mode 100644 index 0000000..770bd18 Binary files /dev/null and b/inst/www/images/shared/app/icons/gmh-icon.png differ diff --git a/inst/www/images/shared/app/icons/noclocks-icon-circular.png b/inst/www/images/shared/app/icons/noclocks-icon-circular.png new file mode 100644 index 0000000..10c918d Binary files /dev/null and b/inst/www/images/shared/app/icons/noclocks-icon-circular.png differ diff --git a/inst/www/img/logos/app-logo.svg b/inst/www/images/shared/app/logos/app-logo.svg similarity index 100% rename from inst/www/img/logos/app-logo.svg rename to inst/www/images/shared/app/logos/app-logo.svg diff --git a/inst/www/images/shared/app/logos/entrata-logo.png b/inst/www/images/shared/app/logos/entrata-logo.png new file mode 100644 index 0000000..48fde2b Binary files /dev/null and b/inst/www/images/shared/app/logos/entrata-logo.png differ diff --git a/inst/www/img/logos/gmh-logo.svg b/inst/www/images/shared/app/logos/gmh-logo.svg similarity index 100% rename from inst/www/img/logos/gmh-logo.svg rename to inst/www/images/shared/app/logos/gmh-logo.svg diff --git a/inst/www/img/logos/noclocks-logo.svg b/inst/www/images/shared/app/logos/noclocks-logo.svg similarity index 100% rename from inst/www/img/logos/noclocks-logo.svg rename to inst/www/images/shared/app/logos/noclocks-logo.svg diff --git a/inst/www/images/shared/favicons/README.md b/inst/www/images/shared/favicons/README.md new file mode 100644 index 0000000..fc9fc33 --- /dev/null +++ b/inst/www/images/shared/favicons/README.md @@ -0,0 +1,25 @@ +# Your Favicon Package + +This package was generated with [RealFaviconGenerator](https://realfavicongenerator.net/) [v0.16](https://realfavicongenerator.net/change_log#v0.16) + +## Install instructions + +To install this package: + +Extract this package in <web site>/img/favicons/. If your site is http://www.example.com, you should be able to access a file named http://www.example.com/img/favicons/favicon.ico. + +Insert the following code in the `head` section of your pages: + + + + + + + + + + + + + +*Optional* - Check your favicon with the [favicon checker](https://realfavicongenerator.net/favicon_checker) \ No newline at end of file diff --git a/inst/www/images/shared/favicons/android/android-chrome-192x192.png b/inst/www/images/shared/favicons/android/android-chrome-192x192.png new file mode 100644 index 0000000..3638fbd Binary files /dev/null and b/inst/www/images/shared/favicons/android/android-chrome-192x192.png differ diff --git a/inst/www/images/shared/favicons/android/android-chrome-512x512.png b/inst/www/images/shared/favicons/android/android-chrome-512x512.png new file mode 100644 index 0000000..1fb30c0 Binary files /dev/null and b/inst/www/images/shared/favicons/android/android-chrome-512x512.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120-precomposed.png new file mode 100644 index 0000000..480e48d Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120.png new file mode 100644 index 0000000..b2e6a79 Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-120x120.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152-precomposed.png new file mode 100644 index 0000000..5eee891 Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152.png new file mode 100644 index 0000000..8587e28 Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-152x152.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180-precomposed.png new file mode 100644 index 0000000..a87014b Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180.png new file mode 100644 index 0000000..715e5cf Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-180x180.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60-precomposed.png new file mode 100644 index 0000000..32162db Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60.png new file mode 100644 index 0000000..c6086e8 Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-60x60.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76-precomposed.png new file mode 100644 index 0000000..2674436 Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76.png new file mode 100644 index 0000000..2b80bcd Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-76x76.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon-precomposed.png b/inst/www/images/shared/favicons/apple/apple-touch-icon-precomposed.png new file mode 100644 index 0000000..a87014b Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon-precomposed.png differ diff --git a/inst/www/images/shared/favicons/apple/apple-touch-icon.png b/inst/www/images/shared/favicons/apple/apple-touch-icon.png new file mode 100644 index 0000000..715e5cf Binary files /dev/null and b/inst/www/images/shared/favicons/apple/apple-touch-icon.png differ diff --git a/inst/www/images/shared/favicons/apple/safari-pinned-tab.svg b/inst/www/images/shared/favicons/apple/safari-pinned-tab.svg new file mode 100644 index 0000000..58606ee --- /dev/null +++ b/inst/www/images/shared/favicons/apple/safari-pinned-tab.svg @@ -0,0 +1,67 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + + + + + + + + + + diff --git a/inst/www/images/shared/favicons/favicon-16x16.png b/inst/www/images/shared/favicons/favicon-16x16.png new file mode 100644 index 0000000..2f53c29 Binary files /dev/null and b/inst/www/images/shared/favicons/favicon-16x16.png differ diff --git a/inst/www/images/shared/favicons/favicon-32x32.png b/inst/www/images/shared/favicons/favicon-32x32.png new file mode 100644 index 0000000..f65073e Binary files /dev/null and b/inst/www/images/shared/favicons/favicon-32x32.png differ diff --git a/inst/www/images/shared/favicons/favicon.ico b/inst/www/images/shared/favicons/favicon.ico new file mode 100644 index 0000000..179e7fc Binary files /dev/null and b/inst/www/images/shared/favicons/favicon.ico differ diff --git a/inst/www/images/shared/favicons/microsoft/browserconfig.xml b/inst/www/images/shared/favicons/microsoft/browserconfig.xml new file mode 100644 index 0000000..558a71e --- /dev/null +++ b/inst/www/images/shared/favicons/microsoft/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/inst/www/images/shared/favicons/microsoft/mstile-150x150.png b/inst/www/images/shared/favicons/microsoft/mstile-150x150.png new file mode 100644 index 0000000..e22d24d Binary files /dev/null and b/inst/www/images/shared/favicons/microsoft/mstile-150x150.png differ diff --git a/inst/www/images/shared/favicons/site.webmanifest b/inst/www/images/shared/favicons/site.webmanifest new file mode 100644 index 0000000..c55824a --- /dev/null +++ b/inst/www/images/shared/favicons/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "GMH Communities Leasing Dashboard", + "short_name": "GMH Communities Leasing Dashboard", + "icons": [ + { + "src": "/img/favicons/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/img/favicons/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/inst/www/images/shared/hexsticker/hex_logo.png b/inst/www/images/shared/hexsticker/hex_logo.png new file mode 100644 index 0000000..d0bba95 Binary files /dev/null and b/inst/www/images/shared/hexsticker/hex_logo.png differ diff --git a/inst/www/images/shared/hexsticker/hex_logo.svg b/inst/www/images/shared/hexsticker/hex_logo.svg new file mode 100644 index 0000000..7ece07a --- /dev/null +++ b/inst/www/images/shared/hexsticker/hex_logo.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/shared/placeholders/company-logo.jpg b/inst/www/images/shared/placeholders/company-logo.jpg new file mode 100644 index 0000000..1ea9d76 Binary files /dev/null and b/inst/www/images/shared/placeholders/company-logo.jpg differ diff --git a/inst/www/img/placeholders/default-image.png b/inst/www/images/shared/placeholders/default-image.png similarity index 100% rename from inst/www/img/placeholders/default-image.png rename to inst/www/images/shared/placeholders/default-image.png diff --git a/inst/www/images/shared/social/brandfetch.svg b/inst/www/images/shared/social/brandfetch.svg new file mode 100644 index 0000000..d1c4001 --- /dev/null +++ b/inst/www/images/shared/social/brandfetch.svg @@ -0,0 +1,3 @@ + + + diff --git a/inst/www/images/shared/social/facebook.svg b/inst/www/images/shared/social/facebook.svg new file mode 100644 index 0000000..1618cd0 --- /dev/null +++ b/inst/www/images/shared/social/facebook.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/inst/www/images/shared/social/instagram.svg b/inst/www/images/shared/social/instagram.svg new file mode 100644 index 0000000..eec74d9 --- /dev/null +++ b/inst/www/images/shared/social/instagram.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/inst/www/images/shared/social/linkedin.svg b/inst/www/images/shared/social/linkedin.svg new file mode 100644 index 0000000..902724e --- /dev/null +++ b/inst/www/images/shared/social/linkedin.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/inst/www/images/shared/social/youtube.svg b/inst/www/images/shared/social/youtube.svg new file mode 100644 index 0000000..3d91e2b --- /dev/null +++ b/inst/www/images/shared/social/youtube.svg @@ -0,0 +1,19 @@ + + + + + youtube [#168] + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/www/images/shared/techstack/R-256x256.png b/inst/www/images/shared/techstack/R-256x256.png new file mode 100644 index 0000000..8d365b0 Binary files /dev/null and b/inst/www/images/shared/techstack/R-256x256.png differ diff --git a/inst/www/images/shared/techstack/datatables.png b/inst/www/images/shared/techstack/datatables.png new file mode 100644 index 0000000..3c7058b Binary files /dev/null and b/inst/www/images/shared/techstack/datatables.png differ diff --git a/inst/www/images/shared/techstack/handsontable.png b/inst/www/images/shared/techstack/handsontable.png new file mode 100644 index 0000000..5b264dc Binary files /dev/null and b/inst/www/images/shared/techstack/handsontable.png differ diff --git a/inst/www/images/shared/techstack/highcharts.png b/inst/www/images/shared/techstack/highcharts.png new file mode 100644 index 0000000..1ffc3c5 Binary files /dev/null and b/inst/www/images/shared/techstack/highcharts.png differ diff --git a/inst/www/images/shared/techstack/httr2.png b/inst/www/images/shared/techstack/httr2.png new file mode 100644 index 0000000..3f3529f Binary files /dev/null and b/inst/www/images/shared/techstack/httr2.png differ diff --git a/inst/www/images/shared/techstack/icons/r.ico b/inst/www/images/shared/techstack/icons/r.ico new file mode 100644 index 0000000..f124269 Binary files /dev/null and b/inst/www/images/shared/techstack/icons/r.ico differ diff --git a/inst/www/images/shared/techstack/postgres-96x96.png b/inst/www/images/shared/techstack/postgres-96x96.png new file mode 100644 index 0000000..38987a0 Binary files /dev/null and b/inst/www/images/shared/techstack/postgres-96x96.png differ diff --git a/inst/www/images/shared/techstack/shiny-hex.svg b/inst/www/images/shared/techstack/shiny-hex.svg new file mode 100644 index 0000000..3c3c1ba --- /dev/null +++ b/inst/www/images/shared/techstack/shiny-hex.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/www/images/shared/techstack/shiny.png b/inst/www/images/shared/techstack/shiny.png new file mode 100644 index 0000000..d95def6 Binary files /dev/null and b/inst/www/images/shared/techstack/shiny.png differ diff --git a/inst/www/images/shared/visualizations/leasing-performance-chart.png b/inst/www/images/shared/visualizations/leasing-performance-chart.png new file mode 100644 index 0000000..838580b Binary files /dev/null and b/inst/www/images/shared/visualizations/leasing-performance-chart.png differ diff --git a/inst/www/images/shared/visualizations/pre-lease-vs-goals-selec.png b/inst/www/images/shared/visualizations/pre-lease-vs-goals-selec.png new file mode 100644 index 0000000..f4d6fea Binary files /dev/null and b/inst/www/images/shared/visualizations/pre-lease-vs-goals-selec.png differ diff --git a/inst/www/images/shared/visualizations/term-pre-lease-select-pr.png b/inst/www/images/shared/visualizations/term-pre-lease-select-pr.png new file mode 100644 index 0000000..aa36178 Binary files /dev/null and b/inst/www/images/shared/visualizations/term-pre-lease-select-pr.png differ diff --git a/inst/www/images/shared/visualizations/total-term-lease-by-type.png b/inst/www/images/shared/visualizations/total-term-lease-by-type.png new file mode 100644 index 0000000..3fbfc5d Binary files /dev/null and b/inst/www/images/shared/visualizations/total-term-lease-by-type.png differ diff --git a/inst/www/scripts/index.js b/inst/www/scripts/index.js new file mode 100644 index 0000000..1be77f9 --- /dev/null +++ b/inst/www/scripts/index.js @@ -0,0 +1,9 @@ +/** + * index.js + */ + +const config = require('./js/config'); +const gmaps = require('./js/gmaps'); +const custom = require('./js/init'); + +custom.init(); diff --git a/inst/www/scripts/js/config.js b/inst/www/scripts/js/config.js new file mode 100644 index 0000000..46ce26e --- /dev/null +++ b/inst/www/scripts/js/config.js @@ -0,0 +1,192 @@ +/* Configuration */ +const CONFIGURATION = { + locations: [ + { + title: "1047 Commonwealth", + address1: "1047 Commonwealth Ave", + address2: "Boston, MA 02215, USA", + coords: { lat: 42.352192191100016, lng: -71.12257497055225 }, + placeId: "ChIJcYT25PZ544kRK42i2BUEzZ8", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.1047commonwealth.com/", + }, + ], + }, + { + title: "The Academy Campustown", + address1: "708 S 6th St", + address2: "Champaign, IL 61820, USA", + coords: { lat: 40.10960277708431, lng: -88.23011387055226 }, + placeId: "ChIJN4K33c7XDIgRc3iISMg8KeQ", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.theacademycampustown.com/", + }, + ], + }, + { + title: "Academy65", + address1: "1325 65th St", + address2: "Sacramento, CA 95819, USA", + coords: { lat: 38.555257751246344, lng: -121.42693518834324 }, + placeId: "ChIJNVcdmCLbmoARwk1t6tpVYUw", + actions: [ + { label: "Book appointment", defaultUrl: "https://www.academy65.com/" }, + ], + }, + { + title: "Academy Lincoln", + address1: "1850 P St", + address2: "Lincoln, NE 68508, USA", + coords: { lat: 40.815055839668794, lng: -96.69498006441803 }, + placeId: "ChIJPTtG0OK-locRmRhgUNC4TBM", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.academylincoln.com/", + }, + ], + }, + { + title: "Shortbread Lofts", + address1: "333 W Rosemary St #130", + address2: "Chapel Hill, NC 27516, USA", + coords: { lat: 35.91205235855523, lng: -79.06111552944775 }, + placeId: "ChIJ8WIQ-eDCrIkRZvPm_rYR5Pc", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.shortbreadlofts.com/", + }, + ], + }, + { + title: "SOVA", + address1: "3021 Hidden Forest Ct", + address2: "Marietta, GA 30066, USA", + coords: { lat: 34.02508811149756, lng: -84.56450617055225 }, + placeId: "ChIJtdXyNiIV9YgRFMwh1GLxWpM", + actions: [ + { label: "Book appointment", defaultUrl: "https://www.sovaksu.com/" }, + ], + }, + { + title: "The Academy At Frisco", + address1: "413 N West Ave", + address2: "Fayetteville, AR 72701, USA", + coords: { lat: 36.068873215972026, lng: -94.16557282944774 }, + placeId: "ChIJA9q3dNtuyYcRyA5bOHvSdPo", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.theacademyatfrisco.com/", + }, + ], + }, + { + title: "The Academy on Charles", + address1: "3700 N Charles St", + address2: "Baltimore, MD 21218, USA", + coords: { lat: 39.333988274593075, lng: -76.61842332944774 }, + placeId: "ChIJte7U-yEFyIkRtigsoa1yq2Y", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.theacademyoncharles.com/contact/", + }, + ], + }, + { + title: "The Dean Campustown", + address1: "708 S 6th St", + address2: "Champaign, IL 61820, USA", + coords: { lat: 40.10960585416846, lng: -88.23011454110451 }, + placeId: "ChIJq0-EID_XDIgRGl5jbXhvDTY", + actions: [ + { + label: "Book appointment", + defaultUrl: + "https://www.thedean.com/campustown/contact/?modalWidget\u003dsg\u0026utm_source\u003dimps.conversionlogix.com\u0026utm_medium\u003dGBP-sg\u0026utm_content\u003dGoogle_appt\u0026utm_campaign\u003dTCC", + }, + ], + }, + { + title: "The Dean Reno", + address1: "1475 N Virginia St", + address2: "Reno, NV 89503, USA", + coords: { lat: 39.543618320312355, lng: -119.81862846441803 }, + placeId: "ChIJOQOrN75HmYAR5HtHpBd3LMU", + actions: [ + { + label: "Book appointment", + defaultUrl: + "https://www.thedeanreno.com/contact/?modalWidget\u003dsg\u0026utm_source\u003dimps.conversionlogix.com\u0026utm_medium\u003dGBP-sg\u0026utm_content\u003dGoogle_appt\u0026utm_campaign\u003dTCC", + }, + ], + }, + { + title: "Rise at Northgate", + address1: "717 University Dr", + address2: "College Station, TX 77840, USA", + coords: { lat: 30.62138841636048, lng: -96.34268981779098 }, + placeId: "ChIJu6bY3r2DRoYRtTUUhRTLQCc", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://www.riseatnorthgate.com/", + }, + ], + }, + { + title: "Torre Student Living", + address1: "2020 Nueces St", + address2: "Austin, TX 78705, USA", + coords: { lat: 30.283805732379562, lng: -97.74426738220902 }, + placeId: "ChIJe8FDGhS1RIYRzn1dvQZpycI", + actions: [ + { + label: "Book appointment", + defaultUrl: "https://torreatx.com/contact-us/", + }, + ], + }, + { + title: "Venue at North Campus", + address1: "13702 42nd St", + address2: "Tampa, FL 33613, USA", + coords: { lat: 28.071236233462187, lng: -82.4144222932541 }, + placeId: "ChIJ25T4QZTHwogRynMARJ5H75Q", + actions: [ + { + label: "Book appointment", + defaultUrl: + "https://www.venueatnorthcampus.com/Apartments/module/application_authentication/https://venueatnorthcampus.com/?switch_cls%5Bid%5D\u003d25368\u0026utm_source\u003dgoogle\u0026utm_medium\u003dorganic\u0026utm_campaign\u003dgmb\u0026utm_content\u003dappointment_link", + }, + ], + }, + ], + mapOptions: { + center: { lat: 38.0, lng: -100.0 }, + fullscreenControl: true, + mapTypeControl: false, + streetViewControl: false, + zoom: 4, + zoomControl: true, + maxZoom: 17, + mapId: "e41a5d4f3d81b765", + }, + mapsApiKey: "AIzaSyCSI8pJJXkS8KVLod37tbNlWLn-UmMGTfo", + capabilities: { + input: true, + autocomplete: true, + directions: false, + distanceMatrix: true, + details: true, + actions: true, + }, +}; + +export { CONFIGURATION }; diff --git a/inst/www/scripts/js/cookies.js b/inst/www/scripts/js/cookies.js new file mode 100644 index 0000000..e69de29 diff --git a/inst/www/scripts/js/gmaps.js b/inst/www/scripts/js/gmaps.js new file mode 100644 index 0000000..0066d9c --- /dev/null +++ b/inst/www/scripts/js/gmaps.js @@ -0,0 +1,11 @@ +/** + * Google Maps JavaScript + */ + +const CONFIGURATION = "./config.js"; + +document.addEventListener("DOMContentLoaded", async () => { + await customElements.whenDefined("gmpx-store-locator"); + const locator = document.querySelector("gmpx-store-locator"); + locator.configureFromQuickBuilder(CONFIGURATION); +}); diff --git a/inst/www/scripts/js/idle.js b/inst/www/scripts/js/idle.js new file mode 100644 index 0000000..c53759f --- /dev/null +++ b/inst/www/scripts/js/idle.js @@ -0,0 +1,28 @@ +/** + * Inactive Idle Timer + */ + + function idleTimer(milliseconds = 120000) { + + // time is in milliseconds (1000 is 1 second) + var t = setTimeout(logout, milliseconds); + + // catch mouse movements + window.onmousemove = resetTimer; + window.onmousedown = resetTimer; + window.onclick = resetTimer; + window.onscroll = resetTimer; + window.onkeypress = resetTimer; + + function logout() { + window.close(); + } + + function resetTimer() { + clearTimeout(t); + t = setTimeout(logout, milliseconds); + } + + } + + idleTimer(); diff --git a/inst/www/scripts/js/iframe.js b/inst/www/scripts/js/iframe.js new file mode 100644 index 0000000..e69de29 diff --git a/inst/www/scripts/js/init.js b/inst/www/scripts/js/init.js new file mode 100644 index 0000000..155fded --- /dev/null +++ b/inst/www/scripts/js/init.js @@ -0,0 +1,32 @@ +var init = function() { + + console.log("(custom.js): Custom JS Initialized"); + // Add custom JS here + $(document).on("shiny:connected", () => { + console.log("(custom.js): Shiny App Connection Initialized."); + // Add custom JS here + }); + + $(document).on("shiny:sessioninitialized", () => { + console.log("(custom.js): Shiny App Session Initialized"); + // Add custom JS here + }); + + $(document).on("shiny:disconnected", () => { + console.log("(custom.js): Shiny App Disconnected"); + // Add custom JS here + }); + + $(document).on("shiny:busy", () => { + console.log("(custom.js): Shiny App Busy"); + // Add custom JS here + }); + + $(document).on("shiny:idle", () => { + console.log("(custom.js): Shiny App Idle"); + // Add custom JS here + }); + +}; + +export { init }; diff --git a/inst/www/scripts/js/redirect.js b/inst/www/scripts/js/redirect.js new file mode 100644 index 0000000..10bed0f --- /dev/null +++ b/inst/www/scripts/js/redirect.js @@ -0,0 +1,12 @@ +$( document ).ready(function() { + Shiny.addCustomMessageHandler('redirect', function(message) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', "/cookie", true); + xhr.setRequestHeader("Header-User-Cookie", message); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4 && xhr.status == 200) + window.location = message; + }; + xhr.send(); + }); +}); diff --git a/inst/www/styles/css/footer.css b/inst/www/styles/css/footer.css deleted file mode 100644 index 99fb365..0000000 --- a/inst/www/styles/css/footer.css +++ /dev/null @@ -1,19 +0,0 @@ -.footer { - background-color: #f8f9fa; - padding: 20px; -} - -.footer-img { - vertical-align: middle; - margin-left: 5px; - height: 20px; -} - -.footer a { - color: #007bff; - text-decoration: none; -} - -.footer a:hover { - text-decoration: underline; -} diff --git a/inst/www/styles/css/styles.min.css b/inst/www/styles/css/styles.min.css new file mode 100644 index 0000000..cbbd98c --- /dev/null +++ b/inst/www/styles/css/styles.min.css @@ -0,0 +1,3 @@ +html .cursor-pointer{cursor:pointer}html .bg-light-grey{background-color:#D2D2D2}html .bg-brand-blue{background-color:#004CA7}html .bg-pale-blue{background-color:#F7FAFD}html .bg-mid-blue{background-color:#3181DE}html .bg-light-blue{background-color:#6ABEEA}html .bg-dark-green{background-color:#86A563}html .bg-light-green{background-color:#ABD27E}html .bg-orange{background-color:#E45C00}html .bg-light-orange{background-color:#FFAE77}html .text-light-grey{color:#D2D2D2}html .text-mid-grey{color:#989898}html .text-mid-blue{color:#3181DE !important}html hr{background-color:#989898}html .w-8{width:8rem}html h4{font-weight:600;font-size:1.2em}.rounded{border-radius:.5rem}.shadow{box-shadow:0 4px 8px rgba(0,0,0,0.1)}@media (max-width: 768px){.hidden-small{display:none !important}}.visible-small{display:none}@media (max-width: 768px){.visible-small{display:block !important}}.container-padding{padding:0.625rem}.container-margin{margin:0.625rem}.hover-dropdown{position:relative;display:inline-flex;align-items:center;justify-content:center}.hover-dropdown-content{display:none;position:absolute;right:0;top:100%;background-color:#fff;font-size:0.95em;border:1px solid rgba(0,0,0,0.175);border-radius:0.375rem;z-index:1}.hover-dropdown-content .custom-item{color:#000;padding:12px 16px;display:block}.hover-dropdown:hover .hover-dropdown-content{display:block}h1,h2{font-family:"Raleway, sans-serif"}gmpx-store-locator{width:100%;height:100%;--gmpx-color-surface: $gmpx-color-surface;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-color-outline: $gmpx-color-outline;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-font-family-base: $gmpx-font-family-base;--gmpx-font-family-headings: $gmpx-font-family-headings;--gmpx-font-size-base: $gmpx-font-size-base;--gmpx-hours-color-open: $gmpx-hours-color-open;--gmpx-hours-color-closed: $gmpx-hours-color-closed;--gmpx-rating-color: $gmpx-rating-color;--gmpx-rating-color-empty: $gmpx-rating-color-empty}gmpx-place-picker{--gmpx-color-surface: #fff;display:block;flex-grow:1;margin:1rem}gmpx-split-layout{flex:1 auto;overflow:auto}#close-button{display:block;margin:1rem}html,body{--gmpx-color-surface: $gmpx-color-on-surface;--gmpx-color-on-primary: $gmpx-color-on-primary;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;background:var(--gmpx-color-surface);display:flex;flex-direction:column;height:100%;margin:0}.logo{background-image:url("https://asset.brandfetch.io/id1vzz_tJL/idP4I1L9jI.svg")}h1,h2{font-family:"Raleway, sans-serif"}.footer{background-color:#F8F8F8;padding:1.25rem}.footer .footer-img{vertical-align:middle;margin-left:0.3125rem;height:1.25rem}.footer a{color:#004CA7;text-decoration:none}.footer a:hover{color:#0056b3;text-decoration:underline}.navbar{border-bottom:2px solid #004CA7}.navbar .dropdown-toggle::after{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f078";border-top:none;vertical-align:0}.navbar .dropdown-menu.show{left:-7rem;background-color:#fff}.navbar .nav-tabs .nav-link{color:#989898}.navbar .nav-tabs .nav-link.active{color:#000;border-bottom:1px solid #000}.big-full-page{min-height:100vh;padding:0.625rem;background-color:#F8F8F8;display:flex;flex-direction:column;align-items:center;justify-content:center}.page-container{width:100%;max-width:1200px;padding:1.25rem;margin:auto;background-color:#fff;box-shadow:0px 4px 8px rgba(0,0,0,0.1);border-radius:0.5rem}@media (max-width: 768px){.page-container{padding:0.625rem}}.page-title{font-size:2em;font-weight:bold;margin-bottom:0.625rem;text-align:center}.page-content{flex-grow:1;padding:0.625rem;color:#989898}@media (max-width: 768px){.page-content{padding:0.3125rem}}#sidebar-container{min-height:100vh;width:12rem;padding:0;border-right:1px solid #D2D2D2;background-color:#F7FAFD;position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:start;transition:width 0.3s ease}#sidebar-container.sidebar-expanded{width:12rem}#sidebar-container.sidebar-collapsed{width:3rem}#sidebar-container.sidebar-collapsed .sidebar-menu-item,#sidebar-container.sidebar-collapsed .sidebar-label{text-align:center}.sidebar-header{padding:0.625rem;font-size:1.5em;font-weight:bold;text-align:center}.sidebar-menu{flex-grow:1;width:100%;padding:0.3125rem 0;display:flex;flex-direction:column}.sidebar-menu .sidebar-menu-item{padding:0.3125rem 0.625rem;color:#989898;text-decoration:none;border-left:3px solid transparent;transition:background-color 0.2s ease, border-color 0.2s ease}.sidebar-menu .sidebar-menu-item:hover{background-color:#D2D2D2;color:#004CA7}.sidebar-menu .sidebar-menu-item.active-sidebar{border-left:3px solid #E3A45A;background-color:#F8F8F8;color:#000}.sidebar-footer{padding:0.625rem;width:100%;text-align:center;color:#989898;border-top:1px solid #D2D2D2}@media (max-width: 768px){#sidebar-container{width:100%;height:auto;flex-direction:row;position:relative;border-right:none;border-bottom:1px solid #D2D2D2}.sidebar-menu-item{padding:0.3125rem;flex-grow:1;text-align:center;border-left:none}}.nav-tabs{border:0}.nav-tabs .nav-link{border:0;color:#989898;padding:0.3125rem}.nav-tabs .nav-link.active{border-bottom:2px solid #000;color:#000}.nav-tabs .nav-link:hover{color:#004CA7;text-decoration:none}.big-tabs{line-height:1.1em;padding:0.625rem}.big-tabs .nav-link{padding:0.625rem;font-size:1.1em}.big-tabs .nav-link.active{border-bottom:2px solid #004CA7}@media (max-width: 768px){.nav-tabs .nav-link{font-size:0.9em;padding:0.3125rem}}.button{padding:0.3125rem 0.625rem;border-radius:0.25rem;font-weight:600;text-align:center;text-decoration:none;transition:background-color 0.3s ease, color 0.3s ease}.btn-primary{background-color:#004CA7;color:#fff;border:1px solid #004CA7}.btn-primary:hover{background-color:#003574;border-color:#003574}.btn-success{background-color:#86A563;color:#fff;border:1px solid #86A563}.btn-success:hover{background-color:#6c874e;border-color:#6c874e}.btn-warning{background-color:#E3A45A;color:#fff;border:1px solid #E3A45A}.btn-warning:hover{background-color:#dc8c2e;border-color:#dc8c2e}.btn-outline-primary{background-color:transparent;color:#004CA7;border:1px solid #004CA7}.btn-outline-primary:hover{background-color:#004CA7;color:#fff}.btn-outline-success{background-color:transparent;color:#86A563;border:1px solid #86A563}.btn-outline-success:hover{background-color:#86A563;color:#fff}.btn-outline-warning{background-color:transparent;color:#E3A45A;border:1px solid #E3A45A}.btn-outline-warning:hover{background-color:#E3A45A;color:#fff}.btn-small{padding:0.3125rem 0.3125rem;font-size:0.85em}.btn-large{padding:0.625rem 1.25rem;font-size:1.1em}.btn-disabled{background-color:#D2D2D2;color:#989898;border:1px solid #D2D2D2;cursor:not-allowed;opacity:0.6}.btn-disabled:hover{background-color:#D2D2D2;color:#989898}.selectize-input{word-break:break-word}.selectize-dropdown .option{word-break:break-word}.table{width:100%;margin-bottom:0.625rem;color:#989898;border-collapse:collapse;background-color:#fff;border:1px solid #D2D2D2;font-size:0.9em}.table th{padding:0.3125rem;text-align:left;font-weight:bold;color:#686868;background-color:#F8F8F8;border-bottom:2px solid #D2D2D2}.table td{padding:0.3125rem;border-top:1px solid #D2D2D2;vertical-align:middle}.table-striped tbody tr:nth-child(odd){background-color:#F8F8F8}.table-hover tbody tr:hover{background-color:#6ABEEA;color:#000}.table-bordered td,.table-bordered th{border:1px solid #D2D2D2}.table-condensed td,.table-condensed th{padding:0.3125rem 0.3125rem}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}.table-responsive .table{width:100%;margin-bottom:0}html{font-size:16px}@media (max-width: 768px){html{font-size:14px}}body{height:100%;margin:0;font-family:"Lato, sans-serif";background-color:#fff} + +/*# sourceMappingURL=data:application/json;base64,ewoJInZlcnNpb24iOiAzLAoJImZpbGUiOiAic3RkaW4uY3NzIiwKCSJzb3VyY2VzIjogWwoJCSJzdGRpbiIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL2luZGV4LnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy91dGlsaXR5L191dGlscy5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvdGhlbWUvX2NvbG9ycy5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvdXRpbGl0eS9fc2V0dGluZ3Muc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL3RoZW1lL19zcGFjaW5nLnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy91dGlsaXR5L19ob3Zlci5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvdXRpbGl0eS9fZ21hcHMuc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL3RoZW1lL190eXBvZ3JhcGh5LnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy90aGVtZS9fY29tcGFueS5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvdGhlbWUvX2xvZ29zLnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy90aGVtZS9fc29jaWFsLnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy9sYXlvdXQvX2Zvb3Rlci5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvbGF5b3V0L19uYXZiYXIuc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL2xheW91dC9fcGFnZS5zY3NzIiwKCQkiaW5zdC93d3cvc3R5bGVzL3Njc3MvbGF5b3V0L19zaWRlYmFyLnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy9sYXlvdXQvX3RhYnMuc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL2VsZW1lbnRzL19idXR0b25zLnNjc3MiLAoJCSJpbnN0L3d3dy9zdHlsZXMvc2Nzcy9lbGVtZW50cy9fY2FyZHMuc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL2VsZW1lbnRzL19zZWxlY3RpemUuc2NzcyIsCgkJImluc3Qvd3d3L3N0eWxlcy9zY3NzL2VsZW1lbnRzL190YWJsZXMuc2NzcyIKCV0sCgkibmFtZXMiOiBbXSwKCSJtYXBwaW5ncyI6ICJBRUVBLEFBQ0UsSUFERSxDQUNGLGVBQWUsQUFBQyxDQUFFLE1BQU0sQ0FBRSxPQUFPLENBQUksQUFEdkMsQUFHRSxJQUhFLENBR0YsY0FBYyxBQUFDLENBQUUsZ0JBQWdCLENDQ3JCLE9BQU8sQ0REeUMsQUFIOUQsQUFJRSxJQUpFLENBSUYsY0FBYyxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMeUMsQUFKOUQsQUFLRSxJQUxFLENBS0YsYUFBYSxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMd0MsQUFMNUQsQUFNRSxJQU5FLENBTUYsWUFBWSxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMdUMsQUFOMUQsQUFPRSxJQVBFLENBT0YsY0FBYyxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMeUMsQUFQOUQsQUFRRSxJQVJFLENBUUYsY0FBYyxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMeUMsQUFSOUQsQUFTRSxJQVRFLENBU0YsZUFBZSxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMMEMsQUFUaEUsQUFVRSxJQVZFLENBVUYsVUFBVSxBQUFDLENBQUUsZ0JBQWdCLENDS3JCLE9BQU8sQ0RMcUMsQUFWdEQsQUFXRSxJQVhFLENBV0YsZ0JBQWdCLEFBQUMsQ0FBRSxnQkFBZ0IsQ0NLckIsT0FBTyxDREwyQyxBQVhsRSxBQWFFLElBYkUsQ0FhRixnQkFBZ0IsQUFBQyxDQUFFLEtBQUssQ0NUWixPQUFPLENEU2dDLEFBYnJELEFBY0UsSUFkRSxDQWNGLGNBQWMsQUFBQyxDQUFFLEtBQUssQ0NSWixPQUFPLENEUThCLEFBZGpELEFBZUUsSUFmRSxDQWVGLGNBQWMsQUFBQyxDQUFFLEtBQUssQ0NKWixPQUFPLENESTJCLFVBQVUsQ0FBSSxBQWY1RCxBQWlCRSxJQWpCRSxDQWlCRixFQUFFLEFBQUMsQ0FBRSxnQkFBZ0IsQ0NYWCxPQUFPLENEVzZCLEFBakJoRCxBQWtCRSxJQWxCRSxDQWtCRixJQUFJLEFBQUMsQ0FBRSxLQUFLLENBQUUsSUFBSSxDQUFJLEFBbEJ4QixBQW9CRSxJQXBCRSxDQW9CRixFQUFFLEFBQUMsQ0FDRCxXQUFXLENBQUUsR0FBRyxDQUNoQixTQUFTLENBQUUsS0FBSyxDQUNqQixBRWdCSCxBQUFBLFFBQVEsQUFBQyxDQUNQLGFBQWEsQ0FYQyxLQUFNLENBWXJCLEFBRUQsQUFBQSxPQUFPLEFBQUMsQ0FSTixVQUFVLENBTEMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsZUFBa0IsQ0FleEMsQUFJQyxNQUFNLG1CQURSLENBQUEsQUFBQSxhQUFhLEFBQUMsQ0FFVixPQUFPLENBQUUsZUFBZSxDQUUzQixDQUFBLEFBRUQsQUFBQSxjQUFjLEFBQUMsQ0FDYixPQUFPLENBQUUsSUFBSSxDQUlkLEFBSEMsTUFBTSxtQkFGUixDQUFBLEFBQUEsY0FBYyxBQUFDLENBR1gsT0FBTyxDQUFFLGdCQUFnQixDQUU1QixDQUFBLEFBR0QsQUFBQSxrQkFBa0IsQUFBQyxDQUNqQixPQUFPLENDNURDLFFBQVEsQ0Q2RGpCLEFBRUQsQUFBQSxpQkFBaUIsQUFBQyxDQUNoQixNQUFNLENDekRFLFFBQVEsQ0QwRGpCLEFFdEVELEFBQUEsZUFBZSxBQUFDLENBQ2QsUUFBUSxDQUFFLFFBQVEsQ0FDbEIsT0FBTyxDQUFFLFdBQVcsQ0FDcEIsV0FBVyxDQUFFLE1BQU0sQ0FDbkIsZUFBZSxDQUFFLE1BQU0sQ0FDeEIsQUFFRCxBQUFBLHVCQUF1QixBQUFDLENBQ3RCLE9BQU8sQ0FBRSxJQUFJLENBQ2IsUUFBUSxDQUFFLFFBQVEsQ0FDbEIsS0FBSyxDQUFFLENBQUMsQ0FDUixHQUFHLENBQUUsSUFBSSxDQUNULGdCQUFnQixDSFBULElBQU8sQ0dRZCxTQUFTLENBQUUsTUFBTSxDQUNqQixNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxpQkFBb0IsQ0FDdEMsYUFBYSxDQUFFLFFBQVEsQ0FDdkIsT0FBTyxDQUFFLENBQUMsQ0FDWCxBQUVELEFBQUEsdUJBQXVCLENBQUMsWUFBWSxBQUFDLENBQ25DLEtBQUssQ0hoQkUsSUFBTyxDR2lCZCxPQUFPLENBQUUsU0FBUyxDQUNsQixPQUFPLENBQUUsS0FBSyxDQUNmLEFBRUQsQUFBQSxlQUFlLENBQUMsS0FBSyxDQUFDLHVCQUF1QixBQUFDLENBQzVDLE9BQU8sQ0FBRSxLQUFLLENBQ2YsQUV4QkQsQUFBQSxFQUFFLENBQUUsRUFBRSxBQUFDLENBQ0wsV0FBVyxDQUpBLHFCQUFxQixDQUtqQyxBRGVELEFBQUEsa0JBQWtCLEFBQUMsQ0FDZixLQUFLLENBQUUsSUFBSSxDQUNYLE1BQU0sQ0FBRSxJQUFJLENBRVosb0JBQW9CLENBQUEsb0JBQUMsQ0FDckIsdUJBQXVCLENBQUEsdUJBQUMsQ0FDeEIsK0JBQStCLENBQUEsK0JBQUMsQ0FDaEMsb0JBQW9CLENBQUEsb0JBQUMsQ0FDckIsb0JBQW9CLENBQUEsb0JBQUMsQ0FDckIsbUNBQW1DLENBQUEsbUNBQUMsQ0FDcEMsdUNBQXVDLENBQUEsdUNBQUMsQ0FDeEMsdUJBQXVCLENBQUEsdUJBQUMsQ0FDeEIsMkJBQTJCLENBQUEsMkJBQUMsQ0FDNUIscUJBQXFCLENBQUEscUJBQUMsQ0FDdEIsdUJBQXVCLENBQUEsdUJBQUMsQ0FDeEIseUJBQXlCLENBQUEseUJBQUMsQ0FDMUIsbUJBQW1CLENBQUEsbUJBQUMsQ0FDcEIseUJBQXlCLENBQUEseUJBQUMsQ0FDN0IsQUFFRCxBQUFBLGlCQUFpQixBQUFDLENBQ2hCLG9CQUFvQixDQUFBLEtBQUMsQ0FDckIsT0FBTyxDQUFFLEtBQUssQ0FDZCxTQUFTLENBQUUsQ0FBQyxDQUNaLE1BQU0sQ0FBRSxJQUFJLENBQ2IsQUFFRCxBQUFBLGlCQUFpQixBQUFDLENBQ2hCLElBQUksQ0FBRSxNQUFNLENBQ1osUUFBUSxDQUFFLElBQUksQ0FDZixBQUVELEFBQUEsYUFBYSxBQUFDLENBQ1osT0FBTyxDQUFFLEtBQUssQ0FDZCxNQUFNLENBQUUsSUFBSSxDQUNiLEFBRUQsQUFBQSxJQUFJLENBQUUsSUFBSSxBQUFDLENBQ1Qsb0JBQW9CLENBQUEsdUJBQUMsQ0FDckIsdUJBQXVCLENBQUEsdUJBQUMsQ0FDeEIsdUJBQXVCLENBQUEsdUJBQUMsQ0FDeEIsK0JBQStCLENBQUEsK0JBQUMsQ0FDaEMsb0JBQW9CLENBQUEsb0JBQUMsQ0FDckIsdUNBQXVDLENBQUEsdUNBQUMsQ0FDeEMsbUNBQW1DLENBQUEsbUNBQUMsQ0FDcEMsVUFBVSxDQUFFLHlCQUF5QixDQUNyQyxPQUFPLENBQUUsSUFBSSxDQUNiLGNBQWMsQ0FBRSxNQUFNLENBQ3RCLE1BQU0sQ0FBRSxJQUFJLENBQ1osTUFBTSxDQUFFLENBQUMsQ0FDVixBR2xFRCxBQUFBLEtBQUssQUFBQyxDQUNKLGdCQUFnQixDQUFFLDREQUF5QixDQUM1QyxBRkhELEFBQUEsRUFBRSxDQUFFLEVBQUUsQUFBQyxDQUNMLFdBQVcsQ0FKQSxxQkFBcUIsQ0FLakMsQUlGRCxBQUFBLE9BQU8sQUFBQyxDQUNOLGdCQUFnQixDVEdFLE9BQU8sQ1NGekIsT0FBTyxDUENBLE9BQU8sQ09nQmYsQUFuQkQsQUFJRSxPQUpLLENBSUwsV0FBVyxBQUFDLENBQ1YsY0FBYyxDQUFFLE1BQU0sQ0FDdEIsV0FBVyxDUEVOLFNBQVMsQ09EZCxNQUFNLENQUUQsT0FBTyxDT1BiLEFBUkgsQUFVRSxPQVZLLENBVUwsQ0FBQyxBQUFDLENBQ0EsS0FBSyxDVEhLLE9BQU8sQ1NJakIsZUFBZSxDQUFFLElBQUksQ0FNdEIsQUFsQkgsQUFjSSxPQWRHLENBVUwsQ0FBQyxDQUlHLEtBQUssQUFBQyxDQUNOLEtBQUssQ1RnQlMsT0FBTyxDU2ZyQixlQUFlLENBQUUsU0FBUyxDQUMzQixBQ2xCTCxBQUFBLE9BQU8sQUFBQyxDQUNOLGFBQWEsQ0FBRSxHQUFHLENBQUMsS0FBSyxDVlFaLE9BQU8sQ1VlcEIsQUF4QkQsQUFHRSxPQUhLLENBR0wsZ0JBQWdCLEVBQUUsS0FBSyxBQUFDLENBQ3RCLFdBQVcsQ0FBRSxxQkFBcUIsQ0FDbEMsV0FBVyxDQUFFLEdBQUcsQ0FDaEIsT0FBTyxDQUFFLE9BQU8sQ0FDaEIsVUFBVSxDQUFFLElBQUksQ0FDaEIsY0FBYyxDQUFFLENBQUMsQ0FDbEIsQUFUSCxBQVdFLE9BWEssQ0FXTCxjQUFjLEFBQUEsS0FBSyxBQUFDLENBQ2xCLElBQUksQ0FBRSxLQUFLLENBQ1gsZ0JBQWdCLENWVlgsSUFBTyxDVVdiLEFBZEgsQUFnQkUsT0FoQkssQ0FnQkwsU0FBUyxDQUFDLFNBQVMsQUFBQyxDQUNsQixLQUFLLENWWEcsT0FBTyxDVWlCaEIsQUF2QkgsQUFtQkksT0FuQkcsQ0FnQkwsU0FBUyxDQUFDLFNBQVMsQUFHaEIsT0FBTyxBQUFDLENBQ1AsS0FBSyxDVmxCRixJQUFPLENVbUJWLGFBQWEsQ0FBRSxHQUFHLENBQUMsS0FBSyxDVm5CckIsSUFBTyxDVW9CWCxBQ3BCTCxBQUFBLGNBQWMsQUFBQyxDQUNiLFVBQVUsQ0FBRSxLQUFLLENBQ2pCLE9BQU8sQ1REQyxRQUFRLENTRWhCLGdCQUFnQixDWEFFLE9BQU8sQ1dDekIsT0FBTyxDQUFFLElBQUksQ0FDYixjQUFjLENBQUUsTUFBTSxDQUN0QixXQUFXLENBQUUsTUFBTSxDQUNuQixlQUFlLENBQUUsTUFBTSxDQUN4QixBQUdELEFBQUEsZUFBZSxBQUFDLENBQ2QsS0FBSyxDQUFFLElBQUksQ0FDWCxTQUFTLENBQUUsTUFBTSxDQUNqQixPQUFPLENUWkEsT0FBTyxDU2FkLE1BQU0sQ0FBRSxJQUFJLENBQ1osZ0JBQWdCLENYZlQsSUFBTyxDV2dCZCxVQUFVLENBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsZUFBa0IsQ0FDMUMsYUFBYSxDQUFFLE1BQU0sQ0FLdEIsQUFIQyxNQUFNLG1CQVRSLENBQUEsQUFBQSxlQUFlLEFBQUMsQ0FVWixPQUFPLENUcEJELFFBQVEsQ1NzQmpCLENBQUEsQUFHRCxBQUFBLFdBQVcsQUFBQyxDQUNWLFNBQVMsQ0FBRSxHQUFHLENBQ2QsV0FBVyxDQUFFLElBQUksQ0FFakIsYUFBYSxDVHRCTCxRQUFRLENTdUJoQixVQUFVLENBQUUsTUFBTSxDQUNuQixBQUdELEFBQUEsYUFBYSxBQUFDLENBQ1osU0FBUyxDQUFFLENBQUMsQ0FDWixPQUFPLENUcENDLFFBQVEsQ1NxQ2hCLEtBQUssQ1hsQ0ssT0FBTyxDV3dDbEIsQUFIQyxNQUFNLG1CQU5SLENBQUEsQUFBQSxhQUFhLEFBQUMsQ0FPVixPQUFPLENUMUNGLFNBQVMsQ1M0Q2pCLENBQUEsQUM1Q0QsQUFBQSxrQkFBa0IsQUFBQyxDQUNqQixVQUFVLENBQUUsS0FBSyxDQUNqQixLQUFLLENBQUUsS0FBSyxDQUNaLE9BQU8sQ0FBRSxDQUFDLENBQ1YsWUFBWSxDQUFFLEdBQUcsQ0FBQyxLQUFLLENaRlgsT0FBTyxDWUduQixnQkFBZ0IsQ1pHTCxPQUFPLENZRmxCLFFBQVEsQ0FBRSxLQUFLLENBQ2YsR0FBRyxDQUFFLENBQUMsQ0FDTixJQUFJLENBQUUsQ0FBQyxDQUNQLE9BQU8sQ0FBRSxJQUFJLENBQ2IsY0FBYyxDQUFFLE1BQU0sQ0FDdEIsV0FBVyxDQUFFLEtBQUssQ0FDbEIsVUFBVSxDQUFFLGVBQWUsQ0FhNUIsQUF6QkQsQUFjRSxrQkFkZ0IsQUFjZixpQkFBaUIsQUFBQyxDQUNqQixLQUFLLENBQUUsS0FBSyxDQUNiLEFBaEJILEFBa0JFLGtCQWxCZ0IsQUFrQmYsa0JBQWtCLEFBQUMsQ0FDbEIsS0FBSyxDQUFFLElBQUksQ0FLWixBQXhCSCxBQW9CSSxrQkFwQmMsQUFrQmYsa0JBQWtCLENBRWpCLGtCQUFrQixDQXBCdEIsa0JBQWtCLEFBa0JmLGtCQUFrQixDQUdqQixjQUFjLEFBQUMsQ0FDYixVQUFVLENBQUUsTUFBTSxDQUNuQixBQUtMLEFBQUEsZUFBZSxBQUFDLENBQ2QsT0FBTyxDVjVCQyxRQUFRLENVNkJoQixTQUFTLENBQUUsS0FBSyxDQUNoQixXQUFXLENBQUUsSUFBSSxDQUVqQixVQUFVLENBQUUsTUFBTSxDQUNuQixBQUdELEFBQUEsYUFBYSxBQUFDLENBQ1osU0FBUyxDQUFFLENBQUMsQ0FDWixLQUFLLENBQUUsSUFBSSxDQUNYLE9BQU8sQ1Z4Q0EsU0FBUyxDVXdDWSxDQUFDLENBQzdCLE9BQU8sQ0FBRSxJQUFJLENBQ2IsY0FBYyxDQUFFLE1BQU0sQ0FvQnZCLEFBekJELEFBT0UsYUFQVyxDQU9YLGtCQUFrQixBQUFDLENBQ2pCLE9BQU8sQ1Y3Q0YsU0FBUyxDQUNSLFFBQVEsQ1U2Q2QsS0FBSyxDWjFDRyxPQUFPLENZMkNmLGVBQWUsQ0FBRSxJQUFJLENBQ3JCLFdBQVcsQ0FBRSxxQkFBcUIsQ0FDbEMsVUFBVSxDQUFFLGtEQUFrRCxDQVkvRCxBQXhCSCxBQWNJLGFBZFMsQ0FPWCxrQkFBa0IsQ0FPZCxLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ1psRFIsT0FBTyxDWW1EZixLQUFLLENaOUNHLE9BQU8sQ1krQ2hCLEFBakJMLEFBbUJJLGFBbkJTLENBT1gsa0JBQWtCLEFBWWYsZUFBZSxBQUFDLENBQ2YsV0FBVyxDQUFFLEdBQUcsQ0FBQyxLQUFLLENaekNqQixPQUFPLENZMENaLGdCQUFnQixDWnZERixPQUFPLENZd0RyQixLQUFLLENaM0RGLElBQU8sQ1k0RFgsQUFLTCxBQUFBLGVBQWUsQUFBQyxDQUNkLE9BQU8sQ1ZqRUMsUUFBUSxDVWtFaEIsS0FBSyxDQUFFLElBQUksQ0FDWCxVQUFVLENBQUUsTUFBTSxDQUNsQixLQUFLLENaakVLLE9BQU8sQ1lrRWpCLFVBQVUsQ0FBRSxHQUFHLENBQUMsS0FBSyxDWnBFVCxPQUFPLENZcUVwQixBQUdELE1BQU0sbUJBQ0osQ0FBQSxBQUFBLGtCQUFrQixBQUFDLENBQ2pCLEtBQUssQ0FBRSxJQUFJLENBQ1gsTUFBTSxDQUFFLElBQUksQ0FDWixjQUFjLENBQUUsR0FBRyxDQUNuQixRQUFRLENBQUUsUUFBUSxDQUNsQixZQUFZLENBQUUsSUFBSSxDQUNsQixhQUFhLENBQUUsR0FBRyxDQUFDLEtBQUssQ1ovRWQsT0FBTyxDWWdGbEIsQUFFRCxBQUFBLGtCQUFrQixBQUFDLENBQ2pCLE9BQU8sQ1ZyRkYsU0FBUyxDVXNGZCxTQUFTLENBQUUsQ0FBQyxDQUNaLFVBQVUsQ0FBRSxNQUFNLENBQ2xCLFdBQVcsQ0FBRSxJQUFJLENBQ2xCLENBUEEsQUNsRkgsQUFBQSxTQUFTLEFBQUMsQ0FDUixNQUFNLENBQUUsQ0FBQyxDQWlCVixBQWxCRCxBQUdFLFNBSE8sQ0FHUCxTQUFTLEFBQUMsQ0FDUixNQUFNLENBQUUsQ0FBQyxDQUNULEtBQUssQ2JERyxPQUFPLENhRWYsT0FBTyxDWE5GLFNBQVMsQ1dpQmYsQUFqQkgsQUFRSSxTQVJLLENBR1AsU0FBUyxBQUtOLE9BQU8sQUFBQyxDQUNQLGFBQWEsQ0FBRSxHQUFHLENBQUMsS0FBSyxDYlRyQixJQUFPLENhVVYsS0FBSyxDYlZGLElBQU8sQ2FXWCxBQVhMLEFBYUksU0FiSyxDQUdQLFNBQVMsQ0FVTCxLQUFLLEFBQUMsQ0FDTixLQUFLLENiUEcsT0FBTyxDYVFmLGVBQWUsQ0FBRSxJQUFJLENBQ3RCLEFBS0wsQUFBQSxTQUFTLEFBQUMsQ0FDUixXQUFXLENBQUUsS0FBSyxDQUNsQixPQUFPLENYdEJDLFFBQVEsQ1dnQ2pCLEFBWkQsQUFJRSxTQUpPLENBSVAsU0FBUyxBQUFDLENBQ1IsT0FBTyxDWHpCRCxRQUFRLENXMEJkLFNBQVMsQ0FBRSxLQUFLLENBS2pCLEFBWEgsQUFRSSxTQVJLLENBSVAsU0FBUyxBQUlOLE9BQU8sQUFBQyxDQUNQLGFBQWEsQ0FBRSxHQUFHLENBQUMsS0FBSyxDYnZCaEIsT0FBTyxDYXdCaEIsQUFLTCxNQUFNLG1CQUNKLENBQUEsQUFBQSxTQUFTLENBQUMsU0FBUyxBQUFDLENBQ2xCLFNBQVMsQ0FBRSxLQUFLLENBQ2hCLE9BQU8sQ1h2Q0YsU0FBUyxDV3dDZixDQUFBLEFDeENILEFBQUEsT0FBTyxBQUFDLENBQ04sT0FBTyxDWkRBLFNBQVMsQ0FDUixRQUFRLENZQ2hCLGFBQWEsQ0FBRSxPQUFPLENBQ3RCLFdBQVcsQ0FBRSxHQUFHLENBQ2hCLFVBQVUsQ0FBRSxNQUFNLENBQ2xCLGVBQWUsQ0FBRSxJQUFJLENBQ3JCLFVBQVUsQ0FBRSwyQ0FBMkMsQ0FDeEQsQUFHRCxBQUFBLFlBQVksQUFBQyxDQUNYLGdCQUFnQixDZFFQLE9BQU8sQ2NQaEIsS0FBSyxDZFhFLElBQU8sQ2NZZCxNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2RNUixPQUFPLENjQWpCLEFBVEQsQUFLRSxZQUxVLENBS1IsS0FBSyxBQUFDLENBQ04sZ0JBQWdCLENkR1QsT0FBTyxDY0ZkLFlBQVksQ2RFTCxPQUFPLENjRGYsQUFHSCxBQUFBLFlBQVksQUFBQyxDQUNYLGdCQUFnQixDZExQLE9BQU8sQ2NNaEIsS0FBSyxDZHRCRSxJQUFPLENjdUJkLE1BQU0sQ0FBRSxHQUFHLENBQUMsS0FBSyxDZFBSLE9BQU8sQ2NhakIsQUFURCxBQUtFLFlBTFUsQ0FLUixLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ2RWVCxPQUFPLENjV2QsWUFBWSxDZFhMLE9BQU8sQ2NZZixBQUdILEFBQUEsWUFBWSxBQUFDLENBQ1gsZ0JBQWdCLENkakJQLE9BQU8sQ2NrQmhCLEtBQUssQ2RqQ0UsSUFBTyxDY2tDZCxNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2RuQlIsT0FBTyxDY3lCakIsQUFURCxBQUtFLFlBTFUsQ0FLUixLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ2R0QlQsT0FBTyxDY3VCZCxZQUFZLENkdkJMLE9BQU8sQ2N3QmYsQUFJSCxBQUFBLG9CQUFvQixBQUFDLENBQ25CLGdCQUFnQixDQUFFLFdBQVcsQ0FDN0IsS0FBSyxDZDNCSSxPQUFPLENjNEJoQixNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2Q1QlIsT0FBTyxDY2tDakIsQUFURCxBQUtFLG9CQUxrQixDQUtoQixLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ2QvQlQsT0FBTyxDY2dDZCxLQUFLLENkbERBLElBQU8sQ2NtRGIsQUFHSCxBQUFBLG9CQUFvQixBQUFDLENBQ25CLGdCQUFnQixDQUFFLFdBQVcsQ0FDN0IsS0FBSyxDZHhDSSxPQUFPLENjeUNoQixNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2R6Q1IsT0FBTyxDYytDakIsQUFURCxBQUtFLG9CQUxrQixDQUtoQixLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ2Q1Q1QsT0FBTyxDYzZDZCxLQUFLLENkN0RBLElBQU8sQ2M4RGIsQUFHSCxBQUFBLG9CQUFvQixBQUFDLENBQ25CLGdCQUFnQixDQUFFLFdBQVcsQ0FDN0IsS0FBSyxDZHBESSxPQUFPLENjcURoQixNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2RyRFIsT0FBTyxDYzJEakIsQUFURCxBQUtFLG9CQUxrQixDQUtoQixLQUFLLEFBQUMsQ0FDTixnQkFBZ0IsQ2R4RFQsT0FBTyxDY3lEZCxLQUFLLENkeEVBLElBQU8sQ2N5RWIsQUFJSCxBQUFBLFVBQVUsQUFBQyxDQUNULE9BQU8sQ1ovRUEsU0FBUyxDQUFULFNBQVMsQ1lnRmhCLFNBQVMsQ0FBRSxNQUFNLENBQ2xCLEFBR0QsQUFBQSxVQUFVLEFBQUMsQ0FDVCxPQUFPLENacEZDLFFBQVEsQ0FDVCxPQUFPLENZb0ZkLFNBQVMsQ0FBRSxLQUFLLENBQ2pCLEFBR0QsQUFBQSxhQUFhLEFBQUMsQ0FDWixnQkFBZ0IsQ2R6RkosT0FBTyxDYzBGbkIsS0FBSyxDZHhGSyxPQUFPLENjeUZqQixNQUFNLENBQUUsR0FBRyxDQUFDLEtBQUssQ2QzRkwsT0FBTyxDYzRGbkIsTUFBTSxDQUFFLFdBQVcsQ0FDbkIsT0FBTyxDQUFFLEdBQUcsQ0FNYixBQVhELEFBT0UsYUFQVyxDQU9ULEtBQUssQUFBQyxDQUNOLGdCQUFnQixDZGhHTixPQUFPLENjaUdqQixLQUFLLENkL0ZHLE9BQU8sQ2NnR2hCLEFFdEdILEFBQUEsZ0JBQWdCLEFBQUMsQ0FDYixVQUFVLENBQUUsVUFBVSxDQUN6QixBQUVELEFBQUEsbUJBQW1CLENBQUMsT0FBTyxBQUFDLENBQ3hCLFVBQVUsQ0FBRSxVQUFVLENBQ3pCLEFDSkQsQUFBQSxNQUFNLEFBQUMsQ0FDTCxLQUFLLENBQUUsSUFBSSxDQUNYLGFBQWEsQ2ZNTCxRQUFRLENlTGhCLEtBQUssQ2pCQ0ssT0FBTyxDaUJBakIsZUFBZSxDQUFFLFFBQVEsQ0FDekIsZ0JBQWdCLENqQkpULElBQU8sQ2lCS2QsTUFBTSxDQUFFLEdBQUcsQ0FBQyxLQUFLLENqQkpMLE9BQU8sQ2lCS25CLFNBQVMsQ0FBRSxLQUFLLENBQ2pCLEFBR0QsQUFBQSxNQUFNLENBQUMsRUFBRSxBQUFDLENBQ1IsT0FBTyxDZlpBLFNBQVMsQ2VhaEIsVUFBVSxDQUFFLElBQUksQ0FDaEIsV0FBVyxDQUFFLElBQUksQ0FDakIsS0FBSyxDakJWTSxPQUFPLENpQldsQixnQkFBZ0IsQ2pCYkUsT0FBTyxDaUJjekIsYUFBYSxDQUFFLEdBQUcsQ0FBQyxLQUFLLENqQmZaLE9BQU8sQ2lCZ0JwQixBQUdELEFBQUEsTUFBTSxDQUFDLEVBQUUsQUFBQyxDQUNSLE9BQU8sQ2Z0QkEsU0FBUyxDZXVCaEIsVUFBVSxDQUFFLEdBQUcsQ0FBQyxLQUFLLENqQnJCVCxPQUFPLENpQnNCbkIsY0FBYyxDQUFFLE1BQU0sQ0FDdkIsQUFHRCxBQUFBLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFNBQVUsQ0FBQSxHQUFHLENBQUUsQ0FDckMsZ0JBQWdCLENqQjFCRSxPQUFPLENpQjJCMUIsQUFHRCxBQUFBLFlBQVksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQUFBQyxDQUMxQixnQkFBZ0IsQ2pCeEJKLE9BQU8sQ2lCeUJuQixLQUFLLENqQm5DRSxJQUFPLENpQm9DZixBQUdELEFBQUEsZUFBZSxDQUFDLEVBQUUsQ0FBRSxlQUFlLENBQUMsRUFBRSxBQUFDLENBQ3JDLE1BQU0sQ0FBRSxHQUFHLENBQUMsS0FBSyxDakJ0Q0wsT0FBTyxDaUJ1Q3BCLEFBR0QsQUFBQSxnQkFBZ0IsQ0FBQyxFQUFFLENBQUUsZ0JBQWdCLENBQUMsRUFBRSxBQUFDLENBQ3ZDLE9BQU8sQ2Y3Q0EsU0FBUyxDQUFULFNBQVMsQ2U4Q2pCLEFBR0QsQUFBQSxpQkFBaUIsQUFBQyxDQUNoQixVQUFVLENBQUUsSUFBSSxDQUNoQiwwQkFBMEIsQ0FBRSxLQUFLLENBQ2pDLFNBQVMsQ0FBRSxJQUFJLENBTWhCLEFBVEQsQUFLRSxpQkFMZSxDQUtmLE1BQU0sQUFBQyxDQUNMLEtBQUssQ0FBRSxJQUFJLENBQ1gsYUFBYSxDQUFFLENBQUMsQ0FDakIsQW5CakNILEFBQUEsSUFBSSxBQUFDLENBQ0gsU0FBUyxDQUFFLElBQUksQ0FLaEIsQUFIQyxNQUFNLG1CQUhSLENBQUEsQUFBQSxJQUFJLEFBQUMsQ0FJRCxTQUFTLENBQUUsSUFBSSxDQUVsQixDQUFBLEFBRUQsQUFBQSxJQUFJLEFBQUMsQ0FDSCxNQUFNLENBQUUsSUFBSSxDQUNaLE1BQU0sQ0FBRSxDQUFDLENBQ1QsV0FBVyxDT3RDRCxrQkFBa0IsQ1B1QzVCLGdCQUFnQixDRW5DVCxJQUFPLENGcUNmIgp9 */ \ No newline at end of file diff --git a/inst/www/styles/repomix-output.txt b/inst/www/styles/repomix-output.txt new file mode 100644 index 0000000..4c02439 --- /dev/null +++ b/inst/www/styles/repomix-output.txt @@ -0,0 +1,797 @@ +This file is a merged representation of the entire codebase, combining all repository files into a single document. +Generated by Repomix on: 2024-11-11T17:57:58.766Z + +================================================================ +File Summary +================================================================ + +Purpose: +-------- +This file contains a packed representation of the entire repository's contents. +It is designed to be easily consumable by AI systems for analysis, code review, +or other automated processes. + +File Format: +------------ +The content is organized as follows: +1. This summary section +2. Repository information +3. Repository structure +4. Multiple file entries, each consisting of: + a. A separator line (================) + b. The file path (File: path/to/file) + c. Another separator line + d. The full contents of the file + e. A blank line + +Usage Guidelines: +----------------- +- This file should be treated as read-only. Any changes should be made to the + original repository files, not this packed version. +- When processing this file, use the file path to distinguish + between different files in the repository. +- Be aware that this file may contain sensitive information. Handle it with + the same level of security as you would the original repository. + +Notes: +------ +- Some files may have been excluded based on .gitignore rules and Repomix's + configuration. +- Binary files are not included in this packed representation. Please refer to + the Repository Structure section for a complete list of file paths, including + binary files. + +Additional Info: +---------------- + +For more information about Repomix, visit: https://github.com/yamadashy/repomix + +================================================================ +Repository Structure +================================================================ +css/footer.css +css/gmaps.css +css/styles.min.css +scss/elements/_buttons.scss +scss/elements/_selectize.scss +scss/elements/_tables.scss +scss/index.scss +scss/layout/_footer.scss +scss/layout/_navbar.scss +scss/layout/_page.scss +scss/layout/_sidebar.scss +scss/layout/_spacing.scss +scss/layout/_tabs.scss +scss/README.md +scss/theme/_colors.scss +scss/theme/_company.scss +scss/theme/_logos.scss +scss/theme/_social.scss +scss/theme/_typography.scss +scss/utility/_gmaps.scss +scss/utility/_hover.scss +scss/utility/_settings.scss +scss/utility/_utils.scss + +================================================================ +Repository Files +================================================================ + +================ +File: css/footer.css +================ +.footer { + background-color: #f8f9fa; + padding: 20px; +} + +.footer-img { + vertical-align: middle; + margin-left: 5px; + height: 20px; +} + +.footer a { + color: #007bff; + text-decoration: none; +} + +.footer a:hover { + text-decoration: underline; +} + +================ +File: css/gmaps.css +================ +html, +body { + height: 100%; + margin: 0; +} + +gmpx-property-locator { + width: 100%; + height: 100%; + /* https://github.com/googlemaps/extended-component-library/blob/main/src/store_locator/README.md */ + --gmpx-color-surface: #fff; + --gmpx-color-on-surface: #212121; + --gmpx-color-on-surface-variant: #757575; + --gmpx-color-primary: #1967d2; + --gmpx-color-outline: #e0e0e0; + --gmpx-fixed-panel-width-row-layout: 28.5em; + --gmpx-fixed-panel-height-column-layout: 65%; + --gmpx-font-family-base: "Roboto", sans-serif; + --gmpx-font-family-headings: "Roboto", sans-serif; + --gmpx-font-size-base: 0.875rem; + --gmpx-hours-color-open: #188038; + --gmpx-hours-color-closed: #d50000; + --gmpx-rating-color: #ffb300; + --gmpx-rating-color-empty: #e0e0e0; +} + +================ +File: css/styles.min.css +================ +h1{font-family:"Raleway, sans-serif"}h2{font-family:"Raleway, sans-serif"}.logo{background-image:url("https://asset.brandfetch.io/id1vzz_tJL/idP4I1L9jI.svg")}h1{font-family:"Raleway, sans-serif"}h2{font-family:"Raleway, sans-serif"}gmpx-store-locator{width:100%;height:100%;--gmpx-color-surface: $gmpx-color-surface;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-color-outline: $gmpx-color-outline;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-font-family-base: $gmpx-font-family-base;--gmpx-font-family-headings: $gmpx-font-family-headings;--gmpx-font-size-base: $gmpx-font-size-base;--gmpx-hours-color-open: $gmpx-hours-color-open;--gmpx-hours-color-closed: $gmpx-hours-color-closed;--gmpx-rating-color: $gmpx-rating-color;--gmpx-rating-color-empty: $gmpx-rating-color-empty}gmpx-place-picker{--gmpx-color-surface: #fff;display:block;flex-grow:1;margin:1rem}gmpx-split-layout{flex:1 auto;overflow:auto}#close-button{display:block;margin:1rem}html,body{--gmpx-color-surface: $gmpx-color-on-surface;--gmpx-color-on-primary: $gmpx-color-on-primary;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;background:var(--gmpx-color-surface);display:flex;flex-direction:column;height:100%;margin:0}html .cursor-pointer{cursor:pointer}html .bg-light-grey{background-color:#D2D2D2}html .bg-brand-blue{background-color:#004CA7}html .bg-pale-blue{background-color:#F7FAFD}html .bg-mid-blue{background-color:#3181DE}html .bg-light-blue{background-color:#6ABEEA}html .bg-dark-green{background-color:#86A563}html .bg-light-green{background-color:#ABD27E}html .bg-orange{background-color:#E45C00}html .bg-light-orange{background-color:#FFAE77}html .text-light-grey{color:#D2D2D2}html .text-mid-grey{color:#989898}html .text-mid-blue{color:#3181DE !important}html hr{background-color:#989898}html .w-8{width:8rem}html h4{font-weight:600;font-size:1.2em}#app.row{margin-left:0px;margin-right:0px}#sidebar-container{min-height:92vh;width:12rem;padding:0;border-right:1px solid #D2D2D2;background-color:#F7FAFD;position:relative}.sidebar-expanded{min-width:12rem}.sidebar-expanded>.sidebar{min-width:10rem}.sidebar-collapsed{width:3rem;max-width:3rem}.active-sidebar{border-left:0.3rem solid #E3A45A !important}.sidebar-menu{padding:.7rem 0rem .7rem 1rem;line-height:1.4rem;display:block}.sidebar-menu-item{padding-left:1rem;border-left:.3rem solid transparent}.tab-sidebar{border-left:.3rem solid transparent;padding:.7rem .7rem;display:block}#settings-container{min-height:92vh;width:12rem;padding:0;border-left:1px solid #D2D2D2;background-color:#F7FAFD}.settings-expanded{min-width:12rem;padding-left:3px}.settings-collapsed{width:3rem;max-width:3rem}.settings-lock-collapsed{display:inline-block;width:100%;text-align:center}.settings-lock-expanded{font-size:0.9em;margin-left:7px}.settings-lock{opacity:.7}.settings-label{margin-top:0px}.settings-icon{float:right}.big-full-page{min-height:100vh}html .navbar{border-bottom:2px solid #004CA7}html .navbar>.dropdown-toggle::after{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f078";border-top:none;vertical-align:0}html .dropdown-menu.show{left:-7rem;background-color:#fff}html .nav-tabs .nav-link{color:#989898}html .nav-tabs{border:0}html .nav-tabs .nav-link{border:0;color:#989898}html .nav-tabs .nav-link.active{border-bottom:1px solid black;color:#000}html .big-tabs{line-height:1.1em}.table{width:100%;margin-bottom:1rem;color:#989898;border-collapse:collapse;border-spacing:0;border:1px solid #D2D2D2;background-color:#fff}.table th,.table td{padding:0.75rem;vertical-align:top;border-top:1px solid #D2D2D2}html .btn-success,html .btn-primary,html .btn-info,html .btn-warning,html .btn-danger,html .btn-dark,html .btn-secondary{color:white}html .btn-outline-primary:hover{color:white}html .btn-outline-primary-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-primary-hover:hover{border-color:#3181DE;color:#3181DE;background-color:transparent}html .btn-outline-info-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-info-hover:hover{border-color:#6ABEEA;color:#6ABEEA;background-color:transparent}html .btn-outline-danger-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-danger-hover:hover{border-color:#BF616A;color:#BF616A;background-color:transparent}html .btn-outline-warning-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-warning-hover:hover{border-color:#E3A45A;color:#E3A45A;background-color:transparent}html .btn-outline-dark-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-dark-hover:hover{border-color:#000;color:#000;background-color:transparent}html .btn-outline-success-hover{background-color:transparent;border-color:#D2D2D2;color:#D2D2D2}html .btn-outline-success-hover:hover{border-color:#86A563;color:#86A563;background-color:transparent}.selectize-input{word-break:break-word}.selectize-dropdown .option{word-break:break-word}.hover-dropdown{position:relative;display:inline-flex;align-items:center;justify-content:center}.hover-dropdown-content{display:none;position:absolute;right:0;top:100%;background-color:#fff;font-size:0.95em;border:1px solid rgba(0,0,0,0.175);border-radius:0.375rem;z-index:1}.hover-dropdown-content .custom-item{color:black;padding:12px 16px;text-decoration:none;display:block}.hover-dropdown:hover .hover-dropdown-content{display:block}.hover-dropdown-button{font-size:25px;color:#3181DE}body{height:100%;margin:0;font-family:"Lato, sans-serif";background-color:#fff;color:#0e1b2e} + +================ +File: scss/elements/_buttons.scss +================ +@import "../theme/colors"; + +html { + .btn-success, .btn-primary, .btn-info, .btn-warning, .btn-danger, .btn-dark, .btn-secondary { + color: map-get($colors, white); + } + + .btn-outline-primary { + &:hover { + color: map-get($colors, white); + } + } + + .btn-outline-primary-hover { + background-color: transparent; + border-color: map-get($colors, light-grey); + color: map-get($colors, light-grey); + + &:hover { + border-color: map-get($colors, mid-blue); + color: map-get($colors, mid-blue); + background-color: transparent; + } + } + + .btn-outline-info-hover { + background-color: transparent; + border-color: $light-grey; + color: $light-grey; + + &:hover { + border-color: $light-blue; + color: $light-blue; + background-color: transparent; + } + } + + .btn-outline-danger-hover { + background-color: transparent; + border-color: $light-grey; + color: $light-grey; + + &:hover { + border-color: $danger; + color: $danger; + background-color: transparent; + } + } + + .btn-outline-warning-hover { + background-color: transparent; + border-color: $light-grey; + color: $light-grey; + + &:hover { + border-color: $warning; + color: $warning; + background-color: transparent; + } + } + + .btn-outline-dark-hover { + background-color: transparent; + border-color: $light-grey; + color: $light-grey; + + &:hover { + border-color: $black; + color: $black; + background-color: transparent; + } + } + + .btn-outline-success-hover { + background-color: transparent; + border-color: $light-grey; + color: $light-grey; + + &:hover { + border-color: $dark-green; + color: $dark-green; + background-color: transparent; + } + } + +} + +================ +File: scss/elements/_selectize.scss +================ +// File: _selectize.scss + +.selectize-input { + word-break: break-word; +} + +.selectize-dropdown .option { + word-break: break-word; +} + +================ +File: scss/elements/_tables.scss +================ +/* _table.scss */ + +.table { + width: 100%; + margin-bottom: 1rem; + color: $mid-grey; + border-collapse: collapse; + border-spacing: 0; + border: 1px solid $light-grey; + background-color: $white; +} + +.table th, .table td { + padding: 0.75rem; + vertical-align: top; + border-top: 1px solid $light-grey; +} + +================ +File: scss/index.scss +================ +// Import utilities +@import "utility/utils"; +@import "utility/settings"; +@import "utility/hover"; +@import "utility/gmaps"; + +// Import theme +@import "theme/colors"; +@import "theme/company"; +@import "theme/logos"; +@import "theme/social"; +@import "theme/typography"; + +// Import layout +@import "layout/footer"; +@import "layout/navbar"; +@import "layout/page"; +@import "layout/sidebar"; +@import "layout/tabs"; + +// Import elements +@import "elements/buttons"; +@import "elements/cards"; +@import "elements/selectize"; +@import "elements/tables"; + +// Main Styles +html { + font-size: 16px; + + @media (max-width: 768px) { + font-size: 14px; + } +} + +body { + height: 100%; + margin: 0; + font-family: $font-body; + background-color: map-get($colors, white); + color: map-get($colors, color-dark); +} + +================ +File: scss/layout/_footer.scss +================ +/* footer.scss */ + +@import "../theme/colors"; +@import "../layout/spacing"; + +.footer { + background-color: $footer-bg; + padding: $padding-large; +} + +.footer-img { + vertical-align: middle; + margin-left: $margin-small; + height: $height-small; +} + +.footer a { + color: $footer-link; + text-decoration: none; + + &:hover { + color: $footer-link-hover; + text-decoration: underline; + } +} + +================ +File: scss/layout/_navbar.scss +================ +@import "../theme/colors"; + +.navbar { + border-bottom: 2px solid map-get($colors, brand-blue); +} + +.navbar > .dropdown-toggle::after { + font-family: "Font Awesome 5 Free"; + font-weight: 900; + content: "\f078"; + border-top: none; + vertical-align: 0; +} + +.dropdown-menu.show { + left: -7rem; + background-color: map-get($colors, white); +} + +.nav-tabs .nav-link { + color: map-get($colors, mid-grey); + + &.active { + color: map-get($colors, black); + border-bottom: 1px solid map-get($colors, black); + } +} + +================ +File: scss/layout/_page.scss +================ +// Full Page (Big) +.big-full-page { + min-height: 100vh; +} + +================ +File: scss/layout/_sidebar.scss +================ +@import "../theme/colors"; +@import "spacing"; + +#sidebar-container { + min-height: 92vh; + width: 12rem; + padding: 0; + border-right: 1px solid map-get($colors, light-grey); + background-color: map-get($colors, pale-blue); + position: relative; +} + +.sidebar-expanded { + min-width: 12rem; +} + +.sidebar-collapsed { + width: 3rem; + max-width: 3rem; +} + +.active-sidebar { + border-left: .3rem solid map-get($colors, warning) !important; +} + +================ +File: scss/layout/_spacing.scss +================ +/* Spacing */ + +// Padding +$padding-small: 0.3125rem; // 5px +$padding-medium: 0.625rem; // 10px +$padding-large: 1.25rem; // 20px + +// Margin +$margin-small: 0.3125rem; // 5px +$margin-medium: 0.625rem; // 10px +$margin-large: 1.25rem; // 20px + +// Heights +$height-small: 1.25rem; // 20px +$height-medium: 2.5rem; // 40px + +================ +File: scss/layout/_tabs.scss +================ +/* _tabs.scss */ + +html { + .nav-tabs { + + border: 0; + + .nav-link { + border: 0; + color: $mid-grey; + + &.active { + border-bottom: 1px solid black; + color: $black; + } + } + + } + + .big-tabs { + line-height: 1.1em; + } +} + +================ +File: scss/README.md +================ +# Styles (SASS/SCSS) + +> [!NOTE] +> This folder contains the styles for the application. +> The styles are written in SASS/SCSS and are compiled to CSS. +> The compiled CSS is then included in the application. + +## Structure + +- **index.scss**: ([index.scss](./index.scss)) - This file is the entry point for the styles. It imports all other style files and compiles them into a single CSS file. This file should not contain any styles but should only import other style files. + +- **Elements**: ([elements/](./elements/)) - This folder contains reusable UI elements or small components that are often used in multiple places across the app (e.g., buttons, tables, cards). These elements do not define the layout but are self-contained elements styled independently. + +- **Layout**: ([layout/](./layout/)) - This folder groups styles related to the structural components of the app, such as the footer, navbar, and sidebar. These styles influence the app's primary structure and page layout, often containing nested elements. + +- **Theme**: ([theme/](./theme/)) - This folder defines all theming aspects, with files for colors, typography, company-specific branding, logos, and social icons. By centralizing theme-related files here, you create a clear and cohesive styling foundation that can be easily adapted to different branding requirements. + +- **Utility**: ([utility/](./utility/)) - This folder holds helper styles, mixins, and global settings like maps styling (_gmaps.scss), hover effects, utility classes, and general settings. This folder is ideal for styles that apply globally or offer helpers to other style files. + +## Importing in `index.scss` + +To compile everything, you can import these in index.scss in a structured order. + +A good order for imports would be: + +- **Utilities**: Importing utilities first is logical since variables, mixins, and helper styles are often referenced throughout other styles. +- **Theme**: Import theme variables, typography, and color settings next, since these are foundational and might be used across elements and layout styles. +- **Layout**: Import layout components next to establish the main structure of the app. +- **Elements**: Finally, import elements to complete the styling of reusable UI components. + +```scss +// Import utilities +@import "utility/utils"; +@import "utility/settings"; +@import "utility/hover"; +@import "utility/gmaps"; + +// Import theme +@import "theme/colors"; +@import "theme/company"; +@import "theme/logos"; +@import "theme/social"; +@import "theme/typography"; + +// Import layout +@import "layout/footer"; +@import "layout/navbar"; +@import "layout/page"; +@import "layout/sidebar"; +@import "layout/tabs"; + +// Import elements +@import "elements/buttons"; +@import "elements/cards"; +@import "elements/selectize"; +@import "elements/tables"; +``` + +## Structure Benefits + +- **Consistency**: This setup keeps all files neatly organized and aligned by functionality, making it clear where to add new styles or modify existing ones. + +- **Scalability**: As the project grows, you can easily add new files to each section without disturbing other parts of the app. + +- **Theming and Utilities**: Keeping theming and utilities separate makes updating styles across the app straightforward and consistent, especially if branding requirements change. + +This structure is robust for a scalable Shiny app or any larger project that requires clear, maintainable SCSS organization. + +================ +File: scss/theme/_colors.scss +================ +/* Colors */ + +// Colors +$colors: ( + black: #000000, + white: #ffffff, + light-grey: #D2D2D2, + super-light-grey: #F8F8F8, + mid-grey: #989898, + dark-grey: #686868, + super-dark-grey: #363636, + brand-blue: #004CA7, + pale-blue: #F7FAFD, + mid-blue: #3181DE, + light-blue: #6ABEEA, + dark-green: #86A563, + light-green: #ABD27E, + orange: #E45C00, + light-orange: #FFAE77, + danger: #BF616A, + warning: #E3A45A, + success: #86A563, + info: #3181DE, + primary: #004CA7 +) + +// Footer Colors +$footer-bg: map-get($colors, super-light-grey); +$footer-link: #007bff; +$footer-link-hover: #0056b3; + +================ +File: scss/theme/_company.scss +================ +/* Company Information */ + +$company-id: "id1vzz_tJL"; +$company-name: "GMH Communities"; +$company-domain: "gmhcommunities.com"; +$company-description: "We are GMH communities, a privately owned, real estate company specializing in the acquisition, development, and management of exceptional living communities."; +$company-long-description: "GMH Communities is a privately owned real estate company that specializes in acquiring, developing, and managing exceptional living communities across the United States. With over 35 years of experience, GMH Communities, owned by GMH Associatesâ„¢, has established itself as a leader and innovator in the industry since 1985. Their comprehensive services cover every aspect of the development process, from preliminary concepts to delivery. The dedicated GMH team handles site selection and acquisition, due diligence, entitlements, design coordination, and construction, ensuring a seamless and efficient experience for their clients. GMH Communities has received numerous accolades for their work, including Best Apartment Community, Best New Development, and Top Project of the Year. These awards reflect their commitment to excellence and their ability to create exceptional living spaces that surpass expectations. As a company that values community, GMH Communities strives to connect their communities, residents, and teams. They maintain a strong online presence on platforms like Facebook, LinkedIn, Instagram, and YouTube, allowing people to stay connected and engaged. For exceptional living communities and a partner you can trust, GMH Communities is the ideal choice. Contact them today to explore their offerings and take the first step towards your dream home."; + +================ +File: scss/theme/_logos.scss +================ +$logo-dark-icon: "https://asset.brandfetch.io/id1vzz_tJL/id7byIk3db.png"; +$logo-dark-image-png: "https://asset.brandfetch.io/id1vzz_tJL/idOtgm52ui.png"; +$logo-dark-image-svg: "https://asset.brandfetch.io/id1vzz_tJL/idP4I1L9jI.svg"; + +.logo { + background-image: url($logo-dark-image-svg); +} + +================ +File: scss/theme/_social.scss +================ +/* Social */ + +$social-youtube: "https://youtube.com/channel/UCEtH3DGx8aexiXLgOi2Kyqg"; +$social-instagram: "https://instagram.com/gmhcommunities"; +$social-linkedin: "https://linkedin.com/company/gmhcommunities"; +$social-facebook: "https://facebook.com/gmhcommunities"; + +================ +File: scss/theme/_typography.scss +================ +$font-title: "Raleway, sans-serif"; +$font-body: "Lato, sans-serif"; + +h1, h2 { + font-family: $font-title; +} + +================ +File: scss/utility/_gmaps.scss +================ +/* https://github.com/googlemaps/extended-component-library/blob/main/src/store_locator/README.md */ + +@import "./_fonts.scss"; + +$gmpx-color-surface: #f6f5ff; +$gmpx-color-on-primary: #f8e8ff; +$gmpx-color-on-surface: #212121; +$gmpx-color-on-surface-variant: #636268; +$gmpx-color-primary: #8a5cf4; +$gmpx-color-outline: #e0e0e0; +$gmpx-fixed-panel-width-row-layout: 28.5em; +$gmpx-fixed-panel-height-column-layout: 65%; +$gmpx-font-family-base: $font-body; +$gmpx-font-family-headings: $font-title; +$gmpx-font-size-base: 0.875rem; +$gmpx-hours-color-open: #188038; +$gmpx-hours-color-closed: #d50000; +$gmpx-rating-color: #ffb300; +$gmpx-rating-color-empty: #e0e0e0; + +gmpx-store-locator { + width: 100%; + height: 100%; + + --gmpx-color-surface: $gmpx-color-surface; + --gmpx-color-on-surface: $gmpx-color-on-surface; + --gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant; + --gmpx-color-primary: $gmpx-color-primary; + --gmpx-color-outline: $gmpx-color-outline; + --gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout; + --gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout; + --gmpx-font-family-base: $gmpx-font-family-base; + --gmpx-font-family-headings: $gmpx-font-family-headings; + --gmpx-font-size-base: $gmpx-font-size-base; + --gmpx-hours-color-open: $gmpx-hours-color-open; + --gmpx-hours-color-closed: $gmpx-hours-color-closed; + --gmpx-rating-color: $gmpx-rating-color; + --gmpx-rating-color-empty: $gmpx-rating-color-empty; +} + +gmpx-place-picker { + --gmpx-color-surface: #fff; + display: block; + flex-grow: 1; + margin: 1rem; +} + +gmpx-split-layout { + flex: 1 auto; + overflow: auto; +} + +#close-button { + display: block; + margin: 1rem; +} + +html, body { + --gmpx-color-surface: $gmpx-color-on-surface; + --gmpx-color-on-primary: $gmpx-color-on-primary; + --gmpx-color-on-surface: $gmpx-color-on-surface; + --gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant; + --gmpx-color-primary: $gmpx-color-primary; + --gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout; + --gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout; + background: var(--gmpx-color-surface); + display: flex; + flex-direction: column; + height: 100%; + margin: 0; +} + +================ +File: scss/utility/_hover.scss +================ +.hover-dropdown { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.hover-dropdown-content { + display: none; + position: absolute; + right: 0; + top: 100%; + background-color: map-get($colors, white); + font-size: 0.95em; + border: 1px solid rgba(0, 0, 0, 0.175); + border-radius: 0.375rem; + z-index: 1; +} + +.hover-dropdown-content .custom-item { + color: map-get($colors, black); + padding: 12px 16px; + display: block; +} + +.hover-dropdown:hover .hover-dropdown-content { + display: block; +} + +================ +File: scss/utility/_settings.scss +================ +@import "../theme/colors"; +@import "../layout/spacing"; + +#settings-container { + min-height: 92vh; + width: 12rem; + padding: 0; + border-left: 1px solid map-get($colors, light-grey); + background-color: map-get($colors, pale-blue); +} + +.settings-expanded { + min-width: 12rem; + padding-left: 3px; +} + +.settings-collapsed { + width: 3rem; + max-width: 3rem; +} + +================ +File: scss/utility/_utils.scss +================ +// _utils.scss + +html { + .cursor-pointer { + cursor: pointer; + } + + .bg-light-grey { + background-color: $light-grey; + } + + .bg-brand-blue { + background-color: $brand-blue; + } + + .bg-pale-blue { + background-color: $pale-blue; + } + + .bg-mid-blue { + background-color: $mid-blue; + } + + .bg-light-blue { + background-color: $light-blue; + } + + .bg-dark-green { + background-color: $dark-green; + } + + .bg-light-green { + background-color: $light-green; + } + + .bg-orange { + background-color: $orange; + } + + .bg-light-orange { + background-color: $light-orange; + } + + .text-light-grey { + color: $light-grey; + } + + .text-mid-grey { + color: $mid-grey; + } + + .text-mid-blue { + color: $mid-blue !important; + } + + hr { + background-color: $mid-grey; + } + + .w-8 { + width: 8rem; + } + + h4 { + font-weight: 600; + font-size: 1.2em; + } +} diff --git a/inst/www/styles/scss/README.md b/inst/www/styles/scss/README.md new file mode 100644 index 0000000..78e8a33 --- /dev/null +++ b/inst/www/styles/scss/README.md @@ -0,0 +1,67 @@ +# Styles (SASS/SCSS) + +> [!NOTE] +> This folder contains the styles for the application. +> The styles are written in SASS/SCSS and are compiled to CSS. +> The compiled CSS is then included in the application. + +## Structure + +- **index.scss**: ([index.scss](./index.scss)) - This file is the entry point for the styles. It imports all other style files and compiles them into a single CSS file. This file should not contain any styles but should only import other style files. + +- **Elements**: ([elements/](./elements/)) - This folder contains reusable UI elements or small components that are often used in multiple places across the app (e.g., buttons, tables, cards). These elements do not define the layout but are self-contained elements styled independently. + +- **Layout**: ([layout/](./layout/)) - This folder groups styles related to the structural components of the app, such as the footer, navbar, and sidebar. These styles influence the app's primary structure and page layout, often containing nested elements. + +- **Theme**: ([theme/](./theme/)) - This folder defines all theming aspects, with files for colors, typography, company-specific branding, logos, and social icons. By centralizing theme-related files here, you create a clear and cohesive styling foundation that can be easily adapted to different branding requirements. + +- **Utility**: ([utility/](./utility/)) - This folder holds helper styles, mixins, and global settings like maps styling (_gmaps.scss), hover effects, utility classes, and general settings. This folder is ideal for styles that apply globally or offer helpers to other style files. + +## Importing in `index.scss` + +To compile everything, you can import these in index.scss in a structured order. + +A good order for imports would be: + +- **Utilities**: Importing utilities first is logical since variables, mixins, and helper styles are often referenced throughout other styles. +- **Theme**: Import theme variables, typography, and color settings next, since these are foundational and might be used across elements and layout styles. +- **Layout**: Import layout components next to establish the main structure of the app. +- **Elements**: Finally, import elements to complete the styling of reusable UI components. + +```scss +// Import utilities +@import "utility/utils"; +@import "utility/settings"; +@import "utility/hover"; +@import "utility/gmaps"; + +// Import theme +@import "theme/colors"; +@import "theme/company"; +@import "theme/logos"; +@import "theme/social"; +@import "theme/typography"; + +// Import layout +@import "layout/footer"; +@import "layout/navbar"; +@import "layout/page"; +@import "layout/sidebar"; +@import "layout/tabs"; + +// Import elements +@import "elements/buttons"; +@import "elements/cards"; +@import "elements/selectize"; +@import "elements/tables"; +``` + +## Structure Benefits + +- **Consistency**: This setup keeps all files neatly organized and aligned by functionality, making it clear where to add new styles or modify existing ones. + +- **Scalability**: As the project grows, you can easily add new files to each section without disturbing other parts of the app. + +- **Theming and Utilities**: Keeping theming and utilities separate makes updating styles across the app straightforward and consistent, especially if branding requirements change. + +This structure is robust for a scalable Shiny app or any larger project that requires clear, maintainable SCSS organization. diff --git a/inst/www/styles/scss/elements/_buttons.scss b/inst/www/styles/scss/elements/_buttons.scss new file mode 100644 index 0000000..c215c4f --- /dev/null +++ b/inst/www/styles/scss/elements/_buttons.scss @@ -0,0 +1,106 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Base Button Styles +.button { + padding: get-padding(small) get-padding(medium); + border-radius: 0.25rem; + font-weight: 600; + text-align: center; + text-decoration: none; + transition: background-color 0.3s ease, color 0.3s ease; +} + +// Solid Buttons +.btn-primary { + background-color: get-color(primary); + color: get-color(white); + border: 1px solid get-color(primary); + + &:hover { + background-color: darken(get-color(primary), 10%); + border-color: darken(get-color(primary), 10%); + } +} + +.btn-success { + background-color: get-color(success); + color: get-color(white); + border: 1px solid get-color(success); + + &:hover { + background-color: darken(get-color(success), 10%); + border-color: darken(get-color(success), 10%); + } +} + +.btn-warning { + background-color: get-color(warning); + color: get-color(white); + border: 1px solid get-color(warning); + + &:hover { + background-color: darken(get-color(warning), 10%); + border-color: darken(get-color(warning), 10%); + } +} + +// Outline Buttons +.btn-outline-primary { + background-color: transparent; + color: get-color(primary); + border: 1px solid get-color(primary); + + &:hover { + background-color: get-color(primary); + color: get-color(white); + } +} + +.btn-outline-success { + background-color: transparent; + color: get-color(success); + border: 1px solid get-color(success); + + &:hover { + background-color: get-color(success); + color: get-color(white); + } +} + +.btn-outline-warning { + background-color: transparent; + color: get-color(warning); + border: 1px solid get-color(warning); + + &:hover { + background-color: get-color(warning); + color: get-color(white); + } +} + +// Small Buttons +.btn-small { + padding: get-padding(small) get-padding(small); + font-size: 0.85em; +} + +// Large Buttons +.btn-large { + padding: get-padding(medium) get-padding(large); + font-size: 1.1em; +} + +// Disabled Button State +.btn-disabled { + background-color: get-color(light-grey); + color: get-color(mid-grey); + border: 1px solid get-color(light-grey); + cursor: not-allowed; + opacity: 0.6; + + &:hover { + background-color: get-color(light-grey); + color: get-color(mid-grey); + } +} diff --git a/inst/www/styles/scss/elements/_cards.scss b/inst/www/styles/scss/elements/_cards.scss new file mode 100644 index 0000000..e69de29 diff --git a/inst/www/styles/scss/elements/_selectize.scss b/inst/www/styles/scss/elements/_selectize.scss new file mode 100644 index 0000000..ec7b00f --- /dev/null +++ b/inst/www/styles/scss/elements/_selectize.scss @@ -0,0 +1,9 @@ +// File: _selectize.scss + +.selectize-input { + word-break: break-word; +} + +.selectize-dropdown .option { + word-break: break-word; +} diff --git a/inst/www/styles/scss/elements/_tables.scss b/inst/www/styles/scss/elements/_tables.scss new file mode 100644 index 0000000..3b04c4a --- /dev/null +++ b/inst/www/styles/scss/elements/_tables.scss @@ -0,0 +1,81 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Base Table Style +.table { + width: 100%; + margin-bottom: get-margin(medium); + color: get-color(mid-grey); + border-collapse: collapse; + background-color: get-color(white); + border: 1px solid get-color(light-grey); + font-size: 0.9em; +} + +// Table Head +.table th { + padding: get-padding(small); + text-align: left; + font-weight: bold; + color: get-color(dark-grey); + background-color: get-color(super-light-grey); + border-bottom: 2px solid get-color(light-grey); +} + +// Table Body +.table td { + padding: get-padding(small); + border-top: 1px solid get-color(light-grey); + vertical-align: middle; +} + +// Striped Rows +.table-striped tbody tr:nth-child(odd) { + background-color: get-color(super-light-grey); +} + +// Hover Effect +.table-hover tbody tr:hover { + background-color: get-color(light-blue); + color: get-color(black); +} + +// Bordered Table +.table-bordered td, .table-bordered th { + border: 1px solid get-color(light-grey); +} + +// Condensed Table for Compact Views +.table-condensed td, .table-condensed th { + padding: get-padding(small) get-padding(small); +} + +// Responsive Overflow Wrapper +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + max-width: 100%; + + .table { + width: 100%; + margin-bottom: 0; + } +} + +// DT Datatables +.dataTable th, .dataTable td { + padding: 10px; + border: 1px solid #ddd; + font-size: 14px; + text-align: center; +} + +.dataTable thead { + background-color: #f2f2f2; + font-weight: bold; +} + +.dataTable .highlight { + background-color: #f9f9f9; + color: #333; +} diff --git a/inst/www/styles/scss/index.scss b/inst/www/styles/scss/index.scss new file mode 100644 index 0000000..bb5a68a --- /dev/null +++ b/inst/www/styles/scss/index.scss @@ -0,0 +1,43 @@ +// Import utilities +@import "utility/utils"; +@import "utility/settings"; +@import "utility/hover"; +@import "utility/gmaps"; + +// Import theme +@import "theme/colors"; +@import "theme/company"; +@import "theme/logos"; +@import "theme/social"; +@import "theme/typography"; +@import "theme/spacing"; + +// Import layout +@import "layout/footer"; +@import "layout/navbar"; +@import "layout/page"; +@import "layout/sidebar"; +@import "layout/tabs"; + +// Import elements +@import "elements/buttons"; +@import "elements/cards"; +@import "elements/selectize"; +@import "elements/tables"; + +// Main Styles +html { + font-size: 16px; + + @media (max-width: 768px) { + font-size: 14px; + } +} + +body { + height: 100%; + margin: 0; + font-family: $font-body; + background-color: get-color(white); + color: get-color(color-dark); +} diff --git a/inst/www/styles/scss/layout/_footer.scss b/inst/www/styles/scss/layout/_footer.scss new file mode 100644 index 0000000..0cd5619 --- /dev/null +++ b/inst/www/styles/scss/layout/_footer.scss @@ -0,0 +1,23 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +.footer { + background-color: $footer-bg; + padding: get-padding(large); + + .footer-img { + vertical-align: middle; + margin-left: get-margin(small); + height: get-height(small); + } + + a { + color: $footer-link; + text-decoration: none; + + &:hover { + color: $footer-link-hover; + text-decoration: underline; + } + } +} diff --git a/inst/www/styles/scss/layout/_navbar.scss b/inst/www/styles/scss/layout/_navbar.scss new file mode 100644 index 0000000..356ce24 --- /dev/null +++ b/inst/www/styles/scss/layout/_navbar.scss @@ -0,0 +1,27 @@ +@import "../theme/colors"; + +.navbar { + border-bottom: 2px solid get-color(brand-blue); + + .dropdown-toggle::after { + font-family: "Font Awesome 5 Free"; + font-weight: 900; + content: "\f078"; + border-top: none; + vertical-align: 0; + } + + .dropdown-menu.show { + left: -7rem; + background-color: get-color(white); + } + + .nav-tabs .nav-link { + color: get-color(mid-grey); + + &.active { + color: get-color(black); + border-bottom: 1px solid get-color(black); + } + } +} diff --git a/inst/www/styles/scss/layout/_page.scss b/inst/www/styles/scss/layout/_page.scss new file mode 100644 index 0000000..930766c --- /dev/null +++ b/inst/www/styles/scss/layout/_page.scss @@ -0,0 +1,49 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Full-page layout style +.big-full-page { + min-height: 100vh; + padding: get-padding(medium); + background-color: get-color(super-light-grey); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +// Container styles +.page-container { + width: 100%; + max-width: 1200px; + padding: get-padding(large); + margin: auto; + background-color: get-color(white); + box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); + border-radius: 0.5rem; + + @media (max-width: 768px) { + padding: get-padding(medium); + } +} + +// Title styling for pages +.page-title { + font-size: 2em; + font-weight: bold; + color: get-color(color-dark); + margin-bottom: get-margin(medium); + text-align: center; +} + +// Content section style +.page-content { + flex-grow: 1; + padding: get-padding(medium); + color: get-color(mid-grey); + + // Responsive adjustment for smaller screens + @media (max-width: 768px) { + padding: get-padding(small); + } +} diff --git a/inst/www/styles/scss/layout/_sidebar.scss b/inst/www/styles/scss/layout/_sidebar.scss new file mode 100644 index 0000000..264ba98 --- /dev/null +++ b/inst/www/styles/scss/layout/_sidebar.scss @@ -0,0 +1,95 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Sidebar Container +#sidebar-container { + min-height: 100vh; + width: 12rem; + padding: 0; + border-right: 1px solid get-color(light-grey); + background-color: get-color(pale-blue); + position: fixed; + top: 0; + left: 0; + display: flex; + flex-direction: column; + align-items: start; + transition: width 0.3s ease; + + &.sidebar-expanded { + width: 12rem; + } + + &.sidebar-collapsed { + width: 3rem; + .sidebar-menu-item, + .sidebar-label { + text-align: center; + } + } +} + +// Sidebar Header (optional, for branding/logo) +.sidebar-header { + padding: get-padding(medium); + font-size: 1.5em; + font-weight: bold; + color: get-color(color-dark); + text-align: center; +} + +// Sidebar Menu +.sidebar-menu { + flex-grow: 1; + width: 100%; + padding: get-padding(small) 0; + display: flex; + flex-direction: column; + + .sidebar-menu-item { + padding: get-padding(small) get-padding(medium); + color: get-color(mid-grey); + text-decoration: none; + border-left: 3px solid transparent; + transition: background-color 0.2s ease, border-color 0.2s ease; + + &:hover { + background-color: get-color(light-grey); + color: get-color(brand-blue); + } + + &.active-sidebar { + border-left: 3px solid get-color(warning); + background-color: get-color(super-light-grey); + color: get-color(black); + } + } +} + +// Sidebar Footer (optional, for links or logout) +.sidebar-footer { + padding: get-padding(medium); + width: 100%; + text-align: center; + color: get-color(mid-grey); + border-top: 1px solid get-color(light-grey); +} + +// Responsive adjustments +@media (max-width: 768px) { + #sidebar-container { + width: 100%; + height: auto; + flex-direction: row; + position: relative; + border-right: none; + border-bottom: 1px solid get-color(light-grey); + } + + .sidebar-menu-item { + padding: get-padding(small); + flex-grow: 1; + text-align: center; + border-left: none; + } +} diff --git a/inst/www/styles/scss/layout/_tabs.scss b/inst/www/styles/scss/layout/_tabs.scss new file mode 100644 index 0000000..d5d3fbc --- /dev/null +++ b/inst/www/styles/scss/layout/_tabs.scss @@ -0,0 +1,46 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Tabs layout styles +.nav-tabs { + border: 0; + + .nav-link { + border: 0; + color: get-color(mid-grey); + padding: get-padding(small); + + &.active { + border-bottom: 2px solid get-color(black); + color: get-color(black); + } + + &:hover { + color: get-color(brand-blue); + text-decoration: none; + } + } +} + +// For larger tabs +.big-tabs { + line-height: 1.1em; + padding: get-padding(medium); + + .nav-link { + padding: get-padding(medium); + font-size: 1.1em; + + &.active { + border-bottom: 2px solid get-color(brand-blue); + } + } +} + +// Responsive adjustments +@media (max-width: 768px) { + .nav-tabs .nav-link { + font-size: 0.9em; + padding: get-padding(small); + } +} diff --git a/inst/www/styles/scss/theme/_colors.scss b/inst/www/styles/scss/theme/_colors.scss new file mode 100644 index 0000000..c7092e5 --- /dev/null +++ b/inst/www/styles/scss/theme/_colors.scss @@ -0,0 +1,35 @@ +// _colors.scss + +// Centralized Colors Map +$colors: ( + black: #000000, + white: #ffffff, + light-grey: #D2D2D2, + super-light-grey: #F8F8F8, + mid-grey: #989898, + dark-grey: #686868, + super-dark-grey: #363636, + brand-blue: #004CA7, + pale-blue: #F7FAFD, + mid-blue: #3181DE, + light-blue: #6ABEEA, + dark-green: #86A563, + light-green: #ABD27E, + orange: #E45C00, + light-orange: #FFAE77, + danger: #BF616A, + warning: #E3A45A, + success: #86A563, + info: #3181DE, + primary: #004CA7 +); + +// Helper functions to retrieve color values +@function get-color($key) { + @return map-get($colors, $key); +} + +// Footer-Specific Colors +$footer-bg: get-color(super-light-grey); +$footer-link: get-color(brand-blue); +$footer-link-hover: #0056b3; diff --git a/inst/www/styles/scss/theme/_company.scss b/inst/www/styles/scss/theme/_company.scss new file mode 100644 index 0000000..3f3577b --- /dev/null +++ b/inst/www/styles/scss/theme/_company.scss @@ -0,0 +1,7 @@ +/* Company Information */ + +$company-id: "id1vzz_tJL"; +$company-name: "GMH Communities"; +$company-domain: "gmhcommunities.com"; +$company-description: "We are GMH communities, a privately owned, real estate company specializing in the acquisition, development, and management of exceptional living communities."; +$company-long-description: "GMH Communities is a privately owned real estate company that specializes in acquiring, developing, and managing exceptional living communities across the United States. With over 35 years of experience, GMH Communities, owned by GMH Associatesâ„¢, has established itself as a leader and innovator in the industry since 1985. Their comprehensive services cover every aspect of the development process, from preliminary concepts to delivery. The dedicated GMH team handles site selection and acquisition, due diligence, entitlements, design coordination, and construction, ensuring a seamless and efficient experience for their clients. GMH Communities has received numerous accolades for their work, including Best Apartment Community, Best New Development, and Top Project of the Year. These awards reflect their commitment to excellence and their ability to create exceptional living spaces that surpass expectations. As a company that values community, GMH Communities strives to connect their communities, residents, and teams. They maintain a strong online presence on platforms like Facebook, LinkedIn, Instagram, and YouTube, allowing people to stay connected and engaged. For exceptional living communities and a partner you can trust, GMH Communities is the ideal choice. Contact them today to explore their offerings and take the first step towards your dream home."; diff --git a/inst/www/styles/scss/theme/_logos.scss b/inst/www/styles/scss/theme/_logos.scss new file mode 100644 index 0000000..b64afcc --- /dev/null +++ b/inst/www/styles/scss/theme/_logos.scss @@ -0,0 +1,7 @@ +$logo-dark-icon: "https://asset.brandfetch.io/id1vzz_tJL/id7byIk3db.png"; +$logo-dark-image-png: "https://asset.brandfetch.io/id1vzz_tJL/idOtgm52ui.png"; +$logo-dark-image-svg: "https://asset.brandfetch.io/id1vzz_tJL/idP4I1L9jI.svg"; + +.logo { + background-image: url($logo-dark-image-svg); +} diff --git a/inst/www/styles/scss/theme/_social.scss b/inst/www/styles/scss/theme/_social.scss new file mode 100644 index 0000000..059a725 --- /dev/null +++ b/inst/www/styles/scss/theme/_social.scss @@ -0,0 +1,6 @@ +/* Social */ + +$social-youtube: "https://youtube.com/channel/UCEtH3DGx8aexiXLgOi2Kyqg"; +$social-instagram: "https://instagram.com/gmhcommunities"; +$social-linkedin: "https://linkedin.com/company/gmhcommunities"; +$social-facebook: "https://facebook.com/gmhcommunities"; diff --git a/inst/www/styles/scss/theme/_spacing.scss b/inst/www/styles/scss/theme/_spacing.scss new file mode 100644 index 0000000..5e71029 --- /dev/null +++ b/inst/www/styles/scss/theme/_spacing.scss @@ -0,0 +1,34 @@ +// _spacing.scss + +// Padding +$padding: ( + small: 0.3125rem, + medium: 0.625rem, + large: 1.25rem +); + +// Margin +$margin: ( + small: 0.3125rem, + medium: 0.625rem, + large: 1.25rem +); + +// Heights +$height: ( + small: 1.25rem, + medium: 2.5rem +); + +// Helper functions for spacing +@function get-padding($size) { + @return map-get($padding, $size); +} + +@function get-margin($size) { + @return map-get($margin, $size); +} + +@function get-height($size) { + @return map-get($height, $size); +} diff --git a/inst/www/styles/scss/theme/_typography.scss b/inst/www/styles/scss/theme/_typography.scss new file mode 100644 index 0000000..0ed635f --- /dev/null +++ b/inst/www/styles/scss/theme/_typography.scss @@ -0,0 +1,6 @@ +$font-title: "Raleway, sans-serif"; +$font-body: "Lato, sans-serif"; + +h1, h2 { + font-family: $font-title; +} diff --git a/inst/www/styles/scss/utility/_gmaps.scss b/inst/www/styles/scss/utility/_gmaps.scss new file mode 100644 index 0000000..c4cd44b --- /dev/null +++ b/inst/www/styles/scss/utility/_gmaps.scss @@ -0,0 +1,71 @@ +/* https://github.com/googlemaps/extended-component-library/blob/main/src/store_locator/README.md */ + +@import "./../theme/_typography"; + +$gmpx-color-surface: #f6f5ff; +$gmpx-color-on-primary: #f8e8ff; +$gmpx-color-on-surface: #212121; +$gmpx-color-on-surface-variant: #636268; +$gmpx-color-primary: #8a5cf4; +$gmpx-color-outline: #e0e0e0; +$gmpx-fixed-panel-width-row-layout: 28.5em; +$gmpx-fixed-panel-height-column-layout: 65%; +$gmpx-font-family-base: $font-body; +$gmpx-font-family-headings: $font-title; +$gmpx-font-size-base: 0.875rem; +$gmpx-hours-color-open: #188038; +$gmpx-hours-color-closed: #d50000; +$gmpx-rating-color: #ffb300; +$gmpx-rating-color-empty: #e0e0e0; + +gmpx-store-locator { + width: 100%; + height: 100%; + + --gmpx-color-surface: $gmpx-color-surface; + --gmpx-color-on-surface: $gmpx-color-on-surface; + --gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant; + --gmpx-color-primary: $gmpx-color-primary; + --gmpx-color-outline: $gmpx-color-outline; + --gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout; + --gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout; + --gmpx-font-family-base: $gmpx-font-family-base; + --gmpx-font-family-headings: $gmpx-font-family-headings; + --gmpx-font-size-base: $gmpx-font-size-base; + --gmpx-hours-color-open: $gmpx-hours-color-open; + --gmpx-hours-color-closed: $gmpx-hours-color-closed; + --gmpx-rating-color: $gmpx-rating-color; + --gmpx-rating-color-empty: $gmpx-rating-color-empty; +} + +gmpx-place-picker { + --gmpx-color-surface: #fff; + display: block; + flex-grow: 1; + margin: 1rem; +} + +gmpx-split-layout { + flex: 1 auto; + overflow: auto; +} + +#close-button { + display: block; + margin: 1rem; +} + +html, body { + --gmpx-color-surface: $gmpx-color-on-surface; + --gmpx-color-on-primary: $gmpx-color-on-primary; + --gmpx-color-on-surface: $gmpx-color-on-surface; + --gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant; + --gmpx-color-primary: $gmpx-color-primary; + --gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout; + --gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout; + background: var(--gmpx-color-surface); + display: flex; + flex-direction: column; + height: 100%; + margin: 0; +} diff --git a/inst/www/styles/scss/utility/_hover.scss b/inst/www/styles/scss/utility/_hover.scss new file mode 100644 index 0000000..0b3cb56 --- /dev/null +++ b/inst/www/styles/scss/utility/_hover.scss @@ -0,0 +1,28 @@ +.hover-dropdown { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.hover-dropdown-content { + display: none; + position: absolute; + right: 0; + top: 100%; + background-color: map-get($colors, white); + font-size: 0.95em; + border: 1px solid rgba(0, 0, 0, 0.175); + border-radius: 0.375rem; + z-index: 1; +} + +.hover-dropdown-content .custom-item { + color: map-get($colors, black); + padding: 12px 16px; + display: block; +} + +.hover-dropdown:hover .hover-dropdown-content { + display: block; +} diff --git a/inst/www/styles/scss/utility/_settings.scss b/inst/www/styles/scss/utility/_settings.scss new file mode 100644 index 0000000..51ea57b --- /dev/null +++ b/inst/www/styles/scss/utility/_settings.scss @@ -0,0 +1,71 @@ +@import "../theme/colors"; +@import "../theme/spacing"; + +// Common Breakpoints for Responsiveness +$breakpoints: ( + small: 576px, + medium: 768px, + large: 992px, + xlarge: 1200px +); + +// Helper function for accessing breakpoints +@function breakpoint($size) { + @return map-get($breakpoints, $size); +} + +// Default Layout Settings +$layout: ( + sidebar-width: 12rem, + sidebar-width-collapsed: 3rem, + container-max-width: 1200px, + header-height: 4rem, + footer-height: 3rem +); + +// Function to get layout settings +@function layout($property) { + @return map-get($layout, $property); +} + +// Border and Box Shadow Settings +$border-radius: 0.5rem; +$box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +$border-color-default: get-color(light-grey); + +// Helper for reusable box-shadow +@mixin box-shadow($shadow: $box-shadow) { + box-shadow: $shadow; +} + +// Utility Classes for Border Radius and Shadows +.rounded { + border-radius: $border-radius; +} + +.shadow { + @include box-shadow(); +} + +// Responsive Visibility Utilities +.hidden-small { + @media (max-width: breakpoint(medium)) { + display: none !important; + } +} + +.visible-small { + display: none; + @media (max-width: breakpoint(medium)) { + display: block !important; + } +} + +// Container Padding and Margin for Consistency +.container-padding { + padding: get-padding(medium); +} + +.container-margin { + margin: get-margin(medium); +} diff --git a/inst/www/styles/scss/utility/_utils.scss b/inst/www/styles/scss/utility/_utils.scss new file mode 100644 index 0000000..fc50fa1 --- /dev/null +++ b/inst/www/styles/scss/utility/_utils.scss @@ -0,0 +1,27 @@ +@import "../theme/colors"; + +html { + .cursor-pointer { cursor: pointer; } + + .bg-light-grey { background-color: get-color(light-grey); } + .bg-brand-blue { background-color: get-color(brand-blue); } + .bg-pale-blue { background-color: get-color(pale-blue); } + .bg-mid-blue { background-color: get-color(mid-blue); } + .bg-light-blue { background-color: get-color(light-blue); } + .bg-dark-green { background-color: get-color(dark-green); } + .bg-light-green { background-color: get-color(light-green); } + .bg-orange { background-color: get-color(orange); } + .bg-light-orange { background-color: get-color(light-orange); } + + .text-light-grey { color: get-color(light-grey); } + .text-mid-grey { color: get-color(mid-grey); } + .text-mid-blue { color: get-color(mid-blue) !important; } + + hr { background-color: get-color(mid-grey); } + .w-8 { width: 8rem; } + + h4 { + font-weight: 600; + font-size: 1.2em; + } +} diff --git a/inst/www/styles/styles.min.css b/inst/www/styles/styles.min.css new file mode 100644 index 0000000..d07b649 --- /dev/null +++ b/inst/www/styles/styles.min.css @@ -0,0 +1 @@ +html .cursor-pointer{cursor:pointer}html .bg-light-grey{background-color:#D2D2D2}html .bg-brand-blue{background-color:#004CA7}html .bg-pale-blue{background-color:#F7FAFD}html .bg-mid-blue{background-color:#3181DE}html .bg-light-blue{background-color:#6ABEEA}html .bg-dark-green{background-color:#86A563}html .bg-light-green{background-color:#ABD27E}html .bg-orange{background-color:#E45C00}html .bg-light-orange{background-color:#FFAE77}html .text-light-grey{color:#D2D2D2}html .text-mid-grey{color:#989898}html .text-mid-blue{color:#3181DE !important}html hr{background-color:#989898}html .w-8{width:8rem}html h4{font-weight:600;font-size:1.2em}.rounded{border-radius:.5rem}.shadow{box-shadow:0 4px 8px rgba(0,0,0,0.1)}@media (max-width: 768px){.hidden-small{display:none !important}}.visible-small{display:none}@media (max-width: 768px){.visible-small{display:block !important}}.container-padding{padding:0.625rem}.container-margin{margin:0.625rem}.hover-dropdown{position:relative;display:inline-flex;align-items:center;justify-content:center}.hover-dropdown-content{display:none;position:absolute;right:0;top:100%;background-color:#fff;font-size:0.95em;border:1px solid rgba(0,0,0,0.175);border-radius:0.375rem;z-index:1}.hover-dropdown-content .custom-item{color:#000;padding:12px 16px;display:block}.hover-dropdown:hover .hover-dropdown-content{display:block}h1,h2{font-family:"Raleway, sans-serif"}gmpx-store-locator{width:100%;height:100%;--gmpx-color-surface: $gmpx-color-surface;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-color-outline: $gmpx-color-outline;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-font-family-base: $gmpx-font-family-base;--gmpx-font-family-headings: $gmpx-font-family-headings;--gmpx-font-size-base: $gmpx-font-size-base;--gmpx-hours-color-open: $gmpx-hours-color-open;--gmpx-hours-color-closed: $gmpx-hours-color-closed;--gmpx-rating-color: $gmpx-rating-color;--gmpx-rating-color-empty: $gmpx-rating-color-empty}gmpx-place-picker{--gmpx-color-surface: #fff;display:block;flex-grow:1;margin:1rem}gmpx-split-layout{flex:1 auto;overflow:auto}#close-button{display:block;margin:1rem}html,body{--gmpx-color-surface: $gmpx-color-on-surface;--gmpx-color-on-primary: $gmpx-color-on-primary;--gmpx-color-on-surface: $gmpx-color-on-surface;--gmpx-color-on-surface-variant: $gmpx-color-on-surface-variant;--gmpx-color-primary: $gmpx-color-primary;--gmpx-fixed-panel-height-column-layout: $gmpx-fixed-panel-height-column-layout;--gmpx-fixed-panel-width-row-layout: $gmpx-fixed-panel-width-row-layout;background:var(--gmpx-color-surface);display:flex;flex-direction:column;height:100%;margin:0}.logo{background-image:url("https://asset.brandfetch.io/id1vzz_tJL/idP4I1L9jI.svg")}h1,h2{font-family:"Raleway, sans-serif"}.footer{background-color:#F8F8F8;padding:1.25rem}.footer .footer-img{vertical-align:middle;margin-left:0.3125rem;height:1.25rem}.footer a{color:#004CA7;text-decoration:none}.footer a:hover{color:#0056b3;text-decoration:underline}.navbar{border-bottom:2px solid #004CA7}.navbar .dropdown-toggle::after{font-family:"Font Awesome 5 Free";font-weight:900;content:"\f078";border-top:none;vertical-align:0}.navbar .dropdown-menu.show{left:-7rem;background-color:#fff}.navbar .nav-tabs .nav-link{color:#989898}.navbar .nav-tabs .nav-link.active{color:#000;border-bottom:1px solid #000}.big-full-page{min-height:100vh;padding:0.625rem;background-color:#F8F8F8;display:flex;flex-direction:column;align-items:center;justify-content:center}.page-container{width:100%;max-width:1200px;padding:1.25rem;margin:auto;background-color:#fff;box-shadow:0px 4px 8px rgba(0,0,0,0.1);border-radius:0.5rem}@media (max-width: 768px){.page-container{padding:0.625rem}}.page-title{font-size:2em;font-weight:bold;margin-bottom:0.625rem;text-align:center}.page-content{flex-grow:1;padding:0.625rem;color:#989898}@media (max-width: 768px){.page-content{padding:0.3125rem}}#sidebar-container{min-height:100vh;width:12rem;padding:0;border-right:1px solid #D2D2D2;background-color:#F7FAFD;position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:start;transition:width 0.3s ease}#sidebar-container.sidebar-expanded{width:12rem}#sidebar-container.sidebar-collapsed{width:3rem}#sidebar-container.sidebar-collapsed .sidebar-menu-item,#sidebar-container.sidebar-collapsed .sidebar-label{text-align:center}.sidebar-header{padding:0.625rem;font-size:1.5em;font-weight:bold;text-align:center}.sidebar-menu{flex-grow:1;width:100%;padding:0.3125rem 0;display:flex;flex-direction:column}.sidebar-menu .sidebar-menu-item{padding:0.3125rem 0.625rem;color:#989898;text-decoration:none;border-left:3px solid transparent;transition:background-color 0.2s ease, border-color 0.2s ease}.sidebar-menu .sidebar-menu-item:hover{background-color:#D2D2D2;color:#004CA7}.sidebar-menu .sidebar-menu-item.active-sidebar{border-left:3px solid #E3A45A;background-color:#F8F8F8;color:#000}.sidebar-footer{padding:0.625rem;width:100%;text-align:center;color:#989898;border-top:1px solid #D2D2D2}@media (max-width: 768px){#sidebar-container{width:100%;height:auto;flex-direction:row;position:relative;border-right:none;border-bottom:1px solid #D2D2D2}.sidebar-menu-item{padding:0.3125rem;flex-grow:1;text-align:center;border-left:none}}.nav-tabs{border:0}.nav-tabs .nav-link{border:0;color:#989898;padding:0.3125rem}.nav-tabs .nav-link.active{border-bottom:2px solid #000;color:#000}.nav-tabs .nav-link:hover{color:#004CA7;text-decoration:none}.big-tabs{line-height:1.1em;padding:0.625rem}.big-tabs .nav-link{padding:0.625rem;font-size:1.1em}.big-tabs .nav-link.active{border-bottom:2px solid #004CA7}@media (max-width: 768px){.nav-tabs .nav-link{font-size:0.9em;padding:0.3125rem}}.button{padding:0.3125rem 0.625rem;border-radius:0.25rem;font-weight:600;text-align:center;text-decoration:none;transition:background-color 0.3s ease, color 0.3s ease}.btn-primary{background-color:#004CA7;color:#fff;border:1px solid #004CA7}.btn-primary:hover{background-color:#003574;border-color:#003574}.btn-success{background-color:#86A563;color:#fff;border:1px solid #86A563}.btn-success:hover{background-color:#6c874e;border-color:#6c874e}.btn-warning{background-color:#E3A45A;color:#fff;border:1px solid #E3A45A}.btn-warning:hover{background-color:#dc8c2e;border-color:#dc8c2e}.btn-outline-primary{background-color:transparent;color:#004CA7;border:1px solid #004CA7}.btn-outline-primary:hover{background-color:#004CA7;color:#fff}.btn-outline-success{background-color:transparent;color:#86A563;border:1px solid #86A563}.btn-outline-success:hover{background-color:#86A563;color:#fff}.btn-outline-warning{background-color:transparent;color:#E3A45A;border:1px solid #E3A45A}.btn-outline-warning:hover{background-color:#E3A45A;color:#fff}.btn-small{padding:0.3125rem 0.3125rem;font-size:0.85em}.btn-large{padding:0.625rem 1.25rem;font-size:1.1em}.btn-disabled{background-color:#D2D2D2;color:#989898;border:1px solid #D2D2D2;cursor:not-allowed;opacity:0.6}.btn-disabled:hover{background-color:#D2D2D2;color:#989898}.selectize-input{word-break:break-word}.selectize-dropdown .option{word-break:break-word}.table{width:100%;margin-bottom:0.625rem;color:#989898;border-collapse:collapse;background-color:#fff;border:1px solid #D2D2D2;font-size:0.9em}.table th{padding:0.3125rem;text-align:left;font-weight:bold;color:#686868;background-color:#F8F8F8;border-bottom:2px solid #D2D2D2}.table td{padding:0.3125rem;border-top:1px solid #D2D2D2;vertical-align:middle}.table-striped tbody tr:nth-child(odd){background-color:#F8F8F8}.table-hover tbody tr:hover{background-color:#6ABEEA;color:#000}.table-bordered td,.table-bordered th{border:1px solid #D2D2D2}.table-condensed td,.table-condensed th{padding:0.3125rem 0.3125rem}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}.table-responsive .table{width:100%;margin-bottom:0}html{font-size:16px}@media (max-width: 768px){html{font-size:14px}}body{height:100%;margin:0;font-family:"Lato, sans-serif";background-color:#fff} diff --git a/man/add_external_resources.Rd b/man/add_external_resources.Rd new file mode 100644 index 0000000..9ccbefe --- /dev/null +++ b/man/add_external_resources.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/assets.R +\name{add_external_resources} +\alias{add_external_resources} +\title{Add External Resources} +\usage{ +add_external_resources() +} +\description{ +Add external resources to the shiny app. + +This function performs the following: +\itemize{ +\item Adds this package's installed \code{www} folder to the shiny app resource paths +via \code{\link[shiny:resourcePaths]{shiny::addResourcePath()}}. +} +} diff --git a/man/compile_styles.Rd b/man/compile_styles.Rd new file mode 100644 index 0000000..b72be4d --- /dev/null +++ b/man/compile_styles.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/assets.R +\name{compile_styles} +\alias{compile_styles} +\title{Compile Styles} +\usage{ +compile_styles( + path = pkg_sys("www", "styles"), + source_map = TRUE, + cache = FALSE +) +} +\arguments{ +\item{path}{The path to the \code{styles} folder. Default is \code{pkg_sys("www", "styles")}. +This folder must contain a \code{scss} folder with a \code{index.scss} file.} +} +\value{ +The path to the compiled CSS file. +} +\description{ +Compile SASS files to CSS. +} +\examples{ +compile_styles() + +} diff --git a/man/entrata_req_auth.Rd b/man/entrata_req_auth.Rd new file mode 100644 index 0000000..4011e4d --- /dev/null +++ b/man/entrata_req_auth.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_auth} +\alias{entrata_req_auth} +\title{Set Basic Authentication for Entrata Request} +\usage{ +entrata_req_auth(req, username = NULL, password = NULL) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{username}{Username for authentication} + +\item{password}{Password for authentication} +} +\value{ +The modified request object with authentication headers. +} +\description{ +Adds basic authentication (username and password) to the Entrata request. +} diff --git a/man/entrata_req_body.Rd b/man/entrata_req_body.Rd new file mode 100644 index 0000000..9f7a2e4 --- /dev/null +++ b/man/entrata_req_body.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_body} +\alias{entrata_req_body} +\title{Set Request Body for Entrata API Request} +\usage{ +entrata_req_body( + req, + id = NULL, + method = NULL, + version = "r1", + params = list() +) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{id}{Request ID} + +\item{method}{The endpoint method name} + +\item{version}{The endpoint method version} + +\item{params}{List of parameters for the method} +} +\value{ +Modified request object with the configured body +} +\description{ +Configures the request body with specific values for the request. +} diff --git a/man/entrata_req_endpoint.Rd b/man/entrata_req_endpoint.Rd new file mode 100644 index 0000000..e04cfdd --- /dev/null +++ b/man/entrata_req_endpoint.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_endpoint} +\alias{entrata_req_endpoint} +\title{Set Endpoint Path for Entrata Request} +\usage{ +entrata_req_endpoint(req, endpoint) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{endpoint}{The API endpoint to set} +} +\value{ +Modified request object with the endpoint URL path appended +} +\description{ +Appends an endpoint path to the request URL. +} diff --git a/man/entrata_req_error.Rd b/man/entrata_req_error.Rd new file mode 100644 index 0000000..1b53462 --- /dev/null +++ b/man/entrata_req_error.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_error} +\alias{entrata_req_error} +\title{Set Error Handling for Entrata Request} +\usage{ +entrata_req_error( + req, + is_error = entrata_resp_is_error, + error_body = entrata_resp_body +) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{is_error}{Function to check if response contains an error} + +\item{error_body}{Function to parse error body in case of an error} +} +\value{ +Modified request with error handling +} +\description{ +Configures error handling for the request, using custom error functions. +} diff --git a/man/entrata_req_log.Rd b/man/entrata_req_log.Rd new file mode 100644 index 0000000..4b248a0 --- /dev/null +++ b/man/entrata_req_log.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_log} +\alias{entrata_req_log} +\title{Log Entrata Request Details} +\usage{ +entrata_req_log(req, log_path = NULL) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{logger}{Optional logger to use} +} +\value{ +The original request object +} +\description{ +Logs request information according to the configured logger. +} diff --git a/man/entrata_req_perform.Rd b/man/entrata_req_perform.Rd new file mode 100644 index 0000000..47b9ce6 --- /dev/null +++ b/man/entrata_req_perform.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_req_perform} +\alias{entrata_req_perform} +\title{Perform Entrata API Request} +\usage{ +entrata_req_perform( + req, + path = NULL, + verbosity = getOption("entrata.verbosity", NULL), + mock = getOption("entrata.mock", NULL), + log = getOption("entrata.log", NULL), + error_call = rlang::current_env(), + ... +) +} +\arguments{ +\item{req}{An httr2 request object} + +\item{verbosity}{Verbosity level of output} + +\item{mock}{Mock request response if needed} + +\item{error_call}{Call environment for error reporting} + +\item{...}{Additional arguments passed to req_perform} + +\item{cache}{Logical indicating if response should be cached} + +\item{cache_path}{Path to cache the request} + +\item{save}{Logical indicating if request should be saved} + +\item{save_path}{Path to save request data} + +\item{debug}{Logical for debugging request} + +\item{logger}{Logger object} +} +\value{ +The response object +} +\description{ +Executes a prepared Entrata request with custom options. +} diff --git a/man/entrata_request.Rd b/man/entrata_request.Rd new file mode 100644 index 0000000..fee0a9c --- /dev/null +++ b/man/entrata_request.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_request} +\alias{entrata_request} +\title{Entrata HTTP Request} +\usage{ +entrata_request( + endpoint, + body_method = list(name = NULL, version = NULL, params = list(NULL)), + options = list(request_id = getOption("entrata.default_request_id", 15L), user_agent = + getOption("entrata.user_agent", "entrata-r/0.1.0"), verbosity = + getOption("entrata.verbosity", "info"), debug = getOption("entrata.debug", FALSE), + log = getOption("entrata.log", NULL), retry = getOption("entrata.retry", 3L), timeout + = getOption("entrata.timeout", 30L), progress = getOption("entrata.progress", FALSE), + cache = getOption("entrata.cache", FALSE), cache_path = + getOption("entrata.cache_path", ":memory:")), + config = get_entrata_config(), + ... +) +} +\arguments{ +\item{endpoint}{Character string specifying the Entrata API endpoint to +send the HTTP request to. Must be one of the valid \code{\link[=entrata_endpoints]{entrata_endpoints()}}. +If left \code{NULL} will default to the base Entrata API URL: +\verb{https://gmhcommunities.entrata.com/api/v1/}.} + +\item{config}{A list of configuration options for the Entrata API. +This should include the base URL, username, and password and +can also include the user agent, default request ID, retry logic, +rate limit handling, error handling, caching options, logging options, +and more.} + +\item{...}{Additional arguments to pass to the request object.} + +\item{method_name}{Character string specifying the \strong{Entrata} endpoint method +(not the HTTP method) to use for the request. Must be one of the valid +\code{\link[=entrata_methods]{entrata_methods()}} for the provided \code{endpoint} value. If left \code{NULL}, +a default method will be determined based on the \code{endpoint} value.} + +\item{method_version}{Character string specifying the version of the +method to use for the request. Must be one of the valid \code{\link[=entrata_method_versions]{entrata_method_versions()}} +based on the provided \code{method} (and \code{endpoint}) values. If left \code{NULL}, +a default version will be determined based on the \code{method} and \code{endpoint} +values (typically default version is \code{"r1"}).} + +\item{method_params}{List of parameters to include in the request body's +"method" object. This is where the actual API method parameters are +specified. The parameters must be in the correct format for the method +being called. If left \code{NULL}, the method will be called with no parameters.} + +\item{request_id}{An integer or string to use for the request ID. +By default this will first check the global option +\code{entrata.default_request_id} and then fall back to \code{15L}.} +} +\value{ +An httr2 request object with the Entrata API request configuration. +} +\description{ +This function prepares the base HTTP API request object for the +GMH Communities Entrata API. +} +\details{ +This is the primary function for preparing HTTP requests to send to the +GMH Communities Entrata API. This function is used by other functions +that call the API to provide a robust and consistent way to prepare the +request object. + +The function handles authentication, headers, default request options, +validation, caching, logging, rate limits, throttling, retry logic, and +error handling. +} diff --git a/man/entrata_request_modifiers.Rd b/man/entrata_request_modifiers.Rd new file mode 100644 index 0000000..b2c9a60 --- /dev/null +++ b/man/entrata_request_modifiers.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_request.R +\name{entrata_request_modifiers} +\alias{entrata_request_modifiers} +\title{Entrata Request Modifiers} +\description{ +These functions are used to modify the Entrata request object before +sending the request to the API. These functions are used to set the +endpoint path, Entrata internal endpoint method (name, version, and params), +additional headers, authentication, request body, error handling, logging, +and more. +} diff --git a/man/entrata_resp_body_json.Rd b/man/entrata_resp_body_json.Rd new file mode 100644 index 0000000..7c5016a --- /dev/null +++ b/man/entrata_resp_body_json.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_response.R +\name{entrata_resp_body_json} +\alias{entrata_resp_body_json} +\title{Entrata Response Body JSON} +\usage{ +entrata_resp_body_json(resp) +} +\arguments{ +\item{resp}{The Entrata API response object. Must be a valid HTTP response.} +} +\value{ +A list containing the request ID, status code, and result object. +} +\description{ +This function extracts the JSON response body from an Entrata API response. +} +\details{ +This function is used to extract the JSON response body from an Entrata API +response object. The function will check the response object for the expected +structure and return the response body as a list containing the request ID, +status code, and result object. +} diff --git a/man/entrata_resp_status.Rd b/man/entrata_resp_status.Rd new file mode 100644 index 0000000..046f6fb --- /dev/null +++ b/man/entrata_resp_status.Rd @@ -0,0 +1,87 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_response.R +\name{entrata_resp_status} +\alias{entrata_resp_status} +\alias{entrata_resp_status_desc} +\alias{entrata_resp_abort} +\alias{entrata_resp_check_status} +\title{Entrata API Response Status Helpers} +\usage{ +entrata_resp_status(resp) + +entrata_resp_status_desc(resp) + +entrata_resp_abort(resp, req, info = NULL, call = rlang::caller_env()) + +entrata_resp_check_status(resp, info = NULL, error_call = rlang::caller_env()) +} +\arguments{ +\item{resp}{\code{\link[httr2:response]{httr2::response()}} object} + +\item{info}{Additional information to include in the error message.} + +\item{call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} + +\item{error_call}{The calling environment for the error. Defaults to the +caller environment.} +} +\value{ +\itemize{ +\item \code{entrata_resp_status()} - The status code of the response. +\item \code{entrata_resp_status_desc()} - The status description of the response. +\item \code{entrata_resp_is_error()} - Logical value indicating whether the response is an error. +\item \code{entrata_resp_check_status()} - Invisibly returns the response if the status is not an error. +\item \code{entrata_resp_abort()} - Aborts the response if the status is an error. +} +} +\description{ +Helper functions for working with the Entrata API response status codes, +descriptions, and errors. +\itemize{ +\item \code{entrata_resp_status()} retrieves the integer \code{HTTP} status code from an +Entrata API response. +\item \code{entrata_resp_status_desc()} retrieves a brief textual description of the +\code{HTTP} status code from an Entrata API response. +\item \code{entrata_resp_is_error()} determines if the response is an error, i.e. +it returns \code{TRUE} if the status code is greater than or equal to \code{400}. +\item \code{entrata_resp_check_status()} checks the status of an Entrata API response +by turning HTTP/Entrata specific errors into R errors. +\item \code{entrata_resp_abort()} aborts the response if the status is an error. +} + +Note that these functions are mostly for internal use but are exported +for clarity and consistency. +} +\details{ +These functions are used to help with the processing of Entrata API +responses. + +The Entrata API is unique in that all endpoints utilize \code{POST} \code{HTTP} methods +and the API will always return a \code{200} status code, regardless of the success +or failure of the request. + +This makes the usage of the default \code{httr2} functions like \code{\link[httr2:resp_status]{httr2::resp_check_status()}} +or \code{\link[httr2:resp_status]{httr2::resp_is_error()}} useless as they rely on the \code{HTTP} status code to +determine if a request was successful or not. + +To mitigate this, we must inspect the response body to determine if the request +was successful or not. If the response body contains an error message, we can +assume that the request was not successful. +} +\section{Functions}{ + +\itemize{ +\item \code{entrata_resp_status()} - Extract the status code from an Entrata API response. +\item \code{entrata_resp_status_desc()} - Extract the status description from an Entrata API response. +\item \code{entrata_resp_is_error()} - Determine if the response is an error. +\item \code{entrata_resp_check_status()} - Check the status of an Entrata API response. +\item \code{entrata_resp_abort()} - Abort the requested response using the response object. +} +} + +\seealso{ +\code{\link[httr2:resp_status]{httr2::resp_status()}} +} diff --git a/man/get_entrata_config.Rd b/man/get_entrata_config.Rd new file mode 100644 index 0000000..3761360 --- /dev/null +++ b/man/get_entrata_config.Rd @@ -0,0 +1,73 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/config.R +\name{get_entrata_config} +\alias{get_entrata_config} +\title{Get Entrata API Configuration} +\usage{ +get_entrata_config( + key = NULL, + file = Sys.getenv("R_CONFIG_FILE", "config.yml"), + config = Sys.getenv("R_CONFIG_ACTIVE", "default") +) +} +\arguments{ +\item{key}{A character string representing the configuration key to retrieve. +Defaults to \code{NULL} which returns the full \code{entrata} specific configuration +object as a list.} + +\item{file}{Configuration file to read from (defaults to +\code{"config.yml"}). If the file isn't found at the location +specified then parent directories are searched for a file +of the same name.} + +\item{config}{Name of configuration to read from. Defaults to +the value of the \code{R_CONFIG_ACTIVE} environment variable +("default" if the variable does not exist).} +} +\value{ +A list, or vector (if \code{key} is specified), corresponding to the +contents of the \code{entrata} configuration key's values (i.e. \code{base_url}, +\code{username}, and \code{password}). +} +\description{ +This function retrieves the Entrata configuration from the specified configuration +file and returns the configuration as a list. You can optionally specify a key +to retrieve a specific configuration value. +} +\details{ +The Entrata configuration is expected to be stored in a YAML configuration file +under the \code{entrata} key. The configuration file should contain the following +fields: +\itemize{ +\item \code{base_url} - The base URL for the Entrata API. +\item \code{username} - The username to use for authenticating with the Entrata API. +\item \code{password} - The password to use for authenticating with the Entrata API. +} + +For example, in this package's used \code{config.yml} file, there is the following +\code{"entrata"} specific (default) configuration: + +\if{html}{\out{
}}\preformatted{default: + entrata: + base_url: "https://gmhcommunities.entrata.com" + username: "" + password: "" +}\if{html}{\out{
}} +} +\seealso{ +\code{\link[config:get]{config::get()}} - the primary workhorse for retrieving configuration +values from configuration files. + +\code{\link[=validate_entrata_config]{validate_entrata_config()}} - a function that validates the +Entrata configuration to ensure that all required fields are present +and valid. + +Other Configuration: +\code{\link{validate_entrata_config}()} + +Other Entrata: +\code{\link{validate_entrata_config}()}, +\code{\link{validate_entrata_request}()} +} +\concept{Configuration} +\concept{Entrata} diff --git a/man/get_entrata_report_info.Rd b/man/get_entrata_report_info.Rd new file mode 100644 index 0000000..3b8783a --- /dev/null +++ b/man/get_entrata_report_info.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_reports.R +\name{get_entrata_report_info} +\alias{get_entrata_report_info} +\title{Get Entrata Report Info} +\usage{ +get_entrata_report_info(report_name, report_version = "latest") +} +\arguments{ +\item{report_name}{A character string representing the name of the report.} + +\item{report_version}{A character string representing the version of the report. +Defaults to "latest".} +} +\value{ +A list containing report name, description, and filters. +} +\description{ +This function retrieves detailed information for a specified +report from Entrata, including filters and descriptions. +} diff --git a/man/get_entrata_reports_list.Rd b/man/get_entrata_reports_list.Rd new file mode 100644 index 0000000..71a3d12 --- /dev/null +++ b/man/get_entrata_reports_list.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_reports.R +\name{get_entrata_reports_list} +\alias{get_entrata_reports_list} +\title{Get Entrata Reports List} +\usage{ +get_entrata_reports_list(latest_only = TRUE) +} +\arguments{ +\item{latest_only}{Logical, if TRUE (default), returns only the latest version +of each report.} +} +\value{ +A tibble containing report information including report name, ID, +system name, and version. +} +\description{ +This function retrieves a list of reports available in the +Entrata system, optionally filtering to only the latest version of each report. +} diff --git a/man/get_latest_report_version.Rd b/man/get_latest_report_version.Rd new file mode 100644 index 0000000..32d8830 --- /dev/null +++ b/man/get_latest_report_version.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/entrata_reports.R +\name{get_latest_report_version} +\alias{get_latest_report_version} +\title{Get Latest Report Version from Entrata} +\usage{ +get_latest_report_version(report_name) +} +\arguments{ +\item{report_name}{A character string representing the name of the report.} +} +\value{ +A character string representing the latest version of the report. +} +\description{ +This function retrieves the latest version of a specified report from Entrata. +It's useful when you need to ensure you're working with the most up-to-date +version of a particular report. +} +\examples{ +\dontrun{ +# Get the latest version of the "pre_lease" report +latest_version <- get_latest_report_version("pre_lease") +print(latest_version) +} + +} +\seealso{ +\code{\link{get_entrata_reports_list}} for getting a list of all available reports +\code{\link{get_entrata_report_info}} for getting detailed information about a specific report +} diff --git a/man/icon_text.Rd b/man/icon_text.Rd new file mode 100644 index 0000000..d8c30eb --- /dev/null +++ b/man/icon_text.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{icon_text} +\alias{icon_text} +\title{Icon Text} +\usage{ +icon_text(icon, text, .function = shiny::icon) +} +\arguments{ +\item{icon}{The icon to display. This can be a character string or an icon +object.} + +\item{text}{The text to display next to the icon.} + +\item{.function}{The function to use to create the icon. Default is \code{shiny::icon}.} +} +\value{ +A \code{tagList} object containing the icon and text. +} +\description{ +This function is used to create a simple icon and text element. +} +\examples{ +icon_text("user", "User") +icon_text(shiny::icon("user"), "User") + +} diff --git a/man/is_boolean_string.Rd b/man/is_boolean_string.Rd new file mode 100644 index 0000000..b7a13d5 --- /dev/null +++ b/man/is_boolean_string.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/validation.R +\name{is_boolean_string} +\alias{is_boolean_string} +\title{Is Boolean String} +\usage{ +is_boolean_string(str) +} +\arguments{ +\item{str}{Character string to check. Typically, with the Entrata API, "boolean" +values are represented as quoted integers (\code{"0"} or \code{"1"}) representing +\code{FALSE} and \code{TRUE}, respectively.} +} +\value{ +\code{TRUE} if the string is a boolean string, \code{FALSE} otherwise. +} +\description{ +Checks if provided string represents a boolean (used by Entrata API). +} +\examples{ +is_boolean_string("0") +} diff --git a/man/is_integer_string.Rd b/man/is_integer_string.Rd new file mode 100644 index 0000000..8503324 --- /dev/null +++ b/man/is_integer_string.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/validation.R +\name{is_integer_string} +\alias{is_integer_string} +\alias{is_integer_string_multi} +\title{Is Integer String} +\usage{ +is_integer_string(str, arg = rlang::caller_arg(str)) + +is_integer_string_multi(str, arg = rlang::caller_arg(str)) +} +\arguments{ +\item{str}{Character string to check. Typically, with the Entrata API, "multiple" +values are represented as comma separated integer strings.} + +\item{arg}{For internal use only, used to capture the name of the argument.} +} +\value{ +\code{TRUE} if the string is parseable to an integer, \code{FALSE} otherwise. +} +\description{ +Validate a string can be parsed into an integer. + +Validate a string with comma separated integers can be parsed into individual integers. +} +\section{Functions}{ +\itemize{ +\item \code{is_integer_string_multi()}: Is Integer String (Multi) + +}} +\examples{ +is_integer_string("1") +[1] TRUE + +is_integer_string("a") +[1] FALSE +is_integer_string_multi("1,2,3") +[1] TRUE +is_integer_string_multi("1,2,3,") +[1] FALSE +is_integer_string_multi("1,2,a,b") +[1] FALSE +} diff --git a/man/mod_footer.Rd b/man/mod_footer.Rd index 0b7f4a5..9457531 100644 --- a/man/mod_footer.Rd +++ b/man/mod_footer.Rd @@ -15,9 +15,9 @@ mod_footer_ui( id = NULL, align = "center", class = "footer", - app_info = .app_info, - client_info = .client_info, - developer_info = .developer_info, + app_info = gmhdatahub::app_info, + client_info = client_info, + developer_info = developer_info, copyright_holder = "No Clocks, LLC", year = format(Sys.Date(), "\%Y"), ... @@ -86,7 +86,7 @@ validate_image(img_path) } } \description{ -A Shiny module for creating the footer of the GMH Leasing Dashboard. +A Shiny module for creating the footer of the GMH Data Hub's Leasing Dashboard. Composed of the \code{ui}, \code{server}, and helper functions: \itemize{ diff --git a/man/mod_home.Rd b/man/mod_home.Rd new file mode 100644 index 0000000..5443991 --- /dev/null +++ b/man/mod_home.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mod_home.R +\name{mod_home} +\alias{mod_home} +\alias{mod_home_ui} +\alias{mod_home_server} +\title{Home (Page) Shiny Module} +\usage{ +mod_home_ui(id, ...) + +mod_home_server(id, filters, data, user) +} +\arguments{ +\item{id}{The module id.} +} +\value{ +\itemize{ +\item \code{mod_home_ui()}: The UI HTML wrapped in a \code{\link[htmltools:tagList]{htmltools::tagList()}}. +\item \code{mod_home_server()}: A shiny server function. +} +} +\description{ +A Shiny module for creating the home page tab of the GMH Data Hub's Leasing +Dashboard. + +This module includes the UI and Server functions: +\itemize{ +\item \code{mod_home_ui()} +\item \code{mod_home_server()} +} +} diff --git a/man/mod_properties.Rd b/man/mod_properties.Rd new file mode 100644 index 0000000..477da06 --- /dev/null +++ b/man/mod_properties.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mod_properties.R +\name{mod_properties} +\alias{mod_properties} +\alias{mod_properties_ui} +\title{Properties Shiny Module} +\usage{ +mod_properties_ui(id, ...) +} +\arguments{ +\item{id}{The module id.} + +\item{...}{Additional parameters.} +} +\value{ +\itemize{ +\item \code{mod_properties_ui()}: Shiny UI. +\item \code{mod_properties_server()}: Shiny Server. +} +} +\description{ +This is the shiny module for the properties page/tab in the shiny app. + +It includes the UI and server functions: +\itemize{ +\item \code{mod_properties_ui()} +\item \code{mod_properties_server()} +} + +The module includes the following children modules for its major functional +areas: +\itemize{ +\item \link{mod_property_tbl} - For listing/displaying all properties. +\item \link{mod_property_map} - For displaying a map of all properties. +\item \link{mod_property_details} - For displaying the details of a single property. +} +} diff --git a/man/pkg_sys.Rd b/man/pkg_sys.Rd new file mode 100644 index 0000000..d355d30 --- /dev/null +++ b/man/pkg_sys.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{pkg_sys} +\alias{pkg_sys} +\alias{pkg_sys_assets} +\alias{pkg_sys_config} +\alias{pkg_sys_templates} +\alias{pkg_sys_examples} +\title{Package System File} +\usage{ +pkg_sys(...) + +pkg_sys_assets(...) + +pkg_sys_config(...) + +pkg_sys_templates(...) + +pkg_sys_examples(...) +} +\arguments{ +\item{...}{A character vector of subdirectories and file name.} +} +\value{ +A character string of the file path. +} +\description{ +This function is a wrapper for the \code{system.file} function. It is used to +retrieve the path to a file within the package directory. +} +\examples{ +pkg_sys("www", "styles", "css", "styles.min.css") +pkg_sys("config", "config.yml") +pkg_sys("extdata") +} diff --git a/man/validate_entrata_config.Rd b/man/validate_entrata_config.Rd new file mode 100644 index 0000000..8c91eba --- /dev/null +++ b/man/validate_entrata_config.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/config.R +\name{validate_entrata_config} +\alias{validate_entrata_config} +\title{Validate Entrata Configuration} +\usage{ +validate_entrata_config( + cfg, + arg = rlang::caller_arg(cfg), + call = rlang::caller_env() +) +} +\arguments{ +\item{cfg}{A list containing the Entrata configuration values or a character +string representing the path to the configuration file.} + +\item{arg}{An argument name as a string. This argument +will be mentioned in error messages as the input that is at the +origin of a problem.} + +\item{call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} +} +\value{ +Will throw an error if the configuration is invalid, otherwise +will invisibly return the validated \code{cfg}. +} +\description{ +This function validates the Entrata configuration to ensure that all +required configuration values are present and that they are of the correct +type. + +If the configuration is invalid, an error will be thrown in the caller +function's caller environment. +} +\details{ +The following validations are performed on the Entrata configuration: +\enumerate{ +\item The Entrata configuration must contain the following keys: +\code{username}, \code{password}, and \code{base_url}. +\item All required keys must not be empty or \code{NULL}. +\item The \code{base_url} key must be a valid \code{entrata.com} domain URL. +} + +To validate the credentials provided in the configuration use the +\code{\link[=entrata_status]{entrata_status()}} function which pings the API to check the status. +} +\seealso{ +\code{\link[=get_entrata_config]{get_entrata_config()}} - a function that retrieves the Entrata +configuration from a configuration file. + +Other Configuration: +\code{\link{get_entrata_config}()} + +Other Validation: +\code{\link{validate_entrata_request}()} + +Other Entrata: +\code{\link{get_entrata_config}()}, +\code{\link{validate_entrata_request}()} +} +\concept{Configuration} +\concept{Entrata} +\concept{Validation} diff --git a/man/validate_entrata_request.Rd b/man/validate_entrata_request.Rd new file mode 100644 index 0000000..c643ff5 --- /dev/null +++ b/man/validate_entrata_request.Rd @@ -0,0 +1,104 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/validation.R +\name{validate_entrata_request} +\alias{validate_entrata_request} +\alias{validate_entrata_request_endpoint} +\alias{validate_entrata_request_endpoint_method} +\alias{validate_entrata_endpoint_method_params} +\alias{validate_entrata_method_version} +\title{Validate Entrata API Request} +\usage{ +validate_entrata_request( + endpoint, + method, + method_params, + method_version = NULL, + arg_endpoint = rlang::caller_arg(endpoint), + arg_method = rlang::caller_arg(method), + arg_method_params = rlang::caller_arg(method_params), + arg_method_version = rlang::caller_arg(method_version), + call = rlang::caller_env() +) + +validate_entrata_request_endpoint( + endpoint, + arg = rlang::caller_arg(endpoint), + call = rlang::caller_env() +) + +validate_entrata_request_endpoint_method( + endpoint, + method, + arg_endpoint = rlang::caller_arg(endpoint), + arg_method = rlang::caller_arg(method), + call = rlang::caller_env() +) + +validate_entrata_endpoint_method_params( + endpoint, + method, + method_params, + arg_endpoint = rlang::caller_arg(endpoint), + arg_method = rlang::caller_arg(method), + arg_method_params = rlang::caller_arg(method_params), + call = rlang::caller_env() +) + +validate_entrata_method_version( + endpoint, + method, + method_version, + arg_endpoint = rlang::caller_arg(endpoint), + arg_method = rlang::caller_arg(method), + arg_method_version = rlang::caller_arg(method_version), + call = rlang::caller_env() +) +} +\arguments{ +\item{endpoint}{The Entrata API endpoint to validate.} + +\item{method}{The method to validate for the provided endpoint.} + +\item{method_params}{A list of parameters to validate for the method.} + +\item{method_version}{The version of the method to validate. Default is \code{NULL}.} + +\item{arg_endpoint, arg_method, arg_method_params, arg_method_version}{Internal +arguments for capturing the caller's argument names.} + +\item{call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} + +\item{arg}{An argument name as a string. This argument +will be mentioned in error messages as the input that is at the +origin of a problem.} +} +\value{ +All validation functions are used for their side effects and have +no return values, except for the main \code{validate_entrata_request()} function, +which will invisibly return \code{TRUE} if the request is valid. +} +\description{ +This function validates an Entrata API request to ensure that the provided +endpoint, method, method parameters, and method version are valid. +} +\details{ +This function is used to validate an Entrata API request before sending it +to the Entrata API. It checks that the provided endpoint is valid, that the +method is valid for the endpoint, that the method parameters are valid for +the method, and that the method version is valid if provided. +} +\seealso{ +\href{https://docs.entrata.com/api/v1/documentation}{Entrata API Documentation} + +Other Entrata: +\code{\link{get_entrata_config}()}, +\code{\link{validate_entrata_config}()} + +Other Validation: +\code{\link{validate_entrata_config}()} +} +\concept{Entrata} +\concept{Validation} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R new file mode 100644 index 0000000..3bc2187 --- /dev/null +++ b/tests/testthat/helper.R @@ -0,0 +1,112 @@ +# environment ------------------------------------------------------------- + +is_github <- function() { + fs::file_exists("/github/workflow/event.json") +} + +# encryption -------------------------------------------------------------- + +decrypt_cfg_file <- function(cfg_path, key = "NOCLOCKS_ENCRYPTION_KEY") { + if (!httr2::secret_has_key(key)) { + cli::cli_alert_danger("Encryption key: {.field {key}} not found.") + cli::cli_abort("Please set the encryption key in your environment variables.") + } + + cfg_file_decrypted_temp <- httr2::secret_decrypt_file( + path = cfg_path, + key = key + ) + + fs::file_move( + cfg_file_decrypted_temp, + fs::path(dirname(cfg_path), "config.yml") + ) + + cfg_file_decrypted <- fs::path(dirname(cfg_path), "config.yml") + + cli::cli_alert_success("Successfully decrypted the config file: {.file cfg_file_decrypted}") + cli::cli_alert_info("The decrypted file is now the active config file.") + + Sys.setenv("R_CONFIG_FILE" = cfg_file_decrypted) + cli::cli_alert_info("Set `R_CONFIG_FILE` to: {.file {cfg_file_decrypted}}") + + return(invisible(cfg_file_decrypted)) +} + +# mocks ------------------------------------------------------------------- + +mock_req_body <- list( + auth = list( + type = "basic" + ), + requestId = 15, + method = list( + name = "getStatus", + version = "r1", + params = list() + ) +) + +mock_res_success <- list( + response = list( + requestId = "15", + code = 200, + result = list( + status = "Success", + message = "API service is available and running." + ) + ) +) + +mock_res_error <- list( + response = list( + requestId = "15", + error = list( + code = 113, + message = "Username and/or password is incorrect." + ) + ) +) + + +# mock response ----------------------------------------------------------- + +# Helper function to create a mock response +create_mock_response <- function(status_code, body) { + structure( + list( + status_code = status_code, + headers = list(`Content-Type` = "application/json"), + body = jsonlite::toJSON(body, auto_unbox = TRUE) + ), + class = "response" + ) +} + +# package root ------------------------------------------------------------ + +test_package_root <- function() { + hold <- tryCatch( + rprojroot::find_package_root_file(), + error = function(e) NULL + ) + + if (!is.null(hold)) { + return(hold) + } + + pkg <- testthat::testing_package() + + hold <- tryCatch( + rprojroot::find_package_root_file( + path = file.path("..", "..", pkg) + ), + error = function(e) NULL + ) + + if (!is.null(hold)) { + return(hold) + } + + rlang::abort("Could not find package root") +} diff --git a/tests/testthat/setup-httptest2.R b/tests/testthat/setup-httptest2.R index 4c9cf1d..c96cca8 100644 --- a/tests/testthat/setup-httptest2.R +++ b/tests/testthat/setup-httptest2.R @@ -1 +1,16 @@ -library(httptest2) + +# ------------------------------------------------------------------------ +# +# Title : Setup httptest2 +# By : Jimmy Briggs +# Date : 2024-09-19 +# +# ------------------------------------------------------------------------ + +library(httptest2, warn.conflicts = FALSE) + +options( + httptest2.versbose = TRUE, + httptest.debug.trace = TRUE, + warn = 1 +) diff --git a/tests/testthat/setup-shinytest2.R b/tests/testthat/setup-shinytest2.R index 59712da..ad95123 100644 --- a/tests/testthat/setup-shinytest2.R +++ b/tests/testthat/setup-shinytest2.R @@ -1,2 +1,11 @@ + +# ------------------------------------------------------------------------ +# +# Title : Setup shinytest2 +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + # Load application support files into testing environment shinytest2::load_app_env("../../inst/shiny/datahub/") diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R new file mode 100644 index 0000000..4678ce6 --- /dev/null +++ b/tests/testthat/setup.R @@ -0,0 +1,45 @@ + +# ------------------------------------------------------------------------ +# +# Title : Main Setup Script +# By : Jimmy Briggs +# Date : 2024-11-11 +# +# ------------------------------------------------------------------------ + +library(httr2, warn.conflicts = FALSE) +library(httptest2, warn.conflicts = FALSE) +library(withr, warn.conflicts = FALSE) + +Sys.setlocale("LC_COLLATE", "C") + +options(warn = 1) + +test_config <- list( + username = "testuser", + password = "testpass", + base_url = "https://api.entrata.com" +) + +test_prop_ids <- c( + "739084", + "641240", + "676055", + "952515", + "518041", + "518042", + "833617", + "1197887", + "1143679", + "1311849" +) + +if (is_github()) { + withr::defer( + { + file.remove(cfg_decrypted) + Sys.unsetenv("R_CONFIG_FILE") + }, + testthat::teardown_env() + ) +} diff --git a/vignettes/assets/entrata-logo-dark.png b/vignettes/assets/entrata-logo-dark.png new file mode 100644 index 0000000..f36cc2e Binary files /dev/null and b/vignettes/assets/entrata-logo-dark.png differ diff --git a/vignettes/assets/entrata-logo-light.png b/vignettes/assets/entrata-logo-light.png new file mode 100644 index 0000000..48fde2b Binary files /dev/null and b/vignettes/assets/entrata-logo-light.png differ diff --git a/vignettes/assets/entrata-logo-square-red.jpg b/vignettes/assets/entrata-logo-square-red.jpg new file mode 100644 index 0000000..0d5a2fb Binary files /dev/null and b/vignettes/assets/entrata-logo-square-red.jpg differ diff --git a/vignettes/entrata.Rmd b/vignettes/entrata.Rmd index 3f9db40..35fcfef 100644 --- a/vignettes/entrata.Rmd +++ b/vignettes/entrata.Rmd @@ -1,8 +1,8 @@ --- -title: "entrata" +title: "Entrata API" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{entrata} + %\VignetteIndexEntry{Entrata API} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -17,3 +17,600 @@ knitr::opts_chunk$set( ```{r setup} # library(gmhdatahub) ``` + +## Entrata API Documentation + +## Properties Endpoint (/properties) + +The `/propertiss` endpoint provides access to property information. + +- **Request URL**: https://gmhcommunities.com/entrata/api/v1/properties + +All requests to the `/properties` endpoint must be authenticated with a valid username and password. + +- **Username** (string, required): Username for authentication. +- **Password** (string, required): Password for authentication. + +Currently we use the following methods for `/properties`: + +- **getProperties**: Retrieves website information for specified property IDs. +- **getFloorPlans**: +- **getPhoneNumber**: +- **getPropertyAddOns**: +- **getRentableItems**: +- **getWebsites**: +- **getReservableAmenities**: + +with `getProperties` being the most commonly used method. + +### Method: getProperties + +- **Description**: Retrieves website information for specified property IDs. + +- **Parameters**: + - **propertyIds** (string, optional): A comma-separated list of property IDs to filter the response. + - **propertyLookupCode** (string, optional): Property lookup code. + - **showAllStatus** (boolean, optional): Whether to show all status information (true/false). + +- **Request Headers**: + +```plaintext +Content-Type: APPLICATION/JSON; CHARSET=UTF-8 +Authorization: Basic REDACTED +``` + +- **Response Headers**: + +```plaintext +access-control-allow-origin: * +access-control-expose-headers: Link, X-Total-Count, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Content-Language +alt-svc: h3=":443"; ma=86400 +cf-cache-status: DYNAMIC +cf-ray: 8e18d24d3fa5dd1a-ATL +content-encoding: br +content-language: en-US +content-type: application/json;charset=utf-8 +date: Tue, 12 Nov 2024 19:10:20 GMT +server: cloudflare +vary: Authorization +x-ratelimit-limit: 15000/day;1000/hour;150/minute +x-ratelimit-remaining: 14996/day;999/hour;149/minute +x-ratelimit-reset: 42580;2980;40 +x-read-only: 000 +``` + +- **Request Body**: + +
View Full Request JSON:

+ +```json +{ + "auth": { + "type" : "basic" + }, + "requestId" : 15, + "method": { + "name": "getProperties", + "version":"r1", + "params": { + "propertyIds" : "739076,739085", + "propertyLookupCode" : "GMH", + "showAllStatus" : "1" + } + } +} +``` + +

+ +- **Response Body**: + +
View Full Response JSON:

+ +```json +{ + "response": { + "requestId": "15", + "code": 200, + "result": { + "PhysicalProperty": { + "Property": [ + { + "PropertyID": 739076, + "MarketingName": "1008 S. 4th", + "Type": "Student", + "webSite": "https://www.theacademycampustown.com/", + "Address": { + "@attributes": { + "AddressType": "property" + }, + "Address": "1008 S. 4th", + "City": "Champaign", + "State": "IL", + "PostalCode": "61820", + "Country": "US", + "Email": "info@theacademycampustown.com" + }, + "Addresses": { + "Address": [ + { + "AddressType": "Primary", + "Address": "1008 S. 4th", + "City": "Champaign", + "StateCode": "IL", + "PostalCode": "61820", + "Country": "US" + }, + { + "AddressType": "Mailing", + "Address": "708 South 6th Street", + "City": "Champaign", + "StateCode": "IL", + "PostalCode": "61820", + "Country": "US" + } + ] + }, + "PostMonths": { + "ArPostMonth": "11/2024", + "ApPostMonth": "11/2024", + "GlPostMonth": "11/2024" + }, + "PropertyHours": { + "OfficeHours": { + "OfficeHour": [ + { + "Day": "Monday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Sunday", + "AvailabilityType": "Open", + "OpenTime": "12:00 PM", + "CloseTime": "4:00 PM" + }, + { + "Day": "Saturday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "4:00 PM" + }, + { + "Day": "Tuesday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Wednesday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Thursday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Friday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + } + ] + } + }, + "IsDisabled": 0, + "IsFeaturedProperty": 0, + "SpaceOptions": { + "SpaceOption": [ + { + "Id": "2", + "Name": "Private" + }, + { + "Id": "3", + "Name": "Shared" + }, + { + "Id": "22", + "Name": "Per Bedroom" + } + ] + }, + "LeaseTerms": { + "LeaseTerm": [ + { + "Id": 11009, + "Name": "Spring Semester 2021", + "TermMonths": 5, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11008, + "Name": "2020 Fall Semester", + "TermMonths": 5, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11037, + "Name": "2021 Fall Semester", + "TermMonths": 5, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11004, + "Name": "2020/2021 6 Month Lease", + "TermMonths": 5, + "IsProspect": true, + "IsRenewal": false + }, + { + "Id": 11096, + "Name": "2021/2022 6 Month Lease", + "TermMonths": 6, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11005, + "Name": "2020/2021 9 Month Lease", + "TermMonths": 10, + "IsProspect": true, + "IsRenewal": false + }, + { + "Id": 11909, + "Name": "Annual", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9861, + "WindowStartDate": "08/15/2025", + "WindowEndDate": "07/30/2026" + } + ] + } + }, + { + "Id": 11458, + "Name": "Transfer 2024/2025", + "TermMonths": 12, + "IsProspect": false, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9335, + "WindowStartDate": "08/16/2024", + "WindowEndDate": "07/30/2025" + } + ] + } + }, + { + "Id": 10894, + "Name": "Immediate Move In 2020/2021", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11121, + "Name": "2022/2023", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11910, + "Name": "MOMI", + "TermMonths": 12, + "IsProspect": false, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9865, + "WindowStartDate": "08/15/2025", + "WindowEndDate": "07/30/2026" + } + ] + } + }, + { + "Id": 11020, + "Name": "Immediate Move-In 2021/2022", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11457, + "Name": "2024/2025", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9331, + "WindowStartDate": "08/16/2024", + "WindowEndDate": "07/30/2025" + } + ] + } + }, + { + "Id": 11199, + "Name": "2023/2024", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10891, + "Name": "2019/2020", + "TermMonths": 13, + "IsProspect": true, + "IsRenewal": true + } + ] + } + }, + { + "PropertyID": 739085, + "MarketingName": "1047 Commonwealth Avenue", + "Type": "Student", + "webSite": "https://1047commonwealthavenue.prospectportal.com/", + "Address": { + "@attributes": { + "AddressType": "property" + }, + "Address": "1047 Commonwealth Avenue", + "City": "Boston", + "State": "MA", + "PostalCode": "02215", + "Country": "US", + "Email": "info@1047commonwealth.com" + }, + "Addresses": { + "Address": [ + { + "AddressType": "Primary", + "Address": "1047 Commonwealth Avenue", + "City": "Boston", + "StateCode": "MA", + "PostalCode": "02215", + "Country": "US" + } + ] + }, + "Phone": { + "PhoneNumber": "6173510288", + "@attributes": { + "PhoneType": "primary" + }, + "PhoneDescription": "Primary" + }, + "PostMonths": { + "ArPostMonth": "11/2024", + "ApPostMonth": "11/2024", + "GlPostMonth": "11/2024" + }, + "PropertyHours": { + "OfficeHours": { + "OfficeHour": [ + { + "Day": "Monday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Tuesday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Wednesday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Thursday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + }, + { + "Day": "Friday", + "AvailabilityType": "Open", + "OpenTime": "10:00 AM", + "CloseTime": "6:00 PM" + } + ] + } + }, + "IsDisabled": 0, + "IsFeaturedProperty": 0, + "SpaceOptions": { + "SpaceOption": [ + { + "Id": "2", + "Name": "Private" + }, + { + "Id": "3", + "Name": "Shared" + } + ] + }, + "LeaseTerms": { + "LeaseTerm": [ + { + "Id": 11007, + "Name": "Group", + "TermMonths": 1, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10888, + "Name": "6 months", + "TermMonths": 6, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10887, + "Name": "9 months", + "TermMonths": 9, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 12060, + "Name": "Academic Year", + "TermMonths": 10, + "IsProspect": true, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9988, + "WindowStartDate": "08/17/2024", + "WindowEndDate": "05/31/2025" + } + ] + } + }, + { + "Id": 11130, + "Name": "2022/2023", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10955, + "Name": "2021 Lease Term", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10954, + "Name": "2020 Lease Term", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 10878, + "Name": "2019/2020", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11226, + "Name": "2023/2024", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + }, + { + "Id": 11529, + "Name": "2024/2025", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9377, + "WindowStartDate": "08/17/2024", + "WindowEndDate": "07/31/2025" + } + ] + } + }, + { + "Id": 11530, + "Name": "Transfer 2024/2025", + "TermMonths": 12, + "IsProspect": false, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9378, + "WindowStartDate": "08/17/2024", + "WindowEndDate": "07/31/2025" + } + ] + } + }, + { + "Id": 11924, + "Name": "Annual", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9882, + "WindowStartDate": "08/18/2025", + "WindowEndDate": "07/31/2026" + } + ] + } + }, + { + "Id": 11925, + "Name": "MOMI", + "TermMonths": 12, + "IsProspect": false, + "IsRenewal": true, + "LeaseStartWindows": { + "LeaseStartWindow": [ + { + "Id": 9883, + "WindowStartDate": "08/18/2025", + "WindowEndDate": "07/31/2026" + } + ] + } + }, + { + "Id": 10886, + "Name": "12 months", + "TermMonths": 12, + "IsProspect": true, + "IsRenewal": true + } + ] + } + } + ] + } + } + } +} +``` + +

diff --git a/vignettes/workflow.Rmd b/vignettes/workflow.Rmd new file mode 100644 index 0000000..c780b60 --- /dev/null +++ b/vignettes/workflow.Rmd @@ -0,0 +1,128 @@ +--- +title: "workflow" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{workflow} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +# library(gmhdatahub) +``` + +## Understanding Key Terms in API Data Processing + +Processing API response data involves a series of steps and concepts that ensure the data is correctly received, interpreted, transformed, and utilized within an application. + +Below is an overview of key terms and their roles within the typical workflow of handling API responses: + +### API Response + +The data returned by an API after a request is made. It usually comes in formats like JSON, XML, or others. + +### Parsing + +- Definition: Analyzing the API response data structure to convert it into a usable format within your application. + +- Example: Converting JSON response data into a list or data frame in R. + +### Serialization & Deserialization + +- **Serialization:** Converting an in-memory data structure into a format that can be easily stored or transmitted (e.g., JSON, XML). + +- **Example:** Using `jsonlite::toJSON()` in R to convert an object into a JSON string before sending it in an API request. + +- **Deserialization:** The inverse process; converting serialized data back into an in-memory data structure. + +- **Example:** Parsing a JSON response using `jsonlite::fromJSON()` in R to convert it into a list or data frame. + +### Marshaling & Unmarshaling + +- **Marshaling:** Transforming memory objects to a format suitable for storage or transmission, often used in remote procedure calls (RPC). + +- **Example:** Using Protocol Buffers to marshal data before sending it to a microservice. + +- **Unmarshaling:** The reverse process; converting marshaled data back into memory objects. + +- **Example:** Decoding Protocol Buffers data back into native objects in a service. + +### Schemas + +- **Definition:** Formal definitions of the structure, types, and constraints of data (e.g., JSON Schema, XML Schema). + +- **Example:** Using a JSON Schema to validate that an API response contains required fields like `id`, `name`, and `email`. + +### Encoding & Decoding + +- **Encoding:** Converting data into a specific format for transmission or storage, ensuring compatibility or efficiency. + +- **Example:** Encoding data as Base64 when embedding binary data in a JSON response. + +- **Decoding:** The reverse process; converting encoded data back into its original format. + +- **Example:** Decoding a Base64 string back into binary data after receiving it from an API. + +### Encryption & Decryption + +**Encryption:** Converting data into a secure format to prevent unauthorized access. + +**Example:** Using HTTPS to encrypt data in transit or encrypting specific fields within an API response. + +**Decryption:** Converting encrypted data back into its original, readable format. + +**Example:** Decrypting a sensitive field in an API response using a predefined key. + +### Extraction + +Retrieving specific pieces of data from a larger dataset. + +**Example:** Extracting the `user` object from a nested JSON API response. + +Transformation +Modifying data from one format or structure to another to meet the application's requirements. + +Example: Converting date strings from the API into JavaScript Date objects. + +10. Enrichment +Enhancing the API response data by adding additional information from other sources. + +Example: Adding geographic coordinates to user data by cross-referencing with a location service. + +11. Validation +Checking that the API response data meets certain criteria or standards. + +Example: Verifying that a numerical field falls within an expected range or that required fields are present. + +12. Normalization +Structuring data to reduce redundancy and improve integrity. + +Example: Splitting a full address into separate street, city, state, and zip fields. + +13. Aggregation +Combining multiple data points into a summarized or consolidated form. + +Example: Calculating the total sales from a list of sales transactions received from an API. + +14. Caching +Storing API response data temporarily to improve performance and reduce redundant requests. + +Example: Using an in-memory cache like Redis to store user profiles fetched from an API. + +15. Error Handling +Managing and responding to errors that occur during the processing of API responses. + +Example: Retrying a failed API request or logging an error for later analysis when parsing fails. + +16. Logging and Monitoring +Recording and tracking the processing of API responses for debugging, auditing, and performance analysis. + +Example: Logging the time taken to parse and process each API response or monitoring for a high rate of failed validations. +