andrewallenbruce / provider

Public Healthcare Provider APIs :stethoscope:
https://andrewallenbruce.github.io/provider/
Other
18 stars 2 forks source link

Feature: NPI Constructor #62

Open andrewallenbruce opened 7 months ago

andrewallenbruce commented 7 months ago

NPI Constructor

Function

```r library(provider) construct_npi <- function(npi) { npi_test <- provider:::validate_npi(npi, print = TRUE) # Remove the 10th digit to create the 9-position identifier part of the NPI id <- unlist(strsplit(npi_test, ""), use.names = FALSE)[1:9] #--- id_print <- rlang::sym(paste0(c(id, "_"), collapse = "")) cli::cli_alert("01. Keep first 9 digits: {.strong {.val {id_print}}}") #--- # Reverse order of digits x <- rev(id) #--- rev_print <- rlang::sym(paste0(x, collapse = "")) cli::cli_alert("02. Reverse order of digits: {.strong {.val {rev_print}}}") #--- # Select index of every other digit idx <- seq(1, length(x), 2) #--- idx_print <- rlang::sym(paste0(x[idx], collapse = " ")) cli::cli_alert("03. Select every other digit: {.strong {.val {idx_print}}}") #--- # Double the value of the alternate digits x[idx] <- as.numeric(x[idx]) * 2 #--- dbl_print <- rlang::sym(paste0(x[idx], collapse = " ")) cli::cli_alert("04. Double each alternate digit: {.strong {.val {dbl_print}}}") ins_print <- rlang::sym(paste0(x, collapse = " ")) cli::cli_alert("05. Insert alternates back into original string: {.strong {.val {ins_print}}}") #--- # Reverse order of digits again x <- rev(x) #--- rev2 <- x rev2_print <- rlang::sym(paste0(x, collapse = " ")) cli::cli_alert("06. Reverse order again: {.strong {.val {rev2_print}}}") #--- # Split and unlist to separate digits x <- unlist(strsplit(x, ""), use.names = FALSE) #--- rev2 <- unlist(strsplit(rev2, ""), use.names = FALSE) add <- sum(as.numeric(x)) add_print <- rlang::sym(paste0(paste0(rev2, collapse = " + "), paste0(" = ", add))) cli::cli_alert("07. Sum the individual digits: {.strong {.val {add_print}}}") #--- # Add constant 24 to the sum of the digits x <- sum(as.numeric(x)) + 24 #--- const_print <- rlang::sym(paste0(paste0(c(add, 24), collapse = " + "), paste0(" = ", add + 24))) cli::cli_alert("08. Add {.emph constant} {.strong 24} to the sum: {.strong {.val {const_print}}}") #--- # Find the next higher number ending in zero y <- ceiling(x / 10) * 10 #--- int_print <- rlang::sym(paste0(paste0("⌈", add + 24,"⌉"), paste0(" = ", y))) cli::cli_alert("09. Find next largest integer divisible by 10: {.strong {.val {int_print}}}") #--- # Find the check digit by subtracting x from y z <- y - x #--- check_print <- rlang::sym(paste0(paste0(c(y, (add + 24)), collapse = " - "), paste0(" = ", z))) cli::cli_alert(c("10. Find the check digit by subtracting {.emph step 08} from {.emph step 09}: {.strong {.val {check_print}}}")) #--- # Append the check digit to the end of the 9-digit identifier id[10] <- z #--- append_print <- rlang::sym(paste0(id, collapse = "")) cli::cli_alert(c("11. Append the check digit to the number from step 01: {.strong {.val {append_print}}}")) #--- # Collapse the vector into a single string npi_valid <- paste0(id, collapse = "") # Is the syntactically valid NPI identical to the test NPI? if (identical(npi_valid, npi_test)) { #--- identical <- rlang::sym(paste0(c(npi_test, npi_valid), collapse = " = ")) cli::cli_alert_success(c("NPI {.strong is} syntactically valid: {.strong {.val {identical}}}")) #--- } if (!identical(npi_valid, npi_test)) { #--- not_identical <- rlang::sym(paste0(c(npi_test, npi_valid), collapse = " != ")) cli::cli_alert_danger(c("NPI {.strong is not} syntactically valid: {.strong {.val {not_identical}}}")) #--- } } ```

Examples:

construct_npi(1234567891)
→ 01. Keep first 9 digits: 123456789_
→ 02. Reverse order of digits:  987654321
→ 03. Select every other digit: 9 7 5 3 1
→ 04. Double each alternate digit: 18 14 10 6 2
→ 05. Insert alternates back into original string: 18 8 14 6 10 4 6 2 2
→ 06. Reverse order again: 2 2 6 4 10 6 14 8 18
→ 07. Sum the individual digits: 2 + 2 + 6 + 4 + 1 + 0 + 6 + 1 + 4 + 8 + 1 + 8 = 43
→ 08. Add constant 24 to the sum: 43 + 24 = 67
→ 09. Find next largest integer divisible by 10: ⌈67⌉ = 70
→ 10. Find the check digit by subtracting step 08 from step 09: 70 - 67 = 3
→ 11. Append the check digit to the number from step 01: 1234567893
✖ NPI is not syntactically valid: 1234567891 != 1234567893

construct_npi(1043477615)
→ 01. Keep first 9 digits: 104347761_
→ 02. Reverse order of digits:  167743401
→ 03. Select every other digit: 1 7 4 4 1
→ 04. Double each alternate digit: 2 14 8 8 2
→ 05. Insert alternates back into original string: 2 6 14 7 8 3 8 0 2
→ 06. Reverse order again: 2 0 8 3 8 7 14 6 2
→ 07. Sum the individual digits: 2 + 0 + 8 + 3 + 8 + 7 + 1 + 4 + 6 + 2 = 41
→ 08. Add constant 24 to the sum: 41 + 24 = 65
→ 09. Find next largest integer divisible by 10: ⌈65⌉ = 70
→ 10. Find the check digit by subtracting step 08 from step 09: 70 - 65 = 5
→ 11. Append the check digit to the number from step 01: 1043477615
✔ NPI is syntactically valid: 1043477615 = 1043477615

construct_npi("0000000000")
→ 01. Keep first 9 digits: 000000000_
→ 02. Reverse order of digits:  000000000
→ 03. Select every other digit: 0 0 0 0 0
→ 04. Double each alternate digit: 0 0 0 0 0
→ 05. Insert alternates back into original string: 0 0 0 0 0 0 0 0 0
→ 06. Reverse order again: 0 0 0 0 0 0 0 0 0
→ 07. Sum the individual digits: 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 = 0
→ 08. Add constant 24 to the sum: 0 + 24 = 24
→ 09. Find next largest integer divisible by 10: ⌈24⌉ = 30
→ 10. Find the check digit by subtracting step 08 from step 09: 30 - 24 = 6
→ 11. Append the check digit to the number from step 01: 0000000006
✖ NPI is not syntactically valid: 0000000000 != 0000000006

Created on 2023-11-23 with reprex v2.0.2

andrewallenbruce commented 7 months ago
Function

``` r construct_npi <- function(npi) { npi_test <- provider:::validate_npi(npi, print = TRUE) #--- cli_npi <- rlang::sym(npi_test) cli::cli_alert("Testing NPI: {.strong {.val {cli_npi}}}") #--- # Remove the 10th digit to create the 9-position identifier part of the NPI id_9 <- unlist(strsplit(npi_test, ""), use.names = FALSE)[1:9] #--- cli_id_9 <- rlang::sym(paste0(c(id_9, "_"), collapse = "")) cli::cli_alert("Keep first 9 digits: {.strong {.val {cli_id_9}}}") #--- # Reverse order of digits x_rev <- rev(id_9) #--- cli_x_rev <- rlang::sym(paste0(x_rev, collapse = "")) cli::cli_alert("Reverse digit order: {.strong {.val {cli_x_rev}}}") #--- # Select index of every other digit x_idx <- seq(1, length(x_rev), 2) #--- cli_x_idx <- rlang::sym(paste0(x_rev[x_idx], collapse = " ")) cli::cli_alert("Select every other digit: {.strong {.val {cli_x_idx}}}") #--- # Double the value of the alternate digits x_rev[x_idx] <- as.numeric(x_rev[x_idx]) * 2 #--- cli_dbl <- rlang::sym(paste0(x_rev[x_idx], collapse = " ")) cli_ins <- rlang::sym(paste0(x_rev, collapse = " ")) cli::cli_alert("Double each: {.strong {.val {cli_dbl}}}") cli::cli_alert("Replace original with doubles: {.strong {.val {cli_ins}}}") #--- # Split and unlist to separate digits x_split <- unlist(strsplit(x_rev, ""), use.names = FALSE) x_add <- sum(as.numeric(x_split)) #--- cli_x_add <- rlang::sym(paste0(paste0(x_split, collapse = " + "), paste0(" = ", x_add))) cli::cli_alert("Sum individual digits: {.strong {.val {cli_x_add}}}") #--- # Add constant 24 to the sum of the digits x_24 <- x_add + 24 #--- sym_24 <- rlang::sym("24") cli_x_24 <- rlang::sym(paste0(paste0(c(x_add, 24), collapse = " + "), paste0(" = ", x_24))) cli::cli_alert("Add {.strong {.val {sym_24}}} to the sum: {.strong {.val {cli_x_24}}}") #--- x_divide <- x_24 / 10 cli_x_divide <- rlang::sym(paste0(paste0(x_24, " / ", 10), paste0(" = ", x_divide))) cli::cli_alert("Divide by 10: {.strong {.val {cli_x_divide}}}") x_divide_first <- as.numeric(unlist(strsplit(as.character(x_divide), ""), use.names = FALSE)[1]) cli_x_first <- rlang::sym(paste0(paste0(x_divide), paste0(" = ", x_divide_first))) cli::cli_alert("Take first digit: {.strong {.val {cli_x_first}}}") x_plus_one <- x_divide_first + 1 cli_x_plus <- rlang::sym(paste0(paste0(x_divide_first, " + ", 1), paste0(" = ", x_plus_one))) cli::cli_alert("Add one: {.strong {.val {cli_x_plus}}}") x_paste_zero <- paste0(x_plus_one, "0") cli_x_zero <- rlang::sym(paste0(paste0(x_plus_one, " * ", 10), paste0(" = ", x_paste_zero))) cli::cli_alert("Multiply by 10: {.strong {.val {cli_x_zero}}}") # Find the next higher number ending in zero x_next <- ceiling(x_24 / 10) * 10 #--- cli_x_next <- rlang::sym(paste0(paste0("⌈", x_24,"⌉"), paste0(" = " , x_next))) cli::cli_alert("This is the next largest integer divisible by 10: {.strong {.val {cli_x_next}}}") #--- # Find the check digit by subtracting x from y x_check <- x_next - x_24 #--- cli_x_check <- rlang::sym(paste0(paste0(c(x_next, x_24), collapse = " - "), paste0(" = ", x_check))) cli::cli_alert(c("Find the check digit: {.strong {.val {cli_x_check}}}")) #--- # Append the check digit to the end of the 9-digit identifier id_10 <- id_9 id_10[10] <- x_check #--- cli_id_10 <- rlang::sym(paste0(id_10, collapse = "")) cli::cli_alert(c("Append check digit to the original value: {.strong {.val {cli_id_10}}}")) #--- # Collapse the vector into a single string npi_valid <- paste0(id_10, collapse = "") # Is the syntactically valid NPI identical to the test NPI? if (identical(npi_valid, npi_test)) { #--- identical <- rlang::sym(paste0(c(npi_test, npi_valid), collapse = " = ")) cli::cli_alert_success(c("NPI {.strong is} syntactically valid: {.strong {.val {identical}}}")) #--- } if (!identical(npi_valid, npi_test)) { #--- not_identical <- rlang::sym(paste0(c(npi_test, npi_valid), collapse = " != ")) cli::cli_alert_danger(c("NPI {.strong is not} syntactically valid: {.strong {.val {not_identical}}}")) #--- } } ```

construct_npi(1234567891)

→ Testing NPI: 1234567891
→ Keep first 9 digits: 123456789_
→ Reverse digit order:  987654321
→ Select every other digit: 9 7 5 3 1
→ Double each: 18 14 10 6 2
→ Replace original with doubles: 18 8 14 6 10 4 6 2 2
→ Sum individual digits: 1 + 8 + 8 + 1 + 4 + 6 + 1 + 0 + 4 + 6 + 2 + 2 = 43
→ Add 24 to the sum: 43 + 24 = 67
→ Divide by 10: 67 / 10 = 6.7
→ Take first digit: 6.7 = 6
→ Add one: 6 + 1 = 7
→ Multiply by 10: 7 * 10 = 70
→ This is the next largest integer divisible by 10: ⌈67⌉ = 70
→ Find the check digit: 70 - 67 = 3
→ Append check digit to the original value: 1234567893
✖ NPI is not syntactically valid: 1234567891 != 1234567893

construct_npi(1043477615)

→ Testing NPI: 1043477615
→ Keep first 9 digits: 104347761_
→ Reverse digit order:  167743401
→ Select every other digit: 1 7 4 4 1
→ Double each: 2 14 8 8 2
→ Replace original with doubles: 2 6 14 7 8 3 8 0 2
→ Sum individual digits: 2 + 6 + 1 + 4 + 7 + 8 + 3 + 8 + 0 + 2 = 41
→ Add 24 to the sum: 41 + 24 = 65
→ Divide by 10: 65 / 10 = 6.5
→ Take first digit: 6.5 = 6
→ Add one: 6 + 1 = 7
→ Multiply by 10: 7 * 10 = 70
→ This is the next largest integer divisible by 10: ⌈65⌉ = 70
→ Find the check digit: 70 - 65 = 5
→ Append check digit to the original value: 1043477615
✔ NPI is syntactically valid: 1043477615 = 1043477615

construct_npi("0000000000")

→ Testing NPI: 0000000000
→ Keep first 9 digits: 000000000_
→ Reverse digit order:  000000000
→ Select every other digit: 0 0 0 0 0
→ Double each: 0 0 0 0 0
→ Replace original with doubles: 0 0 0 0 0 0 0 0 0
→ Sum individual digits: 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 = 0
→ Add 24 to the sum: 0 + 24 = 24
→ Divide by 10: 24 / 10 = 2.4
→ Take first digit: 2.4 = 2
→ Add one: 2 + 1 = 3
→ Multiply by 10: 3 * 10 = 30
→ This is the next largest integer divisible by 10: ⌈24⌉ = 30
→ Find the check digit: 30 - 24 = 6
→ Append check digit to the original value: 0000000006
✖ NPI is not syntactically valid: 0000000000 != 0000000006

Created on 2023-12-03 with reprex v2.0.2