From 54f3fe3c7ef8ac5daf1289be805d9382c48ccfb7 Mon Sep 17 00:00:00 2001 From: "Steven M. Mortimer" Date: Fri, 13 Apr 2018 08:02:16 +0000 Subject: [PATCH] version 0.1.2 --- DESCRIPTION | 37 + LICENSE | 2 + MD5 | 183 + NAMESPACE | 174 + NEWS.md | 78 + R/auth.R | 353 + R/bulk-operation.R | 890 ++ R/bulk-query.R | 191 + R/compatibility.R | 318 + R/create-metadata.R | 107 + R/create.R | 211 + R/delete-metadata.R | 60 + R/delete.R | 173 + R/describe-metadata.R | 68 + R/describe.R | 84 + R/endpoints-bulk.R | 196 + R/endpoints-rest.R | 117 + R/endpoints-soap.R | 36 + R/list-metadata.R | 65 + R/query.R | 195 + R/read-metadata.R | 68 + R/rename-metadata.R | 59 + R/retrieve-metadata.R | 186 + R/retrieve.R | 164 + R/salesforcer.R | 23 + R/search.R | 185 + R/update-metadata.R | 82 + R/update.R | 219 + R/upsert-metadata.R | 85 + R/upsert.R | 247 + R/utils-httr.R | 145 + R/utils-metadata.R | 12422 +++++++++++++++++ R/utils-org.R | 167 + R/utils-xml.R | 309 + R/utils.R | 93 + R/zzz.R | 23 + README.md | 293 + build/vignette.rds | Bin 0 -> 305 bytes inst/doc/getting-started.R | 96 + inst/doc/getting-started.Rmd | 189 + inst/doc/getting-started.html | 225 + inst/doc/transitioning-from-RForcecom.R | 83 + inst/doc/transitioning-from-RForcecom.Rmd | 142 + inst/doc/transitioning-from-RForcecom.html | 207 + inst/doc/working-with-bulk-api.R | 57 + inst/doc/working-with-bulk-api.Rmd | 92 + inst/doc/working-with-bulk-api.html | 163 + man/VERB_n.Rd | 15 + man/build_metadata_xml_from_list.Rd | 30 + man/build_soap_xml_from_list.Rd | 45 + man/catch_errors.Rd | 15 + man/figures/cloud.png | Bin 0 -> 17110 bytes man/figures/logo.png | Bin 0 -> 12013 bytes man/figures/old-logo.png | Bin 0 -> 4897 bytes man/figures/old-salesforcer-hex.png | Bin 0 -> 96602 bytes man/figures/old-salesforcer.png | Bin 0 -> 30993 bytes man/figures/salesforcer.png | Bin 0 -> 48382 bytes man/get_os.Rd | 27 + man/is_legit_token.Rd | 12 + man/make_base_metadata_url.Rd | 15 + man/make_base_rest_url.Rd | 15 + man/make_base_soap_url.Rd | 15 + man/make_bulk_batch_details_url.Rd | 15 + man/make_bulk_batch_status_url.Rd | 15 + man/make_bulk_batches_url.Rd | 15 + man/make_bulk_create_job_url.Rd | 15 + man/make_bulk_delete_job_url.Rd | 15 + man/make_bulk_end_job_generic_url.Rd | 15 + man/make_bulk_get_job_url.Rd | 15 + man/make_bulk_job_records_url.Rd | 16 + man/make_bulk_query_result_url.Rd | 16 + man/make_bulk_query_url.Rd | 15 + man/make_chatter_users_url.Rd | 15 + man/make_composite_batch_url.Rd | 15 + man/make_composite_url.Rd | 15 + man/make_describe_objects_url.Rd | 15 + man/make_login_url.Rd | 15 + man/make_parameterized_search_url.Rd | 22 + man/make_query_url.Rd | 15 + man/make_search_url.Rd | 15 + man/make_soap_xml_skeleton.Rd | 44 + man/metadata_type_validator.Rd | 11151 +++++++++++++++ man/parameterized_search_control.Rd | 48 + man/rDELETE.Rd | 15 + man/rGET.Rd | 15 + man/rPATCH.Rd | 15 + man/rPOST.Rd | 15 + man/rPUT.Rd | 15 + man/rforcecom.bulkAction.Rd | 50 + man/rforcecom.bulkQuery.Rd | 33 + man/rforcecom.create.Rd | 26 + man/rforcecom.delete.Rd | 26 + man/rforcecom.getServerTimestamp.Rd | 18 + man/rforcecom.login.Rd | 26 + man/rforcecom.query.Rd | 26 + man/rforcecom.retrieve.Rd | 41 + man/rforcecom.search.Rd | 20 + man/rforcecom.update.Rd | 28 + man/rforcecom.upsert.Rd | 30 + man/salesforcer.Rd | 17 + man/salesforcer_state.Rd | 15 + man/session_id_available.Rd | 19 + man/sf_abort_job_bulk.Rd | 32 + man/sf_access_token.Rd | 22 + man/sf_auth.Rd | 60 + man/sf_auth_check.Rd | 28 + man/sf_auth_refresh.Rd | 25 + man/sf_batch_details_bulk.Rd | 45 + man/sf_batch_status_bulk.Rd | 45 + man/sf_bulk_operation.Rd | 62 + man/sf_close_job_bulk.Rd | 41 + man/sf_create.Rd | 41 + man/sf_create_batches_bulk.Rd | 53 + man/sf_create_bulk_v1.Rd | 16 + man/sf_create_bulk_v2.Rd | 16 + man/sf_create_job_bulk.Rd | 74 + man/sf_create_job_bulk_v1.Rd | 18 + man/sf_create_job_bulk_v2.Rd | 18 + man/sf_create_metadata.Rd | 83 + man/sf_create_rest.Rd | 16 + man/sf_create_soap.Rd | 16 + man/sf_delete.Rd | 48 + man/sf_delete_job_bulk.Rd | 27 + man/sf_delete_metadata.Rd | 37 + man/sf_describe_metadata.Rd | 26 + man/sf_describe_objects.Rd | 31 + man/sf_end_job_bulk.Rd | 28 + man/sf_get_job_bulk.Rd | 34 + man/sf_get_job_records_bulk.Rd | 52 + man/sf_input_data_validation.Rd | 15 + man/sf_job_batches_bulk.Rd | 40 + man/sf_list_api_limits.Rd | 50 + man/sf_list_metadata.Rd | 37 + man/sf_list_objects.Rd | 19 + man/sf_list_resources.Rd | 20 + man/sf_list_rest_api_versions.Rd | 20 + man/sf_query.Rd | 62 + man/sf_query_bulk.Rd | 42 + man/sf_query_result_bulk.Rd | 46 + man/sf_read_metadata.Rd | 31 + man/sf_rename_metadata.Rd | 36 + man/sf_retrieve.Rd | 42 + man/sf_retrieve_metadata.Rd | 48 + man/sf_retrieve_metadata_check_status.Rd | 44 + man/sf_search.Rd | 56 + man/sf_server_timestamp.Rd | 19 + man/sf_session_id.Rd | 22 + man/sf_submit_query_bulk.Rd | 50 + man/sf_update.Rd | 47 + man/sf_update_bulk_v1.Rd | 16 + man/sf_update_bulk_v2.Rd | 16 + man/sf_update_metadata.Rd | 60 + man/sf_update_rest.Rd | 16 + man/sf_update_soap.Rd | 16 + man/sf_upload_complete_bulk.Rd | 36 + man/sf_upsert.Rd | 58 + man/sf_upsert_bulk_v1.Rd | 16 + man/sf_upsert_bulk_v2.Rd | 16 + man/sf_upsert_metadata.Rd | 63 + man/sf_upsert_rest.Rd | 16 + man/sf_upsert_soap.Rd | 16 + man/sf_user_info.Rd | 19 + man/sf_write_csv.Rd | 15 + man/token_available.Rd | 19 + man/valid_metadata_list.Rd | 14 + man/xmlToList2.Rd | 23 + man/xml_nodeset_to_df.Rd | 21 + tests/testthat.R | 10 + tests/testthat/salesforcer.tar | Bin 0 -> 7680 bytes tests/testthat/salesforcer_test_settings.rds | Bin 0 -> 160 bytes tests/testthat/salesforcer_token.rds | Bin 0 -> 4983 bytes tests/testthat/test-auth.R | 51 + tests/testthat/test-bulk.R | 172 + tests/testthat/test-compatibility.R | 188 + tests/testthat/test-describe.R | 22 + tests/testthat/test-metadata.R | 151 + tests/testthat/test-org-utils.R | 42 + tests/testthat/test-rest.R | 81 + tests/testthat/test-search.R | 38 + tests/testthat/test-soap.R | 81 + tests/testthat/test-utils.R | 39 + vignettes/getting-started.Rmd | 189 + vignettes/transitioning-from-RForcecom.Rmd | 142 + vignettes/working-with-bulk-api.Rmd | 92 + 184 files changed, 35217 insertions(+) create mode 100644 DESCRIPTION create mode 100644 LICENSE create mode 100644 MD5 create mode 100644 NAMESPACE create mode 100644 NEWS.md create mode 100644 R/auth.R create mode 100644 R/bulk-operation.R create mode 100644 R/bulk-query.R create mode 100644 R/compatibility.R create mode 100644 R/create-metadata.R create mode 100644 R/create.R create mode 100644 R/delete-metadata.R create mode 100644 R/delete.R create mode 100644 R/describe-metadata.R create mode 100644 R/describe.R create mode 100644 R/endpoints-bulk.R create mode 100644 R/endpoints-rest.R create mode 100644 R/endpoints-soap.R create mode 100644 R/list-metadata.R create mode 100644 R/query.R create mode 100644 R/read-metadata.R create mode 100644 R/rename-metadata.R create mode 100644 R/retrieve-metadata.R create mode 100644 R/retrieve.R create mode 100644 R/salesforcer.R create mode 100644 R/search.R create mode 100644 R/update-metadata.R create mode 100644 R/update.R create mode 100644 R/upsert-metadata.R create mode 100644 R/upsert.R create mode 100644 R/utils-httr.R create mode 100644 R/utils-metadata.R create mode 100644 R/utils-org.R create mode 100644 R/utils-xml.R create mode 100644 R/utils.R create mode 100644 R/zzz.R create mode 100644 README.md create mode 100644 build/vignette.rds create mode 100644 inst/doc/getting-started.R create mode 100644 inst/doc/getting-started.Rmd create mode 100644 inst/doc/getting-started.html create mode 100644 inst/doc/transitioning-from-RForcecom.R create mode 100644 inst/doc/transitioning-from-RForcecom.Rmd create mode 100644 inst/doc/transitioning-from-RForcecom.html create mode 100644 inst/doc/working-with-bulk-api.R create mode 100644 inst/doc/working-with-bulk-api.Rmd create mode 100644 inst/doc/working-with-bulk-api.html create mode 100644 man/VERB_n.Rd create mode 100644 man/build_metadata_xml_from_list.Rd create mode 100644 man/build_soap_xml_from_list.Rd create mode 100644 man/catch_errors.Rd create mode 100644 man/figures/cloud.png create mode 100644 man/figures/logo.png create mode 100644 man/figures/old-logo.png create mode 100644 man/figures/old-salesforcer-hex.png create mode 100644 man/figures/old-salesforcer.png create mode 100644 man/figures/salesforcer.png create mode 100644 man/get_os.Rd create mode 100644 man/is_legit_token.Rd create mode 100644 man/make_base_metadata_url.Rd create mode 100644 man/make_base_rest_url.Rd create mode 100644 man/make_base_soap_url.Rd create mode 100644 man/make_bulk_batch_details_url.Rd create mode 100644 man/make_bulk_batch_status_url.Rd create mode 100644 man/make_bulk_batches_url.Rd create mode 100644 man/make_bulk_create_job_url.Rd create mode 100644 man/make_bulk_delete_job_url.Rd create mode 100644 man/make_bulk_end_job_generic_url.Rd create mode 100644 man/make_bulk_get_job_url.Rd create mode 100644 man/make_bulk_job_records_url.Rd create mode 100644 man/make_bulk_query_result_url.Rd create mode 100644 man/make_bulk_query_url.Rd create mode 100644 man/make_chatter_users_url.Rd create mode 100644 man/make_composite_batch_url.Rd create mode 100644 man/make_composite_url.Rd create mode 100644 man/make_describe_objects_url.Rd create mode 100644 man/make_login_url.Rd create mode 100644 man/make_parameterized_search_url.Rd create mode 100644 man/make_query_url.Rd create mode 100644 man/make_search_url.Rd create mode 100644 man/make_soap_xml_skeleton.Rd create mode 100644 man/metadata_type_validator.Rd create mode 100644 man/parameterized_search_control.Rd create mode 100644 man/rDELETE.Rd create mode 100644 man/rGET.Rd create mode 100644 man/rPATCH.Rd create mode 100644 man/rPOST.Rd create mode 100644 man/rPUT.Rd create mode 100644 man/rforcecom.bulkAction.Rd create mode 100644 man/rforcecom.bulkQuery.Rd create mode 100644 man/rforcecom.create.Rd create mode 100644 man/rforcecom.delete.Rd create mode 100644 man/rforcecom.getServerTimestamp.Rd create mode 100644 man/rforcecom.login.Rd create mode 100644 man/rforcecom.query.Rd create mode 100644 man/rforcecom.retrieve.Rd create mode 100644 man/rforcecom.search.Rd create mode 100644 man/rforcecom.update.Rd create mode 100644 man/rforcecom.upsert.Rd create mode 100644 man/salesforcer.Rd create mode 100644 man/salesforcer_state.Rd create mode 100644 man/session_id_available.Rd create mode 100644 man/sf_abort_job_bulk.Rd create mode 100644 man/sf_access_token.Rd create mode 100644 man/sf_auth.Rd create mode 100644 man/sf_auth_check.Rd create mode 100644 man/sf_auth_refresh.Rd create mode 100644 man/sf_batch_details_bulk.Rd create mode 100644 man/sf_batch_status_bulk.Rd create mode 100644 man/sf_bulk_operation.Rd create mode 100644 man/sf_close_job_bulk.Rd create mode 100644 man/sf_create.Rd create mode 100644 man/sf_create_batches_bulk.Rd create mode 100644 man/sf_create_bulk_v1.Rd create mode 100644 man/sf_create_bulk_v2.Rd create mode 100644 man/sf_create_job_bulk.Rd create mode 100644 man/sf_create_job_bulk_v1.Rd create mode 100644 man/sf_create_job_bulk_v2.Rd create mode 100644 man/sf_create_metadata.Rd create mode 100644 man/sf_create_rest.Rd create mode 100644 man/sf_create_soap.Rd create mode 100644 man/sf_delete.Rd create mode 100644 man/sf_delete_job_bulk.Rd create mode 100644 man/sf_delete_metadata.Rd create mode 100644 man/sf_describe_metadata.Rd create mode 100644 man/sf_describe_objects.Rd create mode 100644 man/sf_end_job_bulk.Rd create mode 100644 man/sf_get_job_bulk.Rd create mode 100644 man/sf_get_job_records_bulk.Rd create mode 100644 man/sf_input_data_validation.Rd create mode 100644 man/sf_job_batches_bulk.Rd create mode 100644 man/sf_list_api_limits.Rd create mode 100644 man/sf_list_metadata.Rd create mode 100644 man/sf_list_objects.Rd create mode 100644 man/sf_list_resources.Rd create mode 100644 man/sf_list_rest_api_versions.Rd create mode 100644 man/sf_query.Rd create mode 100644 man/sf_query_bulk.Rd create mode 100644 man/sf_query_result_bulk.Rd create mode 100644 man/sf_read_metadata.Rd create mode 100644 man/sf_rename_metadata.Rd create mode 100644 man/sf_retrieve.Rd create mode 100644 man/sf_retrieve_metadata.Rd create mode 100644 man/sf_retrieve_metadata_check_status.Rd create mode 100644 man/sf_search.Rd create mode 100644 man/sf_server_timestamp.Rd create mode 100644 man/sf_session_id.Rd create mode 100644 man/sf_submit_query_bulk.Rd create mode 100644 man/sf_update.Rd create mode 100644 man/sf_update_bulk_v1.Rd create mode 100644 man/sf_update_bulk_v2.Rd create mode 100644 man/sf_update_metadata.Rd create mode 100644 man/sf_update_rest.Rd create mode 100644 man/sf_update_soap.Rd create mode 100644 man/sf_upload_complete_bulk.Rd create mode 100644 man/sf_upsert.Rd create mode 100644 man/sf_upsert_bulk_v1.Rd create mode 100644 man/sf_upsert_bulk_v2.Rd create mode 100644 man/sf_upsert_metadata.Rd create mode 100644 man/sf_upsert_rest.Rd create mode 100644 man/sf_upsert_soap.Rd create mode 100644 man/sf_user_info.Rd create mode 100644 man/sf_write_csv.Rd create mode 100644 man/token_available.Rd create mode 100644 man/valid_metadata_list.Rd create mode 100644 man/xmlToList2.Rd create mode 100644 man/xml_nodeset_to_df.Rd create mode 100644 tests/testthat.R create mode 100644 tests/testthat/salesforcer.tar create mode 100755 tests/testthat/salesforcer_test_settings.rds create mode 100644 tests/testthat/salesforcer_token.rds create mode 100644 tests/testthat/test-auth.R create mode 100644 tests/testthat/test-bulk.R create mode 100644 tests/testthat/test-compatibility.R create mode 100644 tests/testthat/test-describe.R create mode 100644 tests/testthat/test-metadata.R create mode 100644 tests/testthat/test-org-utils.R create mode 100644 tests/testthat/test-rest.R create mode 100644 tests/testthat/test-search.R create mode 100644 tests/testthat/test-soap.R create mode 100644 tests/testthat/test-utils.R create mode 100644 vignettes/getting-started.Rmd create mode 100644 vignettes/transitioning-from-RForcecom.Rmd create mode 100644 vignettes/working-with-bulk-api.Rmd diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..7f71cc0 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,37 @@ +Package: salesforcer +Title: An Implementation of 'Salesforce' APIs Using Tidy Principles +Version: 0.1.2 +Date: 2018-04-12 +Description: An implementation of the 'Salesforce' Platform APIs (REST, SOAP, + Bulk 1.0, Bulk 2.0, and Metadata) . + This package is an articulation of the most API methods into R. The API calls + return XML or JSON that is parsed tidy data structures. For more details please + see the 'Salesforces' API references and this package's website + for more information, + documentation, and examples. +Authors@R: c( + person(c("Steven", "M."), "Mortimer", , "reportmort@gmail.com", c("aut", "cre")), + person("Takekatsu", "Hiramura", , "thira@plavox.info", c("ctb")), + person("Jennifer", "Bryan", , "jenny@rstudio.com", c("ctb")), + person("Joanna", "Zhao", , "joanna.zhao@alumni.ubc.ca", c("ctb")) + ) +URL: https://github.com/StevenMMortimer/salesforcer +BugReports: https://github.com/StevenMMortimer/salesforcer/issues +Encoding: UTF-8 +Depends: R (>= 3.1.0) +License: MIT + file LICENSE +LazyData: true +Imports: methods, httr, dplyr, xml2, XML, jsonlite, purrr, readr, + lubridate +Suggests: knitr, testthat, rmarkdown, here, RForcecom +VignetteBuilder: knitr +RoxygenNote: 6.0.1 +NeedsCompilation: no +Packaged: 2018-04-12 22:00:35 UTC; steven.mortimer +Author: Steven M. Mortimer [aut, cre], + Takekatsu Hiramura [ctb], + Jennifer Bryan [ctb], + Joanna Zhao [ctb] +Maintainer: Steven M. Mortimer +Repository: CRAN +Date/Publication: 2018-04-13 09:02:16 UTC diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1476109 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2018 +COPYRIGHT HOLDER: Steven M. Mortimer \ No newline at end of file diff --git a/MD5 b/MD5 new file mode 100644 index 0000000..bf07f8d --- /dev/null +++ b/MD5 @@ -0,0 +1,183 @@ +4f0b0c37e3de82e7caff7abe7c613060 *DESCRIPTION +4b43692ccfb3554575bae300bf605e7a *LICENSE +5ee77aecce8c659ae6a512d2a0a279da *NAMESPACE +f39d63aaf15edb13779a5e077854bdde *NEWS.md +ae090d7e57a2e3d24b1824f3c203ebcc *R/auth.R +ab6777887902a115ce3fc3d0e7da98f8 *R/bulk-operation.R +5e0c55ba395d5ee61a9b63ce62cae99f *R/bulk-query.R +172735d565e010cc2a79dcad38929a26 *R/compatibility.R +b52b82c1bfb665b45b02df62193d9deb *R/create-metadata.R +b6d6a34bbadd897c513347f7f8f477de *R/create.R +38c77451e30eaa07d2e9968c18533827 *R/delete-metadata.R +8355e0849d701df828d4fdca39b5e8ef *R/delete.R +5ef10a89f090288c78ce78d4cfbb5573 *R/describe-metadata.R +f07b5a4089fb7755d0f33617be1c1bd5 *R/describe.R +644e1485affed3a501e4086f88d6c4be *R/endpoints-bulk.R +258b7211f1ecf4db4d173dc8f67fb279 *R/endpoints-rest.R +24b186a4fc934301d0a4d0882ded335f *R/endpoints-soap.R +6b05588f75d114e6a77552288a1fe6f1 *R/list-metadata.R +bc5342da5066b61105cf14485df7aacb *R/query.R +17c14aa9fc0595d16a12e9cbc6af5437 *R/read-metadata.R +f61efc76704d84ad12bd06e48a1b46d1 *R/rename-metadata.R +8acb18a6aab5f71fbdf3409b343329ae *R/retrieve-metadata.R +63cd1880817df3ab899f8f47ffc05f5a *R/retrieve.R +dcff21ba43165eab62f66788154ac92e *R/salesforcer.R +7a49485223ff6776e116e0a2681d4cd8 *R/search.R +546f1da95d949391a5f8a1fe9eebbfae *R/update-metadata.R +fa052e544b5964e8f3b28d7c2aa9af7e *R/update.R +38d13b46b0a7b883c416541cde7e4c9f *R/upsert-metadata.R +ed1321a225f045aec698ccc32db3cd84 *R/upsert.R +f7a2a68e99b85b434d7383cfa43b38f3 *R/utils-httr.R +5cdd5b0d75c9ec27402088b048f97c4a *R/utils-metadata.R +261b7a6a2a9e2492fd0b0bb9bdfbf133 *R/utils-org.R +5b8606d1710bc122c53740aa619a1357 *R/utils-xml.R +17c4b311f828b4081ab7fbf2b8a93c3a *R/utils.R +d1e7a29a752f6631477762fb2bd63788 *R/zzz.R +e8fc3dc094255ae4aadafc3768271996 *README.md +8f214976418c2684211f230e42002a3d *build/vignette.rds +05d4a5bf8c82c27e1ae3d6e2af6fe029 *inst/doc/getting-started.R +9a4a34fb87e9c321d21b638de6df7e82 *inst/doc/getting-started.Rmd +f9ad1e72e80eb2312f3d783af5dffb9b *inst/doc/getting-started.html +bc2e5dba106ad34ed82f4cd87301f8c1 *inst/doc/transitioning-from-RForcecom.R +2bc9a3303db88713d0e6b6fd011a9cbc *inst/doc/transitioning-from-RForcecom.Rmd +9b9be7047be57936454f9483b32ae511 *inst/doc/transitioning-from-RForcecom.html +0f1e8a785d928a93cc70f9c05674a6b7 *inst/doc/working-with-bulk-api.R +3511f9cab937f92aad664b1f5dc744bf *inst/doc/working-with-bulk-api.Rmd +b19ca06c8dd766ddcb28ef1f1c89574f *inst/doc/working-with-bulk-api.html +517387629e66ac3a1f091fa05d3394d6 *man/VERB_n.Rd +d2414bbf16242a3abdcf0ca76df85224 *man/build_metadata_xml_from_list.Rd +6a4385b349d123fc58b694e39a2f7a14 *man/build_soap_xml_from_list.Rd +46fd203ccdd5251c1a520d28def3ad63 *man/catch_errors.Rd +5a89fe94efa8f263217a399e03989d36 *man/figures/cloud.png +a6a437c9dceba9eec060f9086218b74f *man/figures/logo.png +f3b2cac587da866e21cd3da87e6edf5f *man/figures/old-logo.png +5b3a3b3a2f14891c47b0090ce61c6b6f *man/figures/old-salesforcer-hex.png +dc54f2a38693ba701d67eae10b3f0e34 *man/figures/old-salesforcer.png +07fe10d05a04b2edcc5494fa84282b2f *man/figures/salesforcer.png +5fddb501dce08562c07cf0b33fdbffa2 *man/get_os.Rd +f304216aaa11c0e3fa6f7c9217fda2c9 *man/is_legit_token.Rd +fbdf77226b7796b67e487626ab734fb6 *man/make_base_metadata_url.Rd +cb726dd21fdebfab85081d5547b460ce *man/make_base_rest_url.Rd +a0ad51a4617801ad251c36e74c0405ba *man/make_base_soap_url.Rd +f01ff16e0c0cf9e9ecd5e2c63e05244a *man/make_bulk_batch_details_url.Rd +69cae2e132f790048ee603bfbc3ba49b *man/make_bulk_batch_status_url.Rd +b9f0954045efae4223992ca80d884f57 *man/make_bulk_batches_url.Rd +c9e8f049c369df0502295b91d8756d77 *man/make_bulk_create_job_url.Rd +c7caddc3a8dbbbb6c5ab32a099b17eb0 *man/make_bulk_delete_job_url.Rd +cb54468fde0be7f3e2c3f0212608e1ab *man/make_bulk_end_job_generic_url.Rd +658e6160bc159a7724fec1e8d89847f4 *man/make_bulk_get_job_url.Rd +a94466a3bed8c26ffd28f7173cb486a5 *man/make_bulk_job_records_url.Rd +4c255a798579a4af9837393fe18c8587 *man/make_bulk_query_result_url.Rd +ce303be8ae378e3bfcd297e21924c17c *man/make_bulk_query_url.Rd +54716c1c548e34fa404f40bfd9de5eea *man/make_chatter_users_url.Rd +a41ea3f3193aceb98f3c7d49573886a4 *man/make_composite_batch_url.Rd +da539e2189809798ed821d7513a6a56a *man/make_composite_url.Rd +c23358f419062cc426b6fa925470f0f3 *man/make_describe_objects_url.Rd +41b9a4dfdca8e6d763de66d93bf30509 *man/make_login_url.Rd +f6d4b9267b60f55e5a90c6eb12486170 *man/make_parameterized_search_url.Rd +c059e28c7bfd88bd48eb049b9b52d19b *man/make_query_url.Rd +28c0acc7d741fd895dc2574567042259 *man/make_search_url.Rd +079eb01ef79e175a11adb7916b7ec3af *man/make_soap_xml_skeleton.Rd +6840bf449c84444d54a9181bab4d3a97 *man/metadata_type_validator.Rd +62bc96c6f1071f86155db4609b164655 *man/parameterized_search_control.Rd +eb33a50487990d3de494d82430d08898 *man/rDELETE.Rd +cac33052d0f891f570d1d1d68e781c48 *man/rGET.Rd +3568f54cf55231e26a9fea58be504652 *man/rPATCH.Rd +7f3e6a2bea12cd325e46c0a57321e5d5 *man/rPOST.Rd +e491cfa9c15275a728c1d4400c08c3ee *man/rPUT.Rd +a2033496a7675022a12ba0df80b9ad0b *man/rforcecom.bulkAction.Rd +e9dad4dfc798c91e5de0159372ed335a *man/rforcecom.bulkQuery.Rd +fcb891c0bacba96b9cc9962364ece427 *man/rforcecom.create.Rd +61d66b5c808b485b8c90a543d14aa036 *man/rforcecom.delete.Rd +d322026bafb4cde63261680bbeee8be2 *man/rforcecom.getServerTimestamp.Rd +2290e85e590d9aad7e6f2d65e90635f3 *man/rforcecom.login.Rd +2c4db4b3e339ccc2e47f5d7b42db244c *man/rforcecom.query.Rd +8a509522756293de08902d646c465580 *man/rforcecom.retrieve.Rd +20e1df385a5a34e82992b100ea3f233f *man/rforcecom.search.Rd +9fe253bb02ae3889e83a738fb0f6a2c9 *man/rforcecom.update.Rd +dcaed7131b09388c921bc8fca970dcdb *man/rforcecom.upsert.Rd +e35f570e3ad77a94c8136f7fa956eac0 *man/salesforcer.Rd +609da77721a449ed17f1a776a2d5c5ed *man/salesforcer_state.Rd +a24165d0f023e155f60370125cbd9f96 *man/session_id_available.Rd +f5a8f5746d004b1b309404e3477ce055 *man/sf_abort_job_bulk.Rd +df3dfed9994b364516918a85d6e8da08 *man/sf_access_token.Rd +8c05334b675ac567c5f0a254ed11d4b5 *man/sf_auth.Rd +9ed63f9f51d12a9ddefb175d1cd6c180 *man/sf_auth_check.Rd +43965861493a9811a8f0251412ffff14 *man/sf_auth_refresh.Rd +34fc1b6fd9b54e681cdce281e1ab5106 *man/sf_batch_details_bulk.Rd +4aa3beb674ccd3e6dac941dec0529cd7 *man/sf_batch_status_bulk.Rd +b80f9e14aea4764c2fcb6834cf63249c *man/sf_bulk_operation.Rd +da2ecfd3ef28d787b0a12b97bb7f46e9 *man/sf_close_job_bulk.Rd +150c7bbea50eb425f09fb50551591fd4 *man/sf_create.Rd +7d4ea162e3a09d6db04def9e994970b9 *man/sf_create_batches_bulk.Rd +adec3e198fb53703e7863570a79ea819 *man/sf_create_bulk_v1.Rd +7b896011fcf8f305cf0c0cc511dd2f0b *man/sf_create_bulk_v2.Rd +28b60857f727a09bd1df68e65b56f54d *man/sf_create_job_bulk.Rd +7930cddc46630becb9450fac24439e77 *man/sf_create_job_bulk_v1.Rd +5d6df6ef5ee4b2b3ae4113a813bf8124 *man/sf_create_job_bulk_v2.Rd +63e031ccb1637e6039732a17a0372f42 *man/sf_create_metadata.Rd +02d3b8f99a42c5627b7c1e8a4e818857 *man/sf_create_rest.Rd +5988c0e19f2738e9d1ad8a8b01c7ea5b *man/sf_create_soap.Rd +e7060c61184b7a02edacc081c29ac242 *man/sf_delete.Rd +a80ea03dd4828b16b7fc56691c651e29 *man/sf_delete_job_bulk.Rd +7431437c2c5c4b7629bd2b1ec22e9186 *man/sf_delete_metadata.Rd +475c86d2e03d45550e0dceb25433df49 *man/sf_describe_metadata.Rd +5c7009f35f71ee67510963c399d40332 *man/sf_describe_objects.Rd +fac776c9da27a92915414b122642de4f *man/sf_end_job_bulk.Rd +c324f9752ace31da458790f2c0e6993a *man/sf_get_job_bulk.Rd +c0d2a0b948bb546b447ced52d33f3dbd *man/sf_get_job_records_bulk.Rd +40c687c82963cf2bb68f91dcdb491f30 *man/sf_input_data_validation.Rd +276956e450f0bee21f7d6708a6b9a8ef *man/sf_job_batches_bulk.Rd +98822c782d5bfc367f7e801f7cce9060 *man/sf_list_api_limits.Rd +de70bace50f6560d7258d38e72c20011 *man/sf_list_metadata.Rd +6c9e9544352d45170f62d6794664651f *man/sf_list_objects.Rd +3775807f10c611bb18bff90ce5562645 *man/sf_list_resources.Rd +ad40677f8d842736d7fa20d0bd2b8914 *man/sf_list_rest_api_versions.Rd +19fcce53b657d2ae546fc12e5cb49949 *man/sf_query.Rd +ff817a89672783df9cb5d138efd1de86 *man/sf_query_bulk.Rd +ce9170b8570011125a6c0b0d32d97bd4 *man/sf_query_result_bulk.Rd +9bf25faeace02db3b65ecaa739d3b209 *man/sf_read_metadata.Rd +c3b2b6054cb248e240e2013bd9043e76 *man/sf_rename_metadata.Rd +e1b64ad9c23a0ee83c4133f46dcf24b0 *man/sf_retrieve.Rd +ba29f4047c66df888b0bc3880b06856a *man/sf_retrieve_metadata.Rd +d82255a4fb6e8acff9831a0023ac6bb8 *man/sf_retrieve_metadata_check_status.Rd +57bf368cdb539510062cc3c57cd9aa92 *man/sf_search.Rd +4fb41a218b2a5016325cd607bf99e06a *man/sf_server_timestamp.Rd +543d3cd2789a19b1af520066ae9988ee *man/sf_session_id.Rd +9ba5100e3260c9bd3c41a1fb1018ca12 *man/sf_submit_query_bulk.Rd +8f25f888f86e1f2595468bbf56a9786a *man/sf_update.Rd +e1a6516f470327f361b4075bc7a1f0d4 *man/sf_update_bulk_v1.Rd +c52f273262d98f7a3cf8ae2761bc1182 *man/sf_update_bulk_v2.Rd +f82e07e3ad72f9925dfd023616626a07 *man/sf_update_metadata.Rd +223e6bc9ba383fc538d4f95a1c9411a4 *man/sf_update_rest.Rd +f43aded4c7e91a8be8415b7cab74210e *man/sf_update_soap.Rd +9e429363d782fa19635868a3da0e523f *man/sf_upload_complete_bulk.Rd +67abc36dba72fba99170075eb13aeeda *man/sf_upsert.Rd +d3e6603fa310d9db8c382655148047ac *man/sf_upsert_bulk_v1.Rd +70f0e1c23fe8ea17a820c014975b9c6b *man/sf_upsert_bulk_v2.Rd +14ec62ab279b0651828ef4645e5f2a88 *man/sf_upsert_metadata.Rd +d2c044d4fb32389822eefe05dac7c408 *man/sf_upsert_rest.Rd +0becde61f75efaf5409fd2c7296127a0 *man/sf_upsert_soap.Rd +c29adf2e2893526b57116f08c6e4189f *man/sf_user_info.Rd +c2697af2a73edd46dcbf45ed21508d65 *man/sf_write_csv.Rd +dd6242ee5f3ddb3153e99d21f89f8782 *man/token_available.Rd +8c6aaaad0aa595b89c02860872492c41 *man/valid_metadata_list.Rd +c98d8a95b3a1f5cd501b2672b4b3b227 *man/xmlToList2.Rd +579dd6386385ea98d5cb55aa3cbe83b5 *man/xml_nodeset_to_df.Rd +bc1c59c1e6eebb5d2c9d3154b8913c4a *tests/testthat.R +2cd8853fd97661aff6f497cae856f044 *tests/testthat/salesforcer.tar +887cea5da98699b944218d5014c88e5a *tests/testthat/salesforcer_test_settings.rds +f074069a10a0cafdd722d458dc06d764 *tests/testthat/salesforcer_token.rds +3f4503276e29dfc752b8e38f62be91d2 *tests/testthat/test-auth.R +86c8b7fc45e9d49db5ca7b523b1ba741 *tests/testthat/test-bulk.R +5efd168970e04bcebeab125a512434d7 *tests/testthat/test-compatibility.R +e9e2db5a625df2f189febe52f5aec418 *tests/testthat/test-describe.R +3ede115cb1b5a7f1cc7eda70d78c3cf5 *tests/testthat/test-metadata.R +f8db58a5b82a2f9113dba2d08eddc93d *tests/testthat/test-org-utils.R +382833f21f055309de020aebe8cdd08a *tests/testthat/test-rest.R +4d45c7868c3dbabc6aab27c2c0302d65 *tests/testthat/test-search.R +7dfb7a5eb4010badeda3231d9a3d30a2 *tests/testthat/test-soap.R +5bd6ba6dbf8cd7560806f61ab6a84205 *tests/testthat/test-utils.R +9a4a34fb87e9c321d21b638de6df7e82 *vignettes/getting-started.Rmd +2bc9a3303db88713d0e6b6fd011a9cbc *vignettes/transitioning-from-RForcecom.Rmd +3511f9cab937f92aad664b1f5dc744bf *vignettes/working-with-bulk-api.Rmd diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..f517d6b --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,174 @@ +# Generated by roxygen2: do not edit by hand + +export(VERB_n) +export(build_soap_xml_from_list) +export(catch_errors) +export(get_os) +export(make_base_metadata_url) +export(make_base_rest_url) +export(make_base_soap_url) +export(make_bulk_batch_details_url) +export(make_bulk_batch_status_url) +export(make_bulk_batches_url) +export(make_bulk_create_job_url) +export(make_bulk_delete_job_url) +export(make_bulk_end_job_generic_url) +export(make_bulk_get_job_url) +export(make_bulk_job_records_url) +export(make_bulk_query_result_url) +export(make_bulk_query_url) +export(make_chatter_users_url) +export(make_composite_batch_url) +export(make_composite_url) +export(make_describe_objects_url) +export(make_login_url) +export(make_parameterized_search_url) +export(make_query_url) +export(make_search_url) +export(make_soap_xml_skeleton) +export(metadata_type_validator) +export(parameterized_search_control) +export(rDELETE) +export(rGET) +export(rPATCH) +export(rPOST) +export(rPUT) +export(rforcecom.bulkAction) +export(rforcecom.bulkQuery) +export(rforcecom.create) +export(rforcecom.delete) +export(rforcecom.getServerTimestamp) +export(rforcecom.login) +export(rforcecom.query) +export(rforcecom.retrieve) +export(rforcecom.search) +export(rforcecom.update) +export(rforcecom.upsert) +export(salesforcer_state) +export(session_id_available) +export(sf_abort_job_bulk) +export(sf_access_token) +export(sf_auth) +export(sf_auth_check) +export(sf_auth_refresh) +export(sf_batch_details_bulk) +export(sf_batch_status_bulk) +export(sf_bulk_operation) +export(sf_close_job_bulk) +export(sf_create) +export(sf_create_batches_bulk) +export(sf_create_job_bulk) +export(sf_create_metadata) +export(sf_delete) +export(sf_delete_job_bulk) +export(sf_delete_metadata) +export(sf_describe_metadata) +export(sf_describe_objects) +export(sf_end_job_bulk) +export(sf_get_job_bulk) +export(sf_get_job_records_bulk) +export(sf_input_data_validation) +export(sf_job_batches_bulk) +export(sf_list_api_limits) +export(sf_list_metadata) +export(sf_list_objects) +export(sf_list_resources) +export(sf_list_rest_api_versions) +export(sf_query) +export(sf_query_bulk) +export(sf_query_result_bulk) +export(sf_read_metadata) +export(sf_rename_metadata) +export(sf_retrieve) +export(sf_retrieve_metadata) +export(sf_retrieve_metadata_check_status) +export(sf_search) +export(sf_server_timestamp) +export(sf_session_id) +export(sf_submit_query_bulk) +export(sf_update) +export(sf_update_metadata) +export(sf_upload_complete_bulk) +export(sf_upsert) +export(sf_upsert_metadata) +export(sf_user_info) +export(sf_write_csv) +export(token_available) +export(valid_metadata_list) +export(xmlToList2) +export(xml_nodeset_to_df) +importFrom(XML,"xmlValue<-") +importFrom(XML,addChildren) +importFrom(XML,newXMLNode) +importFrom(XML,xmlApply) +importFrom(XML,xmlAttrs) +importFrom(XML,xmlChildren) +importFrom(XML,xmlInternalTreeParse) +importFrom(XML,xmlParse) +importFrom(XML,xmlRoot) +importFrom(XML,xmlSApply) +importFrom(XML,xmlSize) +importFrom(XML,xmlToList) +importFrom(XML,xmlValue) +importFrom(dplyr,"%>%") +importFrom(dplyr,as_tibble) +importFrom(dplyr,bind_rows) +importFrom(dplyr,contains) +importFrom(dplyr,everything) +importFrom(dplyr,filter) +importFrom(dplyr,funs) +importFrom(dplyr,matches) +importFrom(dplyr,mutate) +importFrom(dplyr,rename) +importFrom(dplyr,rename_at) +importFrom(dplyr,select) +importFrom(dplyr,select_) +importFrom(dplyr,starts_with) +importFrom(dplyr,tibble) +importFrom(dplyr,vars) +importFrom(httr,DELETE) +importFrom(httr,GET) +importFrom(httr,PATCH) +importFrom(httr,POST) +importFrom(httr,PUT) +importFrom(httr,add_headers) +importFrom(httr,build_url) +importFrom(httr,config) +importFrom(httr,content) +importFrom(httr,headers) +importFrom(httr,http_error) +importFrom(httr,oauth2.0_token) +importFrom(httr,oauth_app) +importFrom(httr,oauth_endpoint) +importFrom(httr,parse_url) +importFrom(httr,status_code) +importFrom(httr,upload_file) +importFrom(jsonlite,base64_dec) +importFrom(jsonlite,fromJSON) +importFrom(jsonlite,toJSON) +importFrom(lubridate,dmy_hms) +importFrom(methods,as) +importFrom(purrr,map) +importFrom(purrr,map_df) +importFrom(purrr,map_dfc) +importFrom(readr,cols) +importFrom(readr,read_csv) +importFrom(readr,type_convert) +importFrom(readr,write_csv) +importFrom(stats,quantile) +importFrom(stats,runif) +importFrom(utils,capture.output) +importFrom(utils,head) +importFrom(utils,object.size) +importFrom(xml2,as_list) +importFrom(xml2,read_xml) +importFrom(xml2,url_escape) +importFrom(xml2,xml_add_child) +importFrom(xml2,xml_add_sibling) +importFrom(xml2,xml_child) +importFrom(xml2,xml_find_all) +importFrom(xml2,xml_find_first) +importFrom(xml2,xml_new_document) +importFrom(xml2,xml_ns_strip) +importFrom(xml2,xml_set_namespace) +importFrom(xml2,xml_text) diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..593e321 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,78 @@ +## salesforcer 0.1.2 + +### Features + + * Add support for Bulk 1.0 operations of "create", "update", "upsert", "delete" and "hardDelete" + * Bulk 2.0 operations, by default, now return a single `tbl_df` containing all + of the successful records, error records, and unprocessed records + * Created internal functions that explicity call each API for an operation. For + example, `sf_create()` routes into `sf_create_soap()`, `sf_create_rest()`, and + `sf_bulk_operation()`. + +--- + +## salesforcer 0.1.1 [release](https://github.com/StevenMMortimer/salesforcer/releases/tag/v0.1.1) + +### Features + + * Add `sf_search()` with REST and SOAP API support for SOSL and free text search + * Add `sf_describe_objects()` with REST and SOAP API to return object metadata + * Add REST API support for upsert (`sf_upsert()`) + * Add SOAP API support for the following operations: + * `sf_create()` + * `sf_update()` + * `sf_delete()` + * `sf_retrieve()` + * Add Metadata API support for the following operations: + * `sf_create_metadata()` + * `sf_read_metadata()` + * `sf_update_metadata()` + * `sf_upsert_metadata()` + * `sf_delete_metadata()` + * `sf_describe_metadata()` + * `sf_list_metadata()` + * `sf_rename_metadata()` + * `sf_retrieve_metdata()` + * `sf_deploy_metdata()` + * Make the default file name for a cached token `.httr-oauth-salesforcer` so that + it does not clash with other package token names + +### Bug Fixes + + * `sf_user_info()` returning `argument is of length zero` because token is not +automatically refreshed before calling GET + + * `sf_token()` ignoring basic auth'ed sessions since it was only looking for a token +using `token_avaiable()`. Replace with `sf_auth_check()` so now it considers a +session or a token to be "available" (#1). + +--- + +## salesforcer 0.1.0 [release](https://github.com/StevenMMortimer/salesforcer/releases/tag/v0.1.0) + +### Features + + * OAuth 2.0 and Basic authentication methods (`sf_auth()`) + * Query operations via REST and Bulk APIs (`sf_query()`) + * CRUD operations (Create, Retrieve, Update, Delete) for REST and Bulk APIs: + * `sf_create()` + * `sf_retrieve()` + * `sf_update()` + * `sf_upsert()` + * `sf_delete()` + * Backwards compatibile versions of **RForcecom** package functions: + * `rforcecom.login()` + * `rforcecom.getServerTimestamp()` + * `rforcecom.query()` + * `rforcecom.bulkQuery()` + * `rforcecom.create()` + * `rforcecom.update()` + * `rforcecom.upsert()` + * `rforcecom.delete()` + * Basic utility calls: + * `sf_user_info()` + * `sf_server_timestamp()` + * `sf_list_rest_api_versions()` + * `sf_list_resources()` + * `sf_list_api_limits()` + * `sf_list_objects()` diff --git a/R/auth.R b/R/auth.R new file mode 100644 index 0000000..1b0dae7 --- /dev/null +++ b/R/auth.R @@ -0,0 +1,353 @@ +# Adapted from googlesheets package https://github.com/jennybc/googlesheets + +# Modifications: +# - Changed the scopes and authentication endpoints +# - Renamed the function gs_auth to sf_auth to be consistent with package +# and added basic authentication handling +# - Added basic authentication session handling functions + +# Copyright (c) 2017 Jennifer Bryan, Joanna Zhao +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# environment to store credentials +.state <- new.env(parent = emptyenv()) + +#' Log in to Salesforce +#' +#' Log in using Basic (Username-Password) or OAuth 2.0 authenticaion. OAuth does +#' not require sharing passwords, but will require authorizing \code{salesforcer} +#' as a connected app to view and manage your organization. You will be directed to +#' a web browser, asked to sign in to your Salesforce account, and to grant \code{salesforcer} +#' permission to operate on your behalf. By default, these user credentials are +#' cached in a file named \code{.httr-oauth-salesforcer} in the current working directory. +#' +#' @importFrom httr content oauth2.0_token oauth_app oauth_endpoint +#' @importFrom xml2 xml_new_document xml_add_child xml_add_sibling xml_set_namespace xml_find_first xml_child +#' @param username Salesforce username, typically an email address +#' @param password Salesforce password +#' @param security_token Salesforce security token. Note: A new security token is +#' generated whenever your password is changed. +#' @param login_url a custom login url; defaults to https://login.salesforce.com +#' @param token optional; an actual token object or the path to a valid token +#' stored as an \code{.rds} file +#' @param consumer_key,consumer_secret,callback_url the "Consumer Key","Consumer Secret", +#' and "Callback URL" when using a connected app; defaults to the \code{salesforcer} +#' connected apps' consumer key, secret, and callback url +#' @param cache logical or character; TRUE means to cache using the default cache +#' file \code{.httr-oauth-salesforcer}, FALSE means don't cache. A string means use +#' the specified path as the cache file. +#' @template verbose +#' @examples +#' \dontrun{ +#' # log in using basic authentication (username-password) +#' sf_auth(username = "test@gmail.com", +#' password = "test_password", +#' security_token = ) +#' +#' # log in using OAuth 2.0 +#' # Via brower or refresh of .httr-oauth-salesforcer +#' sf_auth() +#' +#' # Save token and log in using it +#' saveRDS(.state$token, "token.rds") +#' sf_auth(token = "token.rds") +#' } +#' @export +sf_auth <- function(username = NULL, + password = NULL, + security_token = NULL, + login_url = getOption("salesforcer.login_url"), + token = NULL, + consumer_key = getOption("salesforcer.consumer_key"), + consumer_secret = getOption("salesforcer.consumer_secret"), + callback_url = getOption("salesforcer.callback_url"), + cache = getOption("salesforcer.httr_oauth_cache"), + verbose = FALSE){ + + if(!is.null(username) & !is.null(password) & !is.null(security_token)){ + + # basic authentication (username-password) ------------------------------------- + body <- xml_new_document() + + # build the xml request for the SOAP API + body %>% + xml_add_child("Envelope", + "xmlns:soapenv" = "http://schemas.xmlsoap.org/soap/envelope/", + "xmlns:xsi" = "http://www.w3.org/2001/XMLSchema-instance", + "xmlns:urn" = "urn:partner.soap.sforce.com") %>% + xml_set_namespace("soapenv") %>% + xml_add_child("Body") %>% + xml_set_namespace("soapenv") %>% + xml_add_child("login") %>% + xml_set_namespace("urn") %>% + xml_add_child("username", username) %>% + xml_add_sibling("password", paste0(password, security_token)) + + # POST the data using httr package and handle response + httr_response <- rPOST(url = make_login_url(login_url), + headers = c("SOAPAction"="login", "Content-Type"="text/xml"), + body = as.character(body)) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + + # parse the response information + login_reponse <- response_parsed %>% + xml_find_first('.//soapenv:Body') %>% + xml_child() %>% + as_list() + + # set the global .state variable + .state$auth_method <- "Basic" + .state$token = NULL + .state$session_id <- login_reponse$result$sessionId[[1]][1] + .state$instance_url <- gsub('(https://[^/]+)/.*', '\\1', login_reponse$result$serverUrl) + } else { + + # OAuth2.0 authentication + if (is.null(token)) { + + sf_oauth_app <- oauth_app("salesforce", + key = consumer_key, + secret = consumer_secret, + redirect_uri = callback_url) + + sf_oauth_endpoints <- oauth_endpoint(request = NULL, + base_url = "https://login.salesforce.com/services/oauth2", + authorize = "authorize", access = "token", revoke = "revoke") + + sf_token <- oauth2.0_token(endpoint = sf_oauth_endpoints, + app = sf_oauth_app, + cache = cache) + + stopifnot(is_legit_token(sf_token, verbose = TRUE)) + + # set the global .state variable + .state$auth_method <- "OAuth" + .state$token <- sf_token + .state$session_id <- NULL + .state$instance_url <- sf_token$credentials$instance_url + + } else if (inherits(token, "Token2.0")) { + + # accept token from environment ------------------------------------------------ + stopifnot(is_legit_token(token, verbose = TRUE)) + + # set the global .state variable + .state$auth_method <- "OAuth" + .state$token <- token + .state$session_id <- NULL + .state$instance_url <- token$credentials$instance_url + + } else if (inherits(token, "character")) { + + # accept token from file ------------------------------------------------------- + sf_token <- try(suppressWarnings(readRDS(token)), silent = TRUE) + + if (inherits(sf_token, "try-error")) { + spf("Cannot read token from alleged .rds file:\n%s", token) + } else if (!is_legit_token(sf_token, verbose = TRUE)) { + spf("File does not contain a proper token:\n%s", token) + } + + # set the global .state variable + .state$auth_method <- "OAuth" + .state$token <- sf_token + .state$session_id <- NULL + .state$instance_url <- sf_token$credentials$instance_url + + } else { + spf("Input provided via 'token' is neither a", + "token,\nnor a path to an .rds file containing a token.") + } + } + + invisible(list(auth_method=.state$auth_method, + token=.state$token, + session_id=.state$session_id, + instance_url=.state$instance_url)) +} + +#' Check that token appears to be legitimate +#' +#' @keywords internal +is_legit_token <- function(x, verbose = FALSE) { + + if (!inherits(x, "Token2.0")) { + if (verbose) message("Not a Token2.0 object.") + return(FALSE) + } + + if ("invalid_client" %in% unlist(x$credentials)) { + if (verbose) { + message("Authorization error. Please check client_id and client_secret.") + } + return(FALSE) + } + + if ("invalid_request" %in% unlist(x$credentials)) { + if (verbose) message("Authorization error. No access token obtained.") + return(FALSE) + } + + TRUE + +} + +#' Check that an Authorized Salesforce Session Exists +#' +#' Before the user makes any calls requiring an authorized session, check if an +#' OAuth token or session is not already available, call \code{\link{sf_auth}} to +#' by default initiate the OAuth 2.0 workflow that will load a token from cache or +#' launch browser flow. Return the bare token. Use +#' \code{access_token()} to reveal the actual access token, suitable for use +#' with \code{curl}. +#' +#' @template verbose +#' @return a \code{Token2.0} object (an S3 class provided by \code{httr}) or a +#' a character string of the sessionId element of the current authorized +#' API session +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_auth_check <- function(verbose = FALSE) { + if (!token_available(verbose) & !session_id_available(verbose)) { + # not auth'ed at all before a call that requires auth, so + # start up the OAuth 2.0 workflow that should work seamlessly + # if a cached file exists + sf_auth(verbose = verbose) + res <- .state$token + } else if(token_available(verbose)) { + issued_timestamp <- as.numeric(substr(.state$token$credentials$issued_at, 1, 10)) + nows_timestamp <- as.numeric(Sys.time()) + time_diff_in_sec <- nows_timestamp - issued_timestamp + if(time_diff_in_sec > 3600){ + # the token is probably expired even though we have it so refresh + # TODO: must be better way to validate the token. + sf_auth_refresh(verbose = verbose) + } + res <- .state$token + } else if(session_id_available(verbose)) { + res <- .state$session_id + } else { + # somehow we've got a token and session id, just return the token + res <- .state$token + } + invisible(res) +} + +#' Refresh an existing Authorized Salesforce Token +#' +#' Force the current OAuth to refresh. This is only needed for times when you +#' load the token from outside the current working directory, it is expired, and +#' you're running in non-interactive mode. +#' +#' @template verbose +#' @return a \code{Token2.0} object (an S3 class provided by \code{httr}) or a +#' a character string of the sessionId element of the current authorized +#' API session +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_auth_refresh <- function(verbose = FALSE) { + if(token_available(verbose)){ + .state$token <- .state$token$refresh() + } else { + message("No token found. sf_auth_refresh() only refreshes OAuth tokens") + } + invisible(.state$token) +} + +#' Check session_id availability +#' +#' Check if a session_id is available in \code{\link{salesforcer}}'s internal +#' \code{.state} environment. +#' +#' @return logical +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +session_id_available <- function(verbose = TRUE) { + if (is.null(.state$session_id)) { + if (verbose) { + message("The session_id is NULL in salesforcer's internal .state environment. ", + "This can occur if the user is authorized using OAuth 2.0, which doesn't ", + "require a session_id, or the user is not yet performed any authorization ", + "routine.\n", + "When/if needed, 'salesforcer' will initiate authentication ", + "and authorization.\nOr run sf_auth() to trigger this explicitly.") + } + return(FALSE) + } + TRUE +} + +#' Check token availability +#' +#' Check if a token is available in \code{\link{salesforcer}}'s internal +#' \code{.state} environment. +#' +#' @return logical +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +token_available <- function(verbose = TRUE) { + if (is.null(.state$token)) { + if (verbose) { + if (file.exists(".httr-oauth-salesforcer")) { + message("A '.httr-oauth-salesforcer' file exists in current working ", + "directory.\nWhen/if needed, the credentials cached in ", + "'.httr-oauth-salesforcer' will be used for this session.\nOr run sf_auth() ", + "for explicit authentication and authorization.") + } else { + message("No '.httr-oauth-salesforcer' file exists in current working directory.\n", + "When/if needed, salesforcer will initiate authentication ", + "and authorization.\nOr run sf_auth() to trigger this explicitly.") + } + } + return(FALSE) + } + TRUE +} + +#' Return access_token attribute of OAuth 2.0 Token +#' +#' @template verbose +#' @return character; a string of the access_token element of the current token in +#' force; otherwise NULL +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_access_token <- function(verbose = FALSE) { + if (!token_available(verbose = verbose)) return(NULL) + .state$token$credentials$access_token +} + +#' Return session_id resulting from Basic auth routine +#' +#' @template verbose +#' @return character; a string of the sessionId element of the current authorized +#' API session; otherwise NULL +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_session_id <- function(verbose = TRUE) { + if (!session_id_available(verbose = verbose)) return(NULL) + .state$session_id +} \ No newline at end of file diff --git a/R/bulk-operation.R b/R/bulk-operation.R new file mode 100644 index 0000000..2ac7b3c --- /dev/null +++ b/R/bulk-operation.R @@ -0,0 +1,890 @@ +#' Create Bulk API Job +#' +#' This function initializes a Job in the Salesforce Bulk API +#' +#' @template operation +#' @template object_name +#' @template external_id_fieldname +#' @template api_type +#' @param content_type character; being one of 'CSV', 'ZIP_CSV', 'ZIP_XML', or 'ZIP_JSON' to +#' indicate the type of data being passed to the Bulk API +#' @param concurrency_mode character; either "Parallel" or "Serial" that specifies whether batches should be completed +#' sequentially or in parallel. Use "Serial" only if Lock contentions persist with in "Parallel" mode. +#' @param line_ending character; indicating the The line ending used for CSV job data, +#' marking the end of a data row. The default is NULL and determined by the operating system using +#' "CRLF" for Windows machines and "LF" for Unix machines +#' @param column_delimiter character; indicating the column delimiter used for CSV job data. +#' The default value is COMMA. Valid values are: "BACKQUOTE", "CARET", "COMMA", "PIPE", +#' "SEMICOLON", and "TAB". +#' @template verbose +#' @return A \code{tbl_df} parameters defining the created job, including id +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' # insert into Account +#' job_info <- sf_create_job_bulk(operation='insert', object_name='Account') +#' +#' # delete from Account +#' job_info <- sf_create_job_bulk(operation='delete', object_name='Account') +#' +#' # update into Account +#' job_info <- sf_create_job_bulk(operation='update', object_name='Account') +#' +#' # upsert into Account +#' job_info <- sf_create_job_bulk(operation='upsert', +#' externalIdFieldName='My_External_Id__c', +#' object_name='Account') +#' # insert attachments +#' job_info <- sf_create_job_bulk(operation='insert', object_name='Attachment') +#' +#' # query leads +#' job_info <- sf_create_job_bulk(operation='query', object_name='Lead') +#' } +#' @export +sf_create_job_bulk <- function(operation = c("insert", "delete", "upsert", "update", + "hardDelete", "query"), + object_name, + external_id_fieldname = NULL, + api_type = c("Bulk 1.0", "Bulk 2.0"), + content_type=c('CSV', 'ZIP_CSV', 'ZIP_XML', 'ZIP_JSON'), + concurrency_mode=c("Parallel", "Serial"), + line_ending = NULL, + column_delimiter = c('COMMA', 'TAB', 'PIPE', 'SEMICOLON', + 'CARET', 'BACKQUOTE'), + verbose=FALSE){ + + api_type <- match.arg(api_type) + operation <- match.arg(operation) + content_type <- match.arg(content_type) + if(api_type == "Bulk 1.0"){ + job_response <- sf_create_job_bulk_v1(operation=operation, + object_name=object_name, + external_id_fieldname=external_id_fieldname, + content_type=content_type, + concurrency_mode=concurrency_mode, + verbose=verbose) + } else if(api_type == "Bulk 2.0"){ + if(!(operation %in% c("insert", "delete", "upsert", "update"))){ + stop('Bulk 2.0 only supports the following operations: "insert", "delete", "upsert", and "update"') + } + if(!(content_type %in% c("CSV"))){ + stop('Bulk 2.0 only supports the "CSV" content type.') + } + job_response <- sf_create_job_bulk_v2(operation=operation, + object_name=object_name, + external_id_fieldname=external_id_fieldname, + content_type=content_type, + line_ending=line_ending, + column_delimiter=column_delimiter, + verbose=verbose) + } else { + stop("Unknown API type") + } + return(job_response) +} + +#' Create Job using Bulk 1.0 API +#' +#' @importFrom xml2 xml_new_document xml_add_child xml_add_sibling +#' @importFrom httr content +#' @importFrom XML xmlToList +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_job_bulk_v1 <- function(operation = c("insert", "delete", "upsert", "update", + "hardDelete", "query"), + object_name, + external_id_fieldname=NULL, + content_type=c('CSV', 'ZIP_CSV', 'ZIP_XML', 'ZIP_JSON'), + concurrency_mode=c("Parallel", "Serial"), + verbose=FALSE){ + + operation <- match.arg(operation) + content_type <- match.arg(content_type) + concurrency_mode <- match.arg(concurrency_mode) + + # build xml for Bulk 1.0 request + body <- xml_new_document() + body %>% + xml_add_child("jobInfo", + "xmlns" = "http://www.force.com/2009/06/asyncapi/dataload") %>% + xml_add_child("operation", operation) %>% + xml_add_sibling("object", object_name) + + if(operation == "upsert"){ + stopifnot(!is.null(external_id_fieldname)) + body %>% + xml_add_child("externalIdFieldName", external_id_fieldname) + } + + body %>% + xml_add_child("concurrencyMode", concurrency_mode) %>% + xml_add_child("contentType", content_type) + + body <- as.character(body) + + bulk_create_job_url <- make_bulk_create_job_url(api_type="Bulk 1.0") + if (verbose){ + message(bulk_create_job_url) + message(body) + } + httr_response <- rPOST(url = bulk_create_job_url, + headers = c("Accept"="application/xml", + "Content-Type"="application/xml"), + body = body) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + job_info <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('//jobInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + return(job_info) +} + +#' Create Job using Bulk 2.0 API +#' +#' @importFrom xml2 xml_new_document xml_add_child xml_add_sibling +#' @importFrom httr content +#' @importFrom jsonlite toJSON +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_job_bulk_v2 <- function(operation = c("insert", "delete", "upsert", "update"), + object_name, + external_id_fieldname=NULL, + content_type = 'CSV', + line_ending = NULL, + column_delimiter = c('COMMA', 'TAB', 'PIPE', 'SEMICOLON', + 'CARET', 'BACKQUOTE'), + verbose=FALSE){ + + operation <- match.arg(operation) + content_type <- match.arg(content_type) + line_ending <- match.arg(line_ending) + column_delimiter <- match.arg(column_delimiter) + if(column_delimiter != "COMMA"){ + stop("column_delimiter = 'COMMA' is currently the only supported file delimiter") + } + + if(operation == 'upsert'){ + stopifnot(!is.null(external_id_fieldname)) + } + # form body from arguments + request_body <- list(operation = operation, + object = object_name, + contentType = content_type, + externalIdFieldName = external_id_fieldname, + lineEnding = line_ending, + columnDelimiter = column_delimiter) + request_body[sapply(request_body, is.null)] <- NULL + + if(is.null(line_ending)){ + if(get_os()=='windows'){ + request_body$lineEnding <- "CRLF" + } else { + request_body$lineEnding <- "LF" + } + } + stopifnot(request_body$lineEnding %in% c("LF", "CRLF")) + body <- toJSON(request_body, auto_unbox=TRUE, pretty=TRUE) + + bulk_create_job_url <- make_bulk_create_job_url(api_type="Bulk 2.0") + if (verbose){ + message(bulk_create_job_url) + message(body) + } + httr_response <- rPOST(url = bulk_create_job_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = body) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + job_info <- as_tibble(response_parsed) + return(job_info) +} + +#' Get Bulk API Job +#' +#' This function retrieves details about a Job in the Salesforce Bulk API +#' +#' +#' @template job_id +#' @template api_type +#' @template verbose +#' @return A \code{list} of parameters defining the details of the specified job id +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk('insert', 'Account') +#' refreshed_job_info <- sf_get_job_bulk(job_info$id) +#' sf_abort_job_bulk(refreshed_job_info$id) +#' } +#' @export +sf_get_job_bulk <- function(job_id, api_type=c("Bulk 1.0", "Bulk 2.0"), verbose=FALSE){ + api_type <- match.arg(api_type) + bulk_get_job_url <- make_bulk_get_job_url(job_id, api_type=api_type) + if(verbose){ + message(bulk_get_job_url) + } + httr_response <- rGET(url = bulk_get_job_url) + catch_errors(httr_response) + if(api_type == "Bulk 1.0"){ + response_parsed <- content(httr_response, encoding="UTF-8") + job_info <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('//jobInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + } else if(api_type == "Bulk 2.0"){ + response_parsed <- content(httr_response, encoding="UTF-8") + job_info <- as_tibble(response_parsed) + } else { + stop("Unknown API type") + } + return(job_info) +} + +#' End Bulk API Job +#' +#' @template job_id +#' @param end_type character; taking a value of "Closed" or "Aborted" indicating +#' how the bulk job should be ended +#' @template api_type +#' @template verbose +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_end_job_bulk <- function(job_id, + end_type = c("Closed", "UploadComplete", "Aborted"), + api_type = c("Bulk 1.0", "Bulk 2.0"), + verbose = FALSE){ + + end_type <- match.arg(end_type) + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0" & end_type == "Closed"){ + end_typ <- "UploadComplete" + } + request_body <- list(state=end_type) + bulk_end_job_url <- make_bulk_end_job_generic_url(job_id, api_type) + if (verbose){ + message(bulk_end_job_url) + } + if(api_type == "Bulk 2.0"){ + httr_response <- rPATCH(url = bulk_end_job_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = request_body, + encode = "json") + } else { + httr_response <- rPOST(url = bulk_end_job_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = request_body, + encode = "json") + } + catch_errors(httr_response) + return(TRUE) +} + +#' Close Bulk API Job +#' +#' This function closes a Job in the Salesforce Bulk API +#' +#' @template job_id +#' @template api_type +#' @template verbose +#' @return A \code{list} of parameters defining the now closed job +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note This is a legacy function used only with Bulk 1.0. +#' @examples +#' \dontrun{ +#' my_query <- "SELECT Id, Name FROM Account LIMIT 10" +#' job_info <- sf_create_job_bulk(operation='query', object='Account') +#' query_info <- sf_submit_query_bulk(job_id=job_info$id, soql=my_query) +#' recordset <- sf_query_result_bulk(job_id = query_info$jobId, +#' batch_id = query_info$id, +#' result_id = result$result) +#' sf_close_job_bulk(job_info$id) +#' } +#' @export +sf_close_job_bulk <- function(job_id, api_type=c("Bulk 1.0", "Bulk 2.0"), verbose = FALSE){ + api_type <- match.arg(api_type) + job_info <- sf_get_job_bulk(job_id, api_type = api_type, verbose = verbose) + sf_end_job_bulk(job_id, end_type = "Closed", api_type = api_type, verbose=verbose) +} + +#' Signal Upload Complete to Bulk API Job +#' +#' This function signals that uploads are complete to a Job in the Salesforce Bulk API +#' +#' @template job_id +#' @template api_type +#' @template verbose +#' @return A \code{list} of parameters defining the job after signaling a completed upload +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note This function is typically not used directly. It is used in \code{sf_create_batches_bulk()} +#' right after submitting the batches to signal to Salesforce that the batches should +#' no longer be queued. +#' @examples +#' \dontrun{ +#' upload_info <- sf_upload_complete_bulk(job_id=job_info$id) +#' } +#' @export +sf_upload_complete_bulk <- function(job_id, api_type=c("Bulk 2.0"), + verbose = FALSE){ + api_type <- match.arg(api_type) + sf_end_job_bulk(job_id, end_type = "UploadComplete", api_type = api_type, verbose=verbose) +} + +#' Abort Bulk API Job +#' +#' This function aborts a Job in the Salesforce Bulk API +#' +#' @template job_id +#' @template api_type +#' @template verbose +#' @return A \code{list} of parameters defining the now aborted job +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk('insert', 'Account') +#' sf_abort_job_bulk(job_info$id) +#' } +#' @export +sf_abort_job_bulk <- function(job_id, api_type=c("Bulk 2.0"), + verbose = FALSE){ + api_type <- match.arg(api_type) + sf_end_job_bulk(job_id, end_type = "Aborted", api_type = api_type, verbose=verbose) +} + +#' Delete Bulk API Job +#' +#' @template job_id +#' @template api_type +#' @template verbose +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk('insert', 'Account') +#' sf_abort_job_bulk(job_info$id) +#' sf_delete_job_bulk(job_info$id) +#' } +#' @export +sf_delete_job_bulk <- function(job_id, api_type=c("Bulk 2.0"), + verbose=FALSE){ + api_type <- match.arg(api_type) + bulk_delete_job_url <- make_bulk_delete_job_url(job_id, api_type=api_type) + if(verbose){ + message(bulk_delete_job_url) + } + httr_response <- rDELETE(url = bulk_delete_job_url) + catch_errors(httr_response) + return(TRUE) +} + +#' Add Batches to a Bulk API Job +#' +#' This function takes a data frame and submits it in batches to a +#' an already existing Bulk API Job by chunking into temp files +#' +#' @importFrom httr upload_file +#' @template job_id +#' @param input_data \code{named vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; data can be coerced into .csv file for submitting as batch request +#' @template api_type +#' @template verbose +#' @return a \code{tbl_df} containing details of each batch +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' # NOTE THAT YOU MUST FIRST CREATE AN EXTERNAL ID FIELD CALLED My_External_Id +#' # BEFORE RUNNING THIS EXAMPLE +#' # inserting 2 records +#' my_data <- tibble(Name=c('New Record 1', 'New Record 2'), +#' My_External_Id__c=c('11111','22222')) +#' job_info <- sf_create_job_bulk(operation='insert', +#' object='Account') +#' batches_ind <- sf_create_batches_bulk(job_id = job_info$id, +#' input_data = my_data) +#' # upserting 3 records +#' my_data2 <- tibble(My_External_Id__c=c('11111','22222', '99999'), +#' Name=c('Updated_Name1', 'Updated_Name2', 'Upserted_Record')) +#' job_info <- sf_create_job_bulk(operation='upsert', +#' externalIdFieldName='My_External_Id__c', +#' object='Account') +#' batches_ind <- sf_create_batches_bulk(job_id = job_info$id, +#' input_data = my_data2) +#' sf_get_job_bulk(job_info$id) +#' } +#' @export +sf_create_batches_bulk <- function(job_id, + input_data, + api_type=c("Bulk 1.0", "Bulk 2.0"), + verbose = FALSE){ + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + created_batches <- sf_create_batches_bulk_v1(job_id, input_data, verbose=verbose) + } else if(api_type == "Bulk 2.0"){ + created_batches <- sf_create_batches_bulk_v2(job_id, input_data, verbose=verbose) + } else { + stop("Unknown API type") + } + return(created_batches) +} + +#' @importFrom utils head +#' @importFrom stats quantile +sf_create_batches_bulk_v1 <- function(job_id, + input_data, + verbose = FALSE){ + + job_status <- sf_get_job_bulk(job_id, api_type="Bulk 1.0", + verbose = verbose) + stopifnot(job_status$state == "Open") + input_data <- sf_input_data_validation(operation=job_status$operation, + input_data) + + # Batch sizes should be adjusted based on processing times. Start with 5000 + # records and adjust the batch size based on processing time. If it takes more + # than five minutes to process a batch, it may be beneficial to reduce the batch size. + # If it takes a few seconds, the batch size should be increased. If you get a + # timeout error when processing a batch, split your batch into smaller batches, + # and try again. + # https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/asynch_api_batches_intro.htm + batch_size <- 5000 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + bulk_batches_url <- make_bulk_batches_url(job_id, api_type="Bulk 1.0") + if(verbose) { + message(bulk_batches_url) + } + batches_response <- list() + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + f <- tempfile() + sf_write_csv(batched_data, f) + httr_response <- rPOST(url = bulk_batches_url, + headers = c("Content-Type"="text/csv", + "Accept"="application/xml"), + body = upload_file(path=f, type="text/csv")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_batch_info <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('//batchInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + batches_response[[batch+1]] <- this_batch_info + } + batches_response <- bind_rows(batches_response) + return(batches_response) +} + +#' @importFrom utils object.size head +#' @importFrom stats quantile +sf_create_batches_bulk_v2 <- function(job_id, + input_data, + verbose=FALSE){ + + job_status <- sf_get_job_bulk(job_id, api_type="Bulk 2.0", + verbose = verbose) + input_data <- sf_input_data_validation(operation=job_status$operation, + input_data) + + # A request can provide CSV data that does not in total exceed 150 MB of base64 + # encoded content. When job data is uploaded, it is converted to base64. This + # conversion can increase the data size by approximately 50%. To account for + # the base64 conversion increase, upload data that does not exceed 100 MB. + # https://developer.salesforce.com/docs/atlas.en-us.api_bulk_v2.meta/api_bulk_v2/upload_job_data.htm + data_size <- object.size(input_data) + numb_batches <- ceiling((as.numeric(data_size)/(1024^2))/100) # 100MB / (size converted to MB) + batch_size <- ceiling(nrow(input_data) / numb_batches) + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + bulk_batches_url <- make_bulk_batches_url(job_id, api_type="Bulk 2.0") + if(verbose) { + message(bulk_batches_url) + } + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + f <- tempfile() + sf_write_csv(batched_data, f) + httr_response <- rPUT(url = bulk_batches_url, + headers = c("Content-Type"="text/csv", + "Accept"="application/json"), + body = upload_file(path=f, type="text/csv")) + catch_errors(httr_response) + } + # the batches will not start processing (move out of Queued state) until you signal "Upload Complete" + upload_details <- sf_upload_complete_bulk(job_id, verbose = verbose) + return(upload_details) +} + +#' Checking the Status of a Batch in a Bulk API Job +#' +#' This function checks on and returns status information on an existing batch +#' which has already been submitted to Bulk API Job +#' +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom readr type_convert cols +#' @template job_id +#' @template api_type +#' @template verbose +#' @return A \code{tbl_df} of parameters defining the batch identified by the batch_id +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note This is a legacy function used only with Bulk 1.0. +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk(operation = "query", object = "Account") +#' soql <- "SELECT Id, Name FROM Account LIMIT 10" +#' batch_query_info <- sf_submit_query_bulk(job_id = job_info$id, soql = soql) +#' submitted_batches <- sf_job_batches_bulk(job_id=batch_query_info$jobId) +#' job_close_ind <- sf_close_job_bulk(job_info$id) +#' sf_get_job_bulk(job_info$id) +#' } +#' @export +sf_job_batches_bulk <- function(job_id, api_type=c("Bulk 1.0"), verbose=FALSE){ + api_type <- match.arg(api_type) + bulk_batch_status_url <- make_bulk_batches_url(job_id, api_type=api_type) + if(verbose){ + message(bulk_batch_status_url) + } + httr_response <- rGET(url = bulk_batch_status_url) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//batchInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + return(resultset) +} + +#' Checking the Status of a Batch in a Bulk API Job +#' +#' This function checks on and returns status information on an existing batch +#' which has already been submitted to Bulk API Job +#' +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom readr type_convert cols +#' @template job_id +#' @template batch_id +#' @template api_type +#' @template verbose +#' @return A \code{tbl_df} of parameters defining the batch identified by the batch_id +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note This is a legacy function used only with Bulk 1.0. +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk(operation = "query", object = "Account") +#' soql <- "SELECT Id, Name FROM Account LIMIT 10" +#' batch_query_info <- sf_submit_query_bulk(job_id = job_info$id, soql = soql) +#' batch_status <- sf_batch_status_bulk(job_id=batch_query_info$jobId, +#' batch_id=batch_query_info$id) +#' job_close_ind <- sf_close_job_bulk(job_info$id) +#' sf_get_job_bulk(job_info$id) +#' } +#' @export +sf_batch_status_bulk <- function(job_id, batch_id, api_type=c("Bulk 1.0"), + verbose=FALSE){ + api_type <- match.arg(api_type) + bulk_batch_status_url <- make_bulk_batch_status_url(job_id, batch_id, api_type=api_type) + if(verbose){ + message(bulk_batch_status_url) + } + httr_response <- rGET(url = bulk_batch_status_url) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('//batchInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + return(resultset) +} + +#' Returning the Details of a Batch in a Bulk API Job +#' +#' This function returns detailed (row-by-row) information on an existing batch +#' which has already been submitted to Bulk API Job +#' +#' @importFrom readr read_csv +#' @importFrom httr content +#' @importFrom XML xmlToList +#' @importFrom dplyr as_tibble +#' @template job_id +#' @template batch_id +#' @template api_type +#' @template verbose +#' @return A \code{tbl_df}, formatted by salesforce, with information containing the success or failure or certain rows in a submitted batch, +#' unless the operation was query, then it is a data.frame containing the result_id for retrieving the recordset. +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note This is a legacy function used only with Bulk 1.0. +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk(operation = "query", object = "Account") +#' soql <- "SELECT Id, Name FROM Account LIMIT 10" +#' batch_query_info <- sf_submit_query_bulk(job_id = job_info$id, soql = soql) +#' batch_details <- sf_batch_details_bulk(job_id=batch_query_info$jobId, +#' batch_id=batch_query_info$id) +#' sf_close_job_bulk(job_info$id) +#' } +#' @export +sf_batch_details_bulk <- function(job_id, batch_id, api_type=c("Bulk 1.0"), + verbose = FALSE){ + api_type <- match.arg(api_type) + job_status <- sf_get_job_bulk(job_id, api_type=api_type, verbose=verbose) + bulk_batch_details_url <- make_bulk_batch_details_url(job_id, batch_id, api_type) + if(verbose){ + message(bulk_batch_details_url) + } + httr_response <- rGET(url = bulk_batch_details_url) + catch_errors(httr_response) + response_text <- content(httr_response, as="text", encoding="UTF-8") + + content_type <- httr_response$headers$`content-type` + if (grepl('xml', content_type)) { + res <- as_tibble(xmlToList(response_text)) + } else if(grepl('text/csv', content_type)) { + res <- read_csv(response_text) + } else { + message(sprintf("Unhandled content-type: %s", content_type)) + res <- content(httr_response, as="parsed", encoding="UTF-8") + } + return(res) +} + +#' Returning the Details of a Bulk API Job +#' +#' This function returns detailed (row-level) information on a job +#' which has already been submitted completed (successfully or not). +#' +#' @template job_id +#' @template api_type +#' @param record_types character; one or more types of records to retrieve from +#' the results of running the specified job +#' @param combine_record_types logical; indicating for Bulk 2.0 jobs whether the +#' successfulResults, failedResults, and unprocessedRecords should be stacked together +#' using \code{bind_rows} +#' @template verbose +#' @return A \code{tbl_df} or \code{list} of \code{tbl_df}, formatted by Salesforce, +#' with information containing the success or failure or certain rows in a submitted job +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note With Bulk 2.0 the order of records in the response is not guaranteed to +#' match the ordering of records in the original job data. +#' @examples +#' \dontrun{ +#' job_info <- sf_create_job_bulk('insert', 'Account') +#' input_data <- tibble(Name=c("Test Account 1", "Test Account 2")) +#' batches_result <- sf_create_batches_bulk(job_info$id, input_data) +#' # pause a few seconds for operation to finish. Wait longer if job is not complete. +#' Sys.sleep(3) +#' # check status using - sf_get_job_bulk(job_info$id) +#' job_record_details <- sf_get_job_records_bulk(job_id=job_info$id) +#' } +#' @export +sf_get_job_records_bulk <- function(job_id, + api_type = c("Bulk 1.0", "Bulk 2.0"), + record_types = c("successfulResults", + "failedResults", + "unprocessedRecords"), + combine_record_types=TRUE, + verbose=FALSE){ + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + batch_records <- sf_get_job_records_bulk_v1(job_id, verbose=verbose) + } else if(api_type == "Bulk 2.0"){ + batch_records <- sf_get_job_records_bulk_v2(job_id, + record_types=record_types, + combine_record_types=combine_record_types, + verbose=verbose) + + } else { + stop("Unknown API type") + } + return(batch_records) +} + +#' @importFrom dplyr bind_rows +sf_get_job_records_bulk_v1 <- function(job_id, verbose=FALSE){ + batches_info <- sf_job_batches_bulk(job_id, api_type="Bulk 1.0", verbose=verbose) + # loop through all the batches + resultset <- NULL + for(i in 1:nrow(batches_info)){ + this_batch_resultset <- sf_batch_details_bulk(job_id = job_id, + batch_id = batches_info$id[i], + api_type="Bulk 1.0", + verbose = verbose) + resultset <- bind_rows(resultset, this_batch_resultset) + } + return(resultset) +} + +#' @importFrom readr read_csv +#' @importFrom httr content +#' @importFrom dplyr bind_rows +sf_get_job_records_bulk_v2 <- function(job_id, + record_types = c("successfulResults", + "failedResults", + "unprocessedRecords"), + combine_record_types=TRUE, + verbose=FALSE){ + + record_types <- match.arg(record_types, several.ok = TRUE) + records <- list() + for(r in record_types){ + bulk_job_records_url <- make_bulk_job_records_url(job_id, record_type = r, api_type="Bulk 2.0") + if(verbose){ + message(bulk_job_records_url) + } + httr_response <- rGET(url = bulk_job_records_url) + catch_errors(httr_response) + response_text <- content(httr_response, as="text", encoding="UTF-8") + content_type <- httr_response$headers$`content-type` + if(grepl('text/csv', content_type)) { + res <- read_csv(response_text) + } else { + message(sprintf("Unhandled content-type: %s", content_type)) + res <- content(httr_response, as="parsed", encoding="UTF-8") + } + records[[r]] <- res + } + if(combine_record_types){ + res <- bind_rows(records) + } else { + res <- records + } + return(res) +} + +#' Run Bulk Operation +#' +#' This function is a convenience wrapper for submitting bulk API jobs +#' +#' @param input_data \code{named vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; data can be coerced into .csv file for submitting as batch request +#' @template object_name +#' @param operation character; string defining the type of operation being performed +#' @template external_id_fieldname +#' @template api_type +#' @param wait_for_results logical; indicating whether to wait for the operation to complete +#' so that the batch results of individual records can be obtained +#' @param interval_seconds integer; defines the seconds between attempts to check +#' for job completion +#' @param max_attempts integer; defines then max number attempts to check for job +#' completion before stopping +#' @template verbose +#' @return A \code{tbl_df} of the results of the bulk job +#' @note With Bulk 2.0 the order of records in the response is not guaranteed to +#' match the ordering of records in the original job data. +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' n <- 20 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact", 1:n)) +#' # insert new records into the Contact object +#' inserts <- sf_bulk_operation(input_data = new_contacts, +#' object_name = "Contact", +#' operation = "insert") +#' } +#' @export +sf_bulk_operation <- function(input_data, + object_name, + operation = c("insert", "delete", "upsert", + "update", "hardDelete"), + external_id_fieldname = NULL, + api_type = c("Bulk 1.0", "Bulk 2.0"), + wait_for_results = TRUE, + interval_seconds = 3, + max_attempts = 200, + verbose = FALSE){ + + stopifnot(!missing(operation)) + api_type <- match.arg(api_type) + + job_info <- sf_create_job_bulk(operation, object_name=object_name, + external_id_fieldname=external_id_fieldname, + api_type=api_type, verbose=verbose) + batches_info <- sf_create_batches_bulk(job_id = job_info$id, input_data, + api_type=api_type, verbose=verbose) + + if(wait_for_results){ + status_complete <- FALSE + z <- 1 + Sys.sleep(interval_seconds) + while (z < max_attempts & !status_complete){ + if (verbose){ + if(z %% 5 == 0){ + message(paste0("Attempt to retrieve records #", z)) + } + } + Sys.sleep(interval_seconds) + job_status <- sf_get_job_bulk(job_info$id, api_type=api_type, verbose=verbose) + if(api_type == "Bulk 1.0"){ + if(job_status$state == 'Failed' | job_status$state == 'Aborted'){ + stop(job_status$stateMessage) # what does this do if job is aborted? + } else { + # check that all batches have been completed before declaring the job done + job_batches <- sf_job_batches_bulk(job_info$id, api_type=api_type, verbose=verbose) + if(all(job_batches$state == "Completed")){ + status_complete <- TRUE + } else { + # continue checking the status until done or max attempts + z <- z + 1 + } + } + } else if(api_type == "Bulk 2.0"){ + if(job_status$state == 'Failed'){ + stop(job_status$errorMessage) + } else if(job_status$state == "JobComplete"){ + status_complete <- TRUE + } else { + # continue checking the status until done or max attempts + z <- z + 1 + } + } else { + stop("Unknown API type") + } + } + if (!status_complete) { + message("Function's Time Limit Exceeded. Aborting Job Now") + res <- sf_abort_job_bulk(job_info$id, api_type=api_type, verbose=verbose) + } else { + res <- sf_get_job_records_bulk(job_info$id, api_type=api_type, verbose=verbose) + # For Bulk 2.0 jobs -> INVALIDJOBSTATE: Closing already Completed Job not allowed + if(api_type == "Bulk 1.0"){ + close_job_info <- sf_close_job_bulk(job_info$id, api_type=api_type, verbose=verbose) + } + } + } else { + res <- job_info # at least return the job info if not waiting for records + } + return(res) +} diff --git a/R/bulk-query.R b/R/bulk-query.R new file mode 100644 index 0000000..0718f40 --- /dev/null +++ b/R/bulk-query.R @@ -0,0 +1,191 @@ +#' Submit Bulk Query Batch to a Bulk API Job +#' +#' This function takes a SOQL text string and submits the query to +#' an already existing Bulk API Job of operation "query" +#' +#' @importFrom httr upload_file content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom readr type_convert cols +#' @template job_id +#' @template soql +#' @template api_type +#' @template verbose +#' @return A \code{list} parameters of the batch +#' @note Bulk API query doesn't support the following SOQL: +#' \itemize{ +#' \item COUNT +#' \item ROLLUP +#' \item SUM +#' \item GROUP BY CUBE +#' \item OFFSET +#' \item Nested SOQL queries +#' \item Relationship fields +#' } +#' Additionally, Bulk API can't access or query compound address or compound geolocation fields. +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' my_query <- "SELECT Id, Name FROM Account LIMIT 10" +#' job_info <- sf_create_job_bulk(operation='query', object='Account') +#' query_info <- sf_submit_query_bulk(job_id=job_info$id, soql=my_query) +#' } +#' @export +sf_submit_query_bulk <- function(job_id, soql, + api_type=c("Bulk 1.0"), + verbose=FALSE){ + + api_type <- match.arg(api_type) + bulk_query_url <- make_bulk_query_url(job_id, api_type=api_type) + if(verbose){ + message(bulk_query_url) + } + f <- tempfile() + cat(soql, file=f) + httr_response <- rPOST(url = bulk_query_url, + headers = c("Content-Type"="text/csv; charset=UTF-8"), + body = upload_file(path=f, type='text/txt')) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('//batchInfo') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + return(resultset) +} + +#' Retrieving the Results of a Bulk Query Batch in a Bulk API Job +#' +#' This function returns the row-level recordset of a bulk query +#' which has already been submitted to Bulk API Job and has Completed state +#' +#' @importFrom readr read_csv +#' @importFrom httr content +#' @importFrom XML xmlToList +#' @importFrom dplyr as_tibble +#' @template job_id +#' @template batch_id +#' @param result_id a character string returned from \link{sf_batch_details_bulk} when a query has completed and specifies how to get the recordset +#' @template api_type +#' @template verbose +#' @return A \code{tbl_df}, formatted by salesforce, containing query results +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' my_query <- "SELECT Id, Name FROM Account LIMIT 10" +#' job_info <- sf_create_job_bulk(operation='query', object='Account') +#' query_info <- sf_submit_query_bulk(job_id=job_info$id, soql=my_query) +#' result <- sf_batch_details_bulk(job_id = query_info$jobId, +#' batch_id = query_info$id) +#' recordset <- sf_query_result_bulk(job_id = query_info$jobId, +#' batch_id = query_info$id, +#' result_id = result$result) +#' sf_close_job_bulk(job_info$id) +#' } +#' @export +sf_query_result_bulk <- function(job_id, batch_id, result_id, + api_type = c("Bulk 1.0"), + verbose = FALSE){ + + api_type <- match.arg(api_type) + bulk_query_result_url <- make_bulk_query_result_url(job_id, batch_id, result_id, api_type) + if(verbose){ + message(bulk_query_result_url) + } + httr_response <- rGET(url = bulk_query_result_url) + catch_errors(httr_response) + response_text <- content(httr_response, as="text", encoding="UTF-8") + + content_type <- httr_response$headers$`content-type` + if (grepl('xml', content_type)) { + res <- as_tibble(xmlToList(response_text)) + } else if(grepl('text/csv', content_type)) { + res <- read_csv(response_text) + } else { + message(sprintf("Unhandled content-type: %s", content_type)) + res <- content(httr_response, as="parsed", encoding="UTF-8") + } + return(res) +} + +#' Run Bulk Query +#' +#' This function is a convenience wrapper for submitting and retrieving +#' bulk query API jobs +#' +#' @template soql +#' @template object_name +#' @template api_type +#' @param interval_seconds integer; defines the seconds between attempts to check +#' for job completion +#' @param max_attempts integer; defines then max number attempts to check for job +#' completion before stopping +#' @template verbose +#' @return A \code{tbl_df} of the recordset returned by the query +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @examples +#' \dontrun{ +#' # select all Ids from Account object +#' ids <- sf_query_bulk(soql='SELECT Id FROM Account', object_name='Account') +#' } +#' @export +sf_query_bulk <- function(soql, + object_name, + api_type = c("Bulk 1.0"), + interval_seconds=5, + max_attempts=100, + verbose=FALSE){ + + # if(is.null(object_name)){ + # object_name <- gsub("(.*)from\\s+([A-Za-z_]+)\\b(.*)", "\\2", soql, ignore.case = TRUE, perl=TRUE) + # message(sprintf("Guessed target object_name from query string: %s", object_name)) + # } + api_type <- match.arg(api_type) + job_info <- sf_create_job_bulk(operation = "query", + object_name = object_name, + api_type = api_type, + verbose=verbose) + batch_query_info <- sf_submit_query_bulk(job_id = job_info$id, soql = soql, + api_type = api_type, + verbose=verbose) + status_complete <- FALSE + z <- 1 + Sys.sleep(interval_seconds) + while (z < max_attempts & !status_complete){ + if (verbose){ + message(paste0("Attempt #", z)) + } + Sys.sleep(interval_seconds) + batch_query_status <- sf_batch_status_bulk(job_id=batch_query_info$jobId, + batch_id=batch_query_info$id, + api_type = api_type, + verbose=verbose) + if(batch_query_status$state == 'Failed'){ + stop(batch_query_status$stateMessage) + } else if(batch_query_status$state == "Completed"){ + status_complete <- TRUE + } else { + # continue checking the status until done or max attempts + z <- z + 1 + } + } + if (!status_complete) { + message("Function's Time Limit Exceeded. Aborting Job Now") + res <- sf_abort_job_bulk(job_info$id, api_type=api_type, + verbose=verbose) + } else { + batch_query_details <- sf_batch_details_bulk(job_id = batch_query_info$jobId, + batch_id = batch_query_info$id, + api_type = api_type, + verbose = verbose) + res <- sf_query_result_bulk(job_id = batch_query_info$jobId, + batch_id = batch_query_info$id, + result_id = batch_query_details$result, + api_type = "Bulk 1.0", + verbose = verbose) + close_job_info <- sf_close_job_bulk(job_info$id, api_type = api_type, + verbose = verbose) + } + return(res) +} diff --git a/R/compatibility.R b/R/compatibility.R new file mode 100644 index 0000000..2f0cecc --- /dev/null +++ b/R/compatibility.R @@ -0,0 +1,318 @@ +# Adapted from RForcecom package https://github.com/hiratake55/RForcecom + +# Modifications: +# The function documentation and arguments are similar to RForcecom source code +# in order to provide users with a familiar, backwards compatible interface with +# the RForcecom library, but the function internals are original work that +# reference other functions in the salesforcer library + +# Copyright (c) 2012-2015 Takekatsu Hiramura +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#' salesforcer's backwards compatible version of rforcecom.login +#' +#' @param username Your username for login to the Salesforce.com. In many cases, username is your E-mail address. +#' @param password Your password for login to the Salesforce.com. Note: DO NOT FORGET your Security Token. (Ex.) If your password is "Pass1234" and your security token is "XYZXYZXYZXYZ", you should set "Pass1234XYZXYZXYZXYZ". +#' @param loginURL (optional) Login URL. If your environment is sandbox specify (ex:) "https://test.salesforce.com/". +#' @param apiVersion (optional) Version of the REST API and SOAP API that you want to use. (ex:) "35.0" Supported versions from v20.0 and up. +#' @return +#' \item{sessionID}{Session ID.} +#' \item{instanceURL}{Instance URL.} +#' \item{apiVersion}{API Version.} +#' @export +rforcecom.login <- function(username, password, loginURL="https://login.salesforce.com/", apiVersion="35.0"){ + + .Deprecated("sf_auth") + + if(!is.null(loginURL)){ + options(salesforcer.login_url = loginURL) + #message("Ignoring loginURL. If needed, set in options like so: options(salesforcer.login_url = \"https://login.salesforce.com\")") + } + if(!is.null(apiVersion)){ + options(salesforcer.api_version = apiVersion) + #message("Ignoring apiVersion. If needed, set in options like so: options(salesforcer.api_version = \"42.0\")") + } + + sf_auth(username=username, + password=password, + security_token = "") + + current_state <- salesforcer_state() + session <- c("sessionID" = current_state$session_id, + "instanceURL" = paste0(current_state$instance_url, "/"), + "apiVersion" = getOption("salesforcer.api_version")) + + return(unlist(session)) +} + +#' salesforcer's backwards compatible version of rforcecom.query +#' +#' @template session +#' @template soqlQuery +#' @param queryAll logical; indicating if the query recordset should include +#' deleted and archived records (available only when querying Task and Event records) +#' @return Result dataset. +#' @export +rforcecom.query <- function(session, soqlQuery, queryAll=FALSE){ + + .Deprecated("sf_query") + + sf_query(soql=soqlQuery, queryall=queryAll) +} + +#' salesforcer's backwards compatible version of rforcecom.bulkQuery +#' +#' @template session +#' @template soqlQuery +#' @param object character; the name of one Salesforce objects that the +#' function is operating against (e.g. "Account", "Contact", "CustomObject__c") +#' @param interval_seconds an integer defining the seconds between attempts to check for job completion +#' @param max_attempts an integer defining then max number attempts to check for job completion before stopping +#' @template verbose +#' @return A \code{data.frame} of the recordset returned by query +#' @export +rforcecom.bulkQuery <- function(session, + soqlQuery, + object, + interval_seconds=5, + max_attempts=100, + verbose=FALSE){ + + .Deprecated("sf_query") + + sf_query(soql = soqlQuery, + object_name = object, + api_type = "Bulk", + interval_seconds = 5, + max_attempts = 100) +} + +#' salesforcer's backwards compatible version of rforcecom.getServerTimestamp +#' +#' @template session +#' @export +rforcecom.getServerTimestamp <- function(session){ + .Deprecated("sf_server_timestamp") + result <- sf_server_timestamp() + # format like rforcecom.getServerTimestamp() + result <- as.POSIXlt(result, tz="GMT") + return(result) +} + +#' salesforcer's backwards compatible version of rforcecom.create +#' +#' @importFrom dplyr select mutate +#' @template session +#' @template objectName +#' @param fields Field names and values. (ex: Name="CompanyName", Phone="000-000-000" ) +#' @return \code{data.frame} containing the id and success indicator of the record creation process +#' @export +rforcecom.create <- function(session, objectName, fields){ + + .Deprecated("sf_create") + + fields <- as.data.frame(as.list(fields), stringsAsFactors = FALSE) + created_records <- sf_create(input_data=fields, object_name=objectName) + + result <- created_records %>% + select(id, success) %>% + mutate(id = factor(id), + success = factor(success)) %>% + as.data.frame() + + return(result) +} + +#' salesforcer's backwards compatible version of rforcecom.update +#' +#' @template session +#' @template objectName +#' @param id Record ID to update. (ex: "999x000000xxxxxZZZ") +#' @param fields Field names and values. (ex: Name="CompanyName", Phone="000-000-000" ) +#' @return \code{NULL} if successful otherwise the function errors out +#' @export +rforcecom.update <- function(session, objectName, id, fields){ + + .Deprecated("sf_update") + + fields <- as.data.frame(as.list(fields), stringsAsFactors = FALSE) + fields$id <- id + updated_records <- sf_update(fields, object_name=objectName) + + # rforcecom.update returns NULL if successful?? + return(NULL) +} + +#' salesforcer's backwards compatible version of rforcecom.delete +#' +#' @template session +#' @template objectName +#' @param id Record ID to delete. (ex: "999x000000xxxxxZZZ") +#' @return \code{NULL} if successful otherwise the function errors out +#' @export +rforcecom.delete <- function(session, objectName, id){ + + .Deprecated("sf_delete") + + deleted_records <- sf_delete(id, object_name=objectName) + + # rforcecom.delete returns NULL if successful?? + return(NULL) +} + +#' salesforcer's backwards compatible version of rforcecom.upsert +#' +#' @template session +#' @template objectName +#' @param externalIdField An external Key's field name. (ex: "AccountMaster__c") +#' @param externalId An external Key's ID. (ex: "999x000000xxxxxZZZ") +#' @param fields Field names and values. (ex: Name="CompanyName", Phone="000-000-000" ) +#' @return \code{NULL} if successful otherwise the function errors out +#' @export +rforcecom.upsert <- function(session, objectName, + externalIdField, externalId, + fields){ + + .Deprecated("sf_upsert") + + fields[externalIdField] <- externalId + fields <- as.data.frame(as.list(fields), stringsAsFactors = FALSE) + upserted_records <- sf_upsert(input_data = fields, + object_name = objectName, + external_id_fieldname = externalIdField) + + # rforcecom.upsert returns NULL if successful?? + return(NULL) +} + +#' salesforcer's backwards compatible version of rforcecom.search +#' +#' @template session +#' @param queryString Query strings to search. (ex: "United", "Electoronics") +#' @export +rforcecom.search <- function(session, queryString){ + .Deprecated("sf_search") + + queryString <- paste0("FIND {", queryString, "}", sep="") + resultset <- sf_search(search_string = queryString, is_sosl=TRUE) + return(resultset) +} + +#' salesforcer's backwards compatible version of rforcecom.retrieve +#' +#' @template session +#' @template objectName +#' @param fields A List of field names. (ex: c("Id", "Name", "Industry", +#' "AnnualRevenue)")) +#' @param limit Number of the records to retrieve. (ex: 5) +#' @param id Record ID to retrieve. (ex: "999x000000xxxxxZZZ") +#' @param offset Specifies the starting row offset. (ex: "100") +#' @param order A list for controling the order of query results. +#' (ex: "c("Industry","Name")") +#' @param inverse If it is TRUE, the results are ordered in descending order. +#' This parameter works when order parameter has been set. (Default: FALSE) +#' @param nullsLast If it is TRUE, null records list in last. If not null records +#' list in first. This parameter works when order parameter has been set. +#' (Default: FALSE) +#' @export +rforcecom.retrieve <- function(session, objectName, + fields, limit=NULL, id=NULL, + offset=NULL, order=NULL, + inverse=NULL, nullsLast=NULL){ + .Deprecated("sf_retrieve") + + # Make SOQL + fieldList <- paste(fields, collapse=", ") + soqlQuery <- paste("SELECT", fieldList, "FROM", objectName, sep=" ") + + # Add an id + if(!is.null(id)){ + soqlQuery <- paste(soqlQuery, " WHERE Id ='", id, "'", sep="") + } + + # Add order phrase + if(!is.null(order)){ + if(is.list(order)){ orderList <- paste(order, collapse=", ") } + else{ orderList <- order } + soqlQuery <- paste(soqlQuery, " ORDER BY ", orderList, sep="") + if(!is.null(inverse) && inverse == T){ + soqlQuery <- paste(soqlQuery, " DESC", sep="") + } + if(!is.null(nullsLast) && nullsLast == T){ + soqlQuery <- paste(soqlQuery, " NULLS LAST", sep="") + } + } + + # Add limit phrase + if(!is.null(limit)){ + soqlQuery <- paste(soqlQuery, " LIMIT ",limit, sep="") + } + + # Add offset phrase + if(!is.null(offset)){ + soqlQuery <- paste(soqlQuery, " OFFSET ",offset, sep="") + } + + # Send a query + resultSet <- sf_query(soql=soqlQuery) + return(resultSet) +} + +#' Run Bulk Action +#' +#' This function is a convenience wrapper for submitting bulk API jobs +#' +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @param session a named character vector defining parameters of the api connection as returned by \link{rforcecom.login} +#' @param operation a character string defining the type of operation being performed +#' @param data a matrix or data.frame that can be coerced into .csv file for submitting as batch request +#' @param object a character string defining the target salesforce object that the operation will be performed on +#' @template external_id_fieldname +#' @param multiBatch a boolean value defining whether or not submit data in batches to the api +#' @param batchSize an integer value defining the number of records to submit if multiBatch is true. +#' The max value is 10000 in accordance with salesforce limits. +#' @param interval_seconds an integer defining the seconds between attempts to check for job completion +#' @param max_attempts an integer defining then max number attempts to check for job completion before stopping +#' @template verbose +#' @return A \code{tbl_df} of the results of the bulk job +#' @examples +#' \dontrun{ +#' # update Account object +#' updates <- rforcecom.bulkAction(session, operation='update', data=my_data, object='Account') +#' } +#' @export +rforcecom.bulkAction <- function(session, + operation=c('insert', 'delete', 'upsert', + 'update', 'hardDelete'), + data, + object, + external_id_fieldname=NULL, + multiBatch=TRUE, + batchSize=10000, + interval_seconds=5, + max_attempts=100, + verbose=FALSE){ + .Deprecated("sf_bulk_operation") + + operation <- match.arg(operation) + res <- sf_bulk_operation(input_data = data, + object_name = object, + operation = operation, + external_id_fieldname = external_id_fieldname, + api_type = "Bulk 1.0", + interval_seconds = interval_seconds, + max_attempts = max_attempts, + verbose = verbose) + return(res) +} diff --git a/R/create-metadata.R b/R/create-metadata.R new file mode 100644 index 0000000..76a83ea --- /dev/null +++ b/R/create-metadata.R @@ -0,0 +1,107 @@ +#' Create Object or Field Metadata in Salesforce +#' +#' This function takes a list of Metadata components and sends them +#' to Salesforce for creation +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @template metadata +#' @template all_or_none +#' @template verbose +#' @return A \code{tbl_df} containing the creation result for each submitted metadata component +#' @examples +#' \dontrun{ +#' # read the metadata of the existing Account object +#' # we will use this object as a template to create a custom version +#' metadata_info <- sf_read_metadata(metadata_type='CustomObject', +#' object_names=c('Account')) +#' custom_metadata <- metadata_info[[1]] +#' # remove default actionOverrides, this cannot be set during creation +#' custom_metadata[which(names(custom_metadata) %in% c("actionOverrides"))] <- NULL +#' # remove fields since its a custom object and the standard ones no longer exist +#' custom_metadata[which(names(custom_metadata) %in% c("fields"))] <- NULL +#' # remove views so that we get the Standard List Views +#' custom_metadata[which(names(custom_metadata) %in% c("listViews"))] <- NULL +#' # remove links so that we get the Standard Web Links +#' custom_metadata[which(names(custom_metadata) %in% c("webLinks"))] <- NULL +#' # now make some adjustments to customize the object +#' this_label <- 'Custom_Account43' +#' custom_metadata$fullName <- paste0(this_label, '__c') +#' custom_metadata$label <- this_label +#' custom_metadata$pluralLabel <- paste0(this_label, 's') +#' custom_metadata$nameField <- list(displayFormat='AN-{0000}', +#' label='Account Number', +#' type='AutoNumber') +#' custom_metadata$fields <- list(fullName="Phone__c", +#' label="Phone", +#' type="Phone") +#' # set the deployment status, this must be set before creation +#' custom_metadata$deploymentStatus <- 'Deployed' +#' # make a description to identify this easily in the UI setup tab +#' custom_metadata$description <- 'created by the Metadata API' +#' new_custom_object <- sf_create_metadata(metadata_type='CustomObject', +#' metadata=custom_metadata, verbose=TRUE) +#' +#' # adding custom fields to our object +#' # input formatted as a list +#' custom_fields <- list(list(fullName='Custom_Account43__c.CustomField66__c', +#' label='CustomField66', +#' length=100, +#' type='Text'), +#' list(fullName='Custom_Account43__c.CustomField77__c', +#' label='CustomField77', +#' length=100, +#' type='Text')) +#' # formatted as a data.frame +#' custom_fields <- data.frame(fullName=c('Custom_Account43__c.CustomField88__c', +#' 'Custom_Account43__c.CustomField99__c'), +#' label=c('Test Field1', 'Test Field2'), +#' length=c(44,45), +#' type=c('Text', 'Text')) +#' new_custom_fields <- sf_create_metadata(metadata_type = 'CustomField', +#' metadata = custom_fields) +#' } +#' @export +sf_create_metadata <- function(metadata_type, metadata, all_or_none=FALSE, verbose=FALSE){ + + which_operation <- "createMetadata" + + # run some basic validation on the metadata to see if it conforms to WSDL standards + metadata <- metadata_type_validator(obj_type=metadata_type, obj_data=metadata) + + # define the operation + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=metadata, metatype=metadata_type, root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none)), metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} \ No newline at end of file diff --git a/R/create.R b/R/create.R new file mode 100644 index 0000000..b30108b --- /dev/null +++ b/R/create.R @@ -0,0 +1,211 @@ +#' Create Records +#' +#' Adds one or more new records to your organization’s data. +#' +#' @param input_data \code{named vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; data can be coerced into a \code{data.frame} +#' @template object_name +#' @template all_or_none +#' @template api_type +#' @param ... Other arguments passed on to \code{\link{sf_bulk_operation}}. +#' @template verbose +#' @return \code{tbl_df} of records with success indicator +#' @examples +#' \dontrun{ +#' n <- 3 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact", 1:n)) +#' new_contacts_result <- sf_create(new_contacts, object_name="Contact") +#' new_contacts_result <- sf_create(new_contacts, object_name="Contact", api_type="REST") +#' } +#' @export +sf_create <- function(input_data, + object_name, + all_or_none = FALSE, + api_type = c("SOAP", "REST", "Bulk 1.0", "Bulk 2.0"), + ..., + verbose = FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_create_rest(input_data=input_data, + object_name=object_name, + all_or_none=all_or_none, + verbose=verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_create_soap(input_data=input_data, + object_name=object_name, + all_or_none=all_or_none, + verbose=verbose) + } else if(api_type == "Bulk 1.0"){ + resultset <- sf_create_bulk_v1(input_data, object_name = object_name, verbose = verbose, ...) + } else if(api_type == "Bulk 2.0"){ + resultset <- sf_create_bulk_v2(input_data, object_name = object_name, verbose = verbose, ...) + } else { + stop("Unknown API type") + } + return(resultset) +} + + +#' Create Records using SOAP API +#' +#' @importFrom readr cols type_convert +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom dplyr bind_rows +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_soap <- function(input_data, object_name, all_or_none = FALSE, + verbose = FALSE){ + + input_data <- sf_input_data_validation(operation='create', input_data) + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + + # limit this type of request to only 200 records at a time to prevent + # the XML from exceeding a size limit + batch_size <- 200 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + r <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none))) + xml_dat <- build_soap_xml_from_list(input_data = batched_data, + operation = "create", + object_name = object_name, + root = r) + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="create", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_set <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) + resultset <- bind_rows(resultset, this_set) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Create Records using REST API +#' +#' @importFrom readr cols type_convert +#' @importFrom dplyr everything as_tibble bind_rows select +#' @importFrom jsonlite toJSON fromJSON +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_rest <- function(input_data, object_name, all_or_none = FALSE, + verbose = FALSE){ + + # This resource is available in API version 42.0 and later. + stopifnot(as.numeric(getOption("salesforcer.api_version")) >= 42.0) + input_data <- sf_input_data_validation(operation='create', input_data) + # add attributes to insert multiple records at a time + # https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobjects_collections.htm?search_text=update%20multiple + input_data$attributes <- lapply(1:nrow(input_data), FUN=function(x, obj){list(type=obj, referenceId=paste0("ref" ,x))}, obj=object_name) + #input_data$attributes <- list(rep(list(type=object_name), nrow(input_data)))[[1]] + input_data <- input_data %>% select(attributes, everything()) + + composite_url <- make_composite_url() + if(verbose){ + message(composite_url) + } + + # this type of request can only handle 200 records at a time + batch_size <- 200 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose) { + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + httr_response <- rPOST(url = composite_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = toJSON(list(allOrNone = tolower(all_or_none), + records = batched_data), + auto_unbox = TRUE)) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + resultset <- bind_rows(resultset, fromJSON(response_parsed)) + } + resultset <- resultset %>% + as_tibble() %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Create Records using Bulk 1.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_bulk_v1 <- function(input_data, object_name, all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + input_data <- sf_input_data_validation(operation="create", input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + operation="insert", + api_type = "Bulk 1.0", + verbose=verbose, ...) + return(resultset) +} + + +#' Create Records using Bulk 2.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_create_bulk_v2 <- function(input_data, object_name, all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + #The order of records in the response is not guaranteed to match the ordering of records in the original job data. + input_data <- sf_input_data_validation(operation="create", input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + operation="insert", + api_type = "Bulk 2.0", + verbose=verbose, ...) + return(resultset) +} + + diff --git a/R/delete-metadata.R b/R/delete-metadata.R new file mode 100644 index 0000000..e2e72a4 --- /dev/null +++ b/R/delete-metadata.R @@ -0,0 +1,60 @@ +#' Delete Object or Field Metadata in Salesforce +#' +#' This function takes a request of named elements in Salesforce and deletes them. +#' +#' @importFrom XML newXMLNode xmlInternalTreeParse xmlChildren +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @param object_names a character vector of names that we wish to read metadata for +#' @template all_or_none +#' @template verbose +#' @return A \code{data.frame} containing the creation result for each submitted metadata component +#' @seealso \link{sf_list_metadata} +#' @examples +#' \dontrun{ +#' metadata_info <- sf_delete_metadata(metadata_type = 'CustomObject', +#' object_names = c('Custom_Account25__c')) +#' } +#' @export +sf_delete_metadata <- function(metadata_type, object_names, all_or_none=FALSE, verbose=FALSE){ + + stopifnot(all(is.character(object_names))) + stopifnot(metadata_type %in% names(valid_metadata_list())) + + # format names into list + object_list <- as.list(object_names) + names(object_list) <- rep('fullNames', length(object_list)) + + which_operation <- "deleteMetadata" + # define the operation + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + type_node <- newXMLNode("type", metadata_type, parent=operation_node) + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=object_list, metatype=NULL, root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none)), metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} diff --git a/R/delete.R b/R/delete.R new file mode 100644 index 0000000..7b51e29 --- /dev/null +++ b/R/delete.R @@ -0,0 +1,173 @@ +#' Delete Records +#' +#' Deletes one or more records to your organization’s data. +#' +#' @param ids \code{vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; if not a vector, there must be a column called Id (case-insensitive) +#' that can be passed in the request +#' @template object_name +#' @template all_or_none +#' @template api_type +#' @param ... Other arguments passed on to \code{\link{sf_bulk_operation}}. +#' @template verbose +#' @return \code{tbl_df} of records with success indicator +#' @examples +#' \dontrun{ +#' n <- 3 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact", 1:n)) +#' new_contacts_result1 <- sf_create(new_contacts, object_name="Contact") +#' deleted_contacts_result1 <- sf_delete(new_contacts_result1$id, +#' object_name="Contact") +#' +#' new_contacts_result2 <- sf_create(new_contacts, "Contact") +#' deleted_contacts_result2 <- sf_delete(new_contacts_result2$id, +#' object_name="Contact", +#' api_type="Bulk") +#' } +#' @export +sf_delete <- function(ids, + object_name, + all_or_none = FALSE, + api_type = c("REST", "SOAP", "Bulk 1.0", "Bulk 2.0"), + ..., + verbose = FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_delete_rest(ids=ids, object_name=object_name, + all_or_none=all_or_none, verbose=verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_delete_soap(ids=ids, object_name=object_name, + all_or_none=all_or_none, verbose=verbose) + } else if(api_type == "Bulk 1.0"){ + resultset <- sf_delete_bulk_v1(ids=ids, object_name=object_name, verbose=verbose, ...) + } else if(api_type == "Bulk 2.0"){ + resultset <- sf_delete_bulk_v2(ids=ids, object_name=object_name, verbose=verbose, ...) + } else { + stop("Unknown API type") + } + return(resultset) +} + + +sf_delete_soap <- function(ids, object_name, all_or_none = FALSE, + verbose = FALSE){ + + ids <- sf_input_data_validation(ids, operation='delete') + + # limit this type of request to only 200 records at a time to prevent + # the XML from exceeding a size limit + batch_size <- 200 + row_num <- nrow(ids) + batch_id <- (seq.int(row_num)-1) %/% batch_size + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- ids[batch_id == batch, , drop=FALSE] + r <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none))) + xml_dat <- build_soap_xml_from_list(input_data = batched_data, + operation = "delete", + object_name = object_name, + root=r) + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="delete", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_set <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) + resultset <- bind_rows(resultset, this_set) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + +sf_delete_rest <- function(ids, object_name, all_or_none = FALSE, + verbose = FALSE){ + + ids <- sf_input_data_validation(ids, operation='delete') + + composite_url <- make_composite_url() + if(verbose) { + message(composite_url) + } + + # this type of request can only handle 200 records at a time + # so break up larger datasets, batch the data + batch_size <- 200 + row_num <- nrow(ids) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose) { + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- ids[batch_id == batch, , drop=FALSE] + httr_response <- rDELETE(url = composite_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + query = list(allOrNone = tolower(all_or_none), + ids = paste0(batched_data$Id, collapse=","))) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + resultset <- bind_rows(resultset, fromJSON(response_parsed)) + } + resultset <- resultset %>% + as_tibble() %>% + type_convert(col_types = cols()) + return(resultset) +} + +sf_delete_bulk_v1 <- function(ids, object_name, + ..., + verbose = FALSE){ + # allor none? + ids <- sf_input_data_validation(ids, operation='delete') + resultset <- sf_bulk_operation(input_data=ids, object_name=object_name, + operation="delete", + api_type = "Bulk 1.0", + verbose=verbose, ...) + return(resultset) +} + +sf_delete_bulk_v2 <- function(ids, object_name, + ..., + verbose = FALSE){ + # allor none? + ids <- sf_input_data_validation(ids, operation='delete') + resultset <- sf_bulk_operation(input_data=ids, object_name=object_name, + operation="delete", + api_type = "Bulk 2.0", + verbose=verbose, ...) + return(resultset) +} + + diff --git a/R/describe-metadata.R b/R/describe-metadata.R new file mode 100644 index 0000000..9e909bd --- /dev/null +++ b/R/describe-metadata.R @@ -0,0 +1,68 @@ +#' Describe the Metadata in an Organization +#' +#' This function returns details about the organization metadata +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all xml_text read_xml +#' @importFrom purrr map_df map_dfc +#' @importFrom dplyr as_tibble +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template verbose +#' @return A \code{tbl_df} +#' @examples +#' \dontrun{ +#' # describe metadata for the organization associated with the session +#' metadata_info <- sf_describe_metadata() +#' } +#' @export +sf_describe_metadata <- function(verbose=FALSE){ + + which_operation <- "describeMetadata" + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + api_node <- newXMLNode("apiVersion", getOption("salesforcer.api_version"), parent=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, operation_node) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + + metadata_objects <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//metadataObjects') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + summary_elements <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result/partialSaveAllowed|.//result/testRequired') %>% + map_dfc(.f=function(x){ + as_tibble(t(unlist(as_list(read_xml(as(object=x, Class="character")))))) + }) + # add the organizationNamespace separately since it may be null + organization_namespace <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result/organizationNamespace') %>% + xml_text() + organization_namespace <- if(organization_namespace == "") NA_character_ else organization_namespace + + summary_elements$organizationNamespace <- organization_namespace + summary_elements$metadataObjects <- list(metadata_objects) + + return(summary_elements) +} diff --git a/R/describe.R b/R/describe.R new file mode 100644 index 0000000..26cdb4c --- /dev/null +++ b/R/describe.R @@ -0,0 +1,84 @@ +#' SObject Basic Information +#' +#' Describes the individual metadata for the specified object. +#' +#' @importFrom methods as +#' @importFrom dplyr filter tibble +#' @importFrom httr content +#' @importFrom xml2 xml_find_all xml_ns_strip as_list +#' @template object_names +#' @template api_type +#' @template verbose +#' @return \code{list} +#' @examples +#' \dontrun{ +#' account_metadata <- sf_describe_objects("Account") +#' account_metadata_SOAP <- sf_describe_objects("Account", api_type="SOAP") +#' multiple_objs_metadata <- sf_describe_objects(c("Contact", "Lead")) +#' } +#' @export +sf_describe_objects <- function(object_names, + api_type = c("SOAP", "REST", "Bulk"), + verbose = FALSE){ + + which_api <- match.arg(api_type) + object_names <- tibble(sObjectType=unlist(object_names)) + + listed_objects <- sf_list_objects() + valid_object_names <- sapply(listed_objects$sobjects, FUN=function(x){x$name}) + + not_matched_objs <- setdiff(object_names$sObjectType, valid_object_names) + if(length(not_matched_objs) > 0){ + message(sprintf("Skipping the following object(s) for not matching the name of an existing object: %s", paste0(not_matched_objs, collapse=", "))) + } + + object_names <- object_names %>% + filter(sObjectType %in% valid_object_names) %>% + as.data.frame() + + # REST implementation + if(which_api == "REST"){ + + resultset <- list() + for(i in 1:nrow(object_names)){ + describe_object_url <- make_describe_objects_url(object_names[i,"sObjectType"]) + if(verbose) message(describe_object_url) + httr_response <- rGET(url = describe_object_url) + catch_errors(httr_response) + response_parsed <- content(httr_response, as="parsed", encoding="UTF-8") + # need to fix!!!! + resultset[[i]] <- response_parsed$objectDescribe + } + + } else if(which_api == "SOAP"){ + # SOAP implementation + r <- make_soap_xml_skeleton() + xml_dat <- build_soap_xml_from_list(input_data = object_names$sObjectType, + operation = "describeSObjects", + root=r) + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="describeSObjects", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + + invisible(capture.output( + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + # we must use XML because character elements are not automatically unboxed + # see https://github.com/r-lib/xml2/issues/215 + map(.f=function(x){ + xmlToList(xmlParse(as(object=x, Class="character"))) + }) + )) + } else { + stop("Describe SObject is not available for the Bulk API, use REST or SOAP APIs.") + } + return(resultset) +} \ No newline at end of file diff --git a/R/endpoints-bulk.R b/R/endpoints-bulk.R new file mode 100644 index 0000000..753a2c1 --- /dev/null +++ b/R/endpoints-bulk.R @@ -0,0 +1,196 @@ +#' Bulk Create Job URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_create_job_url <- function(api_type=c("Bulk 1.0", "Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + sprintf("%s/services/data/v%s/jobs/ingest", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version")) + } else { + sprintf("%s/services/async/%s/job", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version")) + } +} + +#' Bulk Delete Job Generic URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_get_job_url <- function(job_id, api_type=c("Bulk 1.0", "Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + sprintf("%s/services/data/v%s/jobs/ingest/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } else { + sprintf("%s/services/async/%s/job/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } +} + +#' Bulk End Job Generic URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_end_job_generic_url <- function(job_id, api_type=c("Bulk 1.0", "Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + sprintf("%s/services/data/v%s/jobs/ingest/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } else { + sprintf("%s/services/async/%s/job/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } +} + +#' Bulk Delete Job Generic URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_delete_job_url <- function(job_id, api_type=c("Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + sprintf("%s/services/data/v%s/jobs/ingest/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } +} + +#' Bulk Batches URL Generator +#' +#' @importFrom xml2 url_escape +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_batches_url <- function(job_id, api_type=c("Bulk 1.0", "Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + sprintf("%s/services/data/v%s/jobs/ingest/%s/batches/", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } else { + sprintf("%s/services/async/%s/job/%s/batch", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } +} + +#' Bulk Query URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_query_url <- function(job_id, api_type=c("Bulk 1.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + sprintf("%s/services/async/%s/job/%s/batch", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id) + } +} + +#' Bulk Batch Status URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_batch_status_url <- function(job_id, batch_id, api_type=c("Bulk 1.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + sprintf("%s/services/async/%s/job/%s/batch/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id, batch_id) + } +} + +#' Bulk Batch Details URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_batch_details_url <- function(job_id, batch_id, api_type=c("Bulk 1.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + sprintf("%s/services/async/%s/job/%s/batch/%s/result", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id, batch_id) + } +} + +#' Bulk Query Result URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_query_result_url <- function(job_id, batch_id, result_id, api_type=c("Bulk 1.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + api_type <- match.arg(api_type) + if(api_type == "Bulk 1.0"){ + sprintf("%s/services/async/%s/job/%s/batch/%s/result/%s", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id, batch_id, result_id) + } +} + +#' Bulk Job Records URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_bulk_job_records_url <- function(job_id, + record_type = c("successfulResults", + "failedResults", + "unprocessedRecords"), + api_type = c("Bulk 2.0")){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + record_type <- match.arg(record_type) + api_type <- match.arg(api_type) + if(api_type == "Bulk 2.0"){ + sprintf("%s/services/data/v%s/jobs/ingest/%s/%s/", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + job_id, + record_type) + } +} diff --git a/R/endpoints-rest.R b/R/endpoints-rest.R new file mode 100644 index 0000000..b0f89a9 --- /dev/null +++ b/R/endpoints-rest.R @@ -0,0 +1,117 @@ +#' Base REST API URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_base_rest_url <- function(){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + sprintf("%s/services/data/v%s/", + salesforcer_state()$instance_url, + getOption("salesforcer.api_version")) +} + +#' Parameterized Search URL Generator +#' +#' @importFrom xml2 url_escape +#' @importFrom httr build_url parse_url +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_parameterized_search_url <- function(search_string, params){ + this_url <- parse_url(paste0(make_base_rest_url(), "parameterizedSearch/")) + this_url$query <- c(list(q=url_escape(search_string)), params) + build_url(this_url) +} + +#' Chatter Users URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_chatter_users_url <- function(){ + paste0(make_base_rest_url(), "chatter/users/") +} + +#' Composite URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_composite_url <- function(){ + paste0(make_base_rest_url(), "composite/sobjects") +} + +#' Query URL Generator +#' +#' @importFrom xml2 url_escape +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_query_url <- function(soql, queryall, next_records_url){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + if(!is.null(next_records_url)){ + # pull more records from a previous query + query_url <- sprintf('%s%s', + salesforcer_state()$instance_url, + next_records_url) + } else { + # set the url based on the query + query_url <- sprintf('%s/services/data/v%s/%s/?q=%s', + salesforcer_state()$instance_url, + getOption("salesforcer.api_version"), + if(queryall) "queryAll" else "query", + url_escape(soql)) + } + return(query_url) +} + +#' Parameterized Search URL Generator +#' +#' @importFrom xml2 url_escape +#' @importFrom httr build_url parse_url +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_parameterized_search_url <- function(search_string=NULL, params=NULL){ + this_url <- parse_url(paste0(make_base_rest_url(), "parameterizedSearch/")) + if(!is.null(search_string)){ + if(!is.null(params)){ + this_url$query <- c(list(q=url_escape(search_string)), params) + } else { + this_url$query <- list(q=url_escape(search_string)) + } + } + result <- build_url(this_url) + return(result) +} + +#' Search URL Generator +#' +#' @importFrom xml2 url_escape +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_search_url <- function(search_string){ + paste0(make_base_rest_url(), "search/?q=", + url_escape(search_string, reserved = "{}")) +} + +#' Describe Objects URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_describe_objects_url <- function(object){ + paste0(make_base_rest_url(), "sobjects/", object, "/") +} + +#' Composite Batch URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_composite_batch_url <- function(){ + paste0(make_base_rest_url(), "composite/batch/") +} \ No newline at end of file diff --git a/R/endpoints-soap.R b/R/endpoints-soap.R new file mode 100644 index 0000000..fc8a1ff --- /dev/null +++ b/R/endpoints-soap.R @@ -0,0 +1,36 @@ +#' Login URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_login_url <- function(login_url){ + sprintf('%s/services/Soap/u/%s', + login_url, + getOption("salesforcer.api_version")) +} + +#' Base SOAP API URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_base_soap_url <- function(){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + sprintf('%s/services/Soap/u/%s', + salesforcer_state()$instance_url, + getOption("salesforcer.api_version")) +} + +#' Base Metadata API URL Generator +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +make_base_metadata_url <- function(){ + # ensure we are authenticated first so the url can be formed + sf_auth_check() + sprintf('%s/services/Soap/m/%s', + salesforcer_state()$instance_url, + getOption("salesforcer.api_version")) +} \ No newline at end of file diff --git a/R/list-metadata.R b/R/list-metadata.R new file mode 100644 index 0000000..086207e --- /dev/null +++ b/R/list-metadata.R @@ -0,0 +1,65 @@ +#' List All Objects of a Certain Metadata Type in Salesforce +#' +#' This function takes a query of metadata types and returns a +#' summary of all objects in salesforce of the requested types +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @param queries a \code{list} of \code{list}s with each element consisting of 2 components: 1) +#' the metadata type being requested and 2) the folder associated with the type that required for types +#' that use folders, such as Dashboard, Document, EmailTemplate, or Report. +#' @template verbose +#' @return A \code{tbl_dfs} containing the queried metadata types +#' @note Only 3 queries can be specifed at one time, so the list length must not exceed 3. +#' @examples +#' \dontrun{ +#' # pull back a list of all Custom Objects and Email Templates +#' my_queries <- list(list(type='CustomObject'), +#' list(folder='unfiled$public', +#' type='EmailTemplate')) +#' metadata_info <- sf_list_metadata(queries=my_queries) +#' } +#' @export +sf_list_metadata <- function(queries, verbose=FALSE){ + + which_operation <- "listMetadata" + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + + if(typeof(queries[[1]]) != "list"){ + queries <- list(queries) + } + + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=queries, metatype='ListMetadataQuery', root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + api_node <- newXMLNode("asOfVersion", getOption("salesforcer.api_version"), parent=xml_dat) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} \ No newline at end of file diff --git a/R/query.R b/R/query.R new file mode 100644 index 0000000..62c81fa --- /dev/null +++ b/R/query.R @@ -0,0 +1,195 @@ +#' Perform SOQL Query +#' +#' Executes a query against the specified object and returns data that matches +#' the specified criteria. +#' +#' @template soql +#' @template object_name +#' @param queryall logical; indicating if the query recordset should include +#' deleted and archived records (available only when querying Task and Event records) +#' @param page_size numeric; a number between 200 and 2000 indicating the number of +#' records per page that are returned. Speed benchmarks should be done to better +#' understand the speed implications of choosing high or low values of this argument. +#' @template api_type +#' @param next_records_url character (leave as NULL); a string used internally +#' by the function to paginate through to more records until complete +#' @param ... Other arguments passed on to \code{\link{sf_query_bulk}}. +#' @template verbose +#' @return \code{tbl_df} of records +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @note Bulk API query doesn't support the following SOQL: +#' \itemize{ +#' \item COUNT +#' \item ROLLUP +#' \item SUM +#' \item GROUP BY CUBE +#' \item OFFSET +#' \item Nested SOQL queries +#' \item Relationship fields +#' } +#' Additionally, Bulk API can't access or query compound address or compound geolocation fields. +#' @examples +#' \dontrun{ +#' sf_query("SELECT Id, Account.Name, Email FROM Contact LIMIT 10") +#' sf_query("SELECT Id, Email FROM Contact LIMIT 10", verbose = TRUE) +#' } +#' @export +sf_query <- function(soql, + object_name, + queryall=FALSE, + page_size=1000, + api_type=c("REST", "SOAP", "Bulk 1.0"), + next_records_url=NULL, + ..., + verbose=FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_query_rest(soql=soql, + object_name=object_name, + queryall=queryall, + page_size=page_size, + next_records_url=next_records_url, + verbose=verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_query_soap(soql=soql, + object_name=object_name, + queryall=queryall, + page_size=page_size, + next_records_url=next_records_url, + verbose=verbose) + } else if(api_type == "Bulk 1.0"){ + if(missing(object_name)){ + stop("object_name is missing. This argument must be provided when using the Bulk API.") + } + resultset <- sf_query_bulk(soql=soql, object_name=object_name, verbose=verbose, ...) + } else { + stop("Unknown API type") + } + return(resultset) +} + + +#' @importFrom dplyr bind_rows as_tibble select matches +#' @importFrom httr content +#' @importFrom jsonlite toJSON +#' @importFrom readr type_convert cols +sf_query_rest <- function(soql, + object_name, + queryall=FALSE, + page_size=1000, + api_type=c("REST", "SOAP", "Bulk 1.0"), + next_records_url=NULL, + ..., + verbose=FALSE){ + + query_url <- make_query_url(soql, queryall, next_records_url) + if(verbose) message(query_url) + + # GET the url with the q (query) parameter set to the escaped SOQL string + httr_response <- rGET(url = query_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json", + "Sforce-Query-Options"=sprintf("batchSize=%.0f", page_size))) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + response_parsed <- fromJSON(response_parsed, flatten=TRUE) + if(length(response_parsed$records) > 0){ + resultset <- response_parsed$records %>% + select(-matches("^attributes\\.")) %>% + select(-matches("\\.attributes\\.")) %>% + type_convert(col_types = cols()) %>% + as_tibble() + } else { + resultset <- NULL + } + + if(!response_parsed$done){ + next_records_url <- response_parsed$nextRecordsUrl + } + + # check whether it has next record + if(!is.null(next_records_url)){ + next_records <- sf_query_rest(next_records_url=next_records_url) + resultset <- bind_rows(resultset, next_records) + } + + return(resultset) +} + + +#' @importFrom dplyr bind_rows as_tibble select matches contains rename_at +#' @importFrom httr content +#' @importFrom purrr map_df +#' @importFrom readr type_convert cols +#' @importFrom xml2 xml_find_first xml_find_all xml_text xml_ns_strip +sf_query_soap <- function(soql, + object_name, + queryall=FALSE, + page_size=1000, + next_records_url=NULL, + ..., + verbose=FALSE){ + + if(!is.null(next_records_url)){ + soap_action <- "queryMore" + r <- make_soap_xml_skeleton() + xml_dat <- build_soap_xml_from_list(input_data = next_records_url, + operation = "queryMore", + root=r) + } else { + soap_action <- "query" + r <- make_soap_xml_skeleton(soap_headers=list(QueryOptions=list(batchSize=page_size))) + xml_dat <- build_soap_xml_from_list(input_data = soql, + operation = "query", + root=r) + } + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + message(xml_dat) + } + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"=soap_action, + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//records') + + if(length(resultset) > 0){ + resultset <- resultset %>% + map_df(xml_nodeset_to_df) %>% + select(-matches("sf:type$|sf:Id$")) %>% + rename_at(.vars = vars(contains("sf:")), + .funs = funs(gsub("sf:", "", .))) %>% + rename_at(.vars = vars(contains("Id1")), + .funs = funs(gsub("Id1", "Id", .))) %>% + type_convert(col_types = cols()) %>% + as_tibble() + } else { + resultset <- NULL + } + + done_status <- response_parsed %>% + xml_ns_strip() %>% + xml_find_first('.//done') %>% + xml_text() + + if(done_status == "false"){ + query_locator <- response_parsed %>% + xml_ns_strip() %>% + xml_find_first('.//queryLocator') %>% + xml_text() + next_records <- sf_query_soap(next_records_url=query_locator) + resultset <- bind_rows(resultset, next_records) + } + + return(resultset) +} + +# async-queries/ +# https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/async_query_running_queries.htm diff --git a/R/read-metadata.R b/R/read-metadata.R new file mode 100644 index 0000000..5e4c078 --- /dev/null +++ b/R/read-metadata.R @@ -0,0 +1,68 @@ +#' Read Object or Field Metadata from Salesforce +#' +#' This function takes a a request of named elements in Salesforce and +#' returns their metadata +#' +#' @importFrom XML newXMLNode addChildren xmlParse xmlToList +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @param object_names a character vector of names that we wish to read metadata for +#' @template verbose +#' @return A \code{list} containing a response for each requested object +#' @examples +#' \dontrun{ +#' metadata_info <- sf_read_metadata(metadata_type='CustomObject', +#' object_names=c('Account')) +#' } +#' @export +sf_read_metadata <- function(metadata_type, object_names, verbose=FALSE){ + + stopifnot(all(is.character(object_names))) + stopifnot(metadata_type %in% names(valid_metadata_list())) + + # format names into list + object_list <- as.list(object_names) + names(object_list) <- rep('fullNames', length(object_list)) + + which_operation <- "readMetadata" + # define the operation + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + type_node <- newXMLNode("type", metadata_type, parent=operation_node) + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=object_list, metatype=NULL, root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + invisible(capture.output( + # capture any xmlToList grumblings about Namespace prefix + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//records') %>% + # we must use XML because character elements are not automatically unboxed + # see https://github.com/r-lib/xml2/issues/215 + map(.f=function(x){ + xmlToList(xmlParse(as(object=x, Class="character"))) + }) + )) + + return(resultset) +} diff --git a/R/rename-metadata.R b/R/rename-metadata.R new file mode 100644 index 0000000..6d9760e --- /dev/null +++ b/R/rename-metadata.R @@ -0,0 +1,59 @@ +#' Rename Metadata Elements in Salesforce +#' +#' This function takes an old and new name for a +#' metadata element in Salesforce and applies the new name +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @param old_fullname character; string corresponding to the fullName of the element you would +#' like to rename +#' @param new_fullname character; string corresponding to the new fullName you would like +#' to apply the targeted element +#' @template verbose +#' @return A \code{data.frame} containing the creation result for each submitted metadata component +#' @examples +#' \dontrun{ +#' renamed_custom_object <- sf_rename_metadata(metadata_type = 'CustomObject', +#' old_fullname = 'Custom_Account32__c', +#' new_fullname = 'Custom_Account99__c') +#' } +#' @export +sf_rename_metadata <- function(metadata_type, old_fullname, new_fullname, verbose=FALSE){ + + which_operation <- "renameMetadata" + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + operation_node <- addChildren(operation_node, newXMLNode('type', metadata_type)) + operation_node <- addChildren(operation_node, newXMLNode('oldFullname', old_fullname)) + operation_node <- addChildren(operation_node, newXMLNode('newFullname', new_fullname)) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, operation_node) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} \ No newline at end of file diff --git a/R/retrieve-metadata.R b/R/retrieve-metadata.R new file mode 100644 index 0000000..5bd64f1 --- /dev/null +++ b/R/retrieve-metadata.R @@ -0,0 +1,186 @@ +#' Make A Request to Retrieve the Metadata +#' +#' This function makes a request to retrieve metadata +#' as a package XML files that can be modified and later +#' deployed into an environment +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_retrieve.htm} +#' @param retrieve_request a \code{list} of parameters defining what XML file representations +#' should be returned +#' @param filename a file path to save the zip file in the event that it is downloaded. The +#' name must have a .zip extension. The default behavior will be to save in the current +#' working directory as "package.zip" +#' @param check_interval numeric; specifying the seconds to wait between retrieve +#' status requests to check if complete +#' @param max_tries numeric; specifying the maximum number of times to check +#' whether the retrieve package.zip is complete before the function times out +#' @template verbose +#' @return A \code{list} of details from the created retrieve request +#' @note See the Salesforce documentation for the proper arguments to create a +#' retrieveRequest. Here is a link to that documentation: +#' \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_retrieve_request.htm} +#' @examples +#' \dontrun{ +#' retrieve_request <- list(unpackaged=list(types=list(members='*', +#' name='CustomObject'))) +#' retrieve_info <- sf_retrieve_metadata(retrieve_request) +#' } +#' @export +sf_retrieve_metadata <- function(retrieve_request, + filename='package.zip', + check_interval=3, + max_tries=20, + verbose=FALSE){ + + which_operation <- "retrieve" + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + request_root <- newXMLNode('retrieveRequest', + attrs = c(`xsi:type`='RetrieveRequest'), + suppressNamespaceWarning=TRUE) + + if(typeof(retrieve_request[[1]]) != "list"){ + retrieve_request <- list(retrieve_request) + } + + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=retrieve_request, metatype=NULL, root=request_root) + operation_node <- addChildren(operation_node, xml_dat) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, operation_node) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + # continually check status until complete + counter <- 0 + retrieve_status <- list(done="false") + while(retrieve_status$done != 'true' & counter < max_tries){ + # this will automatically download the contents to package.zip when ready + retrieve_status <- sf_retrieve_metadata_check_status(id = resultset$id, + include_zip = TRUE, + filename = filename, + verbose = verbose) + Sys.sleep(check_interval) + counter <- counter + 1 + } + + return(retrieve_status) +} + + +#' Check on Retrieve Calls and Get Contents If Available +#' +#' This function returns details about an initiated retrieveMetadata requset +#' and saves the results into a zip file +#' +#' @importFrom jsonlite base64_dec +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all as_list read_xml +#' @importFrom purrr map_df map_dfc +#' @importFrom dplyr as_tibble +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_checkretrievestatus.htm} +#' @param id character; string id returned from \link{sf_retrieve_metadata} +#' @param include_zip logical; Set to false to check the status of the retrieval without +#' attempting to retrieve the zip file. If omitted, this argument defaults to true. +#' @param filename a file path to save the zip file in the event that it is downloaded. The +#' name must have a .zip extension. The default behavior will be to save in the current +#' working directory as package.zip +#' @template verbose +#' @return A \code{list} of the response +#' @examples +#' \dontrun{ +#' retrieve_request <- list(unpackaged=list(types=list(members='*', name='CustomObject'))) +#' retrieve_info <- sf_retrieve_metadata(retrieve_request) +#' +#' # check on status, this will automatically download the contents to package.zip when ready +#' retrieve_status <- sf_retrieve_metadata_check_status(retrieve_info$id) +#' } +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_retrieve_metadata_check_status <- function(id, + include_zip=TRUE, + filename='package.zip', + verbose=FALSE){ + + stopifnot(grepl('\\.zip$', filename)) + + which_operation <- "checkRetrieveStatus" + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + addChildren(operation_node, newXMLNode('asyncProcessId', id)) + addChildren(operation_node, newXMLNode('includeZip', tolower(include_zip))) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, operation_node) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + file_properties <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//fileProperties') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + summary_elements <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result/id|.//result/status|.//result/success|.//result/done') %>% + map_dfc(.f=function(x){ + as_tibble(t(unlist(as_list(read_xml(as(object=x, Class="character")))))) + }) + summary_elements$fileProperties <- list(file_properties) + + zip_result <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//zipFile') %>% + xml_text() + + if(summary_elements$done == 'true' & summary_elements$status == 'Succeeded' & + summary_elements$success == 'true' & length(zip_result) == 1 & + tolower(include_zip) == 'true'){ + # save the zip file + decoded_dat <- base64_dec(zip_result) + writeBin(decoded_dat, filename) + message(paste0('Package Manifest Files Saved at: ', filename)) + } + + return(summary_elements) +} \ No newline at end of file diff --git a/R/retrieve.R b/R/retrieve.R new file mode 100644 index 0000000..465122b --- /dev/null +++ b/R/retrieve.R @@ -0,0 +1,164 @@ +#' Retrieve Records By Id +#' +#' Retrieves one or more new records to your organization’s data. +#' +#' @param ids \code{vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; if not a vector, there must be a column called Id (case-insensitive) +#' that can be passed in the request +#' @param fields character; one or more strings indicating the fields to be returned +#' on the records +#' @template object_name +#' @template api_type +#' @template verbose +#' @return \code{tibble} +#' @examples +#' \dontrun{ +#' n <- 3 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact", 1:n)) +#' new_contacts_result <- sf_create(new_contacts, object_name="Contact") +#' retrieved_records <- sf_retrieve(ids=new_contacts_result$id, +#' fields=c("LastName"), +#' object_name="Contact") +#' } +#' @export +sf_retrieve <- function(ids, + fields, + object_name, + api_type = c("REST", "SOAP", "Bulk 1.0", "Bulk 2.0"), + verbose = FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_retrieve_rest(ids=ids, fields=fields, object_name=object_name, + verbose = verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_retrieve_soap(ids=ids, fields=fields, object_name=object_name, + verbose = verbose) + } else if(api_type == "Bulk 1.0"){ + stop("Retrieve is not supported in Bulk API. For retrieving a large number of records use SOQL (queries) instead.") + } else if(api_type == "Bulk 2.0"){ + stop("Retrieve is not supported in Bulk API. For retrieving a large number of records use SOQL (queries) instead.") + } else { + stop("Unknown API type") + } + return(resultset) +} + +#' @importFrom utils head +#' @importFrom stats quantile +#' @importFrom dplyr bind_rows as_tibble select matches rename_at starts_with +#' @importFrom httr content +#' @importFrom purrr map_df +#' @importFrom readr type_convert cols +#' @importFrom xml2 xml_find_first xml_find_all xml_text xml_ns_strip +sf_retrieve_soap <- function(ids, + fields, + object_name, + verbose = FALSE){ + + ids <- sf_input_data_validation(ids, operation='retrieve') + # limit this type of request to only 200 records at a time to prevent + # the XML from exceeding a size limit + batch_size <- 200 + row_num <- nrow(ids) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose) message("Submitting data in ", max(batch_id)+1, " Batches") + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + + batched_data <- ids[batch_id == batch, , drop=FALSE] + r <- make_soap_xml_skeleton() + xml_dat <- build_soap_xml_from_list(input_data = batched_data, + operation = "retrieve", + object_name = object_name, + fields = fields, + root=r) + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="retrieve", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_set <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') + if(length(this_set) > 0){ + this_set <- this_set %>% + map_df(xml_nodeset_to_df) %>% + select(-matches("sf:type")) %>% + rename_at(.vars = vars(starts_with("sf:")), + .funs = funs(gsub("^sf:", "", .))) %>% + select(-matches("Id1")) + } else { + this_set <- NULL + } + resultset <- bind_rows(resultset, this_set) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + +#' @importFrom utils head +#' @importFrom stats quantile +#' @importFrom dplyr bind_rows as_tibble select_ +#' @importFrom httr content +#' @importFrom jsonlite toJSON fromJSON +#' @importFrom readr type_convert cols +sf_retrieve_rest <- function(ids, + fields, + object_name, + verbose = FALSE){ + + ids <- sf_input_data_validation(ids, operation='retrieve') + + # https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobjects_collections_retrieve.htm?search_text=retrieve%20multiple + # this type of request can only handle 2000 records at a time + batch_size <- 2000 + row_num <- nrow(ids) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose) message("Submitting data in ", max(batch_id)+1, " Batches") + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + composite_url <- paste0(make_composite_url(), "/", object_name) + if(verbose) message(composite_url) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- ids[batch_id == batch, , drop=FALSE] + httr_response <- rPOST(url = composite_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = toJSON(list(ids=batched_data$Id, + fields=fields), + auto_unbox = FALSE)) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + resultset <- bind_rows(resultset, fromJSON(response_parsed) %>% select_(.dots = unique(c("Id", fields)))) + } + resultset <- resultset %>% + as_tibble() %>% + type_convert(col_types = cols()) + return(resultset) +} diff --git a/R/salesforcer.R b/R/salesforcer.R new file mode 100644 index 0000000..95bb3a9 --- /dev/null +++ b/R/salesforcer.R @@ -0,0 +1,23 @@ +#' \code{salesforcer} package +#' +#' An R package connecting to Salesforce APIs using tidy principles +#' +#' A package that connects to Salesforce via REST, SOAP, Bulk, and Metadata APIs +#' and emphasizes the use of tidy data principles and the tidyverse. +#' +#' Additional material can be found in the +#' \href{https://github.com/reportmort/salesforcer}{README} on GitHub +#' +#' @docType package +#' @name salesforcer +#' @importFrom dplyr %>% +NULL + +## quiets concerns of R CMD check re: the .'s that appear in pipelines +if(getRversion() >= "2.15.1") utils::globalVariables(c(".", + "id", + "success", + "sObjectType", + "sobject", + "attributes.type", + "sf:type")) \ No newline at end of file diff --git a/R/search.R b/R/search.R new file mode 100644 index 0000000..3cc3142 --- /dev/null +++ b/R/search.R @@ -0,0 +1,185 @@ +#' Perform SOSL Search +#' +#' Searches for records in your organization’s data. +#' +#' @importFrom jsonlite toJSON fromJSON +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom dplyr as_tibble rename rename_at select matches starts_with funs vars everything +#' @importFrom readr type_convert +#' @param search_string character; string to search using parameterized search +#' or SOSL. Note that is_sosl must be set to TRUE and the string valid in order +#' to perform a search using SOSL. +#' @param is_sosl logical; indicating whether or not to try the string as SOSL +#' @template api_type +#' @param parameterized_search_options \code{list}; a list of parameters for +#' controlling the search if not using SOSL. If using SOSL this is ignored. +#' @template verbose +#' @param ... arguments to be used to form the parameterized search options argument +#' if it is not supplied directly. +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl.htm} +#' @return \code{tibble} +#' @examples +#' \dontrun{ +#' # free text search +#' area_code_search_string <- "(336)" +#' search_result <- sf_search(area_code_search_string) +#' +#' # free text search with parameters +#' search_result <- sf_search(area_code_search_string, +#' fields_scope = "PHONE", +#' objects = "Lead", +#' fields = c("id", "phone", "firstname", "lastname")) +#' +#' # using SOSL +#' my_sosl_search <- paste("FIND {(336)} in phone fields returning", +#' "contact(id, phone, firstname, lastname),", +#' "lead(id, phone, firstname, lastname)") +#' sosl_search_result <- sf_search(my_sosl_search, is_sosl=TRUE) +#' } +#' @export +sf_search <- function(search_string, + is_sosl = FALSE, + api_type = c("REST", "SOAP", "Bulk 1.0", "Bulk 2.0"), + parameterized_search_options = list(...), + verbose = FALSE, + ...){ + + which_api <- match.arg(api_type) + + # REST implementation + if(which_api == "REST"){ + + if(is_sosl){ + target_url <- make_search_url(search_string) + if(verbose) message(target_url) + httr_response <- rGET(url = target_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json")) + } else { + parameterized_search_control <- do.call("parameterized_search_control", + parameterized_search_options) + parameterized_search_control <- c(list(q=search_string), parameterized_search_control) + target_url <- make_parameterized_search_url() + if(verbose) message(target_url) + httr_response <- rPOST(url = target_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = toJSON(parameterized_search_control, + auto_unbox = TRUE)) + } + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + resultset <- fromJSON(response_parsed, flatten=TRUE)$searchRecords + if(length(resultset)>0){ + suppressMessages( + resultset <- resultset %>% + rename(sobject = `attributes.type`) %>% + select(-matches("^attributes\\.")) %>% + type_convert() %>% + as_tibble() + ) + } else { + resultset <- NULL + } + } else if(which_api == "SOAP"){ + + # TODO: should SOAP only take SOSL? + if(!is_sosl){ + stop(paste("The SOAP API only takes SOSL formatted search strings.", + "Set is_sosl=TRUE or Use \"REST\" if trying to do a free text search")) + } + r <- make_soap_xml_skeleton() + xml_dat <- build_soap_xml_from_list(input_data = search_string, + operation = "search", + root=r) + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="search", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//record') + if(length(resultset) > 0){ + suppressMessages( + resultset <- resultset %>% + map_df(xml_nodeset_to_df) %>% + rename(sobject=`sf:type`) %>% + rename_at(.vars = vars(starts_with("sf:")), + .funs = funs(sub("^sf:", "", .))) %>% + select(-matches("Id1")) %>% + type_convert() + ) + } else { + resultset <- NULL + } + } else if(which_api == "Bulk 1.0"){ + stop("SOSL is not supported in Bulk API. For retrieving a large number of records use SOQL (queries) instead.") + } else if(which_api == "Bulk 2.0"){ + stop("SOSL is not supported in Bulk API. For retrieving a large number of records use SOQL (queries) instead.") + } else { + stop("Unknown API type") + } + if(!is.null(resultset)){ + resultset <- resultset %>% + select(sobject, everything()) + } + return(resultset) +} + +#' Auxiliary for Controlling Parametrized Searches +#' +#' A function for allowing finer grained control over how a search is performed +#' when not using SOSL +#' +#' @param objects character; objects to search and return in the response. Multiple +#' objects can be provided as a character vector +#' @param fields_scope character; scope of fields to search in order to limit the resources +#' used and improve performance +#' @param fields character; one or more fields to return in the response for each +#' sobject specified. If no fields are specified only the Ids of the matching records +#' are returned. +#' @param overall_limit numeric; the maximum number of results to return across +#' all sobject parameters specified. +#' @param spell_correction logical; specifies whether spell correction should be +#' enabled for a user’s search. +#' @return \code{list} of parameters passed onto sf_search +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_search_parameterized.htm#resources_search_parameterized} +#' @examples +#' \dontrun{ +#' # free text search only on Contact record Phone fields +#' # this will improve the performance of the search +#' my_phone_search <- "(336)" +#' search_result <- sf_search(my_phone_search, +#' objects = c("Contact", "Lead"), +#' fields_scope = "PHONE", +#' fields = c("Id", "FirstName", "LastName")) +#' } +#' @export +parameterized_search_control <- function(objects = NULL, + fields_scope = c("ALL", "NAME", "EMAIL", "PHONE" ,"SIDEBAR"), + fields = NULL, + overall_limit = 2000, + spell_correction = TRUE + ){ + + which_fields_scope <- match.arg(fields_scope) + + if(!is.null(fields) & is.null(objects)){ + stop("You must specify the objects if you are limiting the fields to return.") + } + result <- list() + result$`in` <- which_fields_scope + if(!is.null(fields)) result$fields <- fields + if(!is.null(objects)) result$sobjects <- lapply(objects, FUN=function(x){list(name=x)}) + result$overallLimit <- as.integer(overall_limit) + result$spellCorrection <- tolower(spell_correction) + return(result) +} \ No newline at end of file diff --git a/R/update-metadata.R b/R/update-metadata.R new file mode 100644 index 0000000..6c275a2 --- /dev/null +++ b/R/update-metadata.R @@ -0,0 +1,82 @@ +#' Update Object or Field Metadata in Salesforce +#' +#' This function takes a list of Metadata components and sends them +#' to Salesforce to update an object that already exists +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @template metadata +#' @template all_or_none +#' @template verbose +#' @return A \code{tbl_df} containing the creation result for each submitted metadata component +#' @note The update key is based on the fullName parameter of the metadata, so updates are triggered +#' when an existing Salesforce element matches the metadata type and fullName. +#' @examples +#' \dontrun{ +#' # create an object that we can update +#' base_obj_name <- "Custom_Account1" +#' custom_object <- list() +#' custom_object$fullName <- paste0(base_obj_name, "__c") +#' custom_object$label <- paste0(gsub("_", " ", base_obj_name)) +#' custom_object$pluralLabel <- paste0(base_obj_name, "s") +#' custom_object$nameField <- list(displayFormat = 'AN-{0000}', +#' label = paste0(base_obj_name, ' Number'), +#' type = 'AutoNumber') +#' custom_object$deploymentStatus <- 'Deployed' +#' custom_object$sharingModel <- 'ReadWrite' +#' custom_object$enableActivities <- 'true' +#' custom_object$description <- paste0(base_obj_name, " created by the Metadata API") +#' custom_object_result <- sf_create_metadata(metadata_type = 'CustomObject', +#' metadata = custom_object) +#' # now update the object that was created +#' update_metadata <- custom_object +#' update_metadata$fullName <- 'Custom_Account1__c' +#' update_metadata$label <- 'New Label Custom_Account1' +#' update_metadata$pluralLabel <- 'Custom_Account1s_new' +#' updated_custom_object_result <- sf_update_metadata(metadata_type = 'CustomObject', +#' metadata = update_metadata) +#' } +#' @export +sf_update_metadata <- function(metadata_type, metadata, all_or_none=FALSE, verbose=FALSE){ + + which_operation <- "updateMetadata" + + # run some basic validation on the metadata to see if it conforms to WSDL standards + metadata <- metadata_type_validator(obj_type=metadata_type, obj_data=metadata) + + # define the operation + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=metadata, metatype=metadata_type, root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none)), metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} \ No newline at end of file diff --git a/R/update.R b/R/update.R new file mode 100644 index 0000000..8078778 --- /dev/null +++ b/R/update.R @@ -0,0 +1,219 @@ +#' Update Records +#' +#' Updates one or more records to your organization’s data. +#' +#' @param input_data \code{named vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; data can be coerced into a \code{data.frame} +#' @template object_name +#' @template all_or_none +#' @template api_type +#' @param ... Other arguments passed on to \code{\link{sf_bulk_operation}}. +#' @template verbose +#' @return \code{tbl_df} of records with success indicator +#' @examples +#' \dontrun{ +#' n <- 3 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact", 1:n)) +#' new_contacts_result <- sf_create(new_contacts, "Contact") +#' +#' update_contacts <- tibble(FirstName = rep("TestTest", n), +#' LastName = paste0("Contact", 1:n), +#' Id = new_contacts_result$id) +#' updated_contacts_result1 <- sf_update(update_contacts, "Contact") +#' updated_contacts_result2 <- sf_update(update_contacts, "Contact", +#' api_type="Bulk") +#' } +#' @export +sf_update <- function(input_data, + object_name, + all_or_none = FALSE, + api_type = c("SOAP", "REST", "Bulk 1.0", "Bulk 2.0"), + ..., + verbose = FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_update_rest(input_data=input_data, + object_name=object_name, + all_or_none=all_or_none, + verbose=verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_update_soap(input_data=input_data, + object_name=object_name, + all_or_none=all_or_none, + verbose=verbose) + } else if(api_type == "Bulk 1.0"){ + resultset <- sf_update_bulk_v1(input_data, object_name = object_name, verbose = verbose, ...) + } else if(api_type == "Bulk 2.0"){ + resultset <- sf_update_bulk_v2(input_data, object_name = object_name, verbose = verbose, ...) + } else { + stop("Unknown API type") + } + return(resultset) +} + + +#' Update Records using SOAP API +#' +#' @importFrom readr cols type_convert +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom dplyr bind_rows +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_update_soap <- function(input_data, object_name, all_or_none = FALSE, + verbose = FALSE){ + + input_data <- sf_input_data_validation(operation='update', input_data) + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + + # limit this type of request to only 200 records at a time to prevent + # the XML from exceeding a size limit + batch_size <- 200 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + r <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none))) + xml_dat <- build_soap_xml_from_list(input_data = batched_data, + operation = "update", + object_name = object_name, + root = r) + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="update", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_set <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) + resultset <- bind_rows(resultset, this_set) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Update Records using REST API +#' +#' @importFrom readr cols type_convert +#' @importFrom dplyr everything as_tibble bind_rows select +#' @importFrom jsonlite toJSON fromJSON +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_update_rest <- function(input_data, object_name, all_or_none = FALSE, + verbose = FALSE){ + + # This resource is available in API version 42.0 and later. + stopifnot(as.numeric(getOption("salesforcer.api_version")) >= 42.0) + input_data <- sf_input_data_validation(operation='update', input_data) + input_data$attributes <- lapply(1:nrow(input_data), FUN=function(x, obj){list(type=obj, referenceId=paste0("ref" ,x))}, obj=object_name) + #input_data$attributes <- list(rep(list(type=object_name), nrow(input_data)))[[1]] + input_data <- input_data %>% select(attributes, everything()) + + composite_url <- make_composite_url() + if(verbose){ + message(composite_url) + } + + # add attributes to insert multiple records at a time + # https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobjects_collections.htm?search_text=update%20multiple + # this type of request can only handle 200 records at a time + # so break up larger datasets, batch the data + batch_size <- 200 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose) { + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + httr_response <- rPATCH(url = composite_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = toJSON(list(allOrNone = tolower(all_or_none), + records = batched_data), + auto_unbox = TRUE)) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + resultset <- bind_rows(resultset, fromJSON(response_parsed)) + } + resultset <- resultset %>% + as_tibble() %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Update Records using Bulk 1.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_update_bulk_v1 <- function(input_data, object_name, all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + input_data <- sf_input_data_validation(operation="update", input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + operation="update", + api_type = "Bulk 1.0", + verbose=verbose, ...) + return(resultset) +} + + +#' Update Records using Bulk 2.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_update_bulk_v2 <- function(input_data, object_name, all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + #The order of records in the response is not guaranteed to match the ordering of records in the original job data. + input_data <- sf_input_data_validation(operation='update', input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + operation="update", + api_type = "Bulk 2.0", + verbose=verbose, ...) + return(resultset) +} + + + diff --git a/R/upsert-metadata.R b/R/upsert-metadata.R new file mode 100644 index 0000000..d8be7ca --- /dev/null +++ b/R/upsert-metadata.R @@ -0,0 +1,85 @@ +#' Upsert Object or Field Metadata in Salesforce +#' +#' This function takes a list of Metadata components and sends them +#' to Salesforce for creation or update if the object already exists +#' +#' @importFrom XML newXMLNode addChildren +#' @importFrom readr type_convert cols +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/} +#' @template metadata_type +#' @template metadata +#' @template all_or_none +#' @template verbose +#' @return A \code{tbl_df} containing the creation result for each submitted metadata component +#' @note The upsert key is based on the fullName parameter of the metadata, so updates are triggered +#' when an existing Salesforce element matches the metadata type and fullName. +#' @examples +#' \dontrun{ +#' # create an object that we can confirm the update portion of the upsert +#' base_obj_name <- "Custom_Account1" +#' custom_object <- list() +#' custom_object$fullName <- paste0(base_obj_name, "__c") +#' custom_object$label <- paste0(gsub("_", " ", base_obj_name)) +#' custom_object$pluralLabel <- paste0(base_obj_name, "s") +#' custom_object$nameField <- list(displayFormat = 'AN-{0000}', +#' label = paste0(base_obj_name, ' Number'), +#' type = 'AutoNumber') +#' custom_object$deploymentStatus <- 'Deployed' +#' custom_object$sharingModel <- 'ReadWrite' +#' custom_object$enableActivities <- 'true' +#' custom_object$description <- paste0(base_obj_name, " created by the Metadata API") +#' custom_object_result <- sf_create_metadata(metadata_type = 'CustomObject', +#' metadata = custom_object) +#' # now update the object that was created +#' upsert_metadata <- list(custom_object, custom_object) +#' upsert_metadata[[1]]$fullName <- 'Custom_Account1__c' +#' upsert_metadata[[1]]$label <- 'New Label Custom_Account1' +#' upsert_metadata[[1]]$pluralLabel <- 'Custom_Account1s_new' +#' upsert_metadata[[2]]$fullName <- 'Custom_Account2__c' +#' upsert_metadata[[2]]$label <- 'New Label Custom_Account2' +#' upsert_metadata[[2]]$pluralLabel <- 'Custom_Account2s_new' +#' upserted_custom_object_result <- sf_upsert_metadata(metadata_type = 'CustomObject', +#' metadata = upsert_metadata) +#' } +#' @export +sf_upsert_metadata <- function(metadata_type, metadata, all_or_none=FALSE, verbose=FALSE){ + + which_operation <- "upsertMetadata" + + # run some basic validation on the metadata to see if it conforms to WSDL standards + metadata <- metadata_type_validator(obj_type=metadata_type, obj_data=metadata) + + # define the operation + operation_node <- newXMLNode(which_operation, + namespaceDefinitions=c('http://soap.sforce.com/2006/04/metadata'), + suppressNamespaceWarning = TRUE) + # and add the metadata to it + xml_dat <- build_metadata_xml_from_list(input_data=metadata, metatype=metadata_type, root=operation_node) + + base_metadata_url <- make_base_metadata_url() + root <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none)), metadata_ns=TRUE) + body_node <- newXMLNode("soapenv:Body", parent=root) + body_node <- addChildren(body_node, xml_dat) + + if(verbose) { + print(base_metadata_url) + print(root) + } + + httr_response <- rPOST(url = base_metadata_url, + headers = c("SOAPAction"=which_operation, + "Content-Type"="text/xml"), + body = as(root, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + resultset <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) %>% + type_convert(col_types = cols()) + + return(resultset) +} \ No newline at end of file diff --git a/R/upsert.R b/R/upsert.R new file mode 100644 index 0000000..65db081 --- /dev/null +++ b/R/upsert.R @@ -0,0 +1,247 @@ +#' Upsert Records +#' +#' Upserts one or more new records to your organization’s data. +#' +#' @param input_data \code{named vector}, \code{matrix}, \code{data.frame}, or +#' \code{tbl_df}; data can be coerced into a \code{data.frame} +#' @template object_name +#' @template external_id_fieldname +#' @template all_or_none +#' @template api_type +#' @param ... Other arguments passed on to \code{\link{sf_bulk_operation}}. +#' @template verbose +#' @return \code{tbl_df} of records with success indicator +#' @examples +#' \dontrun{ +#' n <- 2 +#' new_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact-Create-", 1:n), +#' My_External_Id__c=letters[1:n]) +#' new_contacts_result <- sf_create(new_contacts, object_name="Contact") +#' +#' upserted_contacts <- tibble(FirstName = rep("Test", n), +#' LastName = paste0("Contact-Upsert-", 1:n), +#' My_External_Id__c=letters[1:n]) +#' new_record <- tibble(FirstName = "Test", +#' LastName = paste0("Contact-Upsert-", n+1), +#' My_External_Id__c=letters[n+1]) +#' upserted_contacts <- bind_rows(upserted_contacts, new_record) +#' +#' upserted_contacts_result1 <- sf_upsert(upserted_contacts, +#' object_name="Contact", +#' "My_External_Id__c") +#' } +#' @export +sf_upsert <- function(input_data, + object_name, + external_id_fieldname, + all_or_none = FALSE, + api_type = c("SOAP", "REST", "Bulk 1.0", "Bulk 2.0"), + ..., + verbose = FALSE){ + + api_type <- match.arg(api_type) + if(api_type == "REST"){ + resultset <- sf_upsert_rest(input_data=input_data, object_name=object_name, + external_id_fieldname=external_id_fieldname, + all_or_none=all_or_none, verbose=verbose) + } else if(api_type == "SOAP"){ + resultset <- sf_upsert_soap(input_data=input_data, object_name=object_name, + external_id_fieldname=external_id_fieldname, + all_or_none=all_or_none, verbose=verbose) + } else if(api_type == "Bulk 1.0"){ + resultset <- sf_upsert_bulk_v1(input_data=input_data, object_name=object_name, + external_id_fieldname=external_id_fieldname, + verbose = verbose, ...) + } else if(api_type == "Bulk 2.0"){ + resultset <- sf_upsert_bulk_v2(input_data=input_data, object_name=object_name, + external_id_fieldname=external_id_fieldname, + verbose = verbose, ...) + } else { + stop("Unknown API type") + } + return(resultset) +} + + +#' Upsert Records using SOAP API +#' +#' @importFrom readr cols type_convert +#' @importFrom httr content +#' @importFrom xml2 xml_ns_strip xml_find_all +#' @importFrom purrr map_df +#' @importFrom dplyr bind_rows +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_upsert_soap <- function(input_data, object_name, + external_id_fieldname, + all_or_none = FALSE, + verbose = FALSE){ + + input_data <- sf_input_data_validation(operation='upsert', input_data) + + base_soap_url <- make_base_soap_url() + if(verbose) { + message(base_soap_url) + } + + # limit this type of request to only 200 records at a time to prevent + # the XML from exceeding a size limit + batch_size <- 200 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + r <- make_soap_xml_skeleton(soap_headers=list(AllorNoneHeader = tolower(all_or_none))) + xml_dat <- build_soap_xml_from_list(input_data = batched_data, + operation = "upsert", + object_name = object_name, + external_id_fieldname = external_id_fieldname, + root = r) + httr_response <- rPOST(url = base_soap_url, + headers = c("SOAPAction"="upsert", + "Content-Type"="text/xml"), + body = as(xml_dat, "character")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding="UTF-8") + this_set <- response_parsed %>% + xml_ns_strip() %>% + xml_find_all('.//result') %>% + map_df(xml_nodeset_to_df) + resultset <- bind_rows(resultset, this_set) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Upsert Records using REST API +#' +#' @importFrom readr cols type_convert +#' @importFrom dplyr everything as_tibble bind_rows select +#' @importFrom jsonlite toJSON fromJSON +#' @importFrom stats quantile +#' @importFrom utils head +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_upsert_rest <- function(input_data, object_name, + external_id_fieldname, + all_or_none = FALSE, + verbose = FALSE){ + + # This resource is available in API version 42.0 and later. + stopifnot(as.numeric(getOption("salesforcer.api_version")) >= 42.0) + input_data <- sf_input_data_validation(operation='upsert', input_data) + + composite_batch_url <- make_composite_batch_url() + if(verbose) { + message(composite_batch_url) + } + + # limit this type of request to only 25 records, the max for this type of request + batch_size <- 25 + row_num <- nrow(input_data) + batch_id <- (seq.int(row_num)-1) %/% batch_size + if(verbose){ + message("Submitting data in ", max(batch_id)+1, " Batches") + } + message_flag <- unique(as.integer(quantile(0:max(batch_id), c(0.25,0.5,0.75,1)))) + + resultset <- NULL + for(batch in seq(0, max(batch_id))){ + if(verbose){ + batch_msg_flg <- batch %in% message_flag + if(batch_msg_flg){ + message(paste0("Processing Batch # ", head(batch, 1) + 1)) + } + } + batched_data <- input_data[batch_id == batch, , drop=FALSE] + inner_requests <- list() + for(i in 1:nrow(batched_data)){ + this_id <- batched_data[i, external_id_fieldname] + temp_batched_data <- batched_data[,-(which(names(batched_data) == external_id_fieldname))] + temp_batched_data <- temp_batched_data[,!grepl("^ID$|^IDS$", names(temp_batched_data), ignore.case=TRUE)] + inner_requests[[i]] <- list(method="PATCH", + url=paste0("v", getOption("salesforcer.api_version"), + "/sobjects/", object_name, "/", + external_id_fieldname, "/", this_id), + richInput=as.list(temp_batched_data[i,])) + } + request_body <- list(batchRequests=inner_requests) + httr_response <- rPOST(url = composite_batch_url, + headers = c("Accept"="application/json", + "Content-Type"="application/json"), + body = toJSON(request_body, + auto_unbox = TRUE)) + catch_errors(httr_response) + response_parsed <- content(httr_response, "text", encoding="UTF-8") + response_parsed <- fromJSON(response_parsed, flatten=TRUE)$results + response_parsed <- response_parsed %>% + rename_at(.vars = vars(starts_with("result.")), + .funs = funs(sub("^result\\.", "", .))) %>% + select(-matches("statusCode")) %>% + as_tibble() + resultset <- bind_rows(resultset, response_parsed) + } + resultset <- resultset %>% + type_convert(col_types = cols()) + return(resultset) +} + + +#' Upsert Records using Bulk 1.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_upsert_bulk_v1 <- function(input_data, object_name, + external_id_fieldname, + all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + input_data <- sf_input_data_validation(operation="upsert", input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + external_id_fieldname=external_id_fieldname, + operation="upsert", + api_type = "Bulk 1.0", + verbose=verbose, ...) + return(resultset) +} + + +#' Upsert Records using Bulk 2.0 API +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +sf_upsert_bulk_v2 <- function(input_data, object_name, + external_id_fieldname, + all_or_none = FALSE, + ..., + verbose = FALSE){ + # allor none? + #The order of records in the response is not guaranteed to match the ordering of records in the original job data. + input_data <- sf_input_data_validation(operation='upsert', input_data) + resultset <- sf_bulk_operation(input_data=input_data, + object_name=object_name, + external_id_fieldname=external_id_fieldname, + operation="upsert", + api_type = "Bulk 2.0", + verbose=verbose, ...) + return(resultset) +} diff --git a/R/utils-httr.R b/R/utils-httr.R new file mode 100644 index 0000000..e15ce9d --- /dev/null +++ b/R/utils-httr.R @@ -0,0 +1,145 @@ +# Adapted from googlesheets package https://github.com/jennybc/googlesheets + +# Modifications: +# - Added catch_errors() function + +# Copyright (c) 2017 Jennifer Bryan, Joanna Zhao +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +#' Generic implementation of HTTP methods with retries and authentication +#' +#' @importFrom httr status_code config add_headers +#' @importFrom stats runif +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +VERB_n <- function(VERB, n = 5) { + function(url, headers=character(0), ...) { + + current_state <- salesforcer_state() + for (i in seq_len(n)) { + + if(is.null(current_state$auth_method)){ + out <- VERB(url = url, add_headers(headers), ...) + } else if(current_state$auth_method == 'OAuth'){ + if(grepl("/services/data/v[0-9]{2}.[0-9]{1}/jobs/ingest", url)){ + out <- VERB(url = url, add_headers(c(headers, "Authorization"=sprintf("Bearer %s", current_state$token$credentials$access_token))), ...) + } else if(grepl("/services/async", url)){ + out <- VERB(url = url, add_headers(c(headers, "X-SFDC-Session"=current_state$token$credentials$access_token)), ...) + } else { + out <- VERB(url = url, config=config(token=current_state$token), add_headers(headers), ...) + } + } else if (current_state$auth_method == 'Basic') { + out <- VERB(url = url, add_headers(c(headers, "Authorization"=sprintf("Bearer %s", current_state$session_id))), ...) + } + + status <- status_code(out) + if (status < 500 || i == n) break + backoff <- runif(n = 1, min = 0, max = 2 ^ i - 1) + ## TO DO: honor a verbose argument or option + mess <- paste("HTTP error %s on attempt %d ...\n", + " backing off %0.2f seconds, retrying") + mpf(mess, status, i, backoff) + Sys.sleep(backoff) + } + out + } +} + +#' GETs with retries and authentication +#' +#' @importFrom httr GET +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +rGET <- VERB_n(GET) + +#' POSTs with retries and authentication +#' +#' @importFrom httr POST +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +rPOST <- VERB_n(POST) + +#' PATCHs with retries and authentication +#' +#' @importFrom httr PATCH +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +rPATCH <- VERB_n(PATCH) + +#' PUTs with retries and authentication +#' +#' @importFrom httr PUT +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +rPUT <- VERB_n(PUT) + +#' DELETEs with retries and authentication +#' +#' @importFrom httr DELETE +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +rDELETE <- VERB_n(DELETE) + +## good news: these are handy and call. = FALSE is built-in +## bad news: 'fmt' must be exactly 1 string, i.e. you've got to paste, iff +## you're counting on sprintf() substitution +cpf <- function(...) cat(paste0(sprintf(...), "\n")) +mpf <- function(...) message(sprintf(...)) +wpf <- function(...) warning(sprintf(...), call. = FALSE) +spf <- function(...) stop(sprintf(...), call. = FALSE) + +#' Function to catch and print HTTP errors +#' +#' @importFrom httr content http_error +#' @importFrom xml2 as_list xml_find_first +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +catch_errors <- function(x){ + if(http_error(x)){ + response_parsed <- content(x, encoding='UTF-8') + # convert to list if xml content type + content_type <- x$headers$`content-type` + if(grepl('xml', content_type)){ + response_parsed <- as_list(response_parsed) + } + if(status_code(x) < 500){ + if(!is.null(response_parsed$exceptionCode)){ + stop(sprintf("%s: %s", response_parsed$exceptionCode, response_parsed$exceptionMessage)) + } else if(!is.null(response_parsed$error$exceptionCode)){ + stop(sprintf("%s: %s", response_parsed$error$exceptionCode, response_parsed$error$exceptionMessage)) + } else if(!is.null(response_parsed[[1]]$Error$errorCode[[1]])){ + stop(sprintf("%s: %s", response_parsed[[1]]$Error$errorCode[[1]], response_parsed[[1]]$Error$message[[1]])) + } else { + stop(sprintf("%s: %s", response_parsed[[1]]$errorCode, response_parsed[[1]]$message)) + } + } else { + error_message <- response_parsed$Envelope$Body$Fault + stop(error_message$faultstring[[1]][1]) + } + } + invisible(FALSE) +} \ No newline at end of file diff --git a/R/utils-metadata.R b/R/utils-metadata.R new file mode 100644 index 0000000..8c679de --- /dev/null +++ b/R/utils-metadata.R @@ -0,0 +1,12422 @@ +#' Metadata Data Type Validator +#' +#' A function to create a variety of objects that are part of the Metadata API service +#' Below is a list of objects and their required components to be created with this function: +#' +#' \strong{AccessMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_accessmapping.htm}{Salesforce Documentation for AccessMapping} +#' \describe{ +#' \item{accessLevel}{a character} +#' \item{object}{a character} +#' \item{objectField}{a character} +#' \item{userField}{a character} +#' } +#' +#' \strong{AccountSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_accountsettings.htm}{Salesforce Documentation for AccountSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableAccountOwnerReport}{a character either 'true' or 'false'} +#' \item{enableAccountTeams}{a character either 'true' or 'false'} +#' \item{showViewHierarchyLink}{a character either 'true' or 'false'} +#' } +#' +#' \strong{AccountSharingRuleSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_accountsharingrulesettings.htm}{Salesforce Documentation for AccountSharingRuleSettings} +#' \describe{ +#' \item{caseAccessLevel}{a character} +#' \item{contactAccessLevel}{a character} +#' \item{opportunityAccessLevel}{a character} +#' } +#' +#' \strong{ActionLinkGroupTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_actionlinkgrouptemplate.htm}{Salesforce Documentation for ActionLinkGroupTemplate} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionLinkTemplates}{a ActionLinkTemplate} +#' \item{category}{a PlatformActionGroupCategory - which is a character taking one of the following values: +#' \itemize{ +#' \item{Primary} +#' \item{Overflow} +#' } +#' } +#' \item{executionsAllowed}{a ActionLinkExecutionsAllowed - which is a character taking one of the following values: +#' \itemize{ +#' \item{Once} +#' \item{OncePerUser} +#' \item{Unlimited} +#' } +#' } +#' \item{hoursUntilExpiration}{a integer} +#' \item{isPublished}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{ActionLinkTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_actionlinktemplate.htm}{Salesforce Documentation for ActionLinkTemplate} +#' \describe{ +#' \item{actionUrl}{a character} +#' \item{headers}{a character} +#' \item{isConfirmationRequired}{a character either 'true' or 'false'} +#' \item{isGroupDefault}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{labelKey}{a character} +#' \item{linkType}{a ActionLinkType - which is a character taking one of the following values: +#' \itemize{ +#' \item{API} +#' \item{APIAsync} +#' \item{Download} +#' \item{UI} +#' } +#' } +#' \item{method}{a ActionLinkHttpMethod - which is a character taking one of the following values: +#' \itemize{ +#' \item{HttpDelete} +#' \item{HttpHead} +#' \item{HttpGet} +#' \item{HttpPatch} +#' \item{HttpPost} +#' \item{HttpPut} +#' } +#' } +#' \item{position}{a integer} +#' \item{requestBody}{a character} +#' \item{userAlias}{a character} +#' \item{userVisibility}{a ActionLinkUserVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{Creator} +#' \item{Everyone} +#' \item{EveryoneButCreator} +#' \item{Manager} +#' \item{CustomUser} +#' \item{CustomExcludedUser} +#' } +#' } +#' } +#' +#' \strong{ActionOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_actionoverride.htm}{Salesforce Documentation for ActionOverride} +#' \describe{ +#' \item{actionName}{a character} +#' \item{comment}{a character} +#' \item{content}{a character} +#' \item{formFactor}{a FormFactor - which is a character taking one of the following values: +#' \itemize{ +#' \item{Small} +#' \item{Medium} +#' \item{Large} +#' } +#' } +#' \item{skipRecordTypeSelect}{a character either 'true' or 'false'} +#' \item{type}{a ActionOverrideType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{Standard} +#' \item{Scontrol} +#' \item{Visualforce} +#' \item{Flexipage} +#' \item{LightningComponent} +#' } +#' } +#' } +#' +#' \strong{ActivitiesSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_activitiessettings.htm}{Salesforce Documentation for ActivitiesSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{allowUsersToRelateMultipleContactsToTasksAndEvents}{a character either 'true' or 'false'} +#' \item{autoRelateEventAttendees}{a character either 'true' or 'false'} +#' \item{enableActivityReminders}{a character either 'true' or 'false'} +#' \item{enableClickCreateEvents}{a character either 'true' or 'false'} +#' \item{enableDragAndDropScheduling}{a character either 'true' or 'false'} +#' \item{enableEmailTracking}{a character either 'true' or 'false'} +#' \item{enableGroupTasks}{a character either 'true' or 'false'} +#' \item{enableListViewScheduling}{a character either 'true' or 'false'} +#' \item{enableLogNote}{a character either 'true' or 'false'} +#' \item{enableMultidayEvents}{a character either 'true' or 'false'} +#' \item{enableRecurringEvents}{a character either 'true' or 'false'} +#' \item{enableRecurringTasks}{a character either 'true' or 'false'} +#' \item{enableSidebarCalendarShortcut}{a character either 'true' or 'false'} +#' \item{enableSimpleTaskCreateUI}{a character either 'true' or 'false'} +#' \item{enableUNSTaskDelegatedToNotifications}{a character either 'true' or 'false'} +#' \item{meetingRequestsLogo}{a character} +#' \item{showCustomLogoMeetingRequests}{a character either 'true' or 'false'} +#' \item{showEventDetailsMultiUserCalendar}{a character either 'true' or 'false'} +#' \item{showHomePageHoverLinksForEvents}{a character either 'true' or 'false'} +#' \item{showMyTasksHoverLinks}{a character either 'true' or 'false'} +#' } +#' +#' \strong{AddressSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_addresssettings.htm}{Salesforce Documentation for AddressSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{countriesAndStates}{a CountriesAndStates} +#' } +#' +#' \strong{AdjustmentsSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_adjustmentssettings.htm}{Salesforce Documentation for AdjustmentsSettings} +#' \describe{ +#' \item{enableAdjustments}{a character either 'true' or 'false'} +#' \item{enableOwnerAdjustments}{a character either 'true' or 'false'} +#' } +#' +#' \strong{AgentConfigAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentconfigassignments.htm}{Salesforce Documentation for AgentConfigAssignments} +#' \describe{ +#' \item{profiles}{a AgentConfigProfileAssignments} +#' \item{users}{a AgentConfigUserAssignments} +#' } +#' +#' \strong{AgentConfigButtons} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentconfigbuttons.htm}{Salesforce Documentation for AgentConfigButtons} +#' \describe{ +#' \item{button}{a character} +#' } +#' +#' \strong{AgentConfigProfileAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentconfigprofileassignments.htm}{Salesforce Documentation for AgentConfigProfileAssignments} +#' \describe{ +#' \item{profile}{a character} +#' } +#' +#' \strong{AgentConfigSkills} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentconfigskills.htm}{Salesforce Documentation for AgentConfigSkills} +#' \describe{ +#' \item{skill}{a character} +#' } +#' +#' \strong{AgentConfigUserAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentconfiguserassignments.htm}{Salesforce Documentation for AgentConfigUserAssignments} +#' \describe{ +#' \item{user}{a character} +#' } +#' +#' \strong{AnalyticsCloudComponentLayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_analyticscloudcomponentlayoutitem.htm}{Salesforce Documentation for AnalyticsCloudComponentLayoutItem} +#' \describe{ +#' \item{assetType}{a character} +#' \item{devName}{a character} +#' \item{error}{a character} +#' \item{filter}{a character} +#' \item{height}{a integer} +#' \item{hideOnError}{a character either 'true' or 'false'} +#' \item{showHeader}{a character either 'true' or 'false'} +#' \item{showSharing}{a character either 'true' or 'false'} +#' \item{showTitle}{a character either 'true' or 'false'} +#' \item{width}{a character} +#' } +#' +#' \strong{AnalyticSnapshot} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_analyticsnapshot.htm}{Salesforce Documentation for AnalyticSnapshot} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{groupColumn}{a character} +#' \item{mappings}{a AnalyticSnapshotMapping} +#' \item{name}{a character} +#' \item{runningUser}{a character} +#' \item{sourceReport}{a character} +#' \item{targetObject}{a character} +#' } +#' +#' \strong{AnalyticSnapshotMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_analyticsnapshotmapping.htm}{Salesforce Documentation for AnalyticSnapshotMapping} +#' \describe{ +#' \item{aggregateType}{a ReportSummaryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{None} +#' } +#' } +#' \item{sourceField}{a character} +#' \item{sourceType}{a ReportJobSourceTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{tabular} +#' \item{summary} +#' \item{snapshot} +#' } +#' } +#' \item{targetField}{a character} +#' } +#' +#' \strong{ApexClass} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apexclass.htm}{Salesforce Documentation for ApexClass} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{packageVersions}{a PackageVersion} +#' \item{status}{a ApexCodeUnitStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{Inactive} +#' \item{Active} +#' \item{Deleted} +#' } +#' } +#' } +#' +#' \strong{ApexComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apexcomponent.htm}{Salesforce Documentation for ApexComponent} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{packageVersions}{a PackageVersion} +#' } +#' +#' \strong{ApexPage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apexpage.htm}{Salesforce Documentation for ApexPage} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{availableInTouch}{a character either 'true' or 'false'} +#' \item{confirmationTokenRequired}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{packageVersions}{a PackageVersion} +#' } +#' +#' \strong{ApexTestSuite} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apextestsuite.htm}{Salesforce Documentation for ApexTestSuite} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{testClassName}{a character} +#' } +#' +#' \strong{ApexTrigger} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apextrigger.htm}{Salesforce Documentation for ApexTrigger} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{packageVersions}{a PackageVersion} +#' \item{status}{a ApexCodeUnitStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{Inactive} +#' \item{Active} +#' \item{Deleted} +#' } +#' } +#' } +#' +#' \strong{AppActionOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appactionoverride.htm}{Salesforce Documentation for AppActionOverride} +#' \describe{ +#' \item{actionName}{a character (inherited from ActionOverride)} +#' \item{comment}{a character (inherited from ActionOverride)} +#' \item{content}{a character (inherited from ActionOverride)} +#' \item{formFactor}{a FormFactor (inherited from ActionOverride)} +#' \item{skipRecordTypeSelect}{a character either 'true' or 'false' (inherited from ActionOverride)} +#' \item{type}{a ActionOverrideType (inherited from ActionOverride)} +#' \item{pageOrSobjectType}{a character} +#' } +#' +#' \strong{AppBrand} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appbrand.htm}{Salesforce Documentation for AppBrand} +#' \describe{ +#' \item{footerColor}{a character} +#' \item{headerColor}{a character} +#' \item{logo}{a character} +#' \item{logoVersion}{a integer} +#' \item{shouldOverrideOrgTheme}{a character either 'true' or 'false'} +#' } +#' +#' \strong{AppComponentList} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appcomponentlist.htm}{Salesforce Documentation for AppComponentList} +#' \describe{ +#' \item{alignment}{a character} +#' \item{components}{a character} +#' } +#' +#' \strong{AppMenu} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appmenu.htm}{Salesforce Documentation for AppMenu} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{appMenuItems}{a AppMenuItem} +#' } +#' +#' \strong{AppMenuItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appmenuitem.htm}{Salesforce Documentation for AppMenuItem} +#' \describe{ +#' \item{name}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{AppPreferences} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_apppreferences.htm}{Salesforce Documentation for AppPreferences} +#' \describe{ +#' \item{enableCustomizeMyTabs}{a character either 'true' or 'false'} +#' \item{enableKeyboardShortcuts}{a character either 'true' or 'false'} +#' \item{enableListViewHover}{a character either 'true' or 'false'} +#' \item{enableListViewReskin}{a character either 'true' or 'false'} +#' \item{enableMultiMonitorComponents}{a character either 'true' or 'false'} +#' \item{enablePinTabs}{a character either 'true' or 'false'} +#' \item{enableTabHover}{a character either 'true' or 'false'} +#' \item{enableTabLimits}{a character either 'true' or 'false'} +#' \item{saveUserSessions}{a character either 'true' or 'false'} +#' } +#' +#' \strong{AppProfileActionOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appprofileactionoverride.htm}{Salesforce Documentation for AppProfileActionOverride} +#' \describe{ +#' \item{actionName}{a character (inherited from ProfileActionOverride)} +#' \item{content}{a character (inherited from ProfileActionOverride)} +#' \item{formFactor}{a FormFactor (inherited from ProfileActionOverride)} +#' \item{pageOrSobjectType}{a character (inherited from ProfileActionOverride)} +#' \item{recordType}{a character (inherited from ProfileActionOverride)} +#' \item{type}{a ActionOverrideType (inherited from ProfileActionOverride)} +#' \item{profile}{a character} +#' } +#' +#' \strong{ApprovalAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalaction.htm}{Salesforce Documentation for ApprovalAction} +#' \describe{ +#' \item{action}{a WorkflowActionReference} +#' } +#' +#' \strong{ApprovalEntryCriteria} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalentrycriteria.htm}{Salesforce Documentation for ApprovalEntryCriteria} +#' \describe{ +#' \item{booleanFilter}{a character} +#' \item{criteriaItems}{a FilterItem} +#' \item{formula}{a character} +#' } +#' +#' \strong{ApprovalPageField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalpagefield.htm}{Salesforce Documentation for ApprovalPageField} +#' \describe{ +#' \item{field}{a character} +#' } +#' +#' \strong{ApprovalProcess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalprocess.htm}{Salesforce Documentation for ApprovalProcess} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{allowRecall}{a character either 'true' or 'false'} +#' \item{allowedSubmitters}{a ApprovalSubmitter} +#' \item{approvalPageFields}{a ApprovalPageField} +#' \item{approvalStep}{a ApprovalStep} +#' \item{description}{a character} +#' \item{emailTemplate}{a character} +#' \item{enableMobileDeviceAccess}{a character either 'true' or 'false'} +#' \item{entryCriteria}{a ApprovalEntryCriteria} +#' \item{finalApprovalActions}{a ApprovalAction} +#' \item{finalApprovalRecordLock}{a character either 'true' or 'false'} +#' \item{finalRejectionActions}{a ApprovalAction} +#' \item{finalRejectionRecordLock}{a character either 'true' or 'false'} +#' \item{initialSubmissionActions}{a ApprovalAction} +#' \item{label}{a character} +#' \item{nextAutomatedApprover}{a NextAutomatedApprover} +#' \item{postTemplate}{a character} +#' \item{recallActions}{a ApprovalAction} +#' \item{recordEditability}{a RecordEditabilityType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AdminOnly} +#' \item{AdminOrCurrentApprover} +#' } +#' } +#' \item{showApprovalHistory}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ApprovalStep} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalstep.htm}{Salesforce Documentation for ApprovalStep} +#' \describe{ +#' \item{allowDelegate}{a character either 'true' or 'false'} +#' \item{approvalActions}{a ApprovalAction} +#' \item{assignedApprover}{a ApprovalStepApprover} +#' \item{description}{a character} +#' \item{entryCriteria}{a ApprovalEntryCriteria} +#' \item{ifCriteriaNotMet}{a StepCriteriaNotMetType - which is a character taking one of the following values: +#' \itemize{ +#' \item{ApproveRecord} +#' \item{RejectRecord} +#' \item{GotoNextStep} +#' } +#' } +#' \item{label}{a character} +#' \item{name}{a character} +#' \item{rejectBehavior}{a ApprovalStepRejectBehavior} +#' \item{rejectionActions}{a ApprovalAction} +#' } +#' +#' \strong{ApprovalStepApprover} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalstepapprover.htm}{Salesforce Documentation for ApprovalStepApprover} +#' \describe{ +#' \item{approver}{a Approver} +#' \item{whenMultipleApprovers}{a RoutingType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Unanimous} +#' \item{FirstResponse} +#' } +#' } +#' } +#' +#' \strong{ApprovalStepRejectBehavior} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalsteprejectbehavior.htm}{Salesforce Documentation for ApprovalStepRejectBehavior} +#' \describe{ +#' \item{type}{a StepRejectBehaviorType - which is a character taking one of the following values: +#' \itemize{ +#' \item{RejectRequest} +#' \item{BackToPrevious} +#' } +#' } +#' } +#' +#' \strong{ApprovalSubmitter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approvalsubmitter.htm}{Salesforce Documentation for ApprovalSubmitter} +#' \describe{ +#' \item{submitter}{a character} +#' \item{type}{a ProcessSubmitterType - which is a character taking one of the following values: +#' \itemize{ +#' \item{group} +#' \item{role} +#' \item{user} +#' \item{roleSubordinates} +#' \item{roleSubordinatesInternal} +#' \item{owner} +#' \item{creator} +#' \item{partnerUser} +#' \item{customerPortalUser} +#' \item{portalRole} +#' \item{portalRoleSubordinates} +#' \item{allInternalUsers} +#' } +#' } +#' } +#' +#' \strong{Approver} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_approver.htm}{Salesforce Documentation for Approver} +#' \describe{ +#' \item{name}{a character} +#' \item{type}{a NextOwnerType - which is a character taking one of the following values: +#' \itemize{ +#' \item{adhoc} +#' \item{user} +#' \item{userHierarchyField} +#' \item{relatedUserField} +#' \item{queue} +#' } +#' } +#' } +#' +#' \strong{AppWorkspaceConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_appworkspaceconfig.htm}{Salesforce Documentation for AppWorkspaceConfig} +#' \describe{ +#' \item{mappings}{a WorkspaceMapping} +#' } +#' +#' \strong{ArticleTypeChannelDisplay} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_articletypechanneldisplay.htm}{Salesforce Documentation for ArticleTypeChannelDisplay} +#' \describe{ +#' \item{articleTypeTemplates}{a ArticleTypeTemplate} +#' } +#' +#' \strong{ArticleTypeTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_articletypetemplate.htm}{Salesforce Documentation for ArticleTypeTemplate} +#' \describe{ +#' \item{channel}{a Channel - which is a character taking one of the following values: +#' \itemize{ +#' \item{AllChannels} +#' \item{App} +#' \item{Pkb} +#' \item{Csp} +#' \item{Prm} +#' } +#' } +#' \item{page}{a character} +#' \item{template}{a Template - which is a character taking one of the following values: +#' \itemize{ +#' \item{Page} +#' \item{Tab} +#' \item{Toc} +#' } +#' } +#' } +#' +#' \strong{AssignmentRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_assignmentrule.htm}{Salesforce Documentation for AssignmentRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{ruleEntry}{a RuleEntry} +#' } +#' +#' \strong{AssignmentRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_assignmentrules.htm}{Salesforce Documentation for AssignmentRules} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assignmentRule}{a AssignmentRule} +#' } +#' +#' \strong{AssistantRecommendationType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_assistantrecommendationtype.htm}{Salesforce Documentation for AssistantRecommendationType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{platformActionlist}{a PlatformActionList} +#' \item{sobjectType}{a character} +#' \item{title}{a character} +#' } +#' +#' \strong{Attachment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_attachment.htm}{Salesforce Documentation for Attachment} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode} +#' \item{name}{a character} +#' } +#' +#' \strong{AuraDefinitionBundle} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_auradefinitionbundle.htm}{Salesforce Documentation for AuraDefinitionBundle} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{SVGContent}{a character formed using RCurl::base64Encode} +#' \item{apiVersion}{a numeric} +#' \item{controllerContent}{a character formed using RCurl::base64Encode} +#' \item{description}{a character} +#' \item{designContent}{a character formed using RCurl::base64Encode} +#' \item{documentationContent}{a character formed using RCurl::base64Encode} +#' \item{helperContent}{a character formed using RCurl::base64Encode} +#' \item{markup}{a character formed using RCurl::base64Encode} +#' \item{modelContent}{a character formed using RCurl::base64Encode} +#' \item{packageVersions}{a PackageVersion} +#' \item{rendererContent}{a character formed using RCurl::base64Encode} +#' \item{styleContent}{a character formed using RCurl::base64Encode} +#' \item{testsuiteContent}{a character formed using RCurl::base64Encode} +#' \item{type}{a AuraBundleType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Application} +#' \item{Component} +#' \item{Event} +#' \item{Interface} +#' \item{Tokens} +#' } +#' } +#' } +#' +#' \strong{AuthProvider} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_authprovider.htm}{Salesforce Documentation for AuthProvider} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{authorizeUrl}{a character} +#' \item{consumerKey}{a character} +#' \item{consumerSecret}{a character} +#' \item{customMetadataTypeRecord}{a character} +#' \item{defaultScopes}{a character} +#' \item{errorUrl}{a character} +#' \item{executionUser}{a character} +#' \item{friendlyName}{a character} +#' \item{iconUrl}{a character} +#' \item{idTokenIssuer}{a character} +#' \item{includeOrgIdInIdentifier}{a character either 'true' or 'false'} +#' \item{logoutUrl}{a character} +#' \item{plugin}{a character} +#' \item{portal}{a character} +#' \item{providerType}{a AuthProviderType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Facebook} +#' \item{Janrain} +#' \item{Salesforce} +#' \item{OpenIdConnect} +#' \item{MicrosoftACS} +#' \item{LinkedIn} +#' \item{Twitter} +#' \item{Google} +#' \item{GitHub} +#' \item{Custom} +#' } +#' } +#' \item{registrationHandler}{a character} +#' \item{sendAccessTokenInHeader}{a character either 'true' or 'false'} +#' \item{sendClientCredentialsInHeader}{a character either 'true' or 'false'} +#' \item{tokenUrl}{a character} +#' \item{userInfoUrl}{a character} +#' } +#' +#' \strong{AutoResponseRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_autoresponserule.htm}{Salesforce Documentation for AutoResponseRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{ruleEntry}{a RuleEntry} +#' } +#' +#' \strong{AutoResponseRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_autoresponserules.htm}{Salesforce Documentation for AutoResponseRules} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{autoResponseRule}{a AutoResponseRule} +#' } +#' +#' \strong{BrandingSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_brandingset.htm}{Salesforce Documentation for BrandingSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{brandingSetProperty}{a BrandingSetProperty} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{BrandingSetProperty} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_brandingsetproperty.htm}{Salesforce Documentation for BrandingSetProperty} +#' \describe{ +#' \item{propertyName}{a character} +#' \item{propertyValue}{a character} +#' } +#' +#' \strong{BusinessHoursEntry} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_businesshoursentry.htm}{Salesforce Documentation for BusinessHoursEntry} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{default}{a character either 'true' or 'false'} +#' \item{fridayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{fridayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{mondayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{mondayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{name}{a character} +#' \item{saturdayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{saturdayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{sundayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{sundayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{thursdayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{thursdayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{timeZoneId}{a character} +#' \item{tuesdayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{tuesdayStartTime}{a character formatted as 'hh:mm:ssZ} +#' \item{wednesdayEndTime}{a character formatted as 'hh:mm:ssZ} +#' \item{wednesdayStartTime}{a character formatted as 'hh:mm:ssZ} +#' } +#' +#' \strong{BusinessHoursSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_businesshourssettings.htm}{Salesforce Documentation for BusinessHoursSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{businessHours}{a BusinessHoursEntry} +#' \item{holidays}{a Holiday} +#' } +#' +#' \strong{BusinessProcess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_businessprocess.htm}{Salesforce Documentation for BusinessProcess} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{values}{a PicklistValue} +#' } +#' +#' \strong{CallCenter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_callcenter.htm}{Salesforce Documentation for CallCenter} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{adapterUrl}{a character} +#' \item{customSettings}{a character} +#' \item{displayName}{a character} +#' \item{displayNameLabel}{a character} +#' \item{internalNameLabel}{a character} +#' \item{sections}{a CallCenterSection} +#' \item{version}{a character} +#' } +#' +#' \strong{CallCenterItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_callcenteritem.htm}{Salesforce Documentation for CallCenterItem} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{CallCenterSection} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_callcentersection.htm}{Salesforce Documentation for CallCenterSection} +#' \describe{ +#' \item{items}{a CallCenterItem} +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{CampaignInfluenceModel} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_campaigninfluencemodel.htm}{Salesforce Documentation for CampaignInfluenceModel} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{isDefaultModel}{a character either 'true' or 'false'} +#' \item{isModelLocked}{a character either 'true' or 'false'} +#' \item{modelDescription}{a character} +#' \item{name}{a character} +#' \item{recordPreference}{a character} +#' } +#' +#' \strong{CaseSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_casesettings.htm}{Salesforce Documentation for CaseSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{caseAssignNotificationTemplate}{a character} +#' \item{caseCloseNotificationTemplate}{a character} +#' \item{caseCommentNotificationTemplate}{a character} +#' \item{caseCreateNotificationTemplate}{a character} +#' \item{caseFeedItemSettings}{a FeedItemSettings} +#' \item{closeCaseThroughStatusChange}{a character either 'true' or 'false'} +#' \item{defaultCaseOwner}{a character} +#' \item{defaultCaseOwnerType}{a character} +#' \item{defaultCaseUser}{a character} +#' \item{emailActionDefaultsHandlerClass}{a character} +#' \item{emailToCase}{a EmailToCaseSettings} +#' \item{enableCaseFeed}{a character either 'true' or 'false'} +#' \item{enableDraftEmails}{a character either 'true' or 'false'} +#' \item{enableEarlyEscalationRuleTriggers}{a character either 'true' or 'false'} +#' \item{enableEmailActionDefaultsHandler}{a character either 'true' or 'false'} +#' \item{enableSuggestedArticlesApplication}{a character either 'true' or 'false'} +#' \item{enableSuggestedArticlesCustomerPortal}{a character either 'true' or 'false'} +#' \item{enableSuggestedArticlesPartnerPortal}{a character either 'true' or 'false'} +#' \item{enableSuggestedSolutions}{a character either 'true' or 'false'} +#' \item{keepRecordTypeOnAssignmentRule}{a character either 'true' or 'false'} +#' \item{notifyContactOnCaseComment}{a character either 'true' or 'false'} +#' \item{notifyDefaultCaseOwner}{a character either 'true' or 'false'} +#' \item{notifyOwnerOnCaseComment}{a character either 'true' or 'false'} +#' \item{notifyOwnerOnCaseOwnerChange}{a character either 'true' or 'false'} +#' \item{showEmailAttachmentsInCaseAttachmentsRL}{a character either 'true' or 'false'} +#' \item{showFewerCloseActions}{a character either 'true' or 'false'} +#' \item{systemUserEmail}{a character} +#' \item{useSystemEmailAddress}{a character either 'true' or 'false'} +#' \item{useSystemUserAsDefaultCaseUser}{a character either 'true' or 'false'} +#' \item{webToCase}{a WebToCaseSettings} +#' } +#' +#' \strong{CaseSubjectParticle} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_casesubjectparticle.htm}{Salesforce Documentation for CaseSubjectParticle} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{index}{a integer} +#' \item{textField}{a character} +#' \item{type}{a CaseSubjectParticleType - which is a character taking one of the following values: +#' \itemize{ +#' \item{ProvidedString} +#' \item{Source} +#' \item{MessageType} +#' \item{SocialHandle} +#' \item{SocialNetwork} +#' \item{Sentiment} +#' \item{RealName} +#' \item{Content} +#' \item{PipeSeparator} +#' \item{ColonSeparator} +#' \item{HyphenSeparator} +#' } +#' } +#' } +#' +#' \strong{Certificate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_certificate.htm}{Salesforce Documentation for Certificate} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{caSigned}{a character either 'true' or 'false'} +#' \item{encryptedWithPlatformEncryption}{a character either 'true' or 'false'} +#' \item{expirationDate}{a character formatted as 'yyyy-mm-ddThh:mm:ssZ'} +#' \item{keySize}{a integer} +#' \item{masterLabel}{a character} +#' \item{privateKeyExportable}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ChannelLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_channellayout.htm}{Salesforce Documentation for ChannelLayout} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enabledChannels}{a character} +#' \item{label}{a character} +#' \item{layoutItems}{a ChannelLayoutItem} +#' \item{recordType}{a character} +#' } +#' +#' \strong{ChannelLayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_channellayoutitem.htm}{Salesforce Documentation for ChannelLayoutItem} +#' \describe{ +#' \item{field}{a character} +#' } +#' +#' \strong{ChartSummary} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_chartsummary.htm}{Salesforce Documentation for ChartSummary} +#' \describe{ +#' \item{aggregate}{a ReportSummaryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{None} +#' } +#' } +#' \item{axisBinding}{a ChartAxis - which is a character taking one of the following values: +#' \itemize{ +#' \item{x} +#' \item{y} +#' \item{y2} +#' \item{r} +#' } +#' } +#' \item{column}{a character} +#' } +#' +#' \strong{ChatterAnswersReputationLevel} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_chatteranswersreputationlevel.htm}{Salesforce Documentation for ChatterAnswersReputationLevel} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a integer} +#' } +#' +#' \strong{ChatterAnswersSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_chatteranswerssettings.htm}{Salesforce Documentation for ChatterAnswersSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{emailFollowersOnBestAnswer}{a character either 'true' or 'false'} +#' \item{emailFollowersOnReply}{a character either 'true' or 'false'} +#' \item{emailOwnerOnPrivateReply}{a character either 'true' or 'false'} +#' \item{emailOwnerOnReply}{a character either 'true' or 'false'} +#' \item{enableAnswerViaEmail}{a character either 'true' or 'false'} +#' \item{enableChatterAnswers}{a character either 'true' or 'false'} +#' \item{enableFacebookSSO}{a character either 'true' or 'false'} +#' \item{enableInlinePublisher}{a character either 'true' or 'false'} +#' \item{enableReputation}{a character either 'true' or 'false'} +#' \item{enableRichTextEditor}{a character either 'true' or 'false'} +#' \item{facebookAuthProvider}{a character} +#' \item{showInPortals}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ChatterExtension} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_chatterextension.htm}{Salesforce Documentation for ChatterExtension} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{compositionComponent}{a character} +#' \item{description}{a character} +#' \item{extensionName}{a character} +#' \item{headerText}{a character} +#' \item{hoverText}{a character} +#' \item{icon}{a character} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{renderComponent}{a character} +#' \item{type}{a ChatterExtensionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Lightning} +#' } +#' } +#' } +#' +#' \strong{ChatterMobileSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_chattermobilesettings.htm}{Salesforce Documentation for ChatterMobileSettings} +#' \describe{ +#' \item{enablePushNotifications}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CleanDataService} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_cleandataservice.htm}{Salesforce Documentation for CleanDataService} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{cleanRules}{a CleanRule} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{matchEngine}{a character} +#' } +#' +#' \strong{CleanRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_cleanrule.htm}{Salesforce Documentation for CleanRule} +#' \describe{ +#' \item{bulkEnabled}{a character either 'true' or 'false'} +#' \item{bypassTriggers}{a character either 'true' or 'false'} +#' \item{bypassWorkflow}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{developerName}{a character} +#' \item{fieldMappings}{a FieldMapping} +#' \item{masterLabel}{a character} +#' \item{matchRule}{a character} +#' \item{sourceSobjectType}{a character} +#' \item{status}{a CleanRuleStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{Inactive} +#' \item{Active} +#' } +#' } +#' \item{targetSobjectType}{a character} +#' } +#' +#' \strong{CodeLocation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_codelocation.htm}{Salesforce Documentation for CodeLocation} +#' \describe{ +#' \item{column}{a integer} +#' \item{line}{a integer} +#' \item{numExecutions}{a integer} +#' \item{time}{a numeric} +#' } +#' +#' \strong{Community} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_community.htm}{Salesforce Documentation for Community} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{chatterAnswersFacebookSsoUrl}{a character} +#' \item{communityFeedPage}{a character} +#' \item{dataCategoryName}{a character} +#' \item{description}{a character} +#' \item{emailFooterDocument}{a character} +#' \item{emailHeaderDocument}{a character} +#' \item{emailNotificationUrl}{a character} +#' \item{enableChatterAnswers}{a character either 'true' or 'false'} +#' \item{enablePrivateQuestions}{a character either 'true' or 'false'} +#' \item{expertsGroup}{a character} +#' \item{portal}{a character} +#' \item{reputationLevels}{a ReputationLevels} +#' \item{showInPortal}{a character either 'true' or 'false'} +#' \item{site}{a character} +#' } +#' +#' \strong{CommunityCustomThemeLayoutType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitycustomthemelayouttype.htm}{Salesforce Documentation for CommunityCustomThemeLayoutType} +#' \describe{ +#' \item{description}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{CommunityRoles} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communityroles.htm}{Salesforce Documentation for CommunityRoles} +#' \describe{ +#' \item{customerUserRole}{a character} +#' \item{employeeUserRole}{a character} +#' \item{partnerUserRole}{a character} +#' } +#' +#' \strong{CommunityTemplateBundleInfo} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitytemplatebundleinfo.htm}{Salesforce Documentation for CommunityTemplateBundleInfo} +#' \describe{ +#' \item{description}{a character} +#' \item{image}{a character} +#' \item{order}{a integer} +#' \item{title}{a character} +#' \item{type}{a CommunityTemplateBundleInfoType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Highlight} +#' \item{PreviewImage} +#' } +#' } +#' } +#' +#' \strong{CommunityTemplateDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitytemplatedefinition.htm}{Salesforce Documentation for CommunityTemplateDefinition} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{baseTemplate}{a CommunityBaseTemplate - which is a character taking one of the following values: +#' \itemize{ +#' \item{c} +#' } +#' } +#' \item{bundlesInfo}{a CommunityTemplateBundleInfo} +#' \item{category}{a CommunityTemplateCategory - which is a character taking one of the following values: +#' \itemize{ +#' \item{IT} +#' \item{Marketing} +#' \item{Sales} +#' \item{Service} +#' } +#' } +#' \item{defaultBrandingSet}{a character} +#' \item{defaultThemeDefinition}{a character} +#' \item{description}{a character} +#' \item{enableExtendedCleanUpOnDelete}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{navigationLinkSet}{a NavigationLinkSet} +#' \item{pageSetting}{a CommunityTemplatePageSetting} +#' } +#' +#' \strong{CommunityTemplatePageSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitytemplatepagesetting.htm}{Salesforce Documentation for CommunityTemplatePageSetting} +#' \describe{ +#' \item{page}{a character} +#' \item{themeLayout}{a character} +#' } +#' +#' \strong{CommunityThemeDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitythemedefinition.htm}{Salesforce Documentation for CommunityThemeDefinition} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customThemeLayoutType}{a CommunityCustomThemeLayoutType} +#' \item{description}{a character} +#' \item{enableExtendedCleanUpOnDelete}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{themeSetting}{a CommunityThemeSetting} +#' } +#' +#' \strong{CommunityThemeSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_communitythemesetting.htm}{Salesforce Documentation for CommunityThemeSetting} +#' \describe{ +#' \item{customThemeLayoutType}{a character} +#' \item{themeLayout}{a character} +#' \item{themeLayoutType}{a CommunityThemeLayoutType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Login} +#' \item{Home} +#' \item{Inner} +#' } +#' } +#' } +#' +#' \strong{CompactLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_compactlayout.htm}{Salesforce Documentation for CompactLayout} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{fields}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{CompanySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_companysettings.htm}{Salesforce Documentation for CompanySettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{fiscalYear}{a FiscalYearSettings} +#' } +#' +#' \strong{ComponentInstance} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_componentinstance.htm}{Salesforce Documentation for ComponentInstance} +#' \describe{ +#' \item{componentInstanceProperties}{a ComponentInstanceProperty} +#' \item{componentName}{a character} +#' \item{visibilityRule}{a UiFormulaRule} +#' } +#' +#' \strong{ComponentInstanceProperty} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_componentinstanceproperty.htm}{Salesforce Documentation for ComponentInstanceProperty} +#' \describe{ +#' \item{name}{a character} +#' \item{type}{a ComponentInstancePropertyTypeEnum - which is a character taking one of the following values: +#' \itemize{ +#' \item{decorator} +#' } +#' } +#' \item{value}{a character} +#' } +#' +#' \strong{ConnectedApp} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedapp.htm}{Salesforce Documentation for ConnectedApp} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{attributes}{a ConnectedAppAttribute} +#' \item{canvasConfig}{a ConnectedAppCanvasConfig} +#' \item{contactEmail}{a character} +#' \item{contactPhone}{a character} +#' \item{description}{a character} +#' \item{iconUrl}{a character} +#' \item{infoUrl}{a character} +#' \item{ipRanges}{a ConnectedAppIpRange} +#' \item{label}{a character} +#' \item{logoUrl}{a character} +#' \item{mobileAppConfig}{a ConnectedAppMobileDetailConfig} +#' \item{mobileStartUrl}{a character} +#' \item{oauthConfig}{a ConnectedAppOauthConfig} +#' \item{plugin}{a character} +#' \item{samlConfig}{a ConnectedAppSamlConfig} +#' \item{startUrl}{a character} +#' } +#' +#' \strong{ConnectedAppAttribute} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappattribute.htm}{Salesforce Documentation for ConnectedAppAttribute} +#' \describe{ +#' \item{formula}{a character} +#' \item{key}{a character} +#' } +#' +#' \strong{ConnectedAppCanvasConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappcanvasconfig.htm}{Salesforce Documentation for ConnectedAppCanvasConfig} +#' \describe{ +#' \item{accessMethod}{a AccessMethod - which is a character taking one of the following values: +#' \itemize{ +#' \item{Get} +#' \item{Post} +#' } +#' } +#' \item{canvasUrl}{a character} +#' \item{lifecycleClass}{a character} +#' \item{locations}{a CanvasLocationOptions - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Chatter} +#' \item{UserProfile} +#' \item{Visualforce} +#' \item{Aura} +#' \item{Publisher} +#' \item{ChatterFeed} +#' \item{ServiceDesk} +#' \item{OpenCTI} +#' \item{AppLauncher} +#' \item{MobileNav} +#' \item{PageLayout} +#' } +#' } +#' \item{options}{a CanvasOptions - which is a character taking one of the following values: +#' \itemize{ +#' \item{HideShare} +#' \item{HideHeader} +#' \item{PersonalEnabled} +#' } +#' } +#' \item{samlInitiationMethod}{a SamlInitiationMethod - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{IdpInitiated} +#' \item{SpInitiated} +#' } +#' } +#' } +#' +#' \strong{ConnectedAppIpRange} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappiprange.htm}{Salesforce Documentation for ConnectedAppIpRange} +#' \describe{ +#' \item{description}{a character} +#' \item{end}{a character} +#' \item{start}{a character} +#' } +#' +#' \strong{ConnectedAppMobileDetailConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappmobiledetailconfig.htm}{Salesforce Documentation for ConnectedAppMobileDetailConfig} +#' \describe{ +#' \item{applicationBinaryFile}{a character formed using RCurl::base64Encode} +#' \item{applicationBinaryFileName}{a character} +#' \item{applicationBundleIdentifier}{a character} +#' \item{applicationFileLength}{a integer} +#' \item{applicationIconFile}{a character} +#' \item{applicationIconFileName}{a character} +#' \item{applicationInstallUrl}{a character} +#' \item{devicePlatform}{a DevicePlatformType - which is a character taking one of the following values: +#' \itemize{ +#' \item{ios} +#' \item{android} +#' } +#' } +#' \item{deviceType}{a DeviceType - which is a character taking one of the following values: +#' \itemize{ +#' \item{phone} +#' \item{tablet} +#' \item{minitablet} +#' } +#' } +#' \item{minimumOsVersion}{a character} +#' \item{privateApp}{a character either 'true' or 'false'} +#' \item{version}{a character} +#' } +#' +#' \strong{ConnectedAppOauthConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappoauthconfig.htm}{Salesforce Documentation for ConnectedAppOauthConfig} +#' \describe{ +#' \item{callbackUrl}{a character} +#' \item{certificate}{a character} +#' \item{consumerKey}{a character} +#' \item{consumerSecret}{a character} +#' \item{scopes}{a ConnectedAppOauthAccessScope - which is a character taking one of the following values: +#' \itemize{ +#' \item{Basic} +#' \item{Api} +#' \item{Web} +#' \item{Full} +#' \item{Chatter} +#' \item{CustomApplications} +#' \item{RefreshToken} +#' \item{OpenID} +#' \item{Profile} +#' \item{Email} +#' \item{Address} +#' \item{Phone} +#' \item{OfflineAccess} +#' \item{CustomPermissions} +#' \item{Wave} +#' \item{Eclair} +#' } +#' } +#' \item{singleLogoutUrl}{a character} +#' } +#' +#' \strong{ConnectedAppSamlConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_connectedappsamlconfig.htm}{Salesforce Documentation for ConnectedAppSamlConfig} +#' \describe{ +#' \item{acsUrl}{a character} +#' \item{certificate}{a character} +#' \item{encryptionCertificate}{a character} +#' \item{encryptionType}{a SamlEncryptionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AES_128} +#' \item{AES_256} +#' \item{Triple_Des} +#' } +#' } +#' \item{entityUrl}{a character} +#' \item{issuer}{a character} +#' \item{samlIdpSLOBindingEnum}{a SamlIdpSLOBinding - which is a character taking one of the following values: +#' \itemize{ +#' \item{RedirectBinding} +#' \item{PostBinding} +#' } +#' } +#' \item{samlNameIdFormat}{a SamlNameIdFormatType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Unspecified} +#' \item{EmailAddress} +#' \item{Persistent} +#' \item{Transient} +#' } +#' } +#' \item{samlSloUrl}{a character} +#' \item{samlSubjectCustomAttr}{a character} +#' \item{samlSubjectType}{a SamlSubjectType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Username} +#' \item{FederationId} +#' \item{UserId} +#' \item{SpokeId} +#' \item{CustomAttribute} +#' \item{PersistentId} +#' } +#' } +#' } +#' +#' \strong{Container} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_container.htm}{Salesforce Documentation for Container} +#' \describe{ +#' \item{height}{a integer} +#' \item{isContainerAutoSizeEnabled}{a character either 'true' or 'false'} +#' \item{region}{a character} +#' \item{sidebarComponents}{a SidebarComponent} +#' \item{style}{a character} +#' \item{unit}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{ContentAsset} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contentasset.htm}{Salesforce Documentation for ContentAsset} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{format}{a ContentAssetFormat - which is a character taking one of the following values: +#' \itemize{ +#' \item{Original} +#' \item{ZippedVersions} +#' } +#' } +#' \item{language}{a character} +#' \item{masterLabel}{a character} +#' \item{originNetwork}{a character} +#' \item{relationships}{a ContentAssetRelationships} +#' \item{versions}{a ContentAssetVersions} +#' } +#' +#' \strong{ContentAssetLink} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contentassetlink.htm}{Salesforce Documentation for ContentAssetLink} +#' \describe{ +#' \item{access}{a ContentAssetAccess - which is a character taking one of the following values: +#' \itemize{ +#' \item{VIEWER} +#' \item{COLLABORATOR} +#' \item{INFERRED} +#' } +#' } +#' \item{isManagingWorkspace}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{ContentAssetRelationships} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contentassetrelationships.htm}{Salesforce Documentation for ContentAssetRelationships} +#' \describe{ +#' \item{insightsApplication}{a ContentAssetLink} +#' \item{network}{a ContentAssetLink} +#' \item{organization}{a ContentAssetLink} +#' \item{workspace}{a ContentAssetLink} +#' } +#' +#' \strong{ContentAssetVersion} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contentassetversion.htm}{Salesforce Documentation for ContentAssetVersion} +#' \describe{ +#' \item{number}{a character} +#' \item{pathOnClient}{a character} +#' \item{zipEntry}{a character} +#' } +#' +#' \strong{ContentAssetVersions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contentassetversions.htm}{Salesforce Documentation for ContentAssetVersions} +#' \describe{ +#' \item{version}{a ContentAssetVersion} +#' } +#' +#' \strong{ContractSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_contractsettings.htm}{Salesforce Documentation for ContractSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{autoCalculateEndDate}{a character either 'true' or 'false'} +#' \item{autoExpirationDelay}{a character} +#' \item{autoExpirationRecipient}{a character} +#' \item{autoExpireContracts}{a character either 'true' or 'false'} +#' \item{enableContractHistoryTracking}{a character either 'true' or 'false'} +#' \item{notifyOwnersOnContractExpiration}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CorsWhitelistOrigin} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_corswhitelistorigin.htm}{Salesforce Documentation for CorsWhitelistOrigin} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{urlPattern}{a character} +#' } +#' +#' \strong{CountriesAndStates} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_countriesandstates.htm}{Salesforce Documentation for CountriesAndStates} +#' \describe{ +#' \item{countries}{a Country} +#' } +#' +#' \strong{Country} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_country.htm}{Salesforce Documentation for Country} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{integrationValue}{a character} +#' \item{isoCode}{a character} +#' \item{label}{a character} +#' \item{orgDefault}{a character either 'true' or 'false'} +#' \item{standard}{a character either 'true' or 'false'} +#' \item{states}{a State} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CspTrustedSite} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_csptrustedsite.htm}{Salesforce Documentation for CspTrustedSite} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{endpointUrl}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CustomApplication} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customapplication.htm}{Salesforce Documentation for CustomApplication} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionOverrides}{a AppActionOverride} +#' \item{brand}{a AppBrand} +#' \item{consoleConfig}{a ServiceCloudConsoleConfig} +#' \item{defaultLandingTab}{a character} +#' \item{description}{a character} +#' \item{formFactors}{a FormFactor - which is a character taking one of the following values: +#' \itemize{ +#' \item{Small} +#' \item{Medium} +#' \item{Large} +#' } +#' } +#' \item{isServiceCloudConsole}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{logo}{a character} +#' \item{navType}{a NavType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Standard} +#' \item{Console} +#' } +#' } +#' \item{preferences}{a AppPreferences} +#' \item{profileActionOverrides}{a AppProfileActionOverride} +#' \item{setupExperience}{a character} +#' \item{subscriberTabs}{a character} +#' \item{tabs}{a character} +#' \item{uiType}{a UiType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Aloha} +#' \item{Lightning} +#' } +#' } +#' \item{utilityBar}{a character} +#' \item{workspaceConfig}{a AppWorkspaceConfig} +#' } +#' +#' \strong{CustomApplicationComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customapplicationcomponent.htm}{Salesforce Documentation for CustomApplicationComponent} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{buttonIconUrl}{a character} +#' \item{buttonStyle}{a character} +#' \item{buttonText}{a character} +#' \item{buttonWidth}{a integer} +#' \item{height}{a integer} +#' \item{isHeightFixed}{a character either 'true' or 'false'} +#' \item{isHidden}{a character either 'true' or 'false'} +#' \item{isWidthFixed}{a character either 'true' or 'false'} +#' \item{visualforcePage}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{CustomApplicationTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customapplicationtranslation.htm}{Salesforce Documentation for CustomApplicationTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{CustomConsoleComponents} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customconsolecomponents.htm}{Salesforce Documentation for CustomConsoleComponents} +#' \describe{ +#' \item{primaryTabComponents}{a PrimaryTabComponents} +#' \item{subtabComponents}{a SubtabComponents} +#' } +#' +#' \strong{CustomDataType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customdatatype.htm}{Salesforce Documentation for CustomDataType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customDataTypeComponents}{a CustomDataTypeComponent} +#' \item{description}{a character} +#' \item{displayFormula}{a character} +#' \item{editComponentsOnSeparateLines}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{rightAligned}{a character either 'true' or 'false'} +#' \item{supportComponentsInReports}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CustomDataTypeComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customdatatypecomponent.htm}{Salesforce Documentation for CustomDataTypeComponent} +#' \describe{ +#' \item{developerSuffix}{a character} +#' \item{enforceFieldRequiredness}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{length}{a integer} +#' \item{precision}{a integer} +#' \item{scale}{a integer} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' \item{sortPriority}{a integer} +#' \item{type}{a FieldType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AutoNumber} +#' \item{Lookup} +#' \item{MasterDetail} +#' \item{Checkbox} +#' \item{Currency} +#' \item{Date} +#' \item{DateTime} +#' \item{Email} +#' \item{Number} +#' \item{Percent} +#' \item{Phone} +#' \item{Picklist} +#' \item{MultiselectPicklist} +#' \item{Text} +#' \item{TextArea} +#' \item{LongTextArea} +#' \item{Html} +#' \item{Url} +#' \item{EncryptedText} +#' \item{Summary} +#' \item{Hierarchy} +#' \item{File} +#' \item{MetadataRelationship} +#' \item{Location} +#' \item{ExternalLookup} +#' \item{IndirectLookup} +#' \item{CustomDataType} +#' \item{Time} +#' } +#' } +#' } +#' +#' \strong{CustomDataTypeComponentTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customdatatypecomponenttranslation.htm}{Salesforce Documentation for CustomDataTypeComponentTranslation} +#' \describe{ +#' \item{developerSuffix}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{CustomDataTypeTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customdatatypetranslation.htm}{Salesforce Documentation for CustomDataTypeTranslation} +#' \describe{ +#' \item{components}{a CustomDataTypeComponentTranslation} +#' \item{customDataTypeName}{a character} +#' \item{description}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{CustomExperience} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customexperience.htm}{Salesforce Documentation for CustomExperience} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{allowInternalUserLogin}{a character either 'true' or 'false'} +#' \item{branding}{a CustomExperienceBranding} +#' \item{changePasswordEmailTemplate}{a character} +#' \item{emailFooterLogo}{a character} +#' \item{emailFooterText}{a character} +#' \item{emailSenderAddress}{a character} +#' \item{emailSenderName}{a character} +#' \item{enableErrorPageOverridesForVisualforce}{a character either 'true' or 'false'} +#' \item{forgotPasswordEmailTemplate}{a character} +#' \item{picassoSite}{a character} +#' \item{sObjectType}{a character} +#' \item{sendWelcomeEmail}{a character either 'true' or 'false'} +#' \item{site}{a character} +#' \item{siteAsContainerEnabled}{a character either 'true' or 'false'} +#' \item{tabs}{a CustomExperienceTabSet} +#' \item{urlPathPrefix}{a character} +#' \item{welcomeEmailTemplate}{a character} +#' } +#' +#' \strong{CustomExperienceBranding} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customexperiencebranding.htm}{Salesforce Documentation for CustomExperienceBranding} +#' \describe{ +#' \item{loginFooterText}{a character} +#' \item{loginLogo}{a character} +#' \item{pageFooter}{a character} +#' \item{pageHeader}{a character} +#' \item{primaryColor}{a character} +#' \item{primaryComplementColor}{a character} +#' \item{quaternaryColor}{a character} +#' \item{quaternaryComplementColor}{a character} +#' \item{secondaryColor}{a character} +#' \item{tertiaryColor}{a character} +#' \item{tertiaryComplementColor}{a character} +#' \item{zeronaryColor}{a character} +#' \item{zeronaryComplementColor}{a character} +#' } +#' +#' \strong{CustomExperienceTabSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customexperiencetabset.htm}{Salesforce Documentation for CustomExperienceTabSet} +#' \describe{ +#' \item{customTab}{a character} +#' \item{defaultTab}{a character} +#' \item{standardTab}{a character} +#' } +#' +#' \strong{CustomFeedFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customfeedfilter.htm}{Salesforce Documentation for CustomFeedFilter} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{criteria}{a FeedFilterCriterion} +#' \item{description}{a character} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' } +#' +#' \strong{CustomField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customfield.htm}{Salesforce Documentation for CustomField} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{businessOwnerGroup}{a character} +#' \item{businessOwnerUser}{a character} +#' \item{businessStatus}{a character} +#' \item{caseSensitive}{a character either 'true' or 'false'} +#' \item{customDataType}{a character} +#' \item{defaultValue}{a character} +#' \item{deleteConstraint}{a DeleteConstraint - which is a character taking one of the following values: +#' \itemize{ +#' \item{Cascade} +#' \item{Restrict} +#' \item{SetNull} +#' } +#' } +#' \item{deprecated}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{displayFormat}{a character} +#' \item{encrypted}{a character either 'true' or 'false'} +#' \item{escapeMarkup}{a character either 'true' or 'false'} +#' \item{externalDeveloperName}{a character} +#' \item{externalId}{a character either 'true' or 'false'} +#' \item{fieldManageability}{a FieldManageability - which is a character taking one of the following values: +#' \itemize{ +#' \item{DeveloperControlled} +#' \item{SubscriberControlled} +#' \item{Locked} +#' } +#' } +#' \item{formula}{a character} +#' \item{formulaTreatBlanksAs}{a TreatBlanksAs - which is a character taking one of the following values: +#' \itemize{ +#' \item{BlankAsBlank} +#' \item{BlankAsZero} +#' } +#' } +#' \item{inlineHelpText}{a character} +#' \item{isConvertLeadDisabled}{a character either 'true' or 'false'} +#' \item{isFilteringDisabled}{a character either 'true' or 'false'} +#' \item{isNameField}{a character either 'true' or 'false'} +#' \item{isSortingDisabled}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{length}{a integer} +#' \item{lookupFilter}{a LookupFilter} +#' \item{maskChar}{a EncryptedFieldMaskChar - which is a character taking one of the following values: +#' \itemize{ +#' \item{asterisk} +#' \item{X} +#' } +#' } +#' \item{maskType}{a EncryptedFieldMaskType - which is a character taking one of the following values: +#' \itemize{ +#' \item{all} +#' \item{creditCard} +#' \item{ssn} +#' \item{lastFour} +#' \item{sin} +#' \item{nino} +#' } +#' } +#' \item{metadataRelationshipControllingField}{a character} +#' \item{populateExistingRows}{a character either 'true' or 'false'} +#' \item{precision}{a integer} +#' \item{referenceTargetField}{a character} +#' \item{referenceTo}{a character} +#' \item{relationshipLabel}{a character} +#' \item{relationshipName}{a character} +#' \item{relationshipOrder}{a integer} +#' \item{reparentableMasterDetail}{a character either 'true' or 'false'} +#' \item{required}{a character either 'true' or 'false'} +#' \item{restrictedAdminField}{a character either 'true' or 'false'} +#' \item{scale}{a integer} +#' \item{securityClassification}{a SecurityClassification - which is a character taking one of the following values: +#' \itemize{ +#' \item{AccountInformation} +#' \item{ConfigurationAndUsageData} +#' \item{DataIntendedToBePublic} +#' \item{BusinessSetupDataBusinessDataAndAggregates} +#' \item{AssociativeBusinessOrPersonalData} +#' \item{AuthenticationData} +#' } +#' } +#' \item{startingNumber}{a integer} +#' \item{stripMarkup}{a character either 'true' or 'false'} +#' \item{summarizedField}{a character} +#' \item{summaryFilterItems}{a FilterItem} +#' \item{summaryForeignKey}{a character} +#' \item{summaryOperation}{a SummaryOperations - which is a character taking one of the following values: +#' \itemize{ +#' \item{count} +#' \item{sum} +#' \item{min} +#' \item{max} +#' } +#' } +#' \item{trackFeedHistory}{a character either 'true' or 'false'} +#' \item{trackHistory}{a character either 'true' or 'false'} +#' \item{trackTrending}{a character either 'true' or 'false'} +#' \item{type}{a FieldType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AutoNumber} +#' \item{Lookup} +#' \item{MasterDetail} +#' \item{Checkbox} +#' \item{Currency} +#' \item{Date} +#' \item{DateTime} +#' \item{Email} +#' \item{Number} +#' \item{Percent} +#' \item{Phone} +#' \item{Picklist} +#' \item{MultiselectPicklist} +#' \item{Text} +#' \item{TextArea} +#' \item{LongTextArea} +#' \item{Html} +#' \item{Url} +#' \item{EncryptedText} +#' \item{Summary} +#' \item{Hierarchy} +#' \item{File} +#' \item{MetadataRelationship} +#' \item{Location} +#' \item{ExternalLookup} +#' \item{IndirectLookup} +#' \item{CustomDataType} +#' \item{Time} +#' } +#' } +#' \item{unique}{a character either 'true' or 'false'} +#' \item{valueSet}{a ValueSet} +#' \item{visibleLines}{a integer} +#' \item{writeRequiresMasterRead}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CustomFieldTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customfieldtranslation.htm}{Salesforce Documentation for CustomFieldTranslation} +#' \describe{ +#' \item{caseValues}{a ObjectNameCaseValue} +#' \item{gender}{a Gender - which is a character taking one of the following values: +#' \itemize{ +#' \item{Neuter} +#' \item{Masculine} +#' \item{Feminine} +#' \item{AnimateMasculine} +#' } +#' } +#' \item{help}{a character} +#' \item{label}{a character} +#' \item{lookupFilter}{a LookupFilterTranslation} +#' \item{name}{a character} +#' \item{picklistValues}{a PicklistValueTranslation} +#' \item{relationshipLabel}{a character} +#' \item{startsWith}{a StartsWith - which is a character taking one of the following values: +#' \itemize{ +#' \item{Consonant} +#' \item{Vowel} +#' \item{Special} +#' } +#' } +#' } +#' +#' \strong{CustomLabel} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customlabel.htm}{Salesforce Documentation for CustomLabel} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{categories}{a character} +#' \item{language}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' \item{shortDescription}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{CustomLabels} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customlabels.htm}{Salesforce Documentation for CustomLabels} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{labels}{a CustomLabel} +#' } +#' +#' \strong{CustomLabelTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customlabeltranslation.htm}{Salesforce Documentation for CustomLabelTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{CustomMetadata} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custommetadata.htm}{Salesforce Documentation for CustomMetadata} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' \item{values}{a CustomMetadataValue} +#' } +#' +#' \strong{CustomMetadataValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custommetadatavalue.htm}{Salesforce Documentation for CustomMetadataValue} +#' \describe{ +#' \item{field}{a character} +#' \item{value}{a character that appears similar to any of the other accepted types (integer, numeric, date, datetime, boolean)} +#' } +#' +#' \strong{CustomNotificationType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customnotificationtype.htm}{Salesforce Documentation for CustomNotificationType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customNotifTypeName}{a character} +#' \item{description}{a character} +#' \item{desktop}{a character either 'true' or 'false'} +#' \item{email}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{mobile}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CustomObject} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customobject.htm}{Salesforce Documentation for CustomObject} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionOverrides}{a ActionOverride} +#' \item{allowInChatterGroups}{a character either 'true' or 'false'} +#' \item{articleTypeChannelDisplay}{a ArticleTypeChannelDisplay} +#' \item{businessProcesses}{a BusinessProcess} +#' \item{compactLayoutAssignment}{a character} +#' \item{compactLayouts}{a CompactLayout} +#' \item{customHelp}{a character} +#' \item{customHelpPage}{a character} +#' \item{customSettingsType}{a CustomSettingsType - which is a character taking one of the following values: +#' \itemize{ +#' \item{List} +#' \item{Hierarchy} +#' } +#' } +#' \item{dataStewardGroup}{a character} +#' \item{dataStewardUser}{a character} +#' \item{deploymentStatus}{a DeploymentStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{InDevelopment} +#' \item{Deployed} +#' } +#' } +#' \item{deprecated}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{enableActivities}{a character either 'true' or 'false'} +#' \item{enableBulkApi}{a character either 'true' or 'false'} +#' \item{enableChangeDataCapture}{a character either 'true' or 'false'} +#' \item{enableDivisions}{a character either 'true' or 'false'} +#' \item{enableEnhancedLookup}{a character either 'true' or 'false'} +#' \item{enableFeeds}{a character either 'true' or 'false'} +#' \item{enableHistory}{a character either 'true' or 'false'} +#' \item{enableReports}{a character either 'true' or 'false'} +#' \item{enableSearch}{a character either 'true' or 'false'} +#' \item{enableSharing}{a character either 'true' or 'false'} +#' \item{enableStreamingApi}{a character either 'true' or 'false'} +#' \item{eventType}{a PlatformEventType - which is a character taking one of the following values: +#' \itemize{ +#' \item{HighVolume} +#' \item{StandardVolume} +#' } +#' } +#' \item{externalDataSource}{a character} +#' \item{externalName}{a character} +#' \item{externalRepository}{a character} +#' \item{externalSharingModel}{a SharingModel - which is a character taking one of the following values: +#' \itemize{ +#' \item{Private} +#' \item{Read} +#' \item{ReadSelect} +#' \item{ReadWrite} +#' \item{ReadWriteTransfer} +#' \item{FullAccess} +#' \item{ControlledByParent} +#' } +#' } +#' \item{fieldSets}{a FieldSet} +#' \item{fields}{a CustomField} +#' \item{gender}{a Gender - which is a character taking one of the following values: +#' \itemize{ +#' \item{Neuter} +#' \item{Masculine} +#' \item{Feminine} +#' \item{AnimateMasculine} +#' } +#' } +#' \item{historyRetentionPolicy}{a HistoryRetentionPolicy} +#' \item{household}{a character either 'true' or 'false'} +#' \item{indexes}{a Index} +#' \item{label}{a character} +#' \item{listViews}{a ListView} +#' \item{nameField}{a CustomField} +#' \item{pluralLabel}{a character} +#' \item{recordTypeTrackFeedHistory}{a character either 'true' or 'false'} +#' \item{recordTypeTrackHistory}{a character either 'true' or 'false'} +#' \item{recordTypes}{a RecordType} +#' \item{searchLayouts}{a SearchLayouts} +#' \item{sharingModel}{a SharingModel - which is a character taking one of the following values: +#' \itemize{ +#' \item{Private} +#' \item{Read} +#' \item{ReadSelect} +#' \item{ReadWrite} +#' \item{ReadWriteTransfer} +#' \item{FullAccess} +#' \item{ControlledByParent} +#' } +#' } +#' \item{sharingReasons}{a SharingReason} +#' \item{sharingRecalculations}{a SharingRecalculation} +#' \item{startsWith}{a StartsWith - which is a character taking one of the following values: +#' \itemize{ +#' \item{Consonant} +#' \item{Vowel} +#' \item{Special} +#' } +#' } +#' \item{validationRules}{a ValidationRule} +#' \item{visibility}{a SetupObjectVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{Protected} +#' \item{Public} +#' } +#' } +#' \item{webLinks}{a WebLink} +#' } +#' +#' \strong{CustomObjectTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customobjecttranslation.htm}{Salesforce Documentation for CustomObjectTranslation} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{caseValues}{a ObjectNameCaseValue} +#' \item{fieldSets}{a FieldSetTranslation} +#' \item{fields}{a CustomFieldTranslation} +#' \item{gender}{a Gender - which is a character taking one of the following values: +#' \itemize{ +#' \item{Neuter} +#' \item{Masculine} +#' \item{Feminine} +#' \item{AnimateMasculine} +#' } +#' } +#' \item{layouts}{a LayoutTranslation} +#' \item{nameFieldLabel}{a character} +#' \item{quickActions}{a QuickActionTranslation} +#' \item{recordTypes}{a RecordTypeTranslation} +#' \item{sharingReasons}{a SharingReasonTranslation} +#' \item{standardFields}{a StandardFieldTranslation} +#' \item{startsWith}{a StartsWith - which is a character taking one of the following values: +#' \itemize{ +#' \item{Consonant} +#' \item{Vowel} +#' \item{Special} +#' } +#' } +#' \item{validationRules}{a ValidationRuleTranslation} +#' \item{webLinks}{a WebLinkTranslation} +#' \item{workflowTasks}{a WorkflowTaskTranslation} +#' } +#' +#' \strong{CustomPageWebLink} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custompageweblink.htm}{Salesforce Documentation for CustomPageWebLink} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{availability}{a WebLinkAvailability - which is a character taking one of the following values: +#' \itemize{ +#' \item{online} +#' \item{offline} +#' } +#' } +#' \item{description}{a character} +#' \item{displayType}{a WebLinkDisplayType - which is a character taking one of the following values: +#' \itemize{ +#' \item{link} +#' \item{button} +#' \item{massActionButton} +#' } +#' } +#' \item{encodingKey}{a Encoding - which is a character taking one of the following values: +#' \itemize{ +#' \item{UTF-8} +#' \item{ISO-8859-1} +#' \item{Shift_JIS} +#' \item{ISO-2022-JP} +#' \item{EUC-JP} +#' \item{ks_c_5601-1987} +#' \item{Big5} +#' \item{GB2312} +#' \item{Big5-HKSCS} +#' \item{x-SJIS_0213} +#' } +#' } +#' \item{hasMenubar}{a character either 'true' or 'false'} +#' \item{hasScrollbars}{a character either 'true' or 'false'} +#' \item{hasToolbar}{a character either 'true' or 'false'} +#' \item{height}{a integer} +#' \item{isResizable}{a character either 'true' or 'false'} +#' \item{linkType}{a WebLinkType - which is a character taking one of the following values: +#' \itemize{ +#' \item{url} +#' \item{sControl} +#' \item{javascript} +#' \item{page} +#' \item{flow} +#' } +#' } +#' \item{masterLabel}{a character} +#' \item{openType}{a WebLinkWindowType - which is a character taking one of the following values: +#' \itemize{ +#' \item{newWindow} +#' \item{sidebar} +#' \item{noSidebar} +#' \item{replace} +#' \item{onClickJavaScript} +#' } +#' } +#' \item{page}{a character} +#' \item{position}{a WebLinkPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{fullScreen} +#' \item{none} +#' \item{topLeft} +#' } +#' } +#' \item{protected}{a character either 'true' or 'false'} +#' \item{requireRowSelection}{a character either 'true' or 'false'} +#' \item{scontrol}{a character} +#' \item{showsLocation}{a character either 'true' or 'false'} +#' \item{showsStatus}{a character either 'true' or 'false'} +#' \item{url}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{CustomPageWebLinkTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custompageweblinktranslation.htm}{Salesforce Documentation for CustomPageWebLinkTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{CustomPermission} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custompermission.htm}{Salesforce Documentation for CustomPermission} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{connectedApp}{a character} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{requiredPermission}{a CustomPermissionDependencyRequired} +#' } +#' +#' \strong{CustomPermissionDependencyRequired} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_custompermissiondependencyrequired.htm}{Salesforce Documentation for CustomPermissionDependencyRequired} +#' \describe{ +#' \item{customPermission}{a character} +#' \item{dependency}{a character either 'true' or 'false'} +#' } +#' +#' \strong{CustomShortcut} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customshortcut.htm}{Salesforce Documentation for CustomShortcut} +#' \describe{ +#' \item{action}{a character (inherited from DefaultShortcut)} +#' \item{active}{a character either 'true' or 'false' (inherited from DefaultShortcut)} +#' \item{keyCommand}{a character (inherited from DefaultShortcut)} +#' \item{description}{a character} +#' \item{eventName}{a character} +#' } +#' +#' \strong{CustomSite} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customsite.htm}{Salesforce Documentation for CustomSite} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{allowHomePage}{a character either 'true' or 'false'} +#' \item{allowStandardAnswersPages}{a character either 'true' or 'false'} +#' \item{allowStandardIdeasPages}{a character either 'true' or 'false'} +#' \item{allowStandardLookups}{a character either 'true' or 'false'} +#' \item{allowStandardPortalPages}{a character either 'true' or 'false'} +#' \item{allowStandardSearch}{a character either 'true' or 'false'} +#' \item{analyticsTrackingCode}{a character} +#' \item{authorizationRequiredPage}{a character} +#' \item{bandwidthExceededPage}{a character} +#' \item{browserXssProtection}{a character either 'true' or 'false'} +#' \item{changePasswordPage}{a character} +#' \item{chatterAnswersForgotPasswordConfirmPage}{a character} +#' \item{chatterAnswersForgotPasswordPage}{a character} +#' \item{chatterAnswersHelpPage}{a character} +#' \item{chatterAnswersLoginPage}{a character} +#' \item{chatterAnswersRegistrationPage}{a character} +#' \item{clickjackProtectionLevel}{a SiteClickjackProtectionLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{AllowAllFraming} +#' \item{SameOriginOnly} +#' \item{NoFraming} +#' } +#' } +#' \item{contentSniffingProtection}{a character either 'true' or 'false'} +#' \item{cspUpgradeInsecureRequests}{a character either 'true' or 'false'} +#' \item{customWebAddresses}{a SiteWebAddress} +#' \item{description}{a character} +#' \item{favoriteIcon}{a character} +#' \item{fileNotFoundPage}{a character} +#' \item{forgotPasswordPage}{a character} +#' \item{genericErrorPage}{a character} +#' \item{guestProfile}{a character} +#' \item{inMaintenancePage}{a character} +#' \item{inactiveIndexPage}{a character} +#' \item{indexPage}{a character} +#' \item{masterLabel}{a character} +#' \item{myProfilePage}{a character} +#' \item{portal}{a character} +#' \item{referrerPolicyOriginWhenCrossOrigin}{a character either 'true' or 'false'} +#' \item{requireHttps}{a character either 'true' or 'false'} +#' \item{requireInsecurePortalAccess}{a character either 'true' or 'false'} +#' \item{robotsTxtPage}{a character} +#' \item{rootComponent}{a character} +#' \item{selfRegPage}{a character} +#' \item{serverIsDown}{a character} +#' \item{siteAdmin}{a character} +#' \item{siteRedirectMappings}{a SiteRedirectMapping} +#' \item{siteTemplate}{a character} +#' \item{siteType}{a SiteType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Siteforce} +#' \item{Visualforce} +#' \item{User} +#' } +#' } +#' \item{subdomain}{a character} +#' \item{urlPathPrefix}{a character} +#' } +#' +#' \strong{CustomTab} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customtab.htm}{Salesforce Documentation for CustomTab} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionOverrides}{a ActionOverride} +#' \item{auraComponent}{a character} +#' \item{customObject}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{flexiPage}{a character} +#' \item{frameHeight}{a integer} +#' \item{hasSidebar}{a character either 'true' or 'false'} +#' \item{icon}{a character} +#' \item{label}{a character} +#' \item{mobileReady}{a character either 'true' or 'false'} +#' \item{motif}{a character} +#' \item{page}{a character} +#' \item{scontrol}{a character} +#' \item{splashPageLink}{a character} +#' \item{url}{a character} +#' \item{urlEncodingKey}{a Encoding - which is a character taking one of the following values: +#' \itemize{ +#' \item{UTF-8} +#' \item{ISO-8859-1} +#' \item{Shift_JIS} +#' \item{ISO-2022-JP} +#' \item{EUC-JP} +#' \item{ks_c_5601-1987} +#' \item{Big5} +#' \item{GB2312} +#' \item{Big5-HKSCS} +#' \item{x-SJIS_0213} +#' } +#' } +#' } +#' +#' \strong{CustomTabTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customtabtranslation.htm}{Salesforce Documentation for CustomTabTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{CustomValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_customvalue.htm}{Salesforce Documentation for CustomValue} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{color}{a character} +#' \item{default}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' } +#' +#' \strong{Dashboard} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboard.htm}{Salesforce Documentation for Dashboard} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{backgroundEndColor}{a character} +#' \item{backgroundFadeDirection}{a ChartBackgroundDirection - which is a character taking one of the following values: +#' \itemize{ +#' \item{TopToBottom} +#' \item{LeftToRight} +#' \item{Diagonal} +#' } +#' } +#' \item{backgroundStartColor}{a character} +#' \item{chartTheme}{a ChartTheme - which is a character taking one of the following values: +#' \itemize{ +#' \item{light} +#' \item{dark} +#' } +#' } +#' \item{colorPalette}{a ChartColorPalettes - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{gray} +#' \item{colorSafe} +#' \item{unity} +#' \item{justice} +#' \item{nightfall} +#' \item{sunrise} +#' \item{bluegrass} +#' \item{tropic} +#' \item{heat} +#' \item{dusk} +#' \item{pond} +#' \item{watermelon} +#' \item{fire} +#' \item{water} +#' \item{earth} +#' \item{accessible} +#' } +#' } +#' \item{dashboardChartTheme}{a ChartTheme - which is a character taking one of the following values: +#' \itemize{ +#' \item{light} +#' \item{dark} +#' } +#' } +#' \item{dashboardColorPalette}{a ChartColorPalettes - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{gray} +#' \item{colorSafe} +#' \item{unity} +#' \item{justice} +#' \item{nightfall} +#' \item{sunrise} +#' \item{bluegrass} +#' \item{tropic} +#' \item{heat} +#' \item{dusk} +#' \item{pond} +#' \item{watermelon} +#' \item{fire} +#' \item{water} +#' \item{earth} +#' \item{accessible} +#' } +#' } +#' \item{dashboardFilters}{a DashboardFilter} +#' \item{dashboardGridLayout}{a DashboardGridLayout} +#' \item{dashboardResultRefreshedDate}{a character} +#' \item{dashboardResultRunningUser}{a character} +#' \item{dashboardType}{a DashboardType - which is a character taking one of the following values: +#' \itemize{ +#' \item{SpecifiedUser} +#' \item{LoggedInUser} +#' \item{MyTeamUser} +#' } +#' } +#' \item{description}{a character} +#' \item{folderName}{a character} +#' \item{isGridLayout}{a character either 'true' or 'false'} +#' \item{leftSection}{a DashboardComponentSection} +#' \item{middleSection}{a DashboardComponentSection} +#' \item{numSubscriptions}{a integer} +#' \item{rightSection}{a DashboardComponentSection} +#' \item{runningUser}{a character} +#' \item{textColor}{a character} +#' \item{title}{a character} +#' \item{titleColor}{a character} +#' \item{titleSize}{a integer} +#' } +#' +#' \strong{DashboardComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardcomponent.htm}{Salesforce Documentation for DashboardComponent} +#' \describe{ +#' \item{autoselectColumnsFromReport}{a character either 'true' or 'false'} +#' \item{chartAxisRange}{a ChartRangeType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Auto} +#' \item{Manual} +#' } +#' } +#' \item{chartAxisRangeMax}{a numeric} +#' \item{chartAxisRangeMin}{a numeric} +#' \item{chartSummary}{a ChartSummary} +#' \item{componentChartTheme}{a ChartTheme - which is a character taking one of the following values: +#' \itemize{ +#' \item{light} +#' \item{dark} +#' } +#' } +#' \item{componentType}{a DashboardComponentType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Bar} +#' \item{BarGrouped} +#' \item{BarStacked} +#' \item{BarStacked100} +#' \item{Column} +#' \item{ColumnGrouped} +#' \item{ColumnStacked} +#' \item{ColumnStacked100} +#' \item{Line} +#' \item{LineGrouped} +#' \item{Pie} +#' \item{Table} +#' \item{Metric} +#' \item{Gauge} +#' \item{LineCumulative} +#' \item{LineGroupedCumulative} +#' \item{Scontrol} +#' \item{VisualforcePage} +#' \item{Donut} +#' \item{Funnel} +#' \item{ColumnLine} +#' \item{ColumnLineGrouped} +#' \item{ColumnLineStacked} +#' \item{ColumnLineStacked100} +#' \item{Scatter} +#' \item{ScatterGrouped} +#' \item{FlexTable} +#' } +#' } +#' \item{dashboardFilterColumns}{a DashboardFilterColumn} +#' \item{dashboardTableColumn}{a DashboardTableColumn} +#' \item{displayUnits}{a ChartUnits - which is a character taking one of the following values: +#' \itemize{ +#' \item{Auto} +#' \item{Integer} +#' \item{Hundreds} +#' \item{Thousands} +#' \item{Millions} +#' \item{Billions} +#' \item{Trillions} +#' } +#' } +#' \item{drillDownUrl}{a character} +#' \item{drillEnabled}{a character either 'true' or 'false'} +#' \item{drillToDetailEnabled}{a character either 'true' or 'false'} +#' \item{enableHover}{a character either 'true' or 'false'} +#' \item{expandOthers}{a character either 'true' or 'false'} +#' \item{flexComponentProperties}{a DashboardFlexTableComponentProperties} +#' \item{footer}{a character} +#' \item{gaugeMax}{a numeric} +#' \item{gaugeMin}{a numeric} +#' \item{groupingColumn}{a character} +#' \item{header}{a character} +#' \item{indicatorBreakpoint1}{a numeric} +#' \item{indicatorBreakpoint2}{a numeric} +#' \item{indicatorHighColor}{a character} +#' \item{indicatorLowColor}{a character} +#' \item{indicatorMiddleColor}{a character} +#' \item{legendPosition}{a ChartLegendPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{Right} +#' \item{Bottom} +#' \item{OnChart} +#' } +#' } +#' \item{maxValuesDisplayed}{a integer} +#' \item{metricLabel}{a character} +#' \item{page}{a character} +#' \item{pageHeightInPixels}{a integer} +#' \item{report}{a character} +#' \item{scontrol}{a character} +#' \item{scontrolHeightInPixels}{a integer} +#' \item{showPercentage}{a character either 'true' or 'false'} +#' \item{showPicturesOnCharts}{a character either 'true' or 'false'} +#' \item{showPicturesOnTables}{a character either 'true' or 'false'} +#' \item{showRange}{a character either 'true' or 'false'} +#' \item{showTotal}{a character either 'true' or 'false'} +#' \item{showValues}{a character either 'true' or 'false'} +#' \item{sortBy}{a DashboardComponentFilter - which is a character taking one of the following values: +#' \itemize{ +#' \item{RowLabelAscending} +#' \item{RowLabelDescending} +#' \item{RowValueAscending} +#' \item{RowValueDescending} +#' } +#' } +#' \item{title}{a character} +#' \item{useReportChart}{a character either 'true' or 'false'} +#' } +#' +#' \strong{DashboardComponentColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardcomponentcolumn.htm}{Salesforce Documentation for DashboardComponentColumn} +#' \describe{ +#' \item{breakPoint1}{a numeric} +#' \item{breakPoint2}{a numeric} +#' \item{breakPointOrder}{a integer} +#' \item{highRangeColor}{a integer} +#' \item{lowRangeColor}{a integer} +#' \item{midRangeColor}{a integer} +#' \item{reportColumn}{a character} +#' \item{showTotal}{a character either 'true' or 'false'} +#' \item{type}{a DashboardComponentColumnType - which is a character taking one of the following values: +#' \itemize{ +#' \item{NA} +#' } +#' } +#' } +#' +#' \strong{DashboardComponentSection} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardcomponentsection.htm}{Salesforce Documentation for DashboardComponentSection} +#' \describe{ +#' \item{columnSize}{a DashboardComponentSize - which is a character taking one of the following values: +#' \itemize{ +#' \item{Narrow} +#' \item{Medium} +#' \item{Wide} +#' } +#' } +#' \item{components}{a DashboardComponent} +#' } +#' +#' \strong{DashboardComponentSortInfo} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardcomponentsortinfo.htm}{Salesforce Documentation for DashboardComponentSortInfo} +#' \describe{ +#' \item{sortColumn}{a character} +#' \item{sortOrder}{a character} +#' } +#' +#' \strong{DashboardFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardfilter.htm}{Salesforce Documentation for DashboardFilter} +#' \describe{ +#' \item{dashboardFilterOptions}{a DashboardFilterOption} +#' \item{name}{a character} +#' } +#' +#' \strong{DashboardFilterColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardfiltercolumn.htm}{Salesforce Documentation for DashboardFilterColumn} +#' \describe{ +#' \item{column}{a character} +#' } +#' +#' \strong{DashboardFilterOption} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardfilteroption.htm}{Salesforce Documentation for DashboardFilterOption} +#' \describe{ +#' \item{operator}{a DashboardFilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{equals} +#' \item{notEqual} +#' \item{lessThan} +#' \item{greaterThan} +#' \item{lessOrEqual} +#' \item{greaterOrEqual} +#' \item{contains} +#' \item{notContain} +#' \item{startsWith} +#' \item{includes} +#' \item{excludes} +#' \item{between} +#' } +#' } +#' \item{values}{a character} +#' } +#' +#' \strong{DashboardFlexTableComponentProperties} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardflextablecomponentproperties.htm}{Salesforce Documentation for DashboardFlexTableComponentProperties} +#' \describe{ +#' \item{flexTableColumn}{a DashboardComponentColumn} +#' \item{flexTableSortInfo}{a DashboardComponentSortInfo} +#' \item{hideChatterPhotos}{a character either 'true' or 'false'} +#' } +#' +#' \strong{DashboardFolder} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardfolder.htm}{Salesforce Documentation for DashboardFolder} +#' \describe{ +#' \item{accessType}{a FolderAccessTypes (inherited from Folder)} +#' \item{folderShares}{a FolderShare (inherited from Folder)} +#' \item{name}{a character (inherited from Folder)} +#' \item{publicFolderAccess}{a PublicFolderAccess (inherited from Folder)} +#' \item{sharedTo}{a SharedTo (inherited from Folder)} +#' } +#' +#' \strong{DashboardGridComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardgridcomponent.htm}{Salesforce Documentation for DashboardGridComponent} +#' \describe{ +#' \item{colSpan}{a integer} +#' \item{columnIndex}{a integer} +#' \item{dashboardComponent}{a DashboardComponent} +#' \item{rowIndex}{a integer} +#' \item{rowSpan}{a integer} +#' } +#' +#' \strong{DashboardGridLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardgridlayout.htm}{Salesforce Documentation for DashboardGridLayout} +#' \describe{ +#' \item{dashboardGridComponents}{a DashboardGridComponent} +#' \item{numberOfColumns}{a integer} +#' \item{rowHeight}{a integer} +#' } +#' +#' \strong{DashboardMobileSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardmobilesettings.htm}{Salesforce Documentation for DashboardMobileSettings} +#' \describe{ +#' \item{enableDashboardIPadApp}{a character either 'true' or 'false'} +#' } +#' +#' \strong{DashboardTableColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_dashboardtablecolumn.htm}{Salesforce Documentation for DashboardTableColumn} +#' \describe{ +#' \item{aggregateType}{a ReportSummaryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{None} +#' } +#' } +#' \item{calculatePercent}{a character either 'true' or 'false'} +#' \item{column}{a character} +#' \item{decimalPlaces}{a integer} +#' \item{showTotal}{a character either 'true' or 'false'} +#' \item{sortBy}{a DashboardComponentFilter - which is a character taking one of the following values: +#' \itemize{ +#' \item{RowLabelAscending} +#' \item{RowLabelDescending} +#' \item{RowValueAscending} +#' \item{RowValueDescending} +#' } +#' } +#' } +#' +#' \strong{DataCategory} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_datacategory.htm}{Salesforce Documentation for DataCategory} +#' \describe{ +#' \item{dataCategory}{a DataCategory} +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{DataCategoryGroup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_datacategorygroup.htm}{Salesforce Documentation for DataCategoryGroup} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{dataCategory}{a DataCategory} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{objectUsage}{a ObjectUsage} +#' } +#' +#' \strong{DataPipeline} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_datapipeline.htm}{Salesforce Documentation for DataPipeline} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{label}{a character} +#' \item{scriptType}{a DataPipelineType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Pig} +#' } +#' } +#' } +#' +#' \strong{DefaultShortcut} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_defaultshortcut.htm}{Salesforce Documentation for DefaultShortcut} +#' \describe{ +#' \item{action}{a character} +#' \item{active}{a character either 'true' or 'false'} +#' \item{keyCommand}{a character} +#' } +#' +#' \strong{DelegateGroup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_delegategroup.htm}{Salesforce Documentation for DelegateGroup} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customObjects}{a character} +#' \item{groups}{a character} +#' \item{label}{a character} +#' \item{loginAccess}{a character either 'true' or 'false'} +#' \item{permissionSets}{a character} +#' \item{profiles}{a character} +#' \item{roles}{a character} +#' } +#' +#' \strong{DeployDetails} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_deploydetails.htm}{Salesforce Documentation for DeployDetails} +#' \describe{ +#' \item{componentFailures}{a DeployMessage} +#' \item{componentSuccesses}{a DeployMessage} +#' \item{retrieveResult}{a RetrieveResult} +#' \item{runTestResult}{a RunTestsResult} +#' } +#' +#' \strong{DeployOptions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_deployoptions.htm}{Salesforce Documentation for DeployOptions} +#' \describe{ +#' \item{allowMissingFiles}{a character either 'true' or 'false'} +#' \item{autoUpdatePackage}{a character either 'true' or 'false'} +#' \item{checkOnly}{a character either 'true' or 'false'} +#' \item{ignoreWarnings}{a character either 'true' or 'false'} +#' \item{performRetrieve}{a character either 'true' or 'false'} +#' \item{purgeOnDelete}{a character either 'true' or 'false'} +#' \item{rollbackOnError}{a character either 'true' or 'false'} +#' \item{runTests}{a character} +#' \item{singlePackage}{a character either 'true' or 'false'} +#' \item{testLevel}{a TestLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{NoTestRun} +#' \item{RunSpecifiedTests} +#' \item{RunLocalTests} +#' \item{RunAllTestsInOrg} +#' } +#' } +#' } +#' +#' \strong{DescribeMetadataObject} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_describemetadataobject.htm}{Salesforce Documentation for DescribeMetadataObject} +#' \describe{ +#' \item{childXmlNames}{a character} +#' \item{directoryName}{a character} +#' \item{inFolder}{a character either 'true' or 'false'} +#' \item{metaFile}{a character either 'true' or 'false'} +#' \item{suffix}{a character} +#' \item{xmlName}{a character} +#' } +#' +#' \strong{Document} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_document.htm}{Salesforce Documentation for Document} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{description}{a character} +#' \item{internalUseOnly}{a character either 'true' or 'false'} +#' \item{keywords}{a character} +#' \item{name}{a character} +#' \item{public}{a character either 'true' or 'false'} +#' } +#' +#' \strong{DocumentFolder} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_documentfolder.htm}{Salesforce Documentation for DocumentFolder} +#' \describe{ +#' \item{accessType}{a FolderAccessTypes (inherited from Folder)} +#' \item{folderShares}{a FolderShare (inherited from Folder)} +#' \item{name}{a character (inherited from Folder)} +#' \item{publicFolderAccess}{a PublicFolderAccess (inherited from Folder)} +#' \item{sharedTo}{a SharedTo (inherited from Folder)} +#' } +#' +#' \strong{DuplicateRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_duplicaterule.htm}{Salesforce Documentation for DuplicateRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionOnInsert}{a DupeActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Allow} +#' \item{Block} +#' } +#' } +#' \item{actionOnUpdate}{a DupeActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Allow} +#' \item{Block} +#' } +#' } +#' \item{alertText}{a character} +#' \item{description}{a character} +#' \item{duplicateRuleFilter}{a DuplicateRuleFilter} +#' \item{duplicateRuleMatchRules}{a DuplicateRuleMatchRule} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{operationsOnInsert}{a character} +#' \item{operationsOnUpdate}{a character} +#' \item{securityOption}{a DupeSecurityOptionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{EnforceSharingRules} +#' \item{BypassSharingRules} +#' } +#' } +#' \item{sortOrder}{a integer} +#' } +#' +#' \strong{DuplicateRuleFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_duplicaterulefilter.htm}{Salesforce Documentation for DuplicateRuleFilter} +#' \describe{ +#' \item{booleanFilter}{a character} +#' \item{duplicateRuleFilterItems}{a DuplicateRuleFilterItem} +#' } +#' +#' \strong{DuplicateRuleFilterItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_duplicaterulefilteritem.htm}{Salesforce Documentation for DuplicateRuleFilterItem} +#' \describe{ +#' \item{field}{a character (inherited from FilterItem)} +#' \item{operation}{a FilterOperation (inherited from FilterItem)} +#' \item{value}{a character (inherited from FilterItem)} +#' \item{valueField}{a character (inherited from FilterItem)} +#' \item{sortOrder}{a integer} +#' \item{table}{a character} +#' } +#' +#' \strong{DuplicateRuleMatchRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_duplicaterulematchrule.htm}{Salesforce Documentation for DuplicateRuleMatchRule} +#' \describe{ +#' \item{matchRuleSObjectType}{a character} +#' \item{matchingRule}{a character} +#' \item{objectMapping}{a ObjectMapping} +#' } +#' +#' \strong{EclairGeoData} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_eclairgeodata.htm}{Salesforce Documentation for EclairGeoData} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{maps}{a EclairMap} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{EclairMap} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_eclairmap.htm}{Salesforce Documentation for EclairMap} +#' \describe{ +#' \item{boundingBoxBottom}{a numeric} +#' \item{boundingBoxLeft}{a numeric} +#' \item{boundingBoxRight}{a numeric} +#' \item{boundingBoxTop}{a numeric} +#' \item{mapLabel}{a character} +#' \item{mapName}{a character} +#' \item{projection}{a character} +#' } +#' +#' \strong{EmailFolder} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailfolder.htm}{Salesforce Documentation for EmailFolder} +#' \describe{ +#' \item{accessType}{a FolderAccessTypes (inherited from Folder)} +#' \item{folderShares}{a FolderShare (inherited from Folder)} +#' \item{name}{a character (inherited from Folder)} +#' \item{publicFolderAccess}{a PublicFolderAccess (inherited from Folder)} +#' \item{sharedTo}{a SharedTo (inherited from Folder)} +#' } +#' +#' \strong{EmailServicesAddress} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailservicesaddress.htm}{Salesforce Documentation for EmailServicesAddress} +#' \describe{ +#' \item{authorizedSenders}{a character} +#' \item{developerName}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{localPart}{a character} +#' \item{runAsUser}{a character} +#' } +#' +#' \strong{EmailServicesFunction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailservicesfunction.htm}{Salesforce Documentation for EmailServicesFunction} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{apexClass}{a character} +#' \item{attachmentOption}{a EmailServicesAttOptions - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{TextOnly} +#' \item{BinaryOnly} +#' \item{All} +#' \item{NoContent} +#' } +#' } +#' \item{authenticationFailureAction}{a EmailServicesErrorAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{UseSystemDefault} +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' \item{authorizationFailureAction}{a EmailServicesErrorAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{UseSystemDefault} +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' \item{authorizedSenders}{a character} +#' \item{emailServicesAddresses}{a EmailServicesAddress} +#' \item{errorRoutingAddress}{a character} +#' \item{functionInactiveAction}{a EmailServicesErrorAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{UseSystemDefault} +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' \item{functionName}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{isAuthenticationRequired}{a character either 'true' or 'false'} +#' \item{isErrorRoutingEnabled}{a character either 'true' or 'false'} +#' \item{isTextAttachmentsAsBinary}{a character either 'true' or 'false'} +#' \item{isTlsRequired}{a character either 'true' or 'false'} +#' \item{overLimitAction}{a EmailServicesErrorAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{UseSystemDefault} +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' } +#' +#' \strong{EmailTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailtemplate.htm}{Salesforce Documentation for EmailTemplate} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{apiVersion}{a numeric} +#' \item{attachedDocuments}{a character} +#' \item{attachments}{a Attachment} +#' \item{available}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{encodingKey}{a Encoding - which is a character taking one of the following values: +#' \itemize{ +#' \item{UTF-8} +#' \item{ISO-8859-1} +#' \item{Shift_JIS} +#' \item{ISO-2022-JP} +#' \item{EUC-JP} +#' \item{ks_c_5601-1987} +#' \item{Big5} +#' \item{GB2312} +#' \item{Big5-HKSCS} +#' \item{x-SJIS_0213} +#' } +#' } +#' \item{letterhead}{a character} +#' \item{name}{a character} +#' \item{packageVersions}{a PackageVersion} +#' \item{relatedEntityType}{a character} +#' \item{style}{a EmailTemplateStyle - which is a character taking one of the following values: +#' \itemize{ +#' \item{none} +#' \item{freeForm} +#' \item{formalLetter} +#' \item{promotionRight} +#' \item{promotionLeft} +#' \item{newsletter} +#' \item{products} +#' } +#' } +#' \item{subject}{a character} +#' \item{textOnly}{a character} +#' \item{type}{a EmailTemplateType - which is a character taking one of the following values: +#' \itemize{ +#' \item{text} +#' \item{html} +#' \item{custom} +#' \item{visualforce} +#' } +#' } +#' \item{uiType}{a EmailTemplateUiType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Aloha} +#' \item{SFX} +#' \item{SFX_Sample} +#' } +#' } +#' } +#' +#' \strong{EmailToCaseRoutingAddress} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailtocaseroutingaddress.htm}{Salesforce Documentation for EmailToCaseRoutingAddress} +#' \describe{ +#' \item{addressType}{a EmailToCaseRoutingAddressType - which is a character taking one of the following values: +#' \itemize{ +#' \item{EmailToCase} +#' \item{Outlook} +#' } +#' } +#' \item{authorizedSenders}{a character} +#' \item{caseOrigin}{a character} +#' \item{caseOwner}{a character} +#' \item{caseOwnerType}{a character} +#' \item{casePriority}{a character} +#' \item{createTask}{a character either 'true' or 'false'} +#' \item{emailAddress}{a character} +#' \item{emailServicesAddress}{a character} +#' \item{isVerified}{a character either 'true' or 'false'} +#' \item{routingName}{a character} +#' \item{saveEmailHeaders}{a character either 'true' or 'false'} +#' \item{taskStatus}{a character} +#' } +#' +#' \strong{EmailToCaseSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_emailtocasesettings.htm}{Salesforce Documentation for EmailToCaseSettings} +#' \describe{ +#' \item{enableE2CSourceTracking}{a character either 'true' or 'false'} +#' \item{enableEmailToCase}{a character either 'true' or 'false'} +#' \item{enableHtmlEmail}{a character either 'true' or 'false'} +#' \item{enableOnDemandEmailToCase}{a character either 'true' or 'false'} +#' \item{enableThreadIDInBody}{a character either 'true' or 'false'} +#' \item{enableThreadIDInSubject}{a character either 'true' or 'false'} +#' \item{notifyOwnerOnNewCaseEmail}{a character either 'true' or 'false'} +#' \item{overEmailLimitAction}{a EmailToCaseOnFailureActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' \item{preQuoteSignature}{a character either 'true' or 'false'} +#' \item{routingAddresses}{a EmailToCaseRoutingAddress} +#' \item{unauthorizedSenderAction}{a EmailToCaseOnFailureActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Bounce} +#' \item{Discard} +#' \item{Requeue} +#' } +#' } +#' } +#' +#' \strong{EmbeddedServiceBranding} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_embeddedservicebranding.htm}{Salesforce Documentation for EmbeddedServiceBranding} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{contrastInvertedColor}{a character} +#' \item{contrastPrimaryColor}{a character} +#' \item{embeddedServiceConfig}{a character} +#' \item{font}{a character} +#' \item{masterLabel}{a character} +#' \item{navBarColor}{a character} +#' \item{primaryColor}{a character} +#' \item{secondaryColor}{a character} +#' } +#' +#' \strong{EmbeddedServiceConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_embeddedserviceconfig.htm}{Salesforce Documentation for EmbeddedServiceConfig} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{masterLabel}{a character} +#' \item{site}{a character} +#' } +#' +#' \strong{EmbeddedServiceFieldService} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_embeddedservicefieldservice.htm}{Salesforce Documentation for EmbeddedServiceFieldService} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{appointmentBookingFlowName}{a character} +#' \item{cancelApptBookingFlowName}{a character} +#' \item{embeddedServiceConfig}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{fieldServiceConfirmCardImg}{a character} +#' \item{fieldServiceHomeImg}{a character} +#' \item{fieldServiceLogoImg}{a character} +#' \item{masterLabel}{a character} +#' \item{modifyApptBookingFlowName}{a character} +#' \item{shouldShowExistingAppointment}{a character either 'true' or 'false'} +#' \item{shouldShowNewAppointment}{a character either 'true' or 'false'} +#' } +#' +#' \strong{EmbeddedServiceLiveAgent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_embeddedserviceliveagent.htm}{Salesforce Documentation for EmbeddedServiceLiveAgent} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{avatarImg}{a character} +#' \item{customPrechatComponent}{a character} +#' \item{embeddedServiceConfig}{a character} +#' \item{embeddedServiceQuickActions}{a EmbeddedServiceQuickAction} +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{fontSize}{a EmbeddedServiceFontSize - which is a character taking one of the following values: +#' \itemize{ +#' \item{Small} +#' \item{Medium} +#' \item{Large} +#' } +#' } +#' \item{headerBackgroundImg}{a character} +#' \item{liveAgentChatUrl}{a character} +#' \item{liveAgentContentUrl}{a character} +#' \item{liveChatButton}{a character} +#' \item{liveChatDeployment}{a character} +#' \item{masterLabel}{a character} +#' \item{prechatBackgroundImg}{a character} +#' \item{prechatEnabled}{a character either 'true' or 'false'} +#' \item{prechatJson}{a character} +#' \item{scenario}{a EmbeddedServiceScenario - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sales} +#' \item{Service} +#' \item{Basic} +#' } +#' } +#' \item{smallCompanyLogoImg}{a character} +#' \item{waitingStateBackgroundImg}{a character} +#' } +#' +#' \strong{EmbeddedServiceQuickAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_embeddedservicequickaction.htm}{Salesforce Documentation for EmbeddedServiceQuickAction} +#' \describe{ +#' \item{embeddedServiceLiveAgent}{a character} +#' \item{order}{a integer} +#' \item{quickActionDefinition}{a character} +#' } +#' +#' \strong{EntitlementProcess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_entitlementprocess.htm}{Salesforce Documentation for EntitlementProcess} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{SObjectType}{a character} +#' \item{active}{a character either 'true' or 'false'} +#' \item{businessHours}{a character} +#' \item{description}{a character} +#' \item{entryStartDateField}{a character} +#' \item{exitCriteriaBooleanFilter}{a character} +#' \item{exitCriteriaFilterItems}{a FilterItem} +#' \item{exitCriteriaFormula}{a character} +#' \item{isRecordTypeApplied}{a character either 'true' or 'false'} +#' \item{isVersionDefault}{a character either 'true' or 'false'} +#' \item{milestones}{a EntitlementProcessMilestoneItem} +#' \item{name}{a character} +#' \item{recordType}{a character} +#' \item{versionMaster}{a character} +#' \item{versionNotes}{a character} +#' \item{versionNumber}{a integer} +#' } +#' +#' \strong{EntitlementProcessMilestoneItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_entitlementprocessmilestoneitem.htm}{Salesforce Documentation for EntitlementProcessMilestoneItem} +#' \describe{ +#' \item{businessHours}{a character} +#' \item{criteriaBooleanFilter}{a character} +#' \item{milestoneCriteriaFilterItems}{a FilterItem} +#' \item{milestoneCriteriaFormula}{a character} +#' \item{milestoneName}{a character} +#' \item{minutesCustomClass}{a character} +#' \item{minutesToComplete}{a integer} +#' \item{successActions}{a WorkflowActionReference} +#' \item{timeTriggers}{a EntitlementProcessMilestoneTimeTrigger} +#' \item{useCriteriaStartTime}{a character either 'true' or 'false'} +#' } +#' +#' \strong{EntitlementProcessMilestoneTimeTrigger} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_entitlementprocessmilestonetimetrigger.htm}{Salesforce Documentation for EntitlementProcessMilestoneTimeTrigger} +#' \describe{ +#' \item{actions}{a WorkflowActionReference} +#' \item{timeLength}{a integer} +#' \item{workflowTimeTriggerUnit}{a MilestoneTimeUnits - which is a character taking one of the following values: +#' \itemize{ +#' \item{Minutes} +#' \item{Hours} +#' \item{Days} +#' } +#' } +#' } +#' +#' \strong{EntitlementSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_entitlementsettings.htm}{Salesforce Documentation for EntitlementSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assetLookupLimitedToActiveEntitlementsOnAccount}{a character either 'true' or 'false'} +#' \item{assetLookupLimitedToActiveEntitlementsOnContact}{a character either 'true' or 'false'} +#' \item{assetLookupLimitedToSameAccount}{a character either 'true' or 'false'} +#' \item{assetLookupLimitedToSameContact}{a character either 'true' or 'false'} +#' \item{enableEntitlementVersioning}{a character either 'true' or 'false'} +#' \item{enableEntitlements}{a character either 'true' or 'false'} +#' \item{entitlementLookupLimitedToActiveStatus}{a character either 'true' or 'false'} +#' \item{entitlementLookupLimitedToSameAccount}{a character either 'true' or 'false'} +#' \item{entitlementLookupLimitedToSameAsset}{a character either 'true' or 'false'} +#' \item{entitlementLookupLimitedToSameContact}{a character either 'true' or 'false'} +#' } +#' +#' \strong{EntitlementTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_entitlementtemplate.htm}{Salesforce Documentation for EntitlementTemplate} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{businessHours}{a character} +#' \item{casesPerEntitlement}{a integer} +#' \item{entitlementProcess}{a character} +#' \item{isPerIncident}{a character either 'true' or 'false'} +#' \item{term}{a integer} +#' \item{type}{a character} +#' } +#' +#' \strong{EscalationAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_escalationaction.htm}{Salesforce Documentation for EscalationAction} +#' \describe{ +#' \item{assignedTo}{a character} +#' \item{assignedToTemplate}{a character} +#' \item{assignedToType}{a AssignToLookupValueType - which is a character taking one of the following values: +#' \itemize{ +#' \item{User} +#' \item{Queue} +#' } +#' } +#' \item{minutesToEscalation}{a integer} +#' \item{notifyCaseOwner}{a character either 'true' or 'false'} +#' \item{notifyEmail}{a character} +#' \item{notifyTo}{a character} +#' \item{notifyToTemplate}{a character} +#' } +#' +#' \strong{EscalationRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_escalationrule.htm}{Salesforce Documentation for EscalationRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{ruleEntry}{a RuleEntry} +#' } +#' +#' \strong{EscalationRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_escalationrules.htm}{Salesforce Documentation for EscalationRules} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{escalationRule}{a EscalationRule} +#' } +#' +#' \strong{EventDelivery} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_eventdelivery.htm}{Salesforce Documentation for EventDelivery} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{eventParameters}{a EventParameterMap} +#' \item{eventSubscription}{a character} +#' \item{referenceData}{a character} +#' \item{type}{a EventDeliveryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{StartFlow} +#' \item{ResumeFlow} +#' } +#' } +#' } +#' +#' \strong{EventParameterMap} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_eventparametermap.htm}{Salesforce Documentation for EventParameterMap} +#' \describe{ +#' \item{parameterName}{a character} +#' \item{parameterValue}{a character} +#' } +#' +#' \strong{EventSubscription} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_eventsubscription.htm}{Salesforce Documentation for EventSubscription} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{eventParameters}{a EventParameterMap} +#' \item{eventType}{a character} +#' \item{referenceData}{a character} +#' } +#' +#' \strong{ExtendedErrorDetails} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_extendederrordetails.htm}{Salesforce Documentation for ExtendedErrorDetails} +#' \describe{ +#' \item{extendedErrorCode}{a ExtendedErrorCode - which is a character taking one of the following values: +#' \itemize{ +#' \item{ACTIONCALL_DUPLICATE_INPUT_PARAM - Errors with this extended error code have the following properties: +#' actionCallName, parameterName} +#' \item{ACTIONCALL_DUPLICATE_OUTPUT_PARAM - Errors with this extended error code have the following properties: +#' actionCallName, parameterName} +#' \item{ACTIONCALL_MISSING_NAME - Errors with this extended error code have the following properties:} +#' \item{ACTIONCALL_MISSING_REQUIRED_PARAM - Errors with this extended error code have the following properties: +#' actionCallName, parameterName} +#' \item{ACTIONCALL_MISSING_REQUIRED_TYPE - Errors with this extended error code have the following properties: +#' actionCallName} +#' \item{ACTIONCALL_NOT_FOUND_WITH_NAME_AND_TYPE - Errors with this extended error code have the following properties:} +#' \item{ACTIONCALL_NOT_SUPPORTED_FOR_PROCESSTYPE - Errors with this extended error code have the following properties: +#' processType} +#' \item{APEXCALLOUT_INPUT_DUPLICATE - Errors with this extended error code have the following properties: +#' apexClassName, parameterName} +#' \item{APEXCALLOUT_INPUT_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' apexClassName, parameterName} +#' \item{APEXCALLOUT_INVALID - Errors with this extended error code have the following properties: +#' apexClassName} +#' \item{APEXCALLOUT_MISSING_CLASSNAME - Errors with this extended error code have the following properties: +#' apexClassName} +#' \item{APEXCALLOUT_NOT_FOUND - Errors with this extended error code have the following properties: +#' apexClassName} +#' \item{APEXCALLOUT_OUTPUT_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' apexClassName, parameterName} +#' \item{APEXCALLOUT_OUTPUT_NOT_FOUND - Errors with this extended error code have the following properties: +#' apexClassName, parameterName} +#' \item{APEXCALLOUT_REQUIRED_INPUT_MISSING - Errors with this extended error code have the following properties: +#' apexClassName, parameterName} +#' \item{APEXCLASS_MISSING_INTERFACE - Errors with this extended error code have the following properties: +#' apexClassName, parentScreenFieldName} +#' \item{ASSIGNMENTITEM_ELEMENT_MISSING_DATATYPE - Errors with this extended error code have the following properties: +#' assignmentName, operatorName, elementName} +#' \item{ASSIGNMENTITEM_ELEMENT_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName, assignmentName, elementType} +#' \item{ASSIGNMENTITEM_FIELD_INVALID_DATATYPE - Errors with this extended error code have the following properties: +#' fieldValue, dataType, incompatibleDataType} +#' \item{ASSIGNMENTITEM_FIELD_INVALID_DATATYPE_WITH_ELEMENT - Errors with this extended error code have the following properties: +#' elementName, acceptedDataType, dataType, fieldValue} +#' \item{ASSIGNMENTITEM_INCOMPATIBLE_DATATYPES - Errors with this extended error code have the following properties: +#' assignmentName, operatorName, leftElementName, leftElementType, +#' rightElementName, rightElementType} +#' \item{ASSIGNMENTITEM_INVALID_COLLECTION - Errors with this extended error code have the following properties: +#' assignmentName, operatorName, leftElementName, rightElementName} +#' \item{ASSIGNMENTITEM_INVALID_DATATYPE_IN_ELEMENT - Errors with this extended error code have the following properties: +#' elementName, dataType, incompatibleDataType} +#' \item{ASSIGNMENTITEM_INVALID_REFERENCE - Errors with this extended error code have the following properties: +#' parameterName, operatorName} +#' \item{ASSIGNMENTITEM_LEFT_DATATYPE_INVALID_FOR_OPERATOR - Errors with this extended error code have the following properties: +#' assignmentName, operatorName, dataType, elementName} +#' \item{ASSIGNMENTITEM_MODIFIES_NONVARIABLE - Errors with this extended error code have the following properties: +#' assignmentName} +#' \item{ASSIGNMENTITEM_NONEXISTENT_REFERENCE - Errors with this extended error code have the following properties: +#' parameterName, operatorName} +#' \item{ASSIGNMENTITEM_REQUIRED - Errors with this extended error code have the following properties: +#' assignmentName} +#' \item{ASSIGNMENTITEM_RIGHT_DATATYPE_INVALID_FOR_OPERATOR - Errors with this extended error code have the following properties: +#' elementName} +#' \item{AUTOLAUNCHED_CHOICELOOKUP_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' choiceLookupName} +#' \item{AUTOLAUNCHED_CHOICE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{AUTOLAUNCHED_SCREEN_NOT_SUPPORTED - Errors with this extended error code have the following properties:} +#' \item{AUTOLAUNCHED_STEP_NOT_SUPPORTED - Errors with this extended error code have the following properties:} +#' \item{AUTOLAUNCHED_SUBFLOW_INCOMPATIBLE_FLOWTYPE - Errors with this extended error code have the following properties: +#' subflowType} +#' \item{AUTOLAUNCHED_WAIT_NOT_SUPPORTED - Errors with this extended error code have the following properties:} +#' \item{CHOICEFIELD_DEFAULT_CHOICE_NOT_FOUND - Errors with this extended error code have the following properties: +#' screenFieldName} +#' \item{CHOICEFIELD_MISSING_CHOICE - Errors with this extended error code have the following properties: +#' questionName} +#' \item{CHOICELOOKUP_DATATYPE_INCOMPATIBLE_WITH_CHOICEFIELD - Errors with this extended error code have the following properties: +#' choiceName, parentScreenFieldName} +#' \item{CHOICE_DATATYPE_INCOMPATIBLE_WITH_CHOICEFIELD - Errors with this extended error code have the following properties: +#' choiceName, parentScreenFieldName} +#' \item{CHOICE_NOT_SUPPORTED_FOR_SCREENFIELDTYPE - Errors with this extended error code have the following properties: +#' elementName, screenFieldName} +#' \item{CHOICE_USED_MULTIPLE_TIMES_IN_SAME_FIELD - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{CONDITION_DATATYPE_INCOMPATIBLE - Errors with this extended error code have the following properties: +#' leftElementName, leftElementType, operatorName, rightElementName, +#' rightElementType, ruleName} +#' \item{CONDITION_DATATYPE_INCOMPATIBLE_WITH_ELEMENT - Errors with this extended error code have the following properties: +#' elementName, dataType, operatorName, parameterName, ruleName} +#' \item{CONDITION_ELEMENT_DATATYPES_INCOMPATIBLE - Errors with this extended error code have the following properties: +#' elementName, leftElementType, operatorName, rightElementType, ruleName} +#' \item{CONDITION_INVALID_LEFTOPERAND - Errors with this extended error code have the following properties: ruleName} +#' \item{CONDITION_INVALID_LEFT_ELEMENT - Errors with this extended error code have the following properties: +#' elementName, dataType, operatorName, parameterName, ruleName} +#' \item{CONDITION_LOGIC_EXCEEDS_LIMIT - Errors with this extended error code have the following properties: +#' elementName, characterLimit} +#' \item{CONDITION_LOGIC_INVALID - Errors with this extended error code have the following properties: +#' elementName} +#' \item{CONDITION_LOGIC_MISSING - Errors with this extended error code have the following properties: +#' elementName} +#' \item{CONDITION_MISSING_DATATYPE - Errors with this extended error code have the following properties: +#' elementName, dataType, operatorName, parameterName, ruleName} +#' \item{CONDITION_MISSING_OPERATOR - Errors with this extended error code have the following properties: ruleName} +#' \item{CONDITION_REFERENCED_ELEMENT_NOT_FOUND - Errors with this extended error code have the following properties: ruleName} +#' \item{CONDITION_RIGHTOPERAND_NULL - Errors with this extended error code have the following properties: ruleName} +#' \item{CONNECTOR_MISSING_TARGET - Errors with this extended error code have the following properties: +#' elementName} +#' \item{CONSTANT_INCLUDES_REFERENCES - Errors with this extended error code have the following properties: +#' constantName} +#' \item{CUSTOMEVENTS_NOT_ENABLED - Errors with this extended error code have the following properties:} +#' \item{CUSTOMEVENT_MISSING_PROCESSMETADATAVALUES - Errors with this extended error code have the following properties:} +#' \item{CUSTOMEVENT_OBJECTTYPE_NOT_FOUND - Errors with this extended error code have the following properties: +#' objectType} +#' \item{CUSTOMEVENT_OBJECTTYPE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' objectType} +#' \item{CUSTOMEVENT_PROCESSMETADATAVALUES_MISSING_NAME - Errors with this extended error code have the following properties: +#' metadataValue} +#' \item{CUSTOMEVENT_PROCESSMETADATAVALUES_MORE_THAN_ONE_NAME - Errors with this extended error code have the following properties: +#' metadataValue} +#' \item{DATATYPE_INVALID - Errors with this extended error code have the following properties: +#' elementName, dataType} +#' \item{DATATYPE_MISSING - Errors with this extended error code have the following properties: +#' elementName} +#' \item{DECISION_DEFAULT_CONNECTOR_MISSING_LABEL - Errors with this extended error code have the following properties: +#' flowDecision} +#' \item{DECISION_MISSING_OUTCOME - Errors with this extended error code have the following properties: +#' flowDecision} +#' \item{ELEMENT_CONNECTS_TO_SELF - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_COORDINATES_INVALID - Errors with this extended error code have the following properties: +#' coordinateLimit, coordinateName} +#' \item{ELEMENT_INVALID_CONNECTOR - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_INVALID_REFERENCE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_MISSING_CONNECTOR - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_MISSING_LABEL - Errors with this extended error code have the following properties: +#' characterLimit, elementName} +#' \item{ELEMENT_MISSING_NAME - Errors with this extended error code have the following properties: +#' characterLimit} +#' \item{ELEMENT_MISSING_REFERENCE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_MORE_THAN_ONE_FIELD - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_NAME_INVALID - Errors with this extended error code have the following properties:} +#' \item{ELEMENT_NEVER_USED - Errors with this extended error code have the following properties: +#' elementName} +#' \item{ELEMENT_SCALE_SMALLER_THAN_DEFAULTVALUE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{EXTERNAL_OBJECTS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' objectName} +#' \item{EXTERNAL_OBJECT_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldReference} +#' \item{FIELDASSIGNMENT_FIELD_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, elementName} +#' \item{FIELDASSIGNMENT_INVALID_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, elementName, assignmentName} +#' \item{FIELDASSIGNMENT_INVALID_ELEMENT - Errors with this extended error code have the following properties: +#' fieldName, elementName, elementType} +#' \item{FIELDASSIGNMENT_INVALID_REFERENCE - Errors with this extended error code have the following properties: +#' fieldName, parameterName} +#' \item{FIELDASSIGNMENT_MULTIPLE_REFERENCES_SAME_FIELD - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{FIELDASSIGNMENT_PICKLISTFIELD_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, dataType} +#' \item{FIELDASSIGNMENT_REFERENCED_ELEMENT_MISSING_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, elementName, elementType} +#' \item{FIELDSERVICE_UNSUPPORTED_FIELD_TYPE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{FIELD_INVALID_VALUE - Errors with this extended error code have the following properties: +#' fieldName, parameterName} +#' \item{FIELD_NOT_FOUND - Errors with this extended error code have the following properties: +#' objectName, fieldName} +#' \item{FIELD_RELATIONSHIP_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldRelationshipName} +#' \item{FLEXIPAGE_COMPONENT_ATTRIBUTE_EXPRESSION_EXCEPTION - Errors with this extended error code have the following properties: +#' componentName, propertyName, propertyType, errorCode, invalidTokens} +#' \item{FLEXIPAGE_COMPONENT_ATTRIBUTE_GENERIC_EXCEPTION - Errors with this extended error code have the following properties: +#' componentName, propertyName, propertyType, errorIdentifier, errorParams} +#' \item{FLEXIPAGE_COMPONENT_ATTRIBUTE_MISSING_REQUIRED - Errors with this extended error code have the following properties: +#' componentName, propertyName, propertyType} +#' \item{FLEXIPAGE_COMPONENT_ATTRIBUTE_TOO_LONG - Errors with this extended error code have the following properties: +#' componentName, propertyName, propertyType, maxLength} +#' \item{FLEXIPAGE_COMPONENT_MAX_LIMIT_EXCEPTION - Errors with this extended error code have the following properties:} +#' \item{FLEXIPAGE_COMPONENT_RULE_VALIDATION_EXCEPTION - Errors with this extended error code have the following properties: +#' componentName, criterionIndex} +#' \item{FLEXIPAGE_PICKLIST_INVALID_VALUE_EXCEPTION - Errors with this extended error code have the following properties: +#' componentName, propertyName, propertyType, invalidValue} +#' \item{FLOW_INCLUDES_STEP - Errors with this extended error code have the following properties: +#' elementName} +#' \item{FLOW_NAME_USED_IN_OTHER_CLIENT - Errors with this extended error code have the following properties: flowName} +#' \item{FLOW_STAGE_INCLUDES_REFERENCES - Errors with this extended error code have the following properties: +#' stageName} +#' \item{FORMULA_EXPRESSION_INVALID - Errors with this extended error code have the following properties: +#' formulaExpression} +#' \item{INPUTPARAM_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{INPUTPARAM_INCOMPATIBLE_WITH_COLLECTION_VARIABLE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{INPUTPARAM_INCOMPATIBLE_WITH_NONCOLLECTION_VARIABLE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{INPUTPARAM_MISMATCHED_OBJECTTYPE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{INVALID_FLOW - Errors with this extended error code have the following properties:} +#' \item{INVALID_SURVEY_VARIABLE_NAME_OR_TYPE - Errors with this extended error code have the following properties: +#' surveyName} +#' \item{LOOP_ASSIGNNEXTVALUETO_MISMATCHED_DATATYPE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_ASSIGNNEXTVALUETO_MISMATCHED_OBJECTTYPE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_ASSIGNNEXTVALUETO_MISSING - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_ASSIGNNEXTVALUETO_MISSING_VARIABLE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_ASSIGNNEXTVALUETO_REFERENCE_NOT_FOUND - Errors with this extended error code have the following properties: +#' fieldRelationshipName} +#' \item{LOOP_COLLECTION_ELEMENT_NOT_FOUND - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_COLLECTION_NOT_FOUND - Errors with this extended error code have the following properties: +#' elementName} +#' \item{LOOP_COLLECTION_NOT_SUPPORTED_FOR_FIELD - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{LOOP_MISSING_COLLECTION - Errors with this extended error code have the following properties:} +#' \item{OBJECTTYPE_INVALID - Errors with this extended error code have the following properties: +#' objectType} +#' \item{OBJECT_CANNOT_BE_CREATED - Errors with this extended error code have the following properties: +#' objectName} +#' \item{OBJECT_CANNOT_BE_DELETED - Errors with this extended error code have the following properties: +#' objectName} +#' \item{OBJECT_CANNOT_BE_QUERIED - Errors with this extended error code have the following properties: +#' objectName} +#' \item{OBJECT_CANNOT_BE_UPDATED - Errors with this extended error code have the following properties: +#' objectName} +#' \item{OBJECT_ENCRYPTED_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{OBJECT_NOT_FOUND - Errors with this extended error code have the following properties: +#' objectName} +#' \item{OUTPUTPARAM_ASSIGNTOREFERENCE_NOTFOUND - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{OUTPUTPARAM_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{OUTPUTPARAM_MISMATCHED_OBJECTTYPE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{OUTPUTPARAM_MISMATCHED_WITH_COLLECTION_VARIABLE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{OUTPUTPARAM_MISSING_ASSIGNTOREFERENCE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{OUTPUTPARAM_MISTMATCHED_WITH_NONCOLLECTION_VARIABLE - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{PARAM_DATATYPE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{PROCESSMETADATAVALUES_NOT_SUPPORTED_FOR_PROCESSTYPE - Errors with this extended error code have the following properties: +#' processType, metadataValue} +#' \item{PROCESSMETADATAVALUE_NONEXISTENT_ELEMENT - Errors with this extended error code have the following properties: +#' metadataValue} +#' \item{PROCESSTYPE_ELEMENT_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' processType, elementType} +#' \item{PROCESSTYPE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' processType} +#' \item{RECORDFILTER_ENCRYPTED_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{RECORDFILTER_GEOLOCATION_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName, objectName} +#' \item{RECORDFILTER_INVALID_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, elementName, elementType, operatorName} +#' \item{RECORDFILTER_INVALID_ELEMENT - Errors with this extended error code have the following properties: +#' fieldName, assignmentName, elementName, elementType} +#' \item{RECORDFILTER_INVALID_OPERATOR - Errors with this extended error code have the following properties: +#' fieldName, operatorName} +#' \item{RECORDFILTER_INVALID_REFERENCE - Errors with this extended error code have the following properties: +#' fieldName, operatorName} +#' \item{RECORDFILTER_MISSING_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, elementName, elementType, operatorName} +#' \item{RECORDFILTER_MULTIPLE_QUERIES_SAME_FIELD - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{RECORDLOOKUP_IDASSIGNMENT_VARIABLE_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' elementName} +#' \item{RECORDLOOKUP_IDASSIGNMENT_VARIABLE_NOT_FOUND - Errors with this extended error code have the following properties: +#' elementName} +#' \item{RECORDUPDATE_MISSING_FILTERS - Errors with this extended error code have the following properties: +#' objectName} +#' \item{REFERENCED_ELEMENT_NOT_FOUND - Errors with this extended error code have the following properties: +#' elementName, mergeFieldReference} +#' \item{RULE_MISSING_CONDITION - Errors with this extended error code have the following properties: +#' elementName, ruleName} +#' \item{SCREENFIELD_BOOLEAN_ISREQUIRED_IS_FALSE - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{SCREENFIELD_DEFAULTVALUE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName} +#' \item{SCREENFIELD_EXTENSION_COMPONENT_NOT_GLOBAL - Errors with this extended error code have the following properties: +#' elementName} +#' \item{SCREENFIELD_EXTENSION_DUPLICATE_INPUT_PARAM - Errors with this extended error code have the following properties: +#' elementName, extensionName, parameterName} +#' \item{SCREENFIELD_EXTENSION_DUPLICATE_OUTPUT_PARAM - Errors with this extended error code have the following properties: +#' elementName, extensionName, parameterName} +#' \item{SCREENFIELD_EXTENSION_IMPLEMENTATION_INVALID - Errors with this extended error code have the following properties: +#' elementName, extensionName} +#' \item{SCREENFIELD_EXTENSION_INPUT_ATTRIBUTE_INVALID - Errors with this extended error code have the following properties: +#' elementName, extensionName, parameterName} +#' \item{SCREENFIELD_EXTENSION_NAME_INVALID - Errors with this extended error code have the following properties: +#' elementName, extensionName} +#' \item{SCREENFIELD_EXTENSION_NAME_MISSING - Errors with this extended error code have the following properties: +#' elementName, fieldType} +#' \item{SCREENFIELD_EXTENSION_NAME_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName, fieldType} +#' \item{SCREENFIELD_EXTENSION_OUTPUT_ATTRIBUTE_INVALID - Errors with this extended error code have the following properties: +#' elementName, extensionName, parameterName} +#' \item{SCREENFIELD_EXTENSION_REQUIRED_INPUT_MISSING - Errors with this extended error code have the following properties: +#' elementName, extensionName, parameterName} +#' \item{SCREENFIELD_INPUTS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName, fieldType} +#' \item{SCREENFIELD_INVALID_DATATYPE - Errors with this extended error code have the following properties: +#' dataType, fieldType} +#' \item{SCREENFIELD_MULTISELECTCHOICE_SEMICOLON_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{SCREENFIELD_OUTPUTS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName, fieldType} +#' \item{SCREENFIELD_TYPE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName, fieldType} +#' \item{SCREENFIELD_USERINPUT_NOT_SUPPORTED_FOR_CHOICETYPE - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{SCREENFIELD_VALIDATIONRULE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' elementName} +#' \item{SCREENRULE_ACTION_INVALID_ATTRIBUTE - Errors with this extended error code have the following properties: +#' screenRuleName, attributeName} +#' \item{SCREENRULE_ACTION_INVALID_ATTRIBUTE_FOR_API_VERSION - Errors with this extended error code have the following properties: +#' screenRuleName, attributeName} +#' \item{SCREENRULE_ACTION_INVALID_VALUE - Errors with this extended error code have the following properties: +#' screenRuleName, acceptedValues, actionValue} +#' \item{SCREENRULE_ACTION_MISSING_ATTRIBUTE - Errors with this extended error code have the following properties: +#' screenRuleName} +#' \item{SCREENRULE_ACTION_MISSING_FIELDREFERENCE - Errors with this extended error code have the following properties: +#' screenRuleName} +#' \item{SCREENRULE_ACTION_MISSING_VALUE - Errors with this extended error code have the following properties: +#' screenRuleName} +#' \item{SCREENRULE_ATTRIBUTE_NOT_SUPPORTED_FOR_SCREENFIELD - Errors with this extended error code have the following properties: +#' screenRuleName, attributeName, fieldName} +#' \item{SCREENRULE_FIELD_NOT_FOUND_ON_SCREEN - Errors with this extended error code have the following properties: +#' screenRuleName, fieldValue} +#' \item{SCREENRULE_MISSING_ACTION - Errors with this extended error code have the following properties: +#' screenRuleName} +#' \item{SCREENRULE_NOT_SUPPORTED_IN_ORG - Errors with this extended error code have the following properties:} +#' \item{SCREENRULE_SCREENFIELD_NOT_VISIBLE - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{SCREENRULE_VISIBILITY_NOT_SUPPORTED_IN_ORG - Errors with this extended error code have the following properties:} +#' \item{SCREEN_ALLOWBACK_ALLOWFINISH_BOTH_FALSE - Errors with this extended error code have the following properties:} +#' \item{SCREEN_CONTAINS_LIGHTNING_COMPONENT - Errors with this extended error code have the following properties: +#' elementName} +#' \item{SCREEN_MISSING_FOOTER_AND_LIGHTNING_COMPONENT - Errors with this extended error code have the following properties:} +#' \item{SCREEN_MISSING_LABEL - Errors with this extended error code have the following properties: +#' characterLimit} +#' \item{SCREEN_MULTISELECTFIELD_DOESNT_SUPPORT_CHOICE_WITH_USERINPUT - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{SCREEN_PAUSEDTEXT_NOT_SHOWN_WHEN_ALLOWPAUSE_IS_FALSE - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{SETTING_FIELD_MAKES_OTHER_FIELD_REQUIRED - Errors with this extended error code have the following properties: +#' fieldName, requiredField} +#' \item{SETTING_FIELD_MAKES_OTHER_FIELD_UNSUPPORTED - Errors with this extended error code have the following properties: +#' fieldName, otherFieldName} +#' \item{SOBJECT_ELEMENT_INCOMPATIBLE_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, fieldValue} +#' \item{SOBJECT_ELEMENT_MISMATCHED_OBJECTTYPE - Errors with this extended error code have the following properties: +#' objectType, sobjectName} +#' \item{SORT_ENCRYPTED_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName, objectType} +#' \item{SORT_FIELD_MISSING - Errors with this extended error code have the following properties: +#' sortOrder} +#' \item{SORT_FIELD_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName, objectName} +#' \item{SORT_GEOLOCATION_FIELDS_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' fieldName, objectName} +#' \item{SORT_LIMIT_INVALID - Errors with this extended error code have the following properties: maxLimit} +#' \item{SORT_ORDER_MISSING - Errors with this extended error code have the following properties: +#' fieldName} +#' \item{SPECIFIC_FIELD_VALUE_MAKES_OTHER_FIELD_REQUIRED - Errors with this extended error code have the following properties: +#' fieldName, fieldType, requiedField} +#' \item{START_ELEMENT_MISSING - Errors with this extended error code have the following properties:} +#' \item{SUBFLOW_DESKTOP_DESIGNER_FLOWS_NOT_SUPPORTED - Errors with this extended error code have the following properties: flowName} +#' \item{SUBFLOW_INPUT_ELEMENT_INCOMPATIBLE_DATATYPES - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INPUT_INVALID_VALUE - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INPUT_MISMATCHED_COLLECTIONTYPES - Errors with this extended error code have the following properties: +#' subflowName, inputParameterNames} +#' \item{SUBFLOW_INPUT_MISMATCHED_OBJECTS - Errors with this extended error code have the following properties: +#' subflowName, inputParameterNames} +#' \item{SUBFLOW_INPUT_MISSING_NAME - Errors with this extended error code have the following properties: +#' subflowName} +#' \item{SUBFLOW_INPUT_MULTIPLE_ASSIGNMENTS_TO_ONE_VARIABLE - Errors with this extended error code have the following properties: +#' inputVariableName} +#' \item{SUBFLOW_INPUT_REFERENCES_FIELD_ON_SOBJECT_VARIABLE - Errors with this extended error code have the following properties: +#' inputVariableName} +#' \item{SUBFLOW_INPUT_VALUE_INCOMPATIBLE_DATATYPES - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INPUT_VARIABLE_NOT_FOUND_IN_MASTERFLOW - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INPUT_VARIABLE_NOT_FOUND_IN_REFERENCEDFLOW - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INPUT_VARIABLE_NO_INPUT_ACCESS - Errors with this extended error code have the following properties: +#' subflowName, inputAssignmentNames} +#' \item{SUBFLOW_INVALID_NAME - Errors with this extended error code have the following properties:} +#' \item{SUBFLOW_INVALID_REFERENCE - Errors with this extended error code have the following properties: flowName} +#' \item{SUBFLOW_MASTER_FLOW_TYPE_NOT_AUTOLAUNCHED - Errors with this extended error code have the following properties: +#' parentFlowName} +#' \item{SUBFLOW_MISSING_NAME - Errors with this extended error code have the following properties:} +#' \item{SUBFLOW_NO_ACTIVE_VERSION - Errors with this extended error code have the following properties: +#' subflowName, flowName} +#' \item{SUBFLOW_OUTPUT_INCOMPATIBLE_DATATYPES - Errors with this extended error code have the following properties: +#' subflowName, flowVersion, outputParameterNames} +#' \item{SUBFLOW_OUTPUT_MISMATCHED_COLLECTIONTYPES - Errors with this extended error code have the following properties: +#' subflowName, flowVersion, outputParameterNames} +#' \item{SUBFLOW_OUTPUT_MISMATCHED_OBJECTS - Errors with this extended error code have the following properties: +#' subflowName, flowVersion, outputParameterNames} +#' \item{SUBFLOW_OUTPUT_MISSING_ASSIGNTOREFERENCE - Errors with this extended error code have the following properties: +#' outputAssignment} +#' \item{SUBFLOW_OUTPUT_MISSING_NAME - Errors with this extended error code have the following properties: +#' subflowName} +#' \item{SUBFLOW_OUTPUT_MULTIPLE_ASSIGNMENTS_TO_ONE_VARIABLE - Errors with this extended error code have the following properties: +#' outputVariableName} +#' \item{SUBFLOW_OUTPUT_REFERENCES_FIELD_ON_SOBJECT_VARIABLE - Errors with this extended error code have the following properties: +#' outputAssignment} +#' \item{SUBFLOW_OUTPUT_TARGET_DOES_NOT_EXIST_IN_MASTER_FLOW - Errors with this extended error code have the following properties: +#' subflowName, outputAssignmentName} +#' \item{SUBFLOW_OUTPUT_VARIABLE_NOT_FOUND_IN_MASTERFLOW - Errors with this extended error code have the following properties: +#' subflowName, variableName} +#' \item{SUBFLOW_OUTPUT_VARIABLE_NOT_FOUND_IN_REFERENCEDFLOW - Errors with this extended error code have the following properties: +#' subflowName, flowVersion, outputParameterNames} +#' \item{SUBFLOW_OUTPUT_VARIABLE_NO_OUTPUT_ACCESS - Errors with this extended error code have the following properties: +#' subflowName, variableName} +#' \item{SUBFLOW_REFERENCES_MASTERFLOW - Errors with this extended error code have the following properties:} +#' \item{SURVEY_CHOICE_NOT_REFERENCED_BY_A_QUESTION - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{SURVEY_CHOICE_REFERENCED_BY_MULTIPLE_QUESTIONS - Errors with this extended error code have the following properties: +#' choiceName} +#' \item{SURVEY_INACTIVE_SUBFLOWS - Errors with this extended error code have the following properties: +#' subflowName} +#' \item{SURVEY_MISSING_QUESTION_OR_SUBFLOW - Errors with this extended error code have the following properties: +#' surveyName} +#' \item{SURVEY_MISSING_REQUIRED_VARIABLES - Errors with this extended error code have the following properties: +#' surveyName} +#' \item{SURVEY_NESTED_SUBFLOWS - Errors with this extended error code have the following properties: +#' subflowName} +#' \item{SURVEY_NONSURVEY_SUBFLOWS - Errors with this extended error code have the following properties: +#' subflowName} +#' \item{SURVEY_SCREENFIELD_TYPE_NOT_SUPPORTED_FOR_QUESTION - Errors with this extended error code have the following properties: +#' elementName} +#' \item{SURVEY_START_ELEMENT_INVALID - Errors with this extended error code have the following properties:} +#' \item{SURVEY_VARIABLE_ACCESS_INVALID - Errors with this extended error code have the following properties: +#' surveyName} +#' \item{UNEXPECTED_ERROR - Errors with this extended error code have the following properties:} +#' \item{VALUE_CHAR_LIMIT_EXCEEDED - Errors with this extended error code have the following properties: +#' elementName, characterLimit} +#' \item{VARIABLE_FIELD_NOT_SUPPORTED_FOR_DATATYPE - Errors with this extended error code have the following properties: +#' fieldName, datatype} +#' \item{VARIABLE_FIELD_NOT_SUPPORTED_FOR_DATATYPE_AND_COLLECTION - Errors with this extended error code have the following properties: +#' fieldName, datatype} +#' \item{VARIABLE_FIELD_REQUIRED_FOR_DATATYPE - Errors with this extended error code have the following properties: +#' datatype, fieldName} +#' \item{VARIABLE_SCALE_EXCEEDS_LIMIT - Errors with this extended error code have the following properties: +#' elementName} +#' \item{VARIABLE_SCALE_NEGATIVE_INTEGER - Errors with this extended error code have the following properties: +#' elementName} +#' \item{VARIABLE_SCALE_NULL - Errors with this extended error code have the following properties: +#' elementName} +#' \item{WAITEVENT_DEFAULT_CONNECTOR_MISSING_LABEL - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WAITEVENT_DUPLICATE_INPUT_PARAM - Errors with this extended error code have the following properties: +#' parameterName} +#' \item{WAITEVENT_INPUT_NOT_SUPPORTED_FOR_EVENTTYPE - Errors with this extended error code have the following properties: +#' waitEventName, inputParameterName} +#' \item{WAITEVENT_INPUT_REQUIRES_LITERAL_VALUE - Errors with this extended error code have the following properties: +#' waitEventName, parameterName} +#' \item{WAITEVENT_INVALID_CONDITION_LOGIC - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WAITEVENT_MISSING - Errors with this extended error code have the following properties:} +#' \item{WAITEVENT_MISSING_CONNECTOR - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WAITEVENT_MISSING_EVENTTYPE - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WAITEVENT_OBJECT_NOT_SUPPORTED_FOR_EVENTTYPE - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WAITEVENT_OUTPUT_NOT_SUPPORTED_FOR_EVENTTYPE - Errors with this extended error code have the following properties: +#' waitEventName, outputParameter} +#' \item{WAITEVENT_RELATIVEALARM_INVALID_DATETIME_FIELD - Errors with this extended error code have the following properties: +#' waitEventName, eventParameterName, incompatibleValue} +#' \item{WAITEVENT_RELATIVEALARM_INVALID_FIELD - Errors with this extended error code have the following properties: +#' waitEventName, eventParameterName, incompatibleValue} +#' \item{WAITEVENT_RELATIVEALARM_INVALID_OBJECTTYPE - Errors with this extended error code have the following properties: +#' waitEventName, inputParameterName} +#' \item{WAITEVENT_RELATIVEALARM_INVALID_OFFSETNUMBER - Errors with this extended error code have the following properties: +#' waitEventName, eventParameterName, incompatibleValue} +#' \item{WAITEVENT_RELATIVEALARM_INVALID_OFFSETUNIT - Errors with this extended error code have the following properties: +#' waitEventName, eventParameterName, incompatibleValue} +#' \item{WAITEVENT_REQUIRED_INPUT_MISSING - Errors with this extended error code have the following properties: +#' waitEventName, parameterName} +#' \item{WAITEVENT_TYPE_INVALID_OR_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' waitEventName} +#' \item{WORKFLOW_MISSING_PROCESSMETADATAVALUES - Errors with this extended error code have the following properties: flowName} +#' \item{WORKFLOW_OBJECTTYPE_NOT_FOUND - Errors with this extended error code have the following properties: +#' objectType} +#' \item{WORKFLOW_OBJECTTYPE_NOT_SUPPORTED - Errors with this extended error code have the following properties: +#' objectType} +#' \item{WORKFLOW_OBJECTVARIABLE_AND_OLDOBJECTVARIABLE_REFERENCE_SAME_SOBJECT_VARIABLE - Errors with this extended error code have the following properties: +#' objectVariableName, oldObjectVariableName} +#' \item{WORKFLOW_OBJECTVARIABLE_DOESNT_SUPPORT_INPUT - Errors with this extended error code have the following properties: +#' objectType, objectVariableName} +#' \item{WORKFLOW_OLDOBJECTVARIABLE_DOESNT_SUPPORT_INPUT - Errors with this extended error code have the following properties: +#' objectType, oldObjectVariableName} +#' \item{WORKFLOW_PROCESSMETADATAVALUES_MORE_THAN_ONE_NAME - Errors with this extended error code have the following properties: +#' metadataValue} +#' \item{WORKFLOW_PROCESS_METADATAVALUES_MISSING_NAME - Errors with this extended error code have the following properties: +#' metadataValue} +#' \item{WORKFLOW_RECURSIVECOUNTVARIABLE_DOESNT_SUPPORT_INPUT - Errors with this extended error code have the following properties: +#' elementName} +#' \item{WORKFLOW_TRIGGERTYPE_INVALID_VALUE - Errors with this extended error code have the following properties:} +#' } +#' } +#' } +#' +#' \strong{ExternalDataSource} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_externaldatasource.htm}{Salesforce Documentation for ExternalDataSource} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{authProvider}{a character} +#' \item{certificate}{a character} +#' \item{customConfiguration}{a character} +#' \item{endpoint}{a character} +#' \item{isWritable}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{oauthRefreshToken}{a character} +#' \item{oauthScope}{a character} +#' \item{oauthToken}{a character} +#' \item{password}{a character} +#' \item{principalType}{a ExternalPrincipalType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Anonymous} +#' \item{PerUser} +#' \item{NamedUser} +#' } +#' } +#' \item{protocol}{a AuthenticationProtocol - which is a character taking one of the following values: +#' \itemize{ +#' \item{NoAuthentication} +#' \item{Oauth} +#' \item{Password} +#' } +#' } +#' \item{repository}{a character} +#' \item{type}{a ExternalDataSourceType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Datacloud} +#' \item{Datajourney} +#' \item{OpenSearch} +#' \item{Identity} +#' \item{outgoingemail} +#' \item{recommendation} +#' \item{SfdcOrg} +#' \item{OData} +#' \item{OData4} +#' \item{SimpleURL} +#' \item{Wrapper} +#' } +#' } +#' \item{username}{a character} +#' \item{version}{a character} +#' } +#' +#' \strong{ExternalServiceRegistration} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_externalserviceregistration.htm}{Salesforce Documentation for ExternalServiceRegistration} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{namedCredential}{a character} +#' \item{schema}{a character} +#' \item{schemaType}{a character} +#' \item{schemaUrl}{a character} +#' \item{status}{a character} +#' } +#' +#' \strong{FeedFilterCriterion} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_feedfiltercriterion.htm}{Salesforce Documentation for FeedFilterCriterion} +#' \describe{ +#' \item{feedItemType}{a FeedItemType - which is a character taking one of the following values: +#' \itemize{ +#' \item{TrackedChange} +#' \item{UserStatus} +#' \item{TextPost} +#' \item{AdvancedTextPost} +#' \item{LinkPost} +#' \item{ContentPost} +#' \item{PollPost} +#' \item{RypplePost} +#' \item{ProfileSkillPost} +#' \item{DashboardComponentSnapshot} +#' \item{ApprovalPost} +#' \item{CaseCommentPost} +#' \item{ReplyPost} +#' \item{EmailMessageEvent} +#' \item{CallLogPost} +#' \item{ChangeStatusPost} +#' \item{AttachArticleEvent} +#' \item{MilestoneEvent} +#' \item{ActivityEvent} +#' \item{ChatTranscriptPost} +#' \item{CollaborationGroupCreated} +#' \item{CollaborationGroupUnarchived} +#' \item{SocialPost} +#' \item{QuestionPost} +#' \item{FacebookPost} +#' \item{BasicTemplateFeedItem} +#' \item{CreateRecordEvent} +#' \item{CanvasPost} +#' \item{AnnouncementPost} +#' } +#' } +#' \item{feedItemVisibility}{a FeedItemVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{AllUsers} +#' \item{InternalUsers} +#' } +#' } +#' \item{relatedSObjectType}{a character} +#' } +#' +#' \strong{FeedItemSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_feeditemsettings.htm}{Salesforce Documentation for FeedItemSettings} +#' \describe{ +#' \item{characterLimit}{a integer} +#' \item{collapseThread}{a character either 'true' or 'false'} +#' \item{displayFormat}{a FeedItemDisplayFormat - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{HideBlankLines} +#' } +#' } +#' \item{feedItemType}{a FeedItemType - which is a character taking one of the following values: +#' \itemize{ +#' \item{TrackedChange} +#' \item{UserStatus} +#' \item{TextPost} +#' \item{AdvancedTextPost} +#' \item{LinkPost} +#' \item{ContentPost} +#' \item{PollPost} +#' \item{RypplePost} +#' \item{ProfileSkillPost} +#' \item{DashboardComponentSnapshot} +#' \item{ApprovalPost} +#' \item{CaseCommentPost} +#' \item{ReplyPost} +#' \item{EmailMessageEvent} +#' \item{CallLogPost} +#' \item{ChangeStatusPost} +#' \item{AttachArticleEvent} +#' \item{MilestoneEvent} +#' \item{ActivityEvent} +#' \item{ChatTranscriptPost} +#' \item{CollaborationGroupCreated} +#' \item{CollaborationGroupUnarchived} +#' \item{SocialPost} +#' \item{QuestionPost} +#' \item{FacebookPost} +#' \item{BasicTemplateFeedItem} +#' \item{CreateRecordEvent} +#' \item{CanvasPost} +#' \item{AnnouncementPost} +#' } +#' } +#' } +#' +#' \strong{FeedLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_feedlayout.htm}{Salesforce Documentation for FeedLayout} +#' \describe{ +#' \item{autocollapsePublisher}{a character either 'true' or 'false'} +#' \item{compactFeed}{a character either 'true' or 'false'} +#' \item{feedFilterPosition}{a FeedLayoutFilterPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{CenterDropDown} +#' \item{LeftFixed} +#' \item{LeftFloat} +#' } +#' } +#' \item{feedFilters}{a FeedLayoutFilter} +#' \item{fullWidthFeed}{a character either 'true' or 'false'} +#' \item{hideSidebar}{a character either 'true' or 'false'} +#' \item{highlightExternalFeedItems}{a character either 'true' or 'false'} +#' \item{leftComponents}{a FeedLayoutComponent} +#' \item{rightComponents}{a FeedLayoutComponent} +#' \item{useInlineFiltersInConsole}{a character either 'true' or 'false'} +#' } +#' +#' \strong{FeedLayoutComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_feedlayoutcomponent.htm}{Salesforce Documentation for FeedLayoutComponent} +#' \describe{ +#' \item{componentType}{a FeedLayoutComponentType - which is a character taking one of the following values: +#' \itemize{ +#' \item{HelpAndToolLinks} +#' \item{CustomButtons} +#' \item{Following} +#' \item{Followers} +#' \item{CustomLinks} +#' \item{Milestones} +#' \item{Topics} +#' \item{CaseUnifiedFiles} +#' \item{Visualforce} +#' } +#' } +#' \item{height}{a integer} +#' \item{page}{a character} +#' } +#' +#' \strong{FeedLayoutFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_feedlayoutfilter.htm}{Salesforce Documentation for FeedLayoutFilter} +#' \describe{ +#' \item{feedFilterName}{a character} +#' \item{feedFilterType}{a FeedLayoutFilterType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AllUpdates} +#' \item{FeedItemType} +#' \item{Custom} +#' } +#' } +#' \item{feedItemType}{a FeedItemType - which is a character taking one of the following values: +#' \itemize{ +#' \item{TrackedChange} +#' \item{UserStatus} +#' \item{TextPost} +#' \item{AdvancedTextPost} +#' \item{LinkPost} +#' \item{ContentPost} +#' \item{PollPost} +#' \item{RypplePost} +#' \item{ProfileSkillPost} +#' \item{DashboardComponentSnapshot} +#' \item{ApprovalPost} +#' \item{CaseCommentPost} +#' \item{ReplyPost} +#' \item{EmailMessageEvent} +#' \item{CallLogPost} +#' \item{ChangeStatusPost} +#' \item{AttachArticleEvent} +#' \item{MilestoneEvent} +#' \item{ActivityEvent} +#' \item{ChatTranscriptPost} +#' \item{CollaborationGroupCreated} +#' \item{CollaborationGroupUnarchived} +#' \item{SocialPost} +#' \item{QuestionPost} +#' \item{FacebookPost} +#' \item{BasicTemplateFeedItem} +#' \item{CreateRecordEvent} +#' \item{CanvasPost} +#' \item{AnnouncementPost} +#' } +#' } +#' } +#' +#' \strong{FieldMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldmapping.htm}{Salesforce Documentation for FieldMapping} +#' \describe{ +#' \item{SObjectType}{a character} +#' \item{developerName}{a character} +#' \item{fieldMappingRows}{a FieldMappingRow} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{FieldMappingField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldmappingfield.htm}{Salesforce Documentation for FieldMappingField} +#' \describe{ +#' \item{dataServiceField}{a character} +#' \item{dataServiceObjectName}{a character} +#' \item{priority}{a integer} +#' } +#' +#' \strong{FieldMappingRow} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldmappingrow.htm}{Salesforce Documentation for FieldMappingRow} +#' \describe{ +#' \item{SObjectType}{a character} +#' \item{fieldMappingFields}{a FieldMappingField} +#' \item{fieldName}{a character} +#' \item{mappingOperation}{a MappingOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{Autofill} +#' \item{Overwrite} +#' } +#' } +#' } +#' +#' \strong{FieldOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldoverride.htm}{Salesforce Documentation for FieldOverride} +#' \describe{ +#' \item{field}{a character} +#' \item{formula}{a character} +#' \item{literalValue}{a character} +#' } +#' +#' \strong{FieldServiceSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldservicesettings.htm}{Salesforce Documentation for FieldServiceSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{fieldServiceNotificationsOrgPref}{a character either 'true' or 'false'} +#' \item{fieldServiceOrgPref}{a character either 'true' or 'false'} +#' \item{serviceAppointmentsDueDateOffsetOrgValue}{a integer} +#' \item{workOrderLineItemSearchFields}{a character} +#' \item{workOrderSearchFields}{a character} +#' } +#' +#' \strong{FieldSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldset.htm}{Salesforce Documentation for FieldSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{availableFields}{a FieldSetItem} +#' \item{description}{a character} +#' \item{displayedFields}{a FieldSetItem} +#' \item{label}{a character} +#' } +#' +#' \strong{FieldSetItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldsetitem.htm}{Salesforce Documentation for FieldSetItem} +#' \describe{ +#' \item{field}{a character} +#' \item{isFieldManaged}{a character either 'true' or 'false'} +#' \item{isRequired}{a character either 'true' or 'false'} +#' } +#' +#' \strong{FieldSetTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldsettranslation.htm}{Salesforce Documentation for FieldSetTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FieldValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fieldvalue.htm}{Salesforce Documentation for FieldValue} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a character that appears similar to any of the other accepted types (integer, numeric, date, datetime, boolean)} +#' } +#' +#' \strong{FileProperties} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fileproperties.htm}{Salesforce Documentation for FileProperties} +#' \describe{ +#' \item{createdById}{a character} +#' \item{createdByName}{a character} +#' \item{createdDate}{a character formatted as 'yyyy-mm-ddThh:mm:ssZ'} +#' \item{fileName}{a character} +#' \item{fullName}{a character} +#' \item{id}{a character} +#' \item{lastModifiedById}{a character} +#' \item{lastModifiedByName}{a character} +#' \item{lastModifiedDate}{a character formatted as 'yyyy-mm-ddThh:mm:ssZ'} +#' \item{manageableState}{a ManageableState - which is a character taking one of the following values: +#' \itemize{ +#' \item{released} +#' \item{deleted} +#' \item{deprecated} +#' \item{installed} +#' \item{beta} +#' \item{unmanaged} +#' } +#' } +#' \item{namespacePrefix}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{FileTypeDispositionAssignmentBean} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_filetypedispositionassignmentbean.htm}{Salesforce Documentation for FileTypeDispositionAssignmentBean} +#' \describe{ +#' \item{behavior}{a FileDownloadBehavior - which is a character taking one of the following values: +#' \itemize{ +#' \item{DOWNLOAD} +#' \item{EXECUTE_IN_BROWSER} +#' \item{HYBRID} +#' } +#' } +#' \item{fileType}{a FileType - which is a character taking one of the following values: +#' \itemize{ +#' \item{UNKNOWN} +#' \item{PDF} +#' \item{POWER_POINT} +#' \item{POWER_POINT_X} +#' \item{POWER_POINT_M} +#' \item{POWER_POINT_T} +#' \item{WORD} +#' \item{WORD_X} +#' \item{WORD_M} +#' \item{WORD_T} +#' \item{PPS} +#' \item{PPSX} +#' \item{EXCEL} +#' \item{EXCEL_X} +#' \item{EXCEL_M} +#' \item{EXCEL_T} +#' \item{GOOGLE_DOCUMENT} +#' \item{GOOGLE_PRESENTATION} +#' \item{GOOGLE_SPREADSHEET} +#' \item{GOOGLE_DRAWING} +#' \item{GOOGLE_FORM} +#' \item{GOOGLE_SCRIPT} +#' \item{LINK} +#' \item{SLIDE} +#' \item{AAC} +#' \item{ACGI} +#' \item{AI} +#' \item{AVI} +#' \item{BMP} +#' \item{BOXNOTE} +#' \item{CSV} +#' \item{EPS} +#' \item{EXE} +#' \item{FLASH} +#' \item{GIF} +#' \item{GZIP} +#' \item{HTM} +#' \item{HTML} +#' \item{HTX} +#' \item{JPEG} +#' \item{JPE} +#' \item{PJP} +#' \item{PJPEG} +#' \item{JFIF} +#' \item{JPG} +#' \item{JS} +#' \item{MHTM} +#' \item{MHTML} +#' \item{MP3} +#' \item{M4A} +#' \item{M4V} +#' \item{MP4} +#' \item{MPEG} +#' \item{MPG} +#' \item{MOV} +#' \item{MSG} +#' \item{ODP} +#' \item{ODS} +#' \item{ODT} +#' \item{OGV} +#' \item{PNG} +#' \item{PSD} +#' \item{RTF} +#' \item{QUIPDOC} +#' \item{QUIPSHEET} +#' \item{SHTM} +#' \item{SHTML} +#' \item{SNOTE} +#' \item{STYPI} +#' \item{SVG} +#' \item{SVGZ} +#' \item{TEXT} +#' \item{THTML} +#' \item{VISIO} +#' \item{WMV} +#' \item{WRF} +#' \item{XML} +#' \item{ZIP} +#' \item{XZIP} +#' \item{WMA} +#' \item{XSN} +#' \item{TRTF} +#' \item{TXML} +#' \item{WEBVIEW} +#' \item{RFC822} +#' \item{ASF} +#' \item{DWG} +#' \item{JAR} +#' \item{XJS} +#' \item{OPX} +#' \item{XPSD} +#' \item{TIF} +#' \item{TIFF} +#' \item{WAV} +#' \item{CSS} +#' \item{THUMB720BY480} +#' \item{THUMB240BY180} +#' \item{THUMB120BY90} +#' \item{ALLTHUMBS} +#' \item{PAGED_FLASH} +#' \item{PACK} +#' \item{C} +#' \item{CPP} +#' \item{WORDT} +#' \item{INI} +#' \item{JAVA} +#' \item{LOG} +#' \item{POWER_POINTT} +#' \item{SQL} +#' \item{XHTML} +#' \item{EXCELT} +#' } +#' } +#' \item{securityRiskFileType}{a character either 'true' or 'false'} +#' } +#' +#' \strong{FileUploadAndDownloadSecuritySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fileuploadanddownloadsecuritysettings.htm}{Salesforce Documentation for FileUploadAndDownloadSecuritySettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{dispositions}{a FileTypeDispositionAssignmentBean} +#' \item{noHtmlUploadAsAttachment}{a character either 'true' or 'false'} +#' } +#' +#' \strong{FilterItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_filteritem.htm}{Salesforce Documentation for FilterItem} +#' \describe{ +#' \item{field}{a character} +#' \item{operation}{a FilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{equals} +#' \item{notEqual} +#' \item{lessThan} +#' \item{greaterThan} +#' \item{lessOrEqual} +#' \item{greaterOrEqual} +#' \item{contains} +#' \item{notContain} +#' \item{startsWith} +#' \item{includes} +#' \item{excludes} +#' \item{within} +#' } +#' } +#' \item{value}{a character} +#' \item{valueField}{a character} +#' } +#' +#' \strong{FindSimilarOppFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_findsimilaroppfilter.htm}{Salesforce Documentation for FindSimilarOppFilter} +#' \describe{ +#' \item{similarOpportunitiesDisplayColumns}{a character} +#' \item{similarOpportunitiesMatchFields}{a character} +#' } +#' +#' \strong{FiscalYearSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_fiscalyearsettings.htm}{Salesforce Documentation for FiscalYearSettings} +#' \describe{ +#' \item{fiscalYearNameBasedOn}{a character} +#' \item{startMonth}{a character} +#' } +#' +#' \strong{FlexiPage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flexipage.htm}{Salesforce Documentation for FlexiPage} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{flexiPageRegions}{a FlexiPageRegion} +#' \item{masterLabel}{a character} +#' \item{parentFlexiPage}{a character} +#' \item{platformActionlist}{a PlatformActionList} +#' \item{quickActionList}{a QuickActionList} +#' \item{sobjectType}{a character} +#' \item{template}{a FlexiPageTemplateInstance} +#' \item{type}{a FlexiPageType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AppPage} +#' \item{ObjectPage} +#' \item{RecordPage} +#' \item{HomePage} +#' \item{MailAppAppPage} +#' \item{CommAppPage} +#' \item{CommForgotPasswordPage} +#' \item{CommLoginPage} +#' \item{CommObjectPage} +#' \item{CommQuickActionCreatePage} +#' \item{CommRecordPage} +#' \item{CommRelatedListPage} +#' \item{CommSearchResultPage} +#' \item{CommGlobalSearchResultPage} +#' \item{CommSelfRegisterPage} +#' \item{CommThemeLayoutPage} +#' \item{UtilityBar} +#' \item{RecordPreview} +#' } +#' } +#' } +#' +#' \strong{FlexiPageRegion} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flexipageregion.htm}{Salesforce Documentation for FlexiPageRegion} +#' \describe{ +#' \item{appendable}{a RegionFlagStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{disabled} +#' \item{enabled} +#' } +#' } +#' \item{componentInstances}{a ComponentInstance} +#' \item{mode}{a FlexiPageRegionMode - which is a character taking one of the following values: +#' \itemize{ +#' \item{Append} +#' \item{Prepend} +#' \item{Replace} +#' } +#' } +#' \item{name}{a character} +#' \item{prependable}{a RegionFlagStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{disabled} +#' \item{enabled} +#' } +#' } +#' \item{replaceable}{a RegionFlagStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{disabled} +#' \item{enabled} +#' } +#' } +#' \item{type}{a FlexiPageRegionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Region} +#' \item{Facet} +#' } +#' } +#' } +#' +#' \strong{FlexiPageTemplateInstance} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flexipagetemplateinstance.htm}{Salesforce Documentation for FlexiPageTemplateInstance} +#' \describe{ +#' \item{name}{a character} +#' \item{properties}{a ComponentInstanceProperty} +#' } +#' +#' \strong{Flow} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flow.htm}{Salesforce Documentation for Flow} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionCalls}{a FlowActionCall} +#' \item{apexPluginCalls}{a FlowApexPluginCall} +#' \item{assignments}{a FlowAssignment} +#' \item{choices}{a FlowChoice} +#' \item{constants}{a FlowConstant} +#' \item{decisions}{a FlowDecision} +#' \item{description}{a character} +#' \item{dynamicChoiceSets}{a FlowDynamicChoiceSet} +#' \item{formulas}{a FlowFormula} +#' \item{interviewLabel}{a character} +#' \item{label}{a character} +#' \item{loops}{a FlowLoop} +#' \item{processMetadataValues}{a FlowMetadataValue} +#' \item{processType}{a FlowProcessType - which is a character taking one of the following values: +#' \itemize{ +#' \item{AutoLaunchedFlow} +#' \item{Flow} +#' \item{Workflow} +#' \item{CustomEvent} +#' \item{InvocableProcess} +#' \item{LoginFlow} +#' \item{ActionPlan} +#' \item{JourneyBuilderIntegration} +#' \item{UserProvisioningFlow} +#' \item{Survey} +#' \item{FieldServiceMobile} +#' \item{OrchestrationFlow} +#' \item{FieldServiceWeb} +#' \item{TransactionSecurityFlow} +#' } +#' } +#' \item{recordCreates}{a FlowRecordCreate} +#' \item{recordDeletes}{a FlowRecordDelete} +#' \item{recordLookups}{a FlowRecordLookup} +#' \item{recordUpdates}{a FlowRecordUpdate} +#' \item{screens}{a FlowScreen} +#' \item{stages}{a FlowStage} +#' \item{startElementReference}{a character} +#' \item{steps}{a FlowStep} +#' \item{subflows}{a FlowSubflow} +#' \item{textTemplates}{a FlowTextTemplate} +#' \item{variables}{a FlowVariable} +#' \item{waits}{a FlowWait} +#' } +#' +#' \strong{FlowActionCall} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowactioncall.htm}{Salesforce Documentation for FlowActionCall} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{actionName}{a character} +#' \item{actionType}{a InvocableActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{apex} +#' \item{chatterPost} +#' \item{contentWorkspaceEnableFolders} +#' \item{emailAlert} +#' \item{emailSimple} +#' \item{flow} +#' \item{metricRefresh} +#' \item{quickAction} +#' \item{submit} +#' \item{thanks} +#' \item{thunderResponse} +#' \item{createServiceReport} +#' \item{deployOrchestration} +#' \item{createResponseEventAction} +#' \item{generateWorkOrders} +#' \item{deactivateSessionPermSet} +#' \item{activateSessionPermSet} +#' \item{aggregateValue} +#' \item{orchestrationTimer} +#' \item{orchestrationDebugLog} +#' \item{choosePricebook} +#' \item{localAction} +#' } +#' } +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{inputParameters}{a FlowActionCallInputParameter} +#' \item{outputParameters}{a FlowActionCallOutputParameter} +#' } +#' +#' \strong{FlowActionCallInputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowactioncallinputparameter.htm}{Salesforce Documentation for FlowActionCallInputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowActionCallOutputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowactioncalloutputparameter.htm}{Salesforce Documentation for FlowActionCallOutputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FlowApexPluginCall} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowapexplugincall.htm}{Salesforce Documentation for FlowApexPluginCall} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{apexClass}{a character} +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{inputParameters}{a FlowApexPluginCallInputParameter} +#' \item{outputParameters}{a FlowApexPluginCallOutputParameter} +#' } +#' +#' \strong{FlowApexPluginCallInputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowapexplugincallinputparameter.htm}{Salesforce Documentation for FlowApexPluginCallInputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowApexPluginCallOutputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowapexplugincalloutputparameter.htm}{Salesforce Documentation for FlowApexPluginCallOutputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FlowAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowassignment.htm}{Salesforce Documentation for FlowAssignment} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{assignmentItems}{a FlowAssignmentItem} +#' \item{connector}{a FlowConnector} +#' } +#' +#' \strong{FlowAssignmentItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowassignmentitem.htm}{Salesforce Documentation for FlowAssignmentItem} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{operator}{a FlowAssignmentOperator - which is a character taking one of the following values: +#' \itemize{ +#' \item{Assign} +#' \item{Add} +#' \item{Subtract} +#' \item{AddItem} +#' } +#' } +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowBaseElement} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowbaseelement.htm}{Salesforce Documentation for FlowBaseElement} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue} +#' } +#' +#' \strong{FlowCategory} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowcategory.htm}{Salesforce Documentation for FlowCategory} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{flowCategoryItems}{a FlowCategoryItems} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{FlowCategoryItems} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowcategoryitems.htm}{Salesforce Documentation for FlowCategoryItems} +#' \describe{ +#' \item{flow}{a character} +#' } +#' +#' \strong{FlowChoice} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowchoice.htm}{Salesforce Documentation for FlowChoice} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{choiceText}{a character} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{userInput}{a FlowChoiceUserInput} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowChoiceTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowchoicetranslation.htm}{Salesforce Documentation for FlowChoiceTranslation} +#' \describe{ +#' \item{choiceText}{a character} +#' \item{name}{a character} +#' \item{userInput}{a FlowChoiceUserInputTranslation} +#' } +#' +#' \strong{FlowChoiceUserInput} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowchoiceuserinput.htm}{Salesforce Documentation for FlowChoiceUserInput} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{isRequired}{a character either 'true' or 'false'} +#' \item{promptText}{a character} +#' \item{validationRule}{a FlowInputValidationRule} +#' } +#' +#' \strong{FlowChoiceUserInputTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowchoiceuserinputtranslation.htm}{Salesforce Documentation for FlowChoiceUserInputTranslation} +#' \describe{ +#' \item{promptText}{a character} +#' \item{validationRule}{a FlowInputValidationRuleTranslation} +#' } +#' +#' \strong{FlowCondition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowcondition.htm}{Salesforce Documentation for FlowCondition} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{leftValueReference}{a character} +#' \item{operator}{a FlowComparisonOperator - which is a character taking one of the following values: +#' \itemize{ +#' \item{EqualTo} +#' \item{NotEqualTo} +#' \item{GreaterThan} +#' \item{LessThan} +#' \item{GreaterThanOrEqualTo} +#' \item{LessThanOrEqualTo} +#' \item{StartsWith} +#' \item{EndsWith} +#' \item{Contains} +#' \item{IsNull} +#' \item{WasSet} +#' \item{WasSelected} +#' \item{WasVisited} +#' } +#' } +#' \item{rightValue}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowConnector} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowconnector.htm}{Salesforce Documentation for FlowConnector} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{targetReference}{a character} +#' } +#' +#' \strong{FlowConstant} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowconstant.htm}{Salesforce Documentation for FlowConstant} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowDecision} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowdecision.htm}{Salesforce Documentation for FlowDecision} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{defaultConnector}{a FlowConnector} +#' \item{defaultConnectorLabel}{a character} +#' \item{rules}{a FlowRule} +#' } +#' +#' \strong{FlowDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowdefinition.htm}{Salesforce Documentation for FlowDefinition} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{activeVersionNumber}{a integer} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{FlowDefinitionTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowdefinitiontranslation.htm}{Salesforce Documentation for FlowDefinitionTranslation} +#' \describe{ +#' \item{flows}{a FlowTranslation} +#' \item{fullName}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{FlowDynamicChoiceSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowdynamicchoiceset.htm}{Salesforce Documentation for FlowDynamicChoiceSet} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{displayField}{a character} +#' \item{filters}{a FlowRecordFilter} +#' \item{limit}{a integer} +#' \item{object}{a character} +#' \item{outputAssignments}{a FlowOutputFieldAssignment} +#' \item{picklistField}{a character} +#' \item{picklistObject}{a character} +#' \item{sortField}{a character} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' \item{valueField}{a character} +#' } +#' +#' \strong{FlowElement} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowelement.htm}{Salesforce Documentation for FlowElement} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{description}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FlowElementReferenceOrValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowelementreferenceorvalue.htm}{Salesforce Documentation for FlowElementReferenceOrValue} +#' \describe{ +#' \item{booleanValue}{a character either 'true' or 'false'} +#' \item{dateTimeValue}{a character formatted as 'yyyy-mm-ddThh:mm:ssZ'} +#' \item{dateValue}{a character formatted as 'yyyy-mm-dd'} +#' \item{elementReference}{a character} +#' \item{numberValue}{a numeric} +#' \item{stringValue}{a character} +#' } +#' +#' \strong{FlowFormula} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowformula.htm}{Salesforce Documentation for FlowFormula} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{expression}{a character} +#' \item{scale}{a integer} +#' } +#' +#' \strong{FlowInputFieldAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowinputfieldassignment.htm}{Salesforce Documentation for FlowInputFieldAssignment} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{field}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowInputValidationRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowinputvalidationrule.htm}{Salesforce Documentation for FlowInputValidationRule} +#' \describe{ +#' \item{errorMessage}{a character} +#' \item{formulaExpression}{a character} +#' } +#' +#' \strong{FlowInputValidationRuleTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowinputvalidationruletranslation.htm}{Salesforce Documentation for FlowInputValidationRuleTranslation} +#' \describe{ +#' \item{errorMessage}{a character} +#' } +#' +#' \strong{FlowLoop} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowloop.htm}{Salesforce Documentation for FlowLoop} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{assignNextValueToReference}{a character} +#' \item{collectionReference}{a character} +#' \item{iterationOrder}{a IterationOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' \item{nextValueConnector}{a FlowConnector} +#' \item{noMoreValuesConnector}{a FlowConnector} +#' } +#' +#' \strong{FlowMetadataValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowmetadatavalue.htm}{Salesforce Documentation for FlowMetadataValue} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowNode} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flownode.htm}{Salesforce Documentation for FlowNode} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{label}{a character} +#' \item{locationX}{a integer} +#' \item{locationY}{a integer} +#' } +#' +#' \strong{FlowOutputFieldAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowoutputfieldassignment.htm}{Salesforce Documentation for FlowOutputFieldAssignment} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{field}{a character} +#' } +#' +#' \strong{FlowRecordCreate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrecordcreate.htm}{Salesforce Documentation for FlowRecordCreate} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{assignRecordIdToReference}{a character} +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{inputAssignments}{a FlowInputFieldAssignment} +#' \item{inputReference}{a character} +#' \item{object}{a character} +#' } +#' +#' \strong{FlowRecordDelete} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrecorddelete.htm}{Salesforce Documentation for FlowRecordDelete} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{filters}{a FlowRecordFilter} +#' \item{inputReference}{a character} +#' \item{object}{a character} +#' } +#' +#' \strong{FlowRecordFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrecordfilter.htm}{Salesforce Documentation for FlowRecordFilter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{field}{a character} +#' \item{operator}{a FlowRecordFilterOperator - which is a character taking one of the following values: +#' \itemize{ +#' \item{EqualTo} +#' \item{NotEqualTo} +#' \item{GreaterThan} +#' \item{LessThan} +#' \item{GreaterThanOrEqualTo} +#' \item{LessThanOrEqualTo} +#' \item{StartsWith} +#' \item{EndsWith} +#' \item{Contains} +#' \item{IsNull} +#' } +#' } +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowRecordLookup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrecordlookup.htm}{Salesforce Documentation for FlowRecordLookup} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{assignNullValuesIfNoRecordsFound}{a character either 'true' or 'false'} +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{filters}{a FlowRecordFilter} +#' \item{object}{a character} +#' \item{outputAssignments}{a FlowOutputFieldAssignment} +#' \item{outputReference}{a character} +#' \item{queriedFields}{a character} +#' \item{sortField}{a character} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' } +#' +#' \strong{FlowRecordUpdate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrecordupdate.htm}{Salesforce Documentation for FlowRecordUpdate} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{connector}{a FlowConnector} +#' \item{faultConnector}{a FlowConnector} +#' \item{filters}{a FlowRecordFilter} +#' \item{inputAssignments}{a FlowInputFieldAssignment} +#' \item{inputReference}{a character} +#' \item{object}{a character} +#' } +#' +#' \strong{FlowRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowrule.htm}{Salesforce Documentation for FlowRule} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{conditionLogic}{a character} +#' \item{conditions}{a FlowCondition} +#' \item{connector}{a FlowConnector} +#' \item{label}{a character} +#' } +#' +#' \strong{FlowScreen} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreen.htm}{Salesforce Documentation for FlowScreen} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{allowBack}{a character either 'true' or 'false'} +#' \item{allowFinish}{a character either 'true' or 'false'} +#' \item{allowPause}{a character either 'true' or 'false'} +#' \item{connector}{a FlowConnector} +#' \item{fields}{a FlowScreenField} +#' \item{helpText}{a character} +#' \item{pausedText}{a character} +#' \item{rules}{a FlowScreenRule} +#' \item{showFooter}{a character either 'true' or 'false'} +#' \item{showHeader}{a character either 'true' or 'false'} +#' } +#' +#' \strong{FlowScreenField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenfield.htm}{Salesforce Documentation for FlowScreenField} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{choiceReferences}{a character} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{defaultSelectedChoiceReference}{a character} +#' \item{defaultValue}{a FlowElementReferenceOrValue} +#' \item{extensionName}{a character} +#' \item{fieldText}{a character} +#' \item{fieldType}{a FlowScreenFieldType - which is a character taking one of the following values: +#' \itemize{ +#' \item{DisplayText} +#' \item{InputField} +#' \item{LargeTextArea} +#' \item{PasswordField} +#' \item{RadioButtons} +#' \item{DropdownBox} +#' \item{MultiSelectCheckboxes} +#' \item{MultiSelectPicklist} +#' \item{ComponentInstance} +#' } +#' } +#' \item{helpText}{a character} +#' \item{inputParameters}{a FlowScreenFieldInputParameter} +#' \item{isRequired}{a character either 'true' or 'false'} +#' \item{isVisible}{a character either 'true' or 'false'} +#' \item{outputParameters}{a FlowScreenFieldOutputParameter} +#' \item{scale}{a integer} +#' \item{validationRule}{a FlowInputValidationRule} +#' } +#' +#' \strong{FlowScreenFieldInputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenfieldinputparameter.htm}{Salesforce Documentation for FlowScreenFieldInputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowScreenFieldOutputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenfieldoutputparameter.htm}{Salesforce Documentation for FlowScreenFieldOutputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FlowScreenFieldTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenfieldtranslation.htm}{Salesforce Documentation for FlowScreenFieldTranslation} +#' \describe{ +#' \item{fieldText}{a character} +#' \item{helpText}{a character} +#' \item{name}{a character} +#' \item{validationRule}{a FlowInputValidationRuleTranslation} +#' } +#' +#' \strong{FlowScreenRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenrule.htm}{Salesforce Documentation for FlowScreenRule} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{conditionLogic}{a character} +#' \item{conditions}{a FlowCondition} +#' \item{label}{a character} +#' \item{ruleActions}{a FlowScreenRuleAction} +#' } +#' +#' \strong{FlowScreenRuleAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreenruleaction.htm}{Salesforce Documentation for FlowScreenRuleAction} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{attribute}{a character} +#' \item{fieldReference}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowScreenTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowscreentranslation.htm}{Salesforce Documentation for FlowScreenTranslation} +#' \describe{ +#' \item{fields}{a FlowScreenFieldTranslation} +#' \item{helpText}{a character} +#' \item{name}{a character} +#' \item{pausedText}{a character} +#' } +#' +#' \strong{FlowStage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowstage.htm}{Salesforce Documentation for FlowStage} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{stageOrder}{a integer} +#' } +#' +#' \strong{FlowStep} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowstep.htm}{Salesforce Documentation for FlowStep} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{connectors}{a FlowConnector} +#' } +#' +#' \strong{FlowSubflow} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowsubflow.htm}{Salesforce Documentation for FlowSubflow} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{connector}{a FlowConnector} +#' \item{flowName}{a character} +#' \item{inputAssignments}{a FlowSubflowInputAssignment} +#' \item{outputAssignments}{a FlowSubflowOutputAssignment} +#' } +#' +#' \strong{FlowSubflowInputAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowsubflowinputassignment.htm}{Salesforce Documentation for FlowSubflowInputAssignment} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowSubflowOutputAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowsubflowoutputassignment.htm}{Salesforce Documentation for FlowSubflowOutputAssignment} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{FlowTextTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowtexttemplate.htm}{Salesforce Documentation for FlowTextTemplate} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{text}{a character} +#' } +#' +#' \strong{FlowTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowtranslation.htm}{Salesforce Documentation for FlowTranslation} +#' \describe{ +#' \item{choices}{a FlowChoiceTranslation} +#' \item{fullName}{a character} +#' \item{label}{a character} +#' \item{screens}{a FlowScreenTranslation} +#' } +#' +#' \strong{FlowVariable} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowvariable.htm}{Salesforce Documentation for FlowVariable} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{dataType}{a FlowDataType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Currency} +#' \item{Date} +#' \item{Number} +#' \item{String} +#' \item{Boolean} +#' \item{SObject} +#' \item{DateTime} +#' \item{Picklist} +#' \item{Multipicklist} +#' } +#' } +#' \item{isCollection}{a character either 'true' or 'false'} +#' \item{isInput}{a character either 'true' or 'false'} +#' \item{isOutput}{a character either 'true' or 'false'} +#' \item{objectType}{a character} +#' \item{scale}{a integer} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowWait} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowwait.htm}{Salesforce Documentation for FlowWait} +#' \describe{ +#' \item{label}{a character (inherited from FlowNode)} +#' \item{locationX}{a integer (inherited from FlowNode)} +#' \item{locationY}{a integer (inherited from FlowNode)} +#' \item{defaultConnector}{a FlowConnector} +#' \item{defaultConnectorLabel}{a character} +#' \item{faultConnector}{a FlowConnector} +#' \item{waitEvents}{a FlowWaitEvent} +#' } +#' +#' \strong{FlowWaitEvent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowwaitevent.htm}{Salesforce Documentation for FlowWaitEvent} +#' \describe{ +#' \item{description}{a character (inherited from FlowElement)} +#' \item{name}{a character (inherited from FlowElement)} +#' \item{conditionLogic}{a character} +#' \item{conditions}{a FlowCondition} +#' \item{connector}{a FlowConnector} +#' \item{eventType}{a character} +#' \item{inputParameters}{a FlowWaitEventInputParameter} +#' \item{label}{a character} +#' \item{outputParameters}{a FlowWaitEventOutputParameter} +#' } +#' +#' \strong{FlowWaitEventInputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowwaiteventinputparameter.htm}{Salesforce Documentation for FlowWaitEventInputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{name}{a character} +#' \item{value}{a FlowElementReferenceOrValue} +#' } +#' +#' \strong{FlowWaitEventOutputParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_flowwaiteventoutputparameter.htm}{Salesforce Documentation for FlowWaitEventOutputParameter} +#' \describe{ +#' \item{processMetadataValues}{a FlowMetadataValue (inherited from FlowBaseElement)} +#' \item{assignToReference}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{Folder} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_folder.htm}{Salesforce Documentation for Folder} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{accessType}{a FolderAccessTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{Shared} +#' \item{Public} +#' \item{Hidden} +#' \item{PublicInternal} +#' } +#' } +#' \item{folderShares}{a FolderShare} +#' \item{name}{a character} +#' \item{publicFolderAccess}{a PublicFolderAccess - which is a character taking one of the following values: +#' \itemize{ +#' \item{ReadOnly} +#' \item{ReadWrite} +#' } +#' } +#' \item{sharedTo}{a SharedTo} +#' } +#' +#' \strong{FolderShare} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_foldershare.htm}{Salesforce Documentation for FolderShare} +#' \describe{ +#' \item{accessLevel}{a FolderShareAccessLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{View} +#' \item{EditAllContents} +#' \item{Manage} +#' } +#' } +#' \item{sharedTo}{a character} +#' \item{sharedToType}{a FolderSharedToType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Group} +#' \item{Role} +#' \item{RoleAndSubordinates} +#' \item{RoleAndSubordinatesInternal} +#' \item{Manager} +#' \item{ManagerAndSubordinatesInternal} +#' \item{Organization} +#' \item{Territory} +#' \item{TerritoryAndSubordinates} +#' \item{AllPrmUsers} +#' \item{User} +#' \item{PartnerUser} +#' \item{AllCspUsers} +#' \item{CustomerPortalUser} +#' \item{PortalRole} +#' \item{PortalRoleAndSubordinates} +#' \item{ChannelProgramGroup} +#' } +#' } +#' } +#' +#' \strong{ForecastingCategoryMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_forecastingcategorymapping.htm}{Salesforce Documentation for ForecastingCategoryMapping} +#' \describe{ +#' \item{forecastingItemCategoryApiName}{a character} +#' \item{weightedSourceCategories}{a WeightedSourceCategory} +#' } +#' +#' \strong{ForecastingDisplayedFamilySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_forecastingdisplayedfamilysettings.htm}{Salesforce Documentation for ForecastingDisplayedFamilySettings} +#' \describe{ +#' \item{productFamily}{a character} +#' } +#' +#' \strong{ForecastingSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_forecastingsettings.htm}{Salesforce Documentation for ForecastingSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{displayCurrency}{a DisplayCurrency - which is a character taking one of the following values: +#' \itemize{ +#' \item{CORPORATE} +#' \item{PERSONAL} +#' } +#' } +#' \item{enableForecasts}{a character either 'true' or 'false'} +#' \item{forecastingCategoryMappings}{a ForecastingCategoryMapping} +#' \item{forecastingDisplayedFamilySettings}{a ForecastingDisplayedFamilySettings} +#' \item{forecastingTypeSettings}{a ForecastingTypeSettings} +#' } +#' +#' \strong{ForecastingTypeSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_forecastingtypesettings.htm}{Salesforce Documentation for ForecastingTypeSettings} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{adjustmentsSettings}{a AdjustmentsSettings} +#' \item{displayedCategoryApiNames}{a character} +#' \item{forecastRangeSettings}{a ForecastRangeSettings} +#' \item{forecastedCategoryApiNames}{a character} +#' \item{forecastingDateType}{a ForecastingDateType - which is a character taking one of the following values: +#' \itemize{ +#' \item{OpportunityCloseDate} +#' \item{ProductDate} +#' \item{ScheduleDate} +#' } +#' } +#' \item{hasProductFamily}{a character either 'true' or 'false'} +#' \item{isAmount}{a character either 'true' or 'false'} +#' \item{isAvailable}{a character either 'true' or 'false'} +#' \item{isQuantity}{a character either 'true' or 'false'} +#' \item{managerAdjustableCategoryApiNames}{a character} +#' \item{masterLabel}{a character} +#' \item{name}{a character} +#' \item{opportunityListFieldsLabelMappings}{a OpportunityListFieldsLabelMapping} +#' \item{opportunityListFieldsSelectedSettings}{a OpportunityListFieldsSelectedSettings} +#' \item{opportunityListFieldsUnselectedSettings}{a OpportunityListFieldsUnselectedSettings} +#' \item{opportunitySplitName}{a character} +#' \item{ownerAdjustableCategoryApiNames}{a character} +#' \item{quotasSettings}{a QuotasSettings} +#' \item{territory2ModelName}{a character} +#' } +#' +#' \strong{ForecastRangeSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_forecastrangesettings.htm}{Salesforce Documentation for ForecastRangeSettings} +#' \describe{ +#' \item{beginning}{a integer} +#' \item{displaying}{a integer} +#' \item{periodType}{a PeriodTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{Month} +#' \item{Quarter} +#' \item{Week} +#' \item{Year} +#' } +#' } +#' } +#' +#' \strong{GlobalPicklistValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_globalpicklistvalue.htm}{Salesforce Documentation for GlobalPicklistValue} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{color}{a character} +#' \item{default}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' } +#' +#' \strong{GlobalQuickActionTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_globalquickactiontranslation.htm}{Salesforce Documentation for GlobalQuickActionTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{GlobalValueSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_globalvalueset.htm}{Salesforce Documentation for GlobalValueSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customValue}{a CustomValue} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{sorted}{a character either 'true' or 'false'} +#' } +#' +#' \strong{GlobalValueSetTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_globalvaluesettranslation.htm}{Salesforce Documentation for GlobalValueSetTranslation} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{valueTranslation}{a ValueTranslation} +#' } +#' +#' \strong{Group} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_group.htm}{Salesforce Documentation for Group} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{doesIncludeBosses}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{HistoryRetentionPolicy} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_historyretentionpolicy.htm}{Salesforce Documentation for HistoryRetentionPolicy} +#' \describe{ +#' \item{archiveAfterMonths}{a integer} +#' \item{archiveRetentionYears}{a integer} +#' \item{description}{a character} +#' } +#' +#' \strong{Holiday} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_holiday.htm}{Salesforce Documentation for Holiday} +#' \describe{ +#' \item{activityDate}{a character formatted as 'yyyy-mm-dd'} +#' \item{businessHours}{a character} +#' \item{description}{a character} +#' \item{endTime}{a character formatted as 'hh:mm:ssZ} +#' \item{isRecurring}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' \item{recurrenceDayOfMonth}{a integer} +#' \item{recurrenceDayOfWeek}{a character} +#' \item{recurrenceDayOfWeekMask}{a integer} +#' \item{recurrenceEndDate}{a character formatted as 'yyyy-mm-dd'} +#' \item{recurrenceInstance}{a character} +#' \item{recurrenceInterval}{a integer} +#' \item{recurrenceMonthOfYear}{a character} +#' \item{recurrenceStartDate}{a character formatted as 'yyyy-mm-dd'} +#' \item{recurrenceType}{a character} +#' \item{startTime}{a character formatted as 'hh:mm:ssZ} +#' } +#' +#' \strong{HomePageComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_homepagecomponent.htm}{Salesforce Documentation for HomePageComponent} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{body}{a character} +#' \item{height}{a integer} +#' \item{links}{a character} +#' \item{page}{a character} +#' \item{pageComponentType}{a PageComponentType - which is a character taking one of the following values: +#' \itemize{ +#' \item{links} +#' \item{htmlArea} +#' \item{imageOrNote} +#' \item{visualforcePage} +#' } +#' } +#' \item{showLabel}{a character either 'true' or 'false'} +#' \item{showScrollbars}{a character either 'true' or 'false'} +#' \item{width}{a PageComponentWidth - which is a character taking one of the following values: +#' \itemize{ +#' \item{narrow} +#' \item{wide} +#' } +#' } +#' } +#' +#' \strong{HomePageLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_homepagelayout.htm}{Salesforce Documentation for HomePageLayout} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{narrowComponents}{a character} +#' \item{wideComponents}{a character} +#' } +#' +#' \strong{IdeaReputationLevel} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_ideareputationlevel.htm}{Salesforce Documentation for IdeaReputationLevel} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a integer} +#' } +#' +#' \strong{IdeasSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_ideassettings.htm}{Salesforce Documentation for IdeasSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableChatterProfile}{a character either 'true' or 'false'} +#' \item{enableIdeaThemes}{a character either 'true' or 'false'} +#' \item{enableIdeas}{a character either 'true' or 'false'} +#' \item{enableIdeasReputation}{a character either 'true' or 'false'} +#' \item{halfLife}{a numeric} +#' \item{ideasProfilePage}{a character} +#' } +#' +#' \strong{Index} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_index.htm}{Salesforce Documentation for Index} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{fields}{a IndexField} +#' \item{label}{a character} +#' } +#' +#' \strong{IndexField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_indexfield.htm}{Salesforce Documentation for IndexField} +#' \describe{ +#' \item{name}{a character} +#' \item{sortDirection}{a character} +#' } +#' +#' \strong{InsightType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_insighttype.htm}{Salesforce Documentation for InsightType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{defaultTrendType}{a InsightTrendType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Positive} +#' \item{Negative} +#' \item{Informational} +#' \item{Suggestion} +#' } +#' } +#' \item{description}{a character} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{parentType}{a InsightParentType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Opportunity} +#' \item{Account} +#' } +#' } +#' \item{title}{a character} +#' } +#' +#' \strong{InstalledPackage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_installedpackage.htm}{Salesforce Documentation for InstalledPackage} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{password}{a character} +#' \item{versionNumber}{a character} +#' } +#' +#' \strong{IntegrationHubSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_integrationhubsettings.htm}{Salesforce Documentation for IntegrationHubSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{canonicalName}{a character} +#' \item{canonicalNameBindingChar}{a character} +#' \item{description}{a character} +#' \item{isEnabled}{a character either 'true' or 'false'} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{setupData}{a character} +#' \item{setupDefinition}{a character} +#' \item{setupNamespace}{a character} +#' \item{setupSimpleName}{a character} +#' \item{uUID}{a character} +#' \item{version}{a character} +#' \item{versionBuild}{a integer} +#' \item{versionMajor}{a integer} +#' \item{versionMinor}{a integer} +#' } +#' +#' \strong{IntegrationHubSettingsType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_integrationhubsettingstype.htm}{Salesforce Documentation for IntegrationHubSettingsType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{canonicalName}{a character} +#' \item{canonicalNameBindingChar}{a character} +#' \item{description}{a character} +#' \item{isEnabled}{a character either 'true' or 'false'} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{setupNamespace}{a character} +#' \item{setupSimpleName}{a character} +#' \item{uUID}{a character} +#' \item{version}{a character} +#' \item{versionBuild}{a integer} +#' \item{versionMajor}{a integer} +#' \item{versionMinor}{a integer} +#' } +#' +#' \strong{IpRange} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_iprange.htm}{Salesforce Documentation for IpRange} +#' \describe{ +#' \item{description}{a character} +#' \item{end}{a character} +#' \item{start}{a character} +#' } +#' +#' \strong{KeyboardShortcuts} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_keyboardshortcuts.htm}{Salesforce Documentation for KeyboardShortcuts} +#' \describe{ +#' \item{customShortcuts}{a CustomShortcut} +#' \item{defaultShortcuts}{a DefaultShortcut} +#' } +#' +#' \strong{Keyword} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_keyword.htm}{Salesforce Documentation for Keyword} +#' \describe{ +#' \item{keyword}{a character} +#' } +#' +#' \strong{KeywordList} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_keywordlist.htm}{Salesforce Documentation for KeywordList} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{keywords}{a Keyword} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{KnowledgeAnswerSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgeanswersettings.htm}{Salesforce Documentation for KnowledgeAnswerSettings} +#' \describe{ +#' \item{assignTo}{a character} +#' \item{defaultArticleType}{a character} +#' \item{enableArticleCreation}{a character either 'true' or 'false'} +#' } +#' +#' \strong{KnowledgeCaseField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgecasefield.htm}{Salesforce Documentation for KnowledgeCaseField} +#' \describe{ +#' \item{name}{a character} +#' } +#' +#' \strong{KnowledgeCaseFieldsSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgecasefieldssettings.htm}{Salesforce Documentation for KnowledgeCaseFieldsSettings} +#' \describe{ +#' \item{field}{a KnowledgeCaseField} +#' } +#' +#' \strong{KnowledgeCaseSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgecasesettings.htm}{Salesforce Documentation for KnowledgeCaseSettings} +#' \describe{ +#' \item{articlePDFCreationProfile}{a character} +#' \item{articlePublicSharingCommunities}{a KnowledgeCommunitiesSettings} +#' \item{articlePublicSharingSites}{a KnowledgeSitesSettings} +#' \item{articlePublicSharingSitesChatterAnswers}{a KnowledgeSitesSettings} +#' \item{assignTo}{a character} +#' \item{customizationClass}{a character} +#' \item{defaultContributionArticleType}{a character} +#' \item{editor}{a KnowledgeCaseEditor - which is a character taking one of the following values: +#' \itemize{ +#' \item{simple} +#' \item{standard} +#' } +#' } +#' \item{enableArticleCreation}{a character either 'true' or 'false'} +#' \item{enableArticlePublicSharingSites}{a character either 'true' or 'false'} +#' \item{enableCaseDataCategoryMapping}{a character either 'true' or 'false'} +#' \item{useProfileForPDFCreation}{a character either 'true' or 'false'} +#' } +#' +#' \strong{KnowledgeCommunitiesSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgecommunitiessettings.htm}{Salesforce Documentation for KnowledgeCommunitiesSettings} +#' \describe{ +#' \item{community}{a character} +#' } +#' +#' \strong{KnowledgeLanguage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgelanguage.htm}{Salesforce Documentation for KnowledgeLanguage} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{defaultAssignee}{a character} +#' \item{defaultAssigneeType}{a KnowledgeLanguageLookupValueType - which is a character taking one of the following values: +#' \itemize{ +#' \item{User} +#' \item{Queue} +#' } +#' } +#' \item{defaultReviewer}{a character} +#' \item{defaultReviewerType}{a KnowledgeLanguageLookupValueType - which is a character taking one of the following values: +#' \itemize{ +#' \item{User} +#' \item{Queue} +#' } +#' } +#' \item{name}{a character} +#' } +#' +#' \strong{KnowledgeLanguageSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgelanguagesettings.htm}{Salesforce Documentation for KnowledgeLanguageSettings} +#' \describe{ +#' \item{language}{a KnowledgeLanguage} +#' } +#' +#' \strong{KnowledgeSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgesettings.htm}{Salesforce Documentation for KnowledgeSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{answers}{a KnowledgeAnswerSettings} +#' \item{cases}{a KnowledgeCaseSettings} +#' \item{defaultLanguage}{a character} +#' \item{enableChatterQuestionKBDeflection}{a character either 'true' or 'false'} +#' \item{enableCreateEditOnArticlesTab}{a character either 'true' or 'false'} +#' \item{enableExternalMediaContent}{a character either 'true' or 'false'} +#' \item{enableKnowledge}{a character either 'true' or 'false'} +#' \item{enableLightningKnowledge}{a character either 'true' or 'false'} +#' \item{languages}{a KnowledgeLanguageSettings} +#' \item{showArticleSummariesCustomerPortal}{a character either 'true' or 'false'} +#' \item{showArticleSummariesInternalApp}{a character either 'true' or 'false'} +#' \item{showArticleSummariesPartnerPortal}{a character either 'true' or 'false'} +#' \item{showValidationStatusField}{a character either 'true' or 'false'} +#' \item{suggestedArticles}{a KnowledgeSuggestedArticlesSettings} +#' } +#' +#' \strong{KnowledgeSitesSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgesitessettings.htm}{Salesforce Documentation for KnowledgeSitesSettings} +#' \describe{ +#' \item{site}{a character} +#' } +#' +#' \strong{KnowledgeSuggestedArticlesSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgesuggestedarticlessettings.htm}{Salesforce Documentation for KnowledgeSuggestedArticlesSettings} +#' \describe{ +#' \item{caseFields}{a KnowledgeCaseFieldsSettings} +#' \item{useSuggestedArticlesForCase}{a character either 'true' or 'false'} +#' \item{workOrderFields}{a KnowledgeWorkOrderFieldsSettings} +#' \item{workOrderLineItemFields}{a KnowledgeWorkOrderLineItemFieldsSettings} +#' } +#' +#' \strong{KnowledgeWorkOrderField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgeworkorderfield.htm}{Salesforce Documentation for KnowledgeWorkOrderField} +#' \describe{ +#' \item{name}{a character} +#' } +#' +#' \strong{KnowledgeWorkOrderFieldsSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgeworkorderfieldssettings.htm}{Salesforce Documentation for KnowledgeWorkOrderFieldsSettings} +#' \describe{ +#' \item{field}{a KnowledgeWorkOrderField} +#' } +#' +#' \strong{KnowledgeWorkOrderLineItemField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgeworkorderlineitemfield.htm}{Salesforce Documentation for KnowledgeWorkOrderLineItemField} +#' \describe{ +#' \item{name}{a character} +#' } +#' +#' \strong{KnowledgeWorkOrderLineItemFieldsSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_knowledgeworkorderlineitemfieldssettings.htm}{Salesforce Documentation for KnowledgeWorkOrderLineItemFieldsSettings} +#' \describe{ +#' \item{field}{a KnowledgeWorkOrderLineItemField} +#' } +#' +#' \strong{Layout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layout.htm}{Salesforce Documentation for Layout} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customButtons}{a character} +#' \item{customConsoleComponents}{a CustomConsoleComponents} +#' \item{emailDefault}{a character either 'true' or 'false'} +#' \item{excludeButtons}{a character} +#' \item{feedLayout}{a FeedLayout} +#' \item{headers}{a LayoutHeader - which is a character taking one of the following values: +#' \itemize{ +#' \item{PersonalTagging} +#' \item{PublicTagging} +#' } +#' } +#' \item{layoutSections}{a LayoutSection} +#' \item{miniLayout}{a MiniLayout} +#' \item{multilineLayoutFields}{a character} +#' \item{platformActionList}{a PlatformActionList} +#' \item{quickActionList}{a QuickActionList} +#' \item{relatedContent}{a RelatedContent} +#' \item{relatedLists}{a RelatedListItem} +#' \item{relatedObjects}{a character} +#' \item{runAssignmentRulesDefault}{a character either 'true' or 'false'} +#' \item{showEmailCheckbox}{a character either 'true' or 'false'} +#' \item{showHighlightsPanel}{a character either 'true' or 'false'} +#' \item{showInteractionLogPanel}{a character either 'true' or 'false'} +#' \item{showKnowledgeComponent}{a character either 'true' or 'false'} +#' \item{showRunAssignmentRulesCheckbox}{a character either 'true' or 'false'} +#' \item{showSolutionSection}{a character either 'true' or 'false'} +#' \item{showSubmitAndAttachButton}{a character either 'true' or 'false'} +#' \item{summaryLayout}{a SummaryLayout} +#' } +#' +#' \strong{LayoutColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layoutcolumn.htm}{Salesforce Documentation for LayoutColumn} +#' \describe{ +#' \item{layoutItems}{a LayoutItem} +#' \item{reserved}{a character} +#' } +#' +#' \strong{LayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layoutitem.htm}{Salesforce Documentation for LayoutItem} +#' \describe{ +#' \item{analyticsCloudComponent}{a AnalyticsCloudComponentLayoutItem} +#' \item{behavior}{a UiBehavior - which is a character taking one of the following values: +#' \itemize{ +#' \item{Edit} +#' \item{Required} +#' \item{Readonly} +#' } +#' } +#' \item{canvas}{a character} +#' \item{component}{a character} +#' \item{customLink}{a character} +#' \item{emptySpace}{a character either 'true' or 'false'} +#' \item{field}{a character} +#' \item{height}{a integer} +#' \item{page}{a character} +#' \item{reportChartComponent}{a ReportChartComponentLayoutItem} +#' \item{scontrol}{a character} +#' \item{showLabel}{a character either 'true' or 'false'} +#' \item{showScrollbars}{a character either 'true' or 'false'} +#' \item{width}{a character} +#' } +#' +#' \strong{LayoutSection} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layoutsection.htm}{Salesforce Documentation for LayoutSection} +#' \describe{ +#' \item{customLabel}{a character either 'true' or 'false'} +#' \item{detailHeading}{a character either 'true' or 'false'} +#' \item{editHeading}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{layoutColumns}{a LayoutColumn} +#' \item{style}{a LayoutSectionStyle - which is a character taking one of the following values: +#' \itemize{ +#' \item{TwoColumnsTopToBottom} +#' \item{TwoColumnsLeftToRight} +#' \item{OneColumn} +#' \item{CustomLinks} +#' } +#' } +#' } +#' +#' \strong{LayoutSectionTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layoutsectiontranslation.htm}{Salesforce Documentation for LayoutSectionTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{section}{a character} +#' } +#' +#' \strong{LayoutTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_layouttranslation.htm}{Salesforce Documentation for LayoutTranslation} +#' \describe{ +#' \item{layout}{a character} +#' \item{layoutType}{a character} +#' \item{sections}{a LayoutSectionTranslation} +#' } +#' +#' \strong{LeadConvertSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_leadconvertsettings.htm}{Salesforce Documentation for LeadConvertSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{allowOwnerChange}{a character either 'true' or 'false'} +#' \item{objectMapping}{a ObjectMapping} +#' \item{opportunityCreationOptions}{a VisibleOrRequired - which is a character taking one of the following values: +#' \itemize{ +#' \item{VisibleOptional} +#' \item{VisibleRequired} +#' \item{NotVisible} +#' } +#' } +#' } +#' +#' \strong{Letterhead} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_letterhead.htm}{Salesforce Documentation for Letterhead} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{available}{a character either 'true' or 'false'} +#' \item{backgroundColor}{a character} +#' \item{bodyColor}{a character} +#' \item{bottomLine}{a LetterheadLine} +#' \item{description}{a character} +#' \item{footer}{a LetterheadHeaderFooter} +#' \item{header}{a LetterheadHeaderFooter} +#' \item{middleLine}{a LetterheadLine} +#' \item{name}{a character} +#' \item{topLine}{a LetterheadLine} +#' } +#' +#' \strong{LetterheadHeaderFooter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_letterheadheaderfooter.htm}{Salesforce Documentation for LetterheadHeaderFooter} +#' \describe{ +#' \item{backgroundColor}{a character} +#' \item{height}{a integer} +#' \item{horizontalAlignment}{a LetterheadHorizontalAlignment - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Left} +#' \item{Center} +#' \item{Right} +#' } +#' } +#' \item{logo}{a character} +#' \item{verticalAlignment}{a LetterheadVerticalAlignment - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Top} +#' \item{Middle} +#' \item{Bottom} +#' } +#' } +#' } +#' +#' \strong{LetterheadLine} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_letterheadline.htm}{Salesforce Documentation for LetterheadLine} +#' \describe{ +#' \item{color}{a character} +#' \item{height}{a integer} +#' } +#' +#' \strong{LicensedCustomPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_licensedcustompermissions.htm}{Salesforce Documentation for LicensedCustomPermissions} +#' \describe{ +#' \item{customPermission}{a character} +#' \item{licenseDefinition}{a character} +#' } +#' +#' \strong{LicenseDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_licensedefinition.htm}{Salesforce Documentation for LicenseDefinition} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{aggregationGroup}{a character} +#' \item{description}{a character} +#' \item{isPublished}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{licensedCustomPermissions}{a LicensedCustomPermissions} +#' \item{licensingAuthority}{a character} +#' \item{licensingAuthorityProvider}{a character} +#' \item{minPlatformVersion}{a integer} +#' \item{origin}{a character} +#' \item{revision}{a integer} +#' \item{trialLicenseDuration}{a integer} +#' \item{trialLicenseQuantity}{a integer} +#' } +#' +#' \strong{LightningBolt} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningbolt.htm}{Salesforce Documentation for LightningBolt} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{category}{a LightningBoltCategory - which is a character taking one of the following values: +#' \itemize{ +#' \item{IT} +#' \item{Marketing} +#' \item{Sales} +#' \item{Service} +#' } +#' } +#' \item{lightningBoltFeatures}{a LightningBoltFeatures} +#' \item{lightningBoltImages}{a LightningBoltImages} +#' \item{lightningBoltItems}{a LightningBoltItems} +#' \item{masterLabel}{a character} +#' \item{publisher}{a character} +#' \item{summary}{a character} +#' } +#' +#' \strong{LightningBoltFeatures} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningboltfeatures.htm}{Salesforce Documentation for LightningBoltFeatures} +#' \describe{ +#' \item{description}{a character} +#' \item{order}{a integer} +#' \item{title}{a character} +#' } +#' +#' \strong{LightningBoltImages} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningboltimages.htm}{Salesforce Documentation for LightningBoltImages} +#' \describe{ +#' \item{image}{a character} +#' \item{order}{a integer} +#' } +#' +#' \strong{LightningBoltItems} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningboltitems.htm}{Salesforce Documentation for LightningBoltItems} +#' \describe{ +#' \item{name}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{LightningComponentBundle} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningcomponentbundle.htm}{Salesforce Documentation for LightningComponentBundle} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{apiVersion}{a numeric} +#' \item{isExposed}{a character either 'true' or 'false'} +#' } +#' +#' \strong{LightningExperienceTheme} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningexperiencetheme.htm}{Salesforce Documentation for LightningExperienceTheme} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{defaultBrandingSet}{a character} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{shouldOverrideLoadingImage}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ListMetadataQuery} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_listmetadataquery.htm}{Salesforce Documentation for ListMetadataQuery} +#' \describe{ +#' \item{folder}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{ListPlacement} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_listplacement.htm}{Salesforce Documentation for ListPlacement} +#' \describe{ +#' \item{height}{a integer} +#' \item{location}{a character} +#' \item{units}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{ListView} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_listview.htm}{Salesforce Documentation for ListView} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{booleanFilter}{a character} +#' \item{columns}{a character} +#' \item{division}{a character} +#' \item{filterScope}{a FilterScope - which is a character taking one of the following values: +#' \itemize{ +#' \item{Everything} +#' \item{Mine} +#' \item{Queue} +#' \item{Delegated} +#' \item{MyTerritory} +#' \item{MyTeamTerritory} +#' \item{Team} +#' \item{AssignedToMe} +#' } +#' } +#' \item{filters}{a ListViewFilter} +#' \item{label}{a character} +#' \item{language}{a Language - which is a character taking one of the following values: +#' \itemize{ +#' \item{en_US} +#' \item{de} +#' \item{es} +#' \item{fr} +#' \item{it} +#' \item{ja} +#' \item{sv} +#' \item{ko} +#' \item{zh_TW} +#' \item{zh_CN} +#' \item{pt_BR} +#' \item{nl_NL} +#' \item{da} +#' \item{th} +#' \item{fi} +#' \item{ru} +#' \item{es_MX} +#' \item{no} +#' \item{hu} +#' \item{pl} +#' \item{cs} +#' \item{tr} +#' \item{in} +#' \item{ro} +#' \item{vi} +#' \item{uk} +#' \item{iw} +#' \item{el} +#' \item{bg} +#' \item{en_GB} +#' \item{ar} +#' \item{sk} +#' \item{pt_PT} +#' \item{hr} +#' \item{sl} +#' \item{fr_CA} +#' \item{ka} +#' \item{sr} +#' \item{sh} +#' \item{en_AU} +#' \item{en_MY} +#' \item{en_IN} +#' \item{en_PH} +#' \item{en_CA} +#' \item{ro_MD} +#' \item{bs} +#' \item{mk} +#' \item{lv} +#' \item{lt} +#' \item{et} +#' \item{sq} +#' \item{sh_ME} +#' \item{mt} +#' \item{ga} +#' \item{eu} +#' \item{cy} +#' \item{is} +#' \item{ms} +#' \item{tl} +#' \item{lb} +#' \item{rm} +#' \item{hy} +#' \item{hi} +#' \item{ur} +#' \item{bn} +#' \item{de_AT} +#' \item{de_CH} +#' \item{ta} +#' \item{ar_DZ} +#' \item{ar_BH} +#' \item{ar_EG} +#' \item{ar_IQ} +#' \item{ar_JO} +#' \item{ar_KW} +#' \item{ar_LB} +#' \item{ar_LY} +#' \item{ar_MA} +#' \item{ar_OM} +#' \item{ar_QA} +#' \item{ar_SA} +#' \item{ar_SD} +#' \item{ar_SY} +#' \item{ar_TN} +#' \item{ar_AE} +#' \item{ar_YE} +#' \item{zh_SG} +#' \item{zh_HK} +#' \item{en_HK} +#' \item{en_IE} +#' \item{en_SG} +#' \item{en_ZA} +#' \item{fr_BE} +#' \item{fr_LU} +#' \item{fr_CH} +#' \item{de_BE} +#' \item{de_LU} +#' \item{it_CH} +#' \item{nl_BE} +#' \item{es_AR} +#' \item{es_BO} +#' \item{es_CL} +#' \item{es_CO} +#' \item{es_CR} +#' \item{es_DO} +#' \item{es_EC} +#' \item{es_SV} +#' \item{es_GT} +#' \item{es_HN} +#' \item{es_NI} +#' \item{es_PA} +#' \item{es_PY} +#' \item{es_PE} +#' \item{es_PR} +#' \item{es_US} +#' \item{es_UY} +#' \item{es_VE} +#' \item{ca} +#' \item{eo} +#' \item{iw_EO} +#' } +#' } +#' \item{queue}{a character} +#' \item{sharedTo}{a SharedTo} +#' } +#' +#' \strong{ListViewFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_listviewfilter.htm}{Salesforce Documentation for ListViewFilter} +#' \describe{ +#' \item{field}{a character} +#' \item{operation}{a FilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{equals} +#' \item{notEqual} +#' \item{lessThan} +#' \item{greaterThan} +#' \item{lessOrEqual} +#' \item{greaterOrEqual} +#' \item{contains} +#' \item{notContain} +#' \item{startsWith} +#' \item{includes} +#' \item{excludes} +#' \item{within} +#' } +#' } +#' \item{value}{a character} +#' } +#' +#' \strong{LiveAgentConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_liveagentconfig.htm}{Salesforce Documentation for LiveAgentConfig} +#' \describe{ +#' \item{enableLiveChat}{a character either 'true' or 'false'} +#' \item{openNewAccountSubtab}{a character either 'true' or 'false'} +#' \item{openNewCaseSubtab}{a character either 'true' or 'false'} +#' \item{openNewContactSubtab}{a character either 'true' or 'false'} +#' \item{openNewLeadSubtab}{a character either 'true' or 'false'} +#' \item{openNewVFPageSubtab}{a character either 'true' or 'false'} +#' \item{pageNamesToOpen}{a character} +#' \item{showKnowledgeArticles}{a character either 'true' or 'false'} +#' } +#' +#' \strong{LiveAgentSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_liveagentsettings.htm}{Salesforce Documentation for LiveAgentSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableLiveAgent}{a character either 'true' or 'false'} +#' } +#' +#' \strong{LiveChatAgentConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatagentconfig.htm}{Salesforce Documentation for LiveChatAgentConfig} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assignments}{a AgentConfigAssignments} +#' \item{autoGreeting}{a character} +#' \item{capacity}{a integer} +#' \item{criticalWaitTime}{a integer} +#' \item{customAgentName}{a character} +#' \item{enableAgentFileTransfer}{a character either 'true' or 'false'} +#' \item{enableAgentSneakPeek}{a character either 'true' or 'false'} +#' \item{enableAssistanceFlag}{a character either 'true' or 'false'} +#' \item{enableAutoAwayOnDecline}{a character either 'true' or 'false'} +#' \item{enableAutoAwayOnPushTimeout}{a character either 'true' or 'false'} +#' \item{enableChatConferencing}{a character either 'true' or 'false'} +#' \item{enableChatMonitoring}{a character either 'true' or 'false'} +#' \item{enableChatTransferToAgent}{a character either 'true' or 'false'} +#' \item{enableChatTransferToButton}{a character either 'true' or 'false'} +#' \item{enableChatTransferToSkill}{a character either 'true' or 'false'} +#' \item{enableLogoutSound}{a character either 'true' or 'false'} +#' \item{enableNotifications}{a character either 'true' or 'false'} +#' \item{enableRequestSound}{a character either 'true' or 'false'} +#' \item{enableSneakPeek}{a character either 'true' or 'false'} +#' \item{enableVisitorBlocking}{a character either 'true' or 'false'} +#' \item{enableWhisperMessage}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{supervisorDefaultAgentStatusFilter}{a SupervisorAgentStatusFilter - which is a character taking one of the following values: +#' \itemize{ +#' \item{Online} +#' \item{Away} +#' \item{Offline} +#' } +#' } +#' \item{supervisorDefaultButtonFilter}{a character} +#' \item{supervisorDefaultSkillFilter}{a character} +#' \item{supervisorSkills}{a SupervisorAgentConfigSkills} +#' \item{transferableButtons}{a AgentConfigButtons} +#' \item{transferableSkills}{a AgentConfigSkills} +#' } +#' +#' \strong{LiveChatButton} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatbutton.htm}{Salesforce Documentation for LiveChatButton} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{animation}{a LiveChatButtonPresentation - which is a character taking one of the following values: +#' \itemize{ +#' \item{Slide} +#' \item{Fade} +#' \item{Appear} +#' \item{Custom} +#' } +#' } +#' \item{autoGreeting}{a character} +#' \item{chasitorIdleTimeout}{a integer} +#' \item{chasitorIdleTimeoutWarning}{a integer} +#' \item{chatPage}{a character} +#' \item{customAgentName}{a character} +#' \item{deployments}{a LiveChatButtonDeployments} +#' \item{enableQueue}{a character either 'true' or 'false'} +#' \item{inviteEndPosition}{a LiveChatButtonInviteEndPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{TopLeft} +#' \item{Top} +#' \item{TopRight} +#' \item{Left} +#' \item{Center} +#' \item{Right} +#' \item{BottomLeft} +#' \item{Bottom} +#' \item{BottomRight} +#' } +#' } +#' \item{inviteImage}{a character} +#' \item{inviteStartPosition}{a LiveChatButtonInviteStartPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{TopLeft} +#' \item{TopLeftTop} +#' \item{Top} +#' \item{TopRightTop} +#' \item{TopRight} +#' \item{TopRightRight} +#' \item{Right} +#' \item{BottomRightRight} +#' \item{BottomRight} +#' \item{BottomRightBottom} +#' \item{Bottom} +#' \item{BottomLeftBottom} +#' \item{BottomLeft} +#' \item{BottomLeftLeft} +#' \item{Left} +#' \item{TopLeftLeft} +#' } +#' } +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{numberOfReroutingAttempts}{a integer} +#' \item{offlineImage}{a character} +#' \item{onlineImage}{a character} +#' \item{optionsCustomRoutingIsEnabled}{a character either 'true' or 'false'} +#' \item{optionsHasChasitorIdleTimeout}{a character either 'true' or 'false'} +#' \item{optionsHasInviteAfterAccept}{a character either 'true' or 'false'} +#' \item{optionsHasInviteAfterReject}{a character either 'true' or 'false'} +#' \item{optionsHasRerouteDeclinedRequest}{a character either 'true' or 'false'} +#' \item{optionsIsAutoAccept}{a character either 'true' or 'false'} +#' \item{optionsIsInviteAutoRemove}{a character either 'true' or 'false'} +#' \item{overallQueueLength}{a integer} +#' \item{perAgentQueueLength}{a integer} +#' \item{postChatPage}{a character} +#' \item{postChatUrl}{a character} +#' \item{preChatFormPage}{a character} +#' \item{preChatFormUrl}{a character} +#' \item{pushTimeOut}{a integer} +#' \item{routingType}{a LiveChatButtonRoutingType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Choice} +#' \item{LeastActive} +#' \item{MostAvailable} +#' } +#' } +#' \item{site}{a character} +#' \item{skills}{a LiveChatButtonSkills} +#' \item{timeToRemoveInvite}{a integer} +#' \item{type}{a LiveChatButtonType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Standard} +#' \item{Invite} +#' } +#' } +#' \item{windowLanguage}{a Language - which is a character taking one of the following values: +#' \itemize{ +#' \item{en_US} +#' \item{de} +#' \item{es} +#' \item{fr} +#' \item{it} +#' \item{ja} +#' \item{sv} +#' \item{ko} +#' \item{zh_TW} +#' \item{zh_CN} +#' \item{pt_BR} +#' \item{nl_NL} +#' \item{da} +#' \item{th} +#' \item{fi} +#' \item{ru} +#' \item{es_MX} +#' \item{no} +#' \item{hu} +#' \item{pl} +#' \item{cs} +#' \item{tr} +#' \item{in} +#' \item{ro} +#' \item{vi} +#' \item{uk} +#' \item{iw} +#' \item{el} +#' \item{bg} +#' \item{en_GB} +#' \item{ar} +#' \item{sk} +#' \item{pt_PT} +#' \item{hr} +#' \item{sl} +#' \item{fr_CA} +#' \item{ka} +#' \item{sr} +#' \item{sh} +#' \item{en_AU} +#' \item{en_MY} +#' \item{en_IN} +#' \item{en_PH} +#' \item{en_CA} +#' \item{ro_MD} +#' \item{bs} +#' \item{mk} +#' \item{lv} +#' \item{lt} +#' \item{et} +#' \item{sq} +#' \item{sh_ME} +#' \item{mt} +#' \item{ga} +#' \item{eu} +#' \item{cy} +#' \item{is} +#' \item{ms} +#' \item{tl} +#' \item{lb} +#' \item{rm} +#' \item{hy} +#' \item{hi} +#' \item{ur} +#' \item{bn} +#' \item{de_AT} +#' \item{de_CH} +#' \item{ta} +#' \item{ar_DZ} +#' \item{ar_BH} +#' \item{ar_EG} +#' \item{ar_IQ} +#' \item{ar_JO} +#' \item{ar_KW} +#' \item{ar_LB} +#' \item{ar_LY} +#' \item{ar_MA} +#' \item{ar_OM} +#' \item{ar_QA} +#' \item{ar_SA} +#' \item{ar_SD} +#' \item{ar_SY} +#' \item{ar_TN} +#' \item{ar_AE} +#' \item{ar_YE} +#' \item{zh_SG} +#' \item{zh_HK} +#' \item{en_HK} +#' \item{en_IE} +#' \item{en_SG} +#' \item{en_ZA} +#' \item{fr_BE} +#' \item{fr_LU} +#' \item{fr_CH} +#' \item{de_BE} +#' \item{de_LU} +#' \item{it_CH} +#' \item{nl_BE} +#' \item{es_AR} +#' \item{es_BO} +#' \item{es_CL} +#' \item{es_CO} +#' \item{es_CR} +#' \item{es_DO} +#' \item{es_EC} +#' \item{es_SV} +#' \item{es_GT} +#' \item{es_HN} +#' \item{es_NI} +#' \item{es_PA} +#' \item{es_PY} +#' \item{es_PE} +#' \item{es_PR} +#' \item{es_US} +#' \item{es_UY} +#' \item{es_VE} +#' \item{ca} +#' \item{eo} +#' \item{iw_EO} +#' } +#' } +#' } +#' +#' \strong{LiveChatButtonDeployments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatbuttondeployments.htm}{Salesforce Documentation for LiveChatButtonDeployments} +#' \describe{ +#' \item{deployment}{a character} +#' } +#' +#' \strong{LiveChatButtonSkills} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatbuttonskills.htm}{Salesforce Documentation for LiveChatButtonSkills} +#' \describe{ +#' \item{skill}{a character} +#' } +#' +#' \strong{LiveChatDeployment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatdeployment.htm}{Salesforce Documentation for LiveChatDeployment} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{brandingImage}{a character} +#' \item{connectionTimeoutDuration}{a integer} +#' \item{connectionWarningDuration}{a integer} +#' \item{displayQueuePosition}{a character either 'true' or 'false'} +#' \item{domainWhiteList}{a LiveChatDeploymentDomainWhitelist} +#' \item{enablePrechatApi}{a character either 'true' or 'false'} +#' \item{enableTranscriptSave}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{mobileBrandingImage}{a character} +#' \item{site}{a character} +#' \item{windowTitle}{a character} +#' } +#' +#' \strong{LiveChatDeploymentDomainWhitelist} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatdeploymentdomainwhitelist.htm}{Salesforce Documentation for LiveChatDeploymentDomainWhitelist} +#' \describe{ +#' \item{domain}{a character} +#' } +#' +#' \strong{LiveChatSensitiveDataRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livechatsensitivedatarule.htm}{Salesforce Documentation for LiveChatSensitiveDataRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionType}{a SensitiveDataActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Remove} +#' \item{Replace} +#' } +#' } +#' \item{description}{a character} +#' \item{enforceOn}{a integer} +#' \item{isEnabled}{a character either 'true' or 'false'} +#' \item{pattern}{a character} +#' \item{replacement}{a character} +#' } +#' +#' \strong{LiveMessageSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_livemessagesettings.htm}{Salesforce Documentation for LiveMessageSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableLiveMessage}{a character either 'true' or 'false'} +#' } +#' +#' \strong{LogInfo} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_loginfo.htm}{Salesforce Documentation for LogInfo} +#' \describe{ +#' \item{category}{a LogCategory - which is a character taking one of the following values: +#' \itemize{ +#' \item{Db} +#' \item{Workflow} +#' \item{Validation} +#' \item{Callout} +#' \item{Apex_code} +#' \item{Apex_profiling} +#' \item{Visualforce} +#' \item{System} +#' \item{Wave} +#' \item{All} +#' } +#' } +#' \item{level}{a LogCategoryLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Finest} +#' \item{Finer} +#' \item{Fine} +#' \item{Debug} +#' \item{Info} +#' \item{Warn} +#' \item{Error} +#' } +#' } +#' } +#' +#' \strong{LookupFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lookupfilter.htm}{Salesforce Documentation for LookupFilter} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{booleanFilter}{a character} +#' \item{description}{a character} +#' \item{errorMessage}{a character} +#' \item{filterItems}{a FilterItem} +#' \item{infoMessage}{a character} +#' \item{isOptional}{a character either 'true' or 'false'} +#' } +#' +#' \strong{LookupFilterTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lookupfiltertranslation.htm}{Salesforce Documentation for LookupFilterTranslation} +#' \describe{ +#' \item{errorMessage}{a character} +#' \item{informationalMessage}{a character} +#' } +#' +#' \strong{MacroSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_macrosettings.htm}{Salesforce Documentation for MacroSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableAdvancedSearch}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ManagedTopic} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_managedtopic.htm}{Salesforce Documentation for ManagedTopic} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{managedTopicType}{a character} +#' \item{name}{a character} +#' \item{parentName}{a character} +#' \item{position}{a integer} +#' \item{topicDescription}{a character} +#' } +#' +#' \strong{ManagedTopics} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_managedtopics.htm}{Salesforce Documentation for ManagedTopics} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{managedTopic}{a ManagedTopic} +#' } +#' +#' \strong{MarketingActionSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_marketingactionsettings.htm}{Salesforce Documentation for MarketingActionSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableMarketingAction}{a character either 'true' or 'false'} +#' } +#' +#' \strong{MarketingResourceType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_marketingresourcetype.htm}{Salesforce Documentation for MarketingResourceType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{object}{a character} +#' \item{provider}{a character} +#' } +#' +#' \strong{MatchingRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_matchingrule.htm}{Salesforce Documentation for MatchingRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{booleanFilter}{a character} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{matchingRuleItems}{a MatchingRuleItem} +#' \item{ruleStatus}{a MatchingRuleStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{Inactive} +#' \item{DeactivationFailed} +#' \item{Activating} +#' \item{Deactivating} +#' \item{Active} +#' \item{ActivationFailed} +#' } +#' } +#' } +#' +#' \strong{MatchingRuleItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_matchingruleitem.htm}{Salesforce Documentation for MatchingRuleItem} +#' \describe{ +#' \item{blankValueBehavior}{a BlankValueBehavior - which is a character taking one of the following values: +#' \itemize{ +#' \item{MatchBlanks} +#' \item{NullNotAllowed} +#' } +#' } +#' \item{fieldName}{a character} +#' \item{matchingMethod}{a MatchingMethod - which is a character taking one of the following values: +#' \itemize{ +#' \item{Exact} +#' \item{FirstName} +#' \item{LastName} +#' \item{CompanyName} +#' \item{Phone} +#' \item{City} +#' \item{Street} +#' \item{Zip} +#' \item{Title} +#' } +#' } +#' } +#' +#' \strong{MatchingRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_matchingrules.htm}{Salesforce Documentation for MatchingRules} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{matchingRules}{a MatchingRule} +#' } +#' +#' \strong{Metadata} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_metadata.htm}{Salesforce Documentation for Metadata} +#' \describe{ +#' \item{fullName}{a character} +#' } +#' +#' \strong{MetadataWithContent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_metadatawithcontent.htm}{Salesforce Documentation for MetadataWithContent} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{content}{a character formed using RCurl::base64Encode} +#' } +#' +#' \strong{MilestoneType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_milestonetype.htm}{Salesforce Documentation for MilestoneType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{recurrenceType}{a MilestoneTypeRecurrenceType - which is a character taking one of the following values: +#' \itemize{ +#' \item{none} +#' \item{recursIndependently} +#' \item{recursChained} +#' } +#' } +#' } +#' +#' \strong{MiniLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_minilayout.htm}{Salesforce Documentation for MiniLayout} +#' \describe{ +#' \item{fields}{a character} +#' \item{relatedLists}{a RelatedListItem} +#' } +#' +#' \strong{MobileSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_mobilesettings.htm}{Salesforce Documentation for MobileSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{chatterMobile}{a ChatterMobileSettings} +#' \item{dashboardMobile}{a DashboardMobileSettings} +#' \item{salesforceMobile}{a SFDCMobileSettings} +#' \item{touchMobile}{a TouchMobileSettings} +#' } +#' +#' \strong{ModeratedEntityField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_moderatedentityfield.htm}{Salesforce Documentation for ModeratedEntityField} +#' \describe{ +#' \item{entityName}{a character} +#' \item{fieldName}{a character} +#' \item{keywordList}{a character} +#' } +#' +#' \strong{ModerationRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_moderationrule.htm}{Salesforce Documentation for ModerationRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{action}{a ModerationRuleAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{Block} +#' \item{FreezeAndNotify} +#' \item{Review} +#' \item{Replace} +#' \item{Flag} +#' } +#' } +#' \item{actionLimit}{a integer} +#' \item{active}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{entitiesAndFields}{a ModeratedEntityField} +#' \item{masterLabel}{a character} +#' \item{notifyLimit}{a integer} +#' \item{timePeriod}{a RateLimitTimePeriod - which is a character taking one of the following values: +#' \itemize{ +#' \item{Short} +#' \item{Medium} +#' } +#' } +#' \item{type}{a ModerationRuleType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Content} +#' \item{Rate} +#' } +#' } +#' \item{userCriteria}{a character} +#' \item{userMessage}{a character} +#' } +#' +#' \strong{NamedCredential} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_namedcredential.htm}{Salesforce Documentation for NamedCredential} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{allowMergeFieldsInBody}{a character either 'true' or 'false'} +#' \item{allowMergeFieldsInHeader}{a character either 'true' or 'false'} +#' \item{authProvider}{a character} +#' \item{certificate}{a character} +#' \item{endpoint}{a character} +#' \item{generateAuthorizationHeader}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{oauthRefreshToken}{a character} +#' \item{oauthScope}{a character} +#' \item{oauthToken}{a character} +#' \item{password}{a character} +#' \item{principalType}{a ExternalPrincipalType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Anonymous} +#' \item{PerUser} +#' \item{NamedUser} +#' } +#' } +#' \item{protocol}{a AuthenticationProtocol - which is a character taking one of the following values: +#' \itemize{ +#' \item{NoAuthentication} +#' \item{Oauth} +#' \item{Password} +#' } +#' } +#' \item{username}{a character} +#' } +#' +#' \strong{NameSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_namesettings.htm}{Salesforce Documentation for NameSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableMiddleName}{a character either 'true' or 'false'} +#' \item{enableNameSuffix}{a character either 'true' or 'false'} +#' } +#' +#' \strong{NavigationLinkSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_navigationlinkset.htm}{Salesforce Documentation for NavigationLinkSet} +#' \describe{ +#' \item{navigationMenuItem}{a NavigationMenuItem} +#' } +#' +#' \strong{NavigationMenuItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_navigationmenuitem.htm}{Salesforce Documentation for NavigationMenuItem} +#' \describe{ +#' \item{defaultListViewId}{a character} +#' \item{label}{a character} +#' \item{position}{a integer} +#' \item{publiclyAvailable}{a character either 'true' or 'false'} +#' \item{subMenu}{a NavigationSubMenu} +#' \item{target}{a character} +#' \item{targetPreference}{a character} +#' \item{type}{a character} +#' } +#' +#' \strong{NavigationSubMenu} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_navigationsubmenu.htm}{Salesforce Documentation for NavigationSubMenu} +#' \describe{ +#' \item{navigationMenuItem}{a NavigationMenuItem} +#' } +#' +#' \strong{Network} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_network.htm}{Salesforce Documentation for Network} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{allowInternalUserLogin}{a character either 'true' or 'false'} +#' \item{allowMembersToFlag}{a character either 'true' or 'false'} +#' \item{allowedExtensions}{a character} +#' \item{caseCommentEmailTemplate}{a character} +#' \item{changePasswordTemplate}{a character} +#' \item{communityRoles}{a CommunityRoles} +#' \item{description}{a character} +#' \item{disableReputationRecordConversations}{a character either 'true' or 'false'} +#' \item{emailFooterLogo}{a character} +#' \item{emailFooterText}{a character} +#' \item{emailSenderAddress}{a character} +#' \item{emailSenderName}{a character} +#' \item{enableCustomVFErrorPageOverrides}{a character either 'true' or 'false'} +#' \item{enableDirectMessages}{a character either 'true' or 'false'} +#' \item{enableGuestChatter}{a character either 'true' or 'false'} +#' \item{enableGuestFileAccess}{a character either 'true' or 'false'} +#' \item{enableInvitation}{a character either 'true' or 'false'} +#' \item{enableKnowledgeable}{a character either 'true' or 'false'} +#' \item{enableNicknameDisplay}{a character either 'true' or 'false'} +#' \item{enablePrivateMessages}{a character either 'true' or 'false'} +#' \item{enableReputation}{a character either 'true' or 'false'} +#' \item{enableShowAllNetworkSettings}{a character either 'true' or 'false'} +#' \item{enableSiteAsContainer}{a character either 'true' or 'false'} +#' \item{enableTalkingAboutStats}{a character either 'true' or 'false'} +#' \item{enableTopicAssignmentRules}{a character either 'true' or 'false'} +#' \item{enableTopicSuggestions}{a character either 'true' or 'false'} +#' \item{enableUpDownVote}{a character either 'true' or 'false'} +#' \item{feedChannel}{a character} +#' \item{forgotPasswordTemplate}{a character} +#' \item{gatherCustomerSentimentData}{a character either 'true' or 'false'} +#' \item{logoutUrl}{a character} +#' \item{maxFileSizeKb}{a integer} +#' \item{navigationLinkSet}{a NavigationLinkSet} +#' \item{networkMemberGroups}{a NetworkMemberGroup} +#' \item{networkPageOverrides}{a NetworkPageOverride} +#' \item{newSenderAddress}{a character} +#' \item{picassoSite}{a character} +#' \item{recommendationAudience}{a RecommendationAudience} +#' \item{recommendationDefinition}{a RecommendationDefinition} +#' \item{reputationLevels}{a ReputationLevelDefinitions} +#' \item{reputationPointsRules}{a ReputationPointsRules} +#' \item{selfRegProfile}{a character} +#' \item{selfRegistration}{a character either 'true' or 'false'} +#' \item{sendWelcomeEmail}{a character either 'true' or 'false'} +#' \item{site}{a character} +#' \item{status}{a NetworkStatus - which is a character taking one of the following values: +#' \itemize{ +#' \item{UnderConstruction} +#' \item{Live} +#' \item{DownForMaintenance} +#' } +#' } +#' \item{tabs}{a NetworkTabSet} +#' \item{urlPathPrefix}{a character} +#' \item{welcomeTemplate}{a character} +#' } +#' +#' \strong{NetworkAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_networkaccess.htm}{Salesforce Documentation for NetworkAccess} +#' \describe{ +#' \item{ipRanges}{a IpRange} +#' } +#' +#' \strong{NetworkBranding} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_networkbranding.htm}{Salesforce Documentation for NetworkBranding} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{loginFooterText}{a character} +#' \item{loginLogo}{a character} +#' \item{loginLogoName}{a character} +#' \item{loginPrimaryColor}{a character} +#' \item{loginQuaternaryColor}{a character} +#' \item{loginRightFrameUrl}{a character} +#' \item{network}{a character} +#' \item{pageFooter}{a character} +#' \item{pageHeader}{a character} +#' \item{primaryColor}{a character} +#' \item{primaryComplementColor}{a character} +#' \item{quaternaryColor}{a character} +#' \item{quaternaryComplementColor}{a character} +#' \item{secondaryColor}{a character} +#' \item{staticLogoImageUrl}{a character} +#' \item{tertiaryColor}{a character} +#' \item{tertiaryComplementColor}{a character} +#' \item{zeronaryColor}{a character} +#' \item{zeronaryComplementColor}{a character} +#' } +#' +#' \strong{NetworkMemberGroup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_networkmembergroup.htm}{Salesforce Documentation for NetworkMemberGroup} +#' \describe{ +#' \item{permissionSet}{a character} +#' \item{profile}{a character} +#' } +#' +#' \strong{NetworkPageOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_networkpageoverride.htm}{Salesforce Documentation for NetworkPageOverride} +#' \describe{ +#' \item{changePasswordPageOverrideSetting}{a NetworkPageOverrideSetting - which is a character taking one of the following values: +#' \itemize{ +#' \item{Designer} +#' \item{VisualForce} +#' \item{Standard} +#' } +#' } +#' \item{forgotPasswordPageOverrideSetting}{a NetworkPageOverrideSetting - which is a character taking one of the following values: +#' \itemize{ +#' \item{Designer} +#' \item{VisualForce} +#' \item{Standard} +#' } +#' } +#' \item{homePageOverrideSetting}{a NetworkPageOverrideSetting - which is a character taking one of the following values: +#' \itemize{ +#' \item{Designer} +#' \item{VisualForce} +#' \item{Standard} +#' } +#' } +#' \item{loginPageOverrideSetting}{a NetworkPageOverrideSetting - which is a character taking one of the following values: +#' \itemize{ +#' \item{Designer} +#' \item{VisualForce} +#' \item{Standard} +#' } +#' } +#' \item{selfRegProfilePageOverrideSetting}{a NetworkPageOverrideSetting - which is a character taking one of the following values: +#' \itemize{ +#' \item{Designer} +#' \item{VisualForce} +#' \item{Standard} +#' } +#' } +#' } +#' +#' \strong{NetworkTabSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_networktabset.htm}{Salesforce Documentation for NetworkTabSet} +#' \describe{ +#' \item{customTab}{a character} +#' \item{defaultTab}{a character} +#' \item{standardTab}{a character} +#' } +#' +#' \strong{NextAutomatedApprover} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_nextautomatedapprover.htm}{Salesforce Documentation for NextAutomatedApprover} +#' \describe{ +#' \item{useApproverFieldOfRecordOwner}{a character either 'true' or 'false'} +#' \item{userHierarchyField}{a character} +#' } +#' +#' \strong{ObjectMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectmapping.htm}{Salesforce Documentation for ObjectMapping} +#' \describe{ +#' \item{inputObject}{a character} +#' \item{mappingFields}{a ObjectMappingField} +#' \item{outputObject}{a character} +#' } +#' +#' \strong{ObjectMappingField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectmappingfield.htm}{Salesforce Documentation for ObjectMappingField} +#' \describe{ +#' \item{inputField}{a character} +#' \item{outputField}{a character} +#' } +#' +#' \strong{ObjectNameCaseValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectnamecasevalue.htm}{Salesforce Documentation for ObjectNameCaseValue} +#' \describe{ +#' \item{article}{a Article - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Indefinite} +#' \item{Definite} +#' } +#' } +#' \item{caseType}{a CaseType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Nominative} +#' \item{Accusative} +#' \item{Genitive} +#' \item{Dative} +#' \item{Inessive} +#' \item{Elative} +#' \item{Illative} +#' \item{Adessive} +#' \item{Ablative} +#' \item{Allative} +#' \item{Essive} +#' \item{Translative} +#' \item{Partitive} +#' \item{Objective} +#' \item{Subjective} +#' \item{Instrumental} +#' \item{Prepositional} +#' \item{Locative} +#' \item{Vocative} +#' \item{Sublative} +#' \item{Superessive} +#' \item{Delative} +#' \item{Causalfinal} +#' \item{Essiveformal} +#' \item{Termanative} +#' \item{Distributive} +#' \item{Ergative} +#' \item{Adverbial} +#' \item{Abessive} +#' \item{Comitative} +#' } +#' } +#' \item{plural}{a character either 'true' or 'false'} +#' \item{possessive}{a Possessive - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{First} +#' \item{Second} +#' } +#' } +#' \item{value}{a character} +#' } +#' +#' \strong{ObjectRelationship} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectrelationship.htm}{Salesforce Documentation for ObjectRelationship} +#' \describe{ +#' \item{join}{a ObjectRelationship} +#' \item{outerJoin}{a character either 'true' or 'false'} +#' \item{relationship}{a character} +#' } +#' +#' \strong{ObjectSearchSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectsearchsetting.htm}{Salesforce Documentation for ObjectSearchSetting} +#' \describe{ +#' \item{enhancedLookupEnabled}{a character either 'true' or 'false'} +#' \item{lookupAutoCompleteEnabled}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' \item{resultsPerPageCount}{a integer} +#' } +#' +#' \strong{ObjectUsage} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_objectusage.htm}{Salesforce Documentation for ObjectUsage} +#' \describe{ +#' \item{object}{a character} +#' } +#' +#' \strong{OpportunityListFieldsLabelMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_opportunitylistfieldslabelmapping.htm}{Salesforce Documentation for OpportunityListFieldsLabelMapping} +#' \describe{ +#' \item{field}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{OpportunityListFieldsSelectedSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_opportunitylistfieldsselectedsettings.htm}{Salesforce Documentation for OpportunityListFieldsSelectedSettings} +#' \describe{ +#' \item{field}{a character} +#' } +#' +#' \strong{OpportunityListFieldsUnselectedSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_opportunitylistfieldsunselectedsettings.htm}{Salesforce Documentation for OpportunityListFieldsUnselectedSettings} +#' \describe{ +#' \item{field}{a character} +#' } +#' +#' \strong{OpportunitySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_opportunitysettings.htm}{Salesforce Documentation for OpportunitySettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{autoActivateNewReminders}{a character either 'true' or 'false'} +#' \item{enableFindSimilarOpportunities}{a character either 'true' or 'false'} +#' \item{enableOpportunityTeam}{a character either 'true' or 'false'} +#' \item{enableUpdateReminders}{a character either 'true' or 'false'} +#' \item{findSimilarOppFilter}{a FindSimilarOppFilter} +#' \item{promptToAddProducts}{a character either 'true' or 'false'} +#' } +#' +#' \strong{Orchestration} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_orchestration.htm}{Salesforce Documentation for Orchestration} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{context}{a character} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{OrchestrationContext} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_orchestrationcontext.htm}{Salesforce Documentation for OrchestrationContext} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{events}{a OrchestrationContextEvent} +#' \item{masterLabel}{a character} +#' \item{runtimeType}{a character} +#' \item{salesforceObject}{a character} +#' \item{salesforceObjectPrimaryKey}{a character} +#' } +#' +#' \strong{OrchestrationContextEvent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_orchestrationcontextevent.htm}{Salesforce Documentation for OrchestrationContextEvent} +#' \describe{ +#' \item{eventType}{a character} +#' \item{orchestrationEvent}{a character} +#' \item{platformEvent}{a character} +#' \item{platformEventPrimaryKey}{a character} +#' } +#' +#' \strong{OrderSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_ordersettings.htm}{Salesforce Documentation for OrderSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableNegativeQuantity}{a character either 'true' or 'false'} +#' \item{enableOrders}{a character either 'true' or 'false'} +#' \item{enableReductionOrders}{a character either 'true' or 'false'} +#' \item{enableZeroQuantity}{a character either 'true' or 'false'} +#' } +#' +#' \strong{OrganizationSettingsDetail} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_organizationsettingsdetail.htm}{Salesforce Documentation for OrganizationSettingsDetail} +#' \describe{ +#' \item{settingName}{a character} +#' \item{settingValue}{a character either 'true' or 'false'} +#' } +#' +#' \strong{OrgPreferenceSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_orgpreferencesettings.htm}{Salesforce Documentation for OrgPreferenceSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{preferences}{a OrganizationSettingsDetail} +#' } +#' +#' \strong{Package} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_package.htm}{Salesforce Documentation for Package} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{apiAccessLevel}{a APIAccessLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{Unrestricted} +#' \item{Restricted} +#' } +#' } +#' \item{description}{a character} +#' \item{namespacePrefix}{a character} +#' \item{objectPermissions}{a ProfileObjectPermissions} +#' \item{packageType}{a character} +#' \item{postInstallClass}{a character} +#' \item{setupWeblink}{a character} +#' \item{types}{a PackageTypeMembers} +#' \item{uninstallClass}{a character} +#' \item{version}{a character} +#' } +#' +#' \strong{PackageTypeMembers} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_packagetypemembers.htm}{Salesforce Documentation for PackageTypeMembers} +#' \describe{ +#' \item{members}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{PackageVersion} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_packageversion.htm}{Salesforce Documentation for PackageVersion} +#' \describe{ +#' \item{majorNumber}{a integer} +#' \item{minorNumber}{a integer} +#' \item{namespace}{a character} +#' } +#' +#' \strong{PasswordPolicies} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_passwordpolicies.htm}{Salesforce Documentation for PasswordPolicies} +#' \describe{ +#' \item{apiOnlyUserHomePageURL}{a character} +#' \item{complexity}{a Complexity - which is a character taking one of the following values: +#' \itemize{ +#' \item{NoRestriction} +#' \item{AlphaNumeric} +#' \item{SpecialCharacters} +#' \item{UpperLowerCaseNumeric} +#' \item{UpperLowerCaseNumericSpecialCharacters} +#' } +#' } +#' \item{expiration}{a Expiration - which is a character taking one of the following values: +#' \itemize{ +#' \item{ThirtyDays} +#' \item{SixtyDays} +#' \item{NinetyDays} +#' \item{SixMonths} +#' \item{OneYear} +#' \item{Never} +#' } +#' } +#' \item{historyRestriction}{a character} +#' \item{lockoutInterval}{a LockoutInterval - which is a character taking one of the following values: +#' \itemize{ +#' \item{FifteenMinutes} +#' \item{ThirtyMinutes} +#' \item{SixtyMinutes} +#' \item{Forever} +#' } +#' } +#' \item{maxLoginAttempts}{a MaxLoginAttempts - which is a character taking one of the following values: +#' \itemize{ +#' \item{ThreeAttempts} +#' \item{FiveAttempts} +#' \item{TenAttempts} +#' \item{NoLimit} +#' } +#' } +#' \item{minimumPasswordLength}{a character} +#' \item{minimumPasswordLifetime}{a character either 'true' or 'false'} +#' \item{obscureSecretAnswer}{a character either 'true' or 'false'} +#' \item{passwordAssistanceMessage}{a character} +#' \item{passwordAssistanceURL}{a character} +#' \item{questionRestriction}{a QuestionRestriction - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{DoesNotContainPassword} +#' } +#' } +#' } +#' +#' \strong{PathAssistant} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_pathassistant.htm}{Salesforce Documentation for PathAssistant} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{entityName}{a character} +#' \item{fieldName}{a character} +#' \item{masterLabel}{a character} +#' \item{pathAssistantSteps}{a PathAssistantStep} +#' \item{recordTypeName}{a character} +#' } +#' +#' \strong{PathAssistantSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_pathassistantsettings.htm}{Salesforce Documentation for PathAssistantSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{pathAssistantEnabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PathAssistantStep} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_pathassistantstep.htm}{Salesforce Documentation for PathAssistantStep} +#' \describe{ +#' \item{fieldNames}{a character} +#' \item{info}{a character} +#' \item{picklistValueName}{a character} +#' } +#' +#' \strong{PermissionSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionset.htm}{Salesforce Documentation for PermissionSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{applicationVisibilities}{a PermissionSetApplicationVisibility} +#' \item{classAccesses}{a PermissionSetApexClassAccess} +#' \item{customPermissions}{a PermissionSetCustomPermissions} +#' \item{description}{a character} +#' \item{externalDataSourceAccesses}{a PermissionSetExternalDataSourceAccess} +#' \item{fieldPermissions}{a PermissionSetFieldPermissions} +#' \item{hasActivationRequired}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{license}{a character} +#' \item{objectPermissions}{a PermissionSetObjectPermissions} +#' \item{pageAccesses}{a PermissionSetApexPageAccess} +#' \item{recordTypeVisibilities}{a PermissionSetRecordTypeVisibility} +#' \item{tabSettings}{a PermissionSetTabSetting} +#' \item{userPermissions}{a PermissionSetUserPermission} +#' } +#' +#' \strong{PermissionSetApexClassAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetapexclassaccess.htm}{Salesforce Documentation for PermissionSetApexClassAccess} +#' \describe{ +#' \item{apexClass}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetApexPageAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetapexpageaccess.htm}{Salesforce Documentation for PermissionSetApexPageAccess} +#' \describe{ +#' \item{apexPage}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetApplicationVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetapplicationvisibility.htm}{Salesforce Documentation for PermissionSetApplicationVisibility} +#' \describe{ +#' \item{application}{a character} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetCustomPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetcustompermissions.htm}{Salesforce Documentation for PermissionSetCustomPermissions} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{PermissionSetExternalDataSourceAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetexternaldatasourceaccess.htm}{Salesforce Documentation for PermissionSetExternalDataSourceAccess} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{externalDataSource}{a character} +#' } +#' +#' \strong{PermissionSetFieldPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetfieldpermissions.htm}{Salesforce Documentation for PermissionSetFieldPermissions} +#' \describe{ +#' \item{editable}{a character either 'true' or 'false'} +#' \item{field}{a character} +#' \item{readable}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetGroup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetgroup.htm}{Salesforce Documentation for PermissionSetGroup} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{isCalculatingChanges}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{permissionSets}{a character} +#' } +#' +#' \strong{PermissionSetObjectPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetobjectpermissions.htm}{Salesforce Documentation for PermissionSetObjectPermissions} +#' \describe{ +#' \item{allowCreate}{a character either 'true' or 'false'} +#' \item{allowDelete}{a character either 'true' or 'false'} +#' \item{allowEdit}{a character either 'true' or 'false'} +#' \item{allowRead}{a character either 'true' or 'false'} +#' \item{modifyAllRecords}{a character either 'true' or 'false'} +#' \item{object}{a character} +#' \item{viewAllRecords}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetRecordTypeVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetrecordtypevisibility.htm}{Salesforce Documentation for PermissionSetRecordTypeVisibility} +#' \describe{ +#' \item{recordType}{a character} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PermissionSetTabSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsettabsetting.htm}{Salesforce Documentation for PermissionSetTabSetting} +#' \describe{ +#' \item{tab}{a character} +#' \item{visibility}{a PermissionSetTabVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Available} +#' \item{Visible} +#' } +#' } +#' } +#' +#' \strong{PermissionSetUserPermission} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_permissionsetuserpermission.htm}{Salesforce Documentation for PermissionSetUserPermission} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{PersonalJourneySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_personaljourneysettings.htm}{Salesforce Documentation for PersonalJourneySettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableExactTargetForSalesforceApps}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PersonListSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_personlistsettings.htm}{Salesforce Documentation for PersonListSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enablePersonList}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PicklistEntry} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_picklistentry.htm}{Salesforce Documentation for PicklistEntry} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{defaultValue}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{validFor}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{PicklistValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_picklistvalue.htm}{Salesforce Documentation for PicklistValue} +#' \describe{ +#' \item{color}{a character (inherited from GlobalPicklistValue)} +#' \item{default}{a character either 'true' or 'false' (inherited from GlobalPicklistValue)} +#' \item{description}{a character (inherited from GlobalPicklistValue)} +#' \item{isActive}{a character either 'true' or 'false' (inherited from GlobalPicklistValue)} +#' \item{allowEmail}{a character either 'true' or 'false'} +#' \item{closed}{a character either 'true' or 'false'} +#' \item{controllingFieldValues}{a character} +#' \item{converted}{a character either 'true' or 'false'} +#' \item{cssExposed}{a character either 'true' or 'false'} +#' \item{forecastCategory}{a ForecastCategories - which is a character taking one of the following values: +#' \itemize{ +#' \item{Omitted} +#' \item{Pipeline} +#' \item{BestCase} +#' \item{Forecast} +#' \item{Closed} +#' } +#' } +#' \item{highPriority}{a character either 'true' or 'false'} +#' \item{probability}{a integer} +#' \item{reverseRole}{a character} +#' \item{reviewed}{a character either 'true' or 'false'} +#' \item{won}{a character either 'true' or 'false'} +#' } +#' +#' \strong{PicklistValueTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_picklistvaluetranslation.htm}{Salesforce Documentation for PicklistValueTranslation} +#' \describe{ +#' \item{masterLabel}{a character} +#' \item{translation}{a character} +#' } +#' +#' \strong{PlatformActionList} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_platformactionlist.htm}{Salesforce Documentation for PlatformActionList} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actionListContext}{a PlatformActionListContext - which is a character taking one of the following values: +#' \itemize{ +#' \item{ListView} +#' \item{RelatedList} +#' \item{ListViewRecord} +#' \item{RelatedListRecord} +#' \item{Record} +#' \item{FeedElement} +#' \item{Chatter} +#' \item{Global} +#' \item{Flexipage} +#' \item{MruList} +#' \item{MruRow} +#' \item{RecordEdit} +#' \item{Photo} +#' \item{BannerPhoto} +#' \item{ObjectHomeChart} +#' \item{ListViewDefinition} +#' \item{Dockable} +#' \item{Lookup} +#' \item{Assistant} +#' } +#' } +#' \item{platformActionListItems}{a PlatformActionListItem} +#' \item{relatedSourceEntity}{a character} +#' } +#' +#' \strong{PlatformActionListItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_platformactionlistitem.htm}{Salesforce Documentation for PlatformActionListItem} +#' \describe{ +#' \item{actionName}{a character} +#' \item{actionType}{a PlatformActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{QuickAction} +#' \item{StandardButton} +#' \item{CustomButton} +#' \item{ProductivityAction} +#' \item{ActionLink} +#' \item{InvocableAction} +#' } +#' } +#' \item{sortOrder}{a integer} +#' \item{subtype}{a character} +#' } +#' +#' \strong{PlatformCachePartition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_platformcachepartition.htm}{Salesforce Documentation for PlatformCachePartition} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{isDefaultPartition}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{platformCachePartitionTypes}{a PlatformCachePartitionType} +#' } +#' +#' \strong{PlatformCachePartitionType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_platformcachepartitiontype.htm}{Salesforce Documentation for PlatformCachePartitionType} +#' \describe{ +#' \item{allocatedCapacity}{a integer} +#' \item{allocatedPurchasedCapacity}{a integer} +#' \item{allocatedTrialCapacity}{a integer} +#' \item{cacheType}{a PlatformCacheType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Session} +#' \item{Organization} +#' } +#' } +#' } +#' +#' \strong{Portal} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_portal.htm}{Salesforce Documentation for Portal} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{admin}{a character} +#' \item{defaultLanguage}{a character} +#' \item{description}{a character} +#' \item{emailSenderAddress}{a character} +#' \item{emailSenderName}{a character} +#' \item{enableSelfCloseCase}{a character either 'true' or 'false'} +#' \item{footerDocument}{a character} +#' \item{forgotPassTemplate}{a character} +#' \item{headerDocument}{a character} +#' \item{isSelfRegistrationActivated}{a character either 'true' or 'false'} +#' \item{loginHeaderDocument}{a character} +#' \item{logoDocument}{a character} +#' \item{logoutUrl}{a character} +#' \item{newCommentTemplate}{a character} +#' \item{newPassTemplate}{a character} +#' \item{newUserTemplate}{a character} +#' \item{ownerNotifyTemplate}{a character} +#' \item{selfRegNewUserUrl}{a character} +#' \item{selfRegUserDefaultProfile}{a character} +#' \item{selfRegUserDefaultRole}{a PortalRoles - which is a character taking one of the following values: +#' \itemize{ +#' \item{Executive} +#' \item{Manager} +#' \item{Worker} +#' \item{PersonAccount} +#' } +#' } +#' \item{selfRegUserTemplate}{a character} +#' \item{showActionConfirmation}{a character either 'true' or 'false'} +#' \item{stylesheetDocument}{a character} +#' \item{type}{a PortalType - which is a character taking one of the following values: +#' \itemize{ +#' \item{CustomerSuccess} +#' \item{Partner} +#' \item{Network} +#' } +#' } +#' } +#' +#' \strong{PostTemplate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_posttemplate.htm}{Salesforce Documentation for PostTemplate} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{default}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{fields}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{PrimaryTabComponents} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_primarytabcomponents.htm}{Salesforce Documentation for PrimaryTabComponents} +#' \describe{ +#' \item{containers}{a Container} +#' } +#' +#' \strong{ProductSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_productsettings.htm}{Salesforce Documentation for ProductSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableCascadeActivateToRelatedPrices}{a character either 'true' or 'false'} +#' \item{enableQuantitySchedule}{a character either 'true' or 'false'} +#' \item{enableRevenueSchedule}{a character either 'true' or 'false'} +#' } +#' +#' \strong{Profile} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profile.htm}{Salesforce Documentation for Profile} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{applicationVisibilities}{a ProfileApplicationVisibility} +#' \item{categoryGroupVisibilities}{a ProfileCategoryGroupVisibility} +#' \item{classAccesses}{a ProfileApexClassAccess} +#' \item{custom}{a character either 'true' or 'false'} +#' \item{customPermissions}{a ProfileCustomPermissions} +#' \item{description}{a character} +#' \item{externalDataSourceAccesses}{a ProfileExternalDataSourceAccess} +#' \item{fieldPermissions}{a ProfileFieldLevelSecurity} +#' \item{layoutAssignments}{a ProfileLayoutAssignment} +#' \item{loginHours}{a ProfileLoginHours} +#' \item{loginIpRanges}{a ProfileLoginIpRange} +#' \item{objectPermissions}{a ProfileObjectPermissions} +#' \item{pageAccesses}{a ProfileApexPageAccess} +#' \item{profileActionOverrides}{a ProfileActionOverride} +#' \item{recordTypeVisibilities}{a ProfileRecordTypeVisibility} +#' \item{tabVisibilities}{a ProfileTabVisibility} +#' \item{userLicense}{a character} +#' \item{userPermissions}{a ProfileUserPermission} +#' } +#' +#' \strong{ProfileActionOverride} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileactionoverride.htm}{Salesforce Documentation for ProfileActionOverride} +#' \describe{ +#' \item{actionName}{a character} +#' \item{content}{a character} +#' \item{formFactor}{a FormFactor - which is a character taking one of the following values: +#' \itemize{ +#' \item{Small} +#' \item{Medium} +#' \item{Large} +#' } +#' } +#' \item{pageOrSobjectType}{a character} +#' \item{recordType}{a character} +#' \item{type}{a ActionOverrideType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{Standard} +#' \item{Scontrol} +#' \item{Visualforce} +#' \item{Flexipage} +#' \item{LightningComponent} +#' } +#' } +#' } +#' +#' \strong{ProfileApexClassAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileapexclassaccess.htm}{Salesforce Documentation for ProfileApexClassAccess} +#' \describe{ +#' \item{apexClass}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileApexPageAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileapexpageaccess.htm}{Salesforce Documentation for ProfileApexPageAccess} +#' \describe{ +#' \item{apexPage}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileApplicationVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileapplicationvisibility.htm}{Salesforce Documentation for ProfileApplicationVisibility} +#' \describe{ +#' \item{application}{a character} +#' \item{default}{a character either 'true' or 'false'} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileCategoryGroupVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilecategorygroupvisibility.htm}{Salesforce Documentation for ProfileCategoryGroupVisibility} +#' \describe{ +#' \item{dataCategories}{a character} +#' \item{dataCategoryGroup}{a character} +#' \item{visibility}{a CategoryGroupVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{ALL} +#' \item{NONE} +#' \item{CUSTOM} +#' } +#' } +#' } +#' +#' \strong{ProfileCustomPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilecustompermissions.htm}{Salesforce Documentation for ProfileCustomPermissions} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{ProfileExternalDataSourceAccess} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileexternaldatasourceaccess.htm}{Salesforce Documentation for ProfileExternalDataSourceAccess} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{externalDataSource}{a character} +#' } +#' +#' \strong{ProfileFieldLevelSecurity} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilefieldlevelsecurity.htm}{Salesforce Documentation for ProfileFieldLevelSecurity} +#' \describe{ +#' \item{editable}{a character either 'true' or 'false'} +#' \item{field}{a character} +#' \item{readable}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileLayoutAssignment} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilelayoutassignment.htm}{Salesforce Documentation for ProfileLayoutAssignment} +#' \describe{ +#' \item{layout}{a character} +#' \item{recordType}{a character} +#' } +#' +#' \strong{ProfileLoginHours} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileloginhours.htm}{Salesforce Documentation for ProfileLoginHours} +#' \describe{ +#' \item{fridayEnd}{a character} +#' \item{fridayStart}{a character} +#' \item{mondayEnd}{a character} +#' \item{mondayStart}{a character} +#' \item{saturdayEnd}{a character} +#' \item{saturdayStart}{a character} +#' \item{sundayEnd}{a character} +#' \item{sundayStart}{a character} +#' \item{thursdayEnd}{a character} +#' \item{thursdayStart}{a character} +#' \item{tuesdayEnd}{a character} +#' \item{tuesdayStart}{a character} +#' \item{wednesdayEnd}{a character} +#' \item{wednesdayStart}{a character} +#' } +#' +#' \strong{ProfileLoginIpRange} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileloginiprange.htm}{Salesforce Documentation for ProfileLoginIpRange} +#' \describe{ +#' \item{description}{a character} +#' \item{endAddress}{a character} +#' \item{startAddress}{a character} +#' } +#' +#' \strong{ProfileObjectPermissions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileobjectpermissions.htm}{Salesforce Documentation for ProfileObjectPermissions} +#' \describe{ +#' \item{allowCreate}{a character either 'true' or 'false'} +#' \item{allowDelete}{a character either 'true' or 'false'} +#' \item{allowEdit}{a character either 'true' or 'false'} +#' \item{allowRead}{a character either 'true' or 'false'} +#' \item{modifyAllRecords}{a character either 'true' or 'false'} +#' \item{object}{a character} +#' \item{viewAllRecords}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfilePasswordPolicy} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilepasswordpolicy.htm}{Salesforce Documentation for ProfilePasswordPolicy} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{lockoutInterval}{a integer} +#' \item{maxLoginAttempts}{a integer} +#' \item{minimumPasswordLength}{a integer} +#' \item{minimumPasswordLifetime}{a character either 'true' or 'false'} +#' \item{obscure}{a character either 'true' or 'false'} +#' \item{passwordComplexity}{a integer} +#' \item{passwordExpiration}{a integer} +#' \item{passwordHistory}{a integer} +#' \item{passwordQuestion}{a integer} +#' \item{profile}{a character} +#' } +#' +#' \strong{ProfileRecordTypeVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilerecordtypevisibility.htm}{Salesforce Documentation for ProfileRecordTypeVisibility} +#' \describe{ +#' \item{default}{a character either 'true' or 'false'} +#' \item{personAccountDefault}{a character either 'true' or 'false'} +#' \item{recordType}{a character} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileSessionSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profilesessionsetting.htm}{Salesforce Documentation for ProfileSessionSetting} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{externalCommunityUserIdentityVerif}{a character either 'true' or 'false'} +#' \item{forceLogout}{a character either 'true' or 'false'} +#' \item{profile}{a character} +#' \item{requiredSessionLevel}{a SessionSecurityLevel - which is a character taking one of the following values: +#' \itemize{ +#' \item{LOW} +#' \item{STANDARD} +#' \item{HIGH_ASSURANCE} +#' } +#' } +#' \item{sessionPersistence}{a character either 'true' or 'false'} +#' \item{sessionTimeout}{a integer} +#' \item{sessionTimeoutWarning}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ProfileTabVisibility} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profiletabvisibility.htm}{Salesforce Documentation for ProfileTabVisibility} +#' \describe{ +#' \item{tab}{a character} +#' \item{visibility}{a TabVisibility - which is a character taking one of the following values: +#' \itemize{ +#' \item{Hidden} +#' \item{DefaultOff} +#' \item{DefaultOn} +#' } +#' } +#' } +#' +#' \strong{ProfileUserPermission} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profileuserpermission.htm}{Salesforce Documentation for ProfileUserPermission} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{PublicGroups} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_publicgroups.htm}{Salesforce Documentation for PublicGroups} +#' \describe{ +#' \item{publicGroup}{a character} +#' } +#' +#' \strong{PushNotification} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_pushnotification.htm}{Salesforce Documentation for PushNotification} +#' \describe{ +#' \item{fieldNames}{a character} +#' \item{objectName}{a character} +#' } +#' +#' \strong{Queue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_queue.htm}{Salesforce Documentation for Queue} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{doesSendEmailToMembers}{a character either 'true' or 'false'} +#' \item{email}{a character} +#' \item{name}{a character} +#' \item{queueMembers}{a QueueMembers} +#' \item{queueRoutingConfig}{a character} +#' \item{queueSobject}{a QueueSobject} +#' } +#' +#' \strong{QueueMembers} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_queuemembers.htm}{Salesforce Documentation for QueueMembers} +#' \describe{ +#' \item{publicGroups}{a PublicGroups} +#' \item{roleAndSubordinates}{a RoleAndSubordinates} +#' \item{roleAndSubordinatesInternal}{a RoleAndSubordinatesInternal} +#' \item{roles}{a Roles} +#' \item{users}{a Users} +#' } +#' +#' \strong{QueueSobject} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_queuesobject.htm}{Salesforce Documentation for QueueSobject} +#' \describe{ +#' \item{sobjectType}{a character} +#' } +#' +#' \strong{QuickAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickaction.htm}{Salesforce Documentation for QuickAction} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{canvas}{a character} +#' \item{description}{a character} +#' \item{fieldOverrides}{a FieldOverride} +#' \item{flowDefinition}{a character} +#' \item{height}{a integer} +#' \item{icon}{a character} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{lightningComponent}{a character} +#' \item{optionsCreateFeedItem}{a character either 'true' or 'false'} +#' \item{page}{a character} +#' \item{quickActionLayout}{a QuickActionLayout} +#' \item{quickActionSendEmailOptions}{a QuickActionSendEmailOptions} +#' \item{standardLabel}{a QuickActionLabel - which is a character taking one of the following values: +#' \itemize{ +#' \item{LogACall} +#' \item{LogANote} +#' \item{New} +#' \item{NewRecordType} +#' \item{Update} +#' \item{NewChild} +#' \item{NewChildRecordType} +#' \item{CreateNew} +#' \item{CreateNewRecordType} +#' \item{SendEmail} +#' \item{QuickRecordType} +#' \item{Quick} +#' \item{EditDescription} +#' \item{Defer} +#' \item{ChangeDueDate} +#' \item{ChangePriority} +#' \item{ChangeStatus} +#' \item{SocialPost} +#' \item{Escalate} +#' \item{EscalateToRecord} +#' \item{OfferFeedback} +#' \item{RequestFeedback} +#' \item{AddRecord} +#' \item{AddMember} +#' \item{Reply} +#' \item{ReplyAll} +#' \item{Forward} +#' } +#' } +#' \item{successMessage}{a character} +#' \item{targetObject}{a character} +#' \item{targetParentField}{a character} +#' \item{targetRecordType}{a character} +#' \item{type}{a QuickActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Create} +#' \item{VisualforcePage} +#' \item{Post} +#' \item{SendEmail} +#' \item{LogACall} +#' \item{SocialPost} +#' \item{Canvas} +#' \item{Update} +#' \item{LightningComponent} +#' \item{Flow} +#' } +#' } +#' \item{width}{a integer} +#' } +#' +#' \strong{QuickActionLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionlayout.htm}{Salesforce Documentation for QuickActionLayout} +#' \describe{ +#' \item{layoutSectionStyle}{a LayoutSectionStyle - which is a character taking one of the following values: +#' \itemize{ +#' \item{TwoColumnsTopToBottom} +#' \item{TwoColumnsLeftToRight} +#' \item{OneColumn} +#' \item{CustomLinks} +#' } +#' } +#' \item{quickActionLayoutColumns}{a QuickActionLayoutColumn} +#' } +#' +#' \strong{QuickActionLayoutColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionlayoutcolumn.htm}{Salesforce Documentation for QuickActionLayoutColumn} +#' \describe{ +#' \item{quickActionLayoutItems}{a QuickActionLayoutItem} +#' } +#' +#' \strong{QuickActionLayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionlayoutitem.htm}{Salesforce Documentation for QuickActionLayoutItem} +#' \describe{ +#' \item{emptySpace}{a character either 'true' or 'false'} +#' \item{field}{a character} +#' \item{uiBehavior}{a UiBehavior - which is a character taking one of the following values: +#' \itemize{ +#' \item{Edit} +#' \item{Required} +#' \item{Readonly} +#' } +#' } +#' } +#' +#' \strong{QuickActionList} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionlist.htm}{Salesforce Documentation for QuickActionList} +#' \describe{ +#' \item{quickActionListItems}{a QuickActionListItem} +#' } +#' +#' \strong{QuickActionListItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionlistitem.htm}{Salesforce Documentation for QuickActionListItem} +#' \describe{ +#' \item{quickActionName}{a character} +#' } +#' +#' \strong{QuickActionSendEmailOptions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactionsendemailoptions.htm}{Salesforce Documentation for QuickActionSendEmailOptions} +#' \describe{ +#' \item{defaultEmailTemplateName}{a character} +#' \item{ignoreDefaultEmailTemplateSubject}{a character either 'true' or 'false'} +#' } +#' +#' \strong{QuickActionTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickactiontranslation.htm}{Salesforce Documentation for QuickActionTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{QuotasSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quotassettings.htm}{Salesforce Documentation for QuotasSettings} +#' \describe{ +#' \item{showQuotas}{a character either 'true' or 'false'} +#' } +#' +#' \strong{QuoteSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quotesettings.htm}{Salesforce Documentation for QuoteSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableQuote}{a character either 'true' or 'false'} +#' } +#' +#' \strong{RecommendationAudience} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recommendationaudience.htm}{Salesforce Documentation for RecommendationAudience} +#' \describe{ +#' \item{recommendationAudienceDetails}{a RecommendationAudienceDetail} +#' } +#' +#' \strong{RecommendationAudienceDetail} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recommendationaudiencedetail.htm}{Salesforce Documentation for RecommendationAudienceDetail} +#' \describe{ +#' \item{audienceCriteriaType}{a AudienceCriteriaType - which is a character taking one of the following values: +#' \itemize{ +#' \item{CustomList} +#' \item{MaxDaysInCommunity} +#' } +#' } +#' \item{audienceCriteriaValue}{a character} +#' \item{setupName}{a character} +#' } +#' +#' \strong{RecommendationDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recommendationdefinition.htm}{Salesforce Documentation for RecommendationDefinition} +#' \describe{ +#' \item{recommendationDefinitionDetails}{a RecommendationDefinitionDetail} +#' } +#' +#' \strong{RecommendationDefinitionDetail} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recommendationdefinitiondetail.htm}{Salesforce Documentation for RecommendationDefinitionDetail} +#' \describe{ +#' \item{actionUrl}{a character} +#' \item{description}{a character} +#' \item{linkText}{a character} +#' \item{scheduledRecommendations}{a ScheduledRecommendation} +#' \item{setupName}{a character} +#' \item{title}{a character} +#' } +#' +#' \strong{RecommendationStrategy} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recommendationstrategy.htm}{Salesforce Documentation for RecommendationStrategy} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{recommendationStrategyName}{a character} +#' \item{strategyNode}{a StrategyNode} +#' } +#' +#' \strong{RecordType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recordtype.htm}{Salesforce Documentation for RecordType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{businessProcess}{a character} +#' \item{compactLayoutAssignment}{a character} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{picklistValues}{a RecordTypePicklistValue} +#' } +#' +#' \strong{RecordTypePicklistValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recordtypepicklistvalue.htm}{Salesforce Documentation for RecordTypePicklistValue} +#' \describe{ +#' \item{picklist}{a character} +#' \item{values}{a PicklistValue} +#' } +#' +#' \strong{RecordTypeTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_recordtypetranslation.htm}{Salesforce Documentation for RecordTypeTranslation} +#' \describe{ +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{RelatedContent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_relatedcontent.htm}{Salesforce Documentation for RelatedContent} +#' \describe{ +#' \item{relatedContentItems}{a RelatedContentItem} +#' } +#' +#' \strong{RelatedContentItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_relatedcontentitem.htm}{Salesforce Documentation for RelatedContentItem} +#' \describe{ +#' \item{layoutItem}{a LayoutItem} +#' } +#' +#' \strong{RelatedList} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_relatedlist.htm}{Salesforce Documentation for RelatedList} +#' \describe{ +#' \item{hideOnDetail}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' } +#' +#' \strong{RelatedListItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_relatedlistitem.htm}{Salesforce Documentation for RelatedListItem} +#' \describe{ +#' \item{customButtons}{a character} +#' \item{excludeButtons}{a character} +#' \item{fields}{a character} +#' \item{relatedList}{a character} +#' \item{sortField}{a character} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' } +#' +#' \strong{RemoteSiteSetting} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_remotesitesetting.htm}{Salesforce Documentation for RemoteSiteSetting} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{disableProtocolSecurity}{a character either 'true' or 'false'} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{url}{a character} +#' } +#' +#' \strong{Report} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_report.htm}{Salesforce Documentation for Report} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{aggregates}{a ReportAggregate} +#' \item{block}{a Report} +#' \item{blockInfo}{a ReportBlockInfo} +#' \item{buckets}{a ReportBucketField} +#' \item{chart}{a ReportChart} +#' \item{colorRanges}{a ReportColorRange} +#' \item{columns}{a ReportColumn} +#' \item{crossFilters}{a ReportCrossFilter} +#' \item{currency}{a CurrencyIsoCode - which is a character taking one of the following values: +#' \itemize{ +#' \item{ADP} +#' \item{AED} +#' \item{AFA} +#' \item{AFN} +#' \item{ALL} +#' \item{AMD} +#' \item{ANG} +#' \item{AOA} +#' \item{ARS} +#' \item{ATS} +#' \item{AUD} +#' \item{AWG} +#' \item{AZM} +#' \item{AZN} +#' \item{BAM} +#' \item{BBD} +#' \item{BDT} +#' \item{BEF} +#' \item{BGL} +#' \item{BGN} +#' \item{BHD} +#' \item{BIF} +#' \item{BMD} +#' \item{BND} +#' \item{BOB} +#' \item{BOV} +#' \item{BRB} +#' \item{BRL} +#' \item{BSD} +#' \item{BTN} +#' \item{BWP} +#' \item{BYB} +#' \item{BYN} +#' \item{BYR} +#' \item{BZD} +#' \item{CAD} +#' \item{CDF} +#' \item{CHF} +#' \item{CLF} +#' \item{CLP} +#' \item{CNY} +#' \item{COP} +#' \item{CRC} +#' \item{CSD} +#' \item{CUC} +#' \item{CUP} +#' \item{CVE} +#' \item{CYP} +#' \item{CZK} +#' \item{DEM} +#' \item{DJF} +#' \item{DKK} +#' \item{DOP} +#' \item{DZD} +#' \item{ECS} +#' \item{EEK} +#' \item{EGP} +#' \item{ERN} +#' \item{ESP} +#' \item{ETB} +#' \item{EUR} +#' \item{FIM} +#' \item{FJD} +#' \item{FKP} +#' \item{FRF} +#' \item{GBP} +#' \item{GEL} +#' \item{GHC} +#' \item{GHS} +#' \item{GIP} +#' \item{GMD} +#' \item{GNF} +#' \item{GRD} +#' \item{GTQ} +#' \item{GWP} +#' \item{GYD} +#' \item{HKD} +#' \item{HNL} +#' \item{HRD} +#' \item{HRK} +#' \item{HTG} +#' \item{HUF} +#' \item{IDR} +#' \item{IEP} +#' \item{ILS} +#' \item{INR} +#' \item{IQD} +#' \item{IRR} +#' \item{ISK} +#' \item{ITL} +#' \item{JMD} +#' \item{JOD} +#' \item{JPY} +#' \item{KES} +#' \item{KGS} +#' \item{KHR} +#' \item{KMF} +#' \item{KPW} +#' \item{KRW} +#' \item{KWD} +#' \item{KYD} +#' \item{KZT} +#' \item{LAK} +#' \item{LBP} +#' \item{LKR} +#' \item{LRD} +#' \item{LSL} +#' \item{LTL} +#' \item{LUF} +#' \item{LVL} +#' \item{LYD} +#' \item{MAD} +#' \item{MDL} +#' \item{MGA} +#' \item{MGF} +#' \item{MKD} +#' \item{MMK} +#' \item{MNT} +#' \item{MOP} +#' \item{MRO} +#' \item{MTL} +#' \item{MUR} +#' \item{MVR} +#' \item{MWK} +#' \item{MXN} +#' \item{MXV} +#' \item{MYR} +#' \item{MZM} +#' \item{MZN} +#' \item{NAD} +#' \item{NGN} +#' \item{NIO} +#' \item{NLG} +#' \item{NOK} +#' \item{NPR} +#' \item{NZD} +#' \item{OMR} +#' \item{PAB} +#' \item{PEN} +#' \item{PGK} +#' \item{PHP} +#' \item{PKR} +#' \item{PLN} +#' \item{PTE} +#' \item{PYG} +#' \item{QAR} +#' \item{RMB} +#' \item{ROL} +#' \item{RON} +#' \item{RSD} +#' \item{RUB} +#' \item{RUR} +#' \item{RWF} +#' \item{SAR} +#' \item{SBD} +#' \item{SCR} +#' \item{SDD} +#' \item{SDG} +#' \item{SEK} +#' \item{SGD} +#' \item{SHP} +#' \item{SIT} +#' \item{SKK} +#' \item{SLL} +#' \item{SOS} +#' \item{SRD} +#' \item{SRG} +#' \item{SSP} +#' \item{STD} +#' \item{SUR} +#' \item{SVC} +#' \item{SYP} +#' \item{SZL} +#' \item{THB} +#' \item{TJR} +#' \item{TJS} +#' \item{TMM} +#' \item{TMT} +#' \item{TND} +#' \item{TOP} +#' \item{TPE} +#' \item{TRL} +#' \item{TRY} +#' \item{TTD} +#' \item{TWD} +#' \item{TZS} +#' \item{UAH} +#' \item{UGX} +#' \item{USD} +#' \item{UYU} +#' \item{UZS} +#' \item{VEB} +#' \item{VEF} +#' \item{VND} +#' \item{VUV} +#' \item{WST} +#' \item{XAF} +#' \item{XCD} +#' \item{XOF} +#' \item{XPF} +#' \item{YER} +#' \item{YUM} +#' \item{ZAR} +#' \item{ZMK} +#' \item{ZMW} +#' \item{ZWD} +#' \item{ZWL} +#' } +#' } +#' \item{dataCategoryFilters}{a ReportDataCategoryFilter} +#' \item{description}{a character} +#' \item{division}{a character} +#' \item{filter}{a ReportFilter} +#' \item{folderName}{a character} +#' \item{format}{a ReportFormat - which is a character taking one of the following values: +#' \itemize{ +#' \item{MultiBlock} +#' \item{Matrix} +#' \item{Summary} +#' \item{Tabular} +#' } +#' } +#' \item{groupingsAcross}{a ReportGrouping} +#' \item{groupingsDown}{a ReportGrouping} +#' \item{historicalSelector}{a ReportHistoricalSelector} +#' \item{name}{a character} +#' \item{numSubscriptions}{a integer} +#' \item{params}{a ReportParam} +#' \item{reportType}{a character} +#' \item{roleHierarchyFilter}{a character} +#' \item{rowLimit}{a integer} +#' \item{scope}{a character} +#' \item{showCurrentDate}{a character either 'true' or 'false'} +#' \item{showDetails}{a character either 'true' or 'false'} +#' \item{sortColumn}{a character} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' \item{territoryHierarchyFilter}{a character} +#' \item{timeFrameFilter}{a ReportTimeFrameFilter} +#' \item{userFilter}{a character} +#' } +#' +#' \strong{ReportAggregate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportaggregate.htm}{Salesforce Documentation for ReportAggregate} +#' \describe{ +#' \item{acrossGroupingContext}{a character} +#' \item{calculatedFormula}{a character} +#' \item{datatype}{a ReportAggregateDatatype - which is a character taking one of the following values: +#' \itemize{ +#' \item{currency} +#' \item{percent} +#' \item{number} +#' } +#' } +#' \item{description}{a character} +#' \item{developerName}{a character} +#' \item{downGroupingContext}{a character} +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{isCrossBlock}{a character either 'true' or 'false'} +#' \item{masterLabel}{a character} +#' \item{reportType}{a character} +#' \item{scale}{a integer} +#' } +#' +#' \strong{ReportAggregateReference} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportaggregatereference.htm}{Salesforce Documentation for ReportAggregateReference} +#' \describe{ +#' \item{aggregate}{a character} +#' } +#' +#' \strong{ReportBlockInfo} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportblockinfo.htm}{Salesforce Documentation for ReportBlockInfo} +#' \describe{ +#' \item{aggregateReferences}{a ReportAggregateReference} +#' \item{blockId}{a character} +#' \item{joinTable}{a character} +#' } +#' +#' \strong{ReportBucketField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportbucketfield.htm}{Salesforce Documentation for ReportBucketField} +#' \describe{ +#' \item{bucketType}{a ReportBucketFieldType - which is a character taking one of the following values: +#' \itemize{ +#' \item{text} +#' \item{number} +#' \item{picklist} +#' } +#' } +#' \item{developerName}{a character} +#' \item{masterLabel}{a character} +#' \item{nullTreatment}{a ReportFormulaNullTreatment - which is a character taking one of the following values: +#' \itemize{ +#' \item{n} +#' \item{z} +#' } +#' } +#' \item{otherBucketLabel}{a character} +#' \item{sourceColumnName}{a character} +#' \item{useOther}{a character either 'true' or 'false'} +#' \item{values}{a ReportBucketFieldValue} +#' } +#' +#' \strong{ReportBucketFieldSourceValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportbucketfieldsourcevalue.htm}{Salesforce Documentation for ReportBucketFieldSourceValue} +#' \describe{ +#' \item{from}{a character} +#' \item{sourceValue}{a character} +#' \item{to}{a character} +#' } +#' +#' \strong{ReportBucketFieldValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportbucketfieldvalue.htm}{Salesforce Documentation for ReportBucketFieldValue} +#' \describe{ +#' \item{sourceValues}{a ReportBucketFieldSourceValue} +#' \item{value}{a character} +#' } +#' +#' \strong{ReportChart} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportchart.htm}{Salesforce Documentation for ReportChart} +#' \describe{ +#' \item{backgroundColor1}{a character} +#' \item{backgroundColor2}{a character} +#' \item{backgroundFadeDir}{a ChartBackgroundDirection - which is a character taking one of the following values: +#' \itemize{ +#' \item{TopToBottom} +#' \item{LeftToRight} +#' \item{Diagonal} +#' } +#' } +#' \item{chartSummaries}{a ChartSummary} +#' \item{chartType}{a ChartType - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Scatter} +#' \item{ScatterGrouped} +#' \item{Bubble} +#' \item{BubbleGrouped} +#' \item{HorizontalBar} +#' \item{HorizontalBarGrouped} +#' \item{HorizontalBarStacked} +#' \item{HorizontalBarStackedTo100} +#' \item{VerticalColumn} +#' \item{VerticalColumnGrouped} +#' \item{VerticalColumnStacked} +#' \item{VerticalColumnStackedTo100} +#' \item{Line} +#' \item{LineGrouped} +#' \item{LineCumulative} +#' \item{LineCumulativeGrouped} +#' \item{Pie} +#' \item{Donut} +#' \item{Funnel} +#' \item{VerticalColumnLine} +#' \item{VerticalColumnGroupedLine} +#' \item{VerticalColumnStackedLine} +#' \item{Plugin} +#' } +#' } +#' \item{enableHoverLabels}{a character either 'true' or 'false'} +#' \item{expandOthers}{a character either 'true' or 'false'} +#' \item{groupingColumn}{a character} +#' \item{legendPosition}{a ChartLegendPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{Right} +#' \item{Bottom} +#' \item{OnChart} +#' } +#' } +#' \item{location}{a ChartPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{CHART_TOP} +#' \item{CHART_BOTTOM} +#' } +#' } +#' \item{secondaryGroupingColumn}{a character} +#' \item{showAxisLabels}{a character either 'true' or 'false'} +#' \item{showPercentage}{a character either 'true' or 'false'} +#' \item{showTotal}{a character either 'true' or 'false'} +#' \item{showValues}{a character either 'true' or 'false'} +#' \item{size}{a ReportChartSize - which is a character taking one of the following values: +#' \itemize{ +#' \item{Tiny} +#' \item{Small} +#' \item{Medium} +#' \item{Large} +#' \item{Huge} +#' } +#' } +#' \item{summaryAxisManualRangeEnd}{a numeric} +#' \item{summaryAxisManualRangeStart}{a numeric} +#' \item{summaryAxisRange}{a ChartRangeType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Auto} +#' \item{Manual} +#' } +#' } +#' \item{textColor}{a character} +#' \item{textSize}{a integer} +#' \item{title}{a character} +#' \item{titleColor}{a character} +#' \item{titleSize}{a integer} +#' } +#' +#' \strong{ReportChartComponentLayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportchartcomponentlayoutitem.htm}{Salesforce Documentation for ReportChartComponentLayoutItem} +#' \describe{ +#' \item{cacheData}{a character either 'true' or 'false'} +#' \item{contextFilterableField}{a character} +#' \item{error}{a character} +#' \item{hideOnError}{a character either 'true' or 'false'} +#' \item{includeContext}{a character either 'true' or 'false'} +#' \item{reportName}{a character} +#' \item{showTitle}{a character either 'true' or 'false'} +#' \item{size}{a ReportChartComponentSize - which is a character taking one of the following values: +#' \itemize{ +#' \item{SMALL} +#' \item{MEDIUM} +#' \item{LARGE} +#' } +#' } +#' } +#' +#' \strong{ReportColorRange} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportcolorrange.htm}{Salesforce Documentation for ReportColorRange} +#' \describe{ +#' \item{aggregate}{a ReportSummaryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{None} +#' } +#' } +#' \item{columnName}{a character} +#' \item{highBreakpoint}{a numeric} +#' \item{highColor}{a character} +#' \item{lowBreakpoint}{a numeric} +#' \item{lowColor}{a character} +#' \item{midColor}{a character} +#' } +#' +#' \strong{ReportColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportcolumn.htm}{Salesforce Documentation for ReportColumn} +#' \describe{ +#' \item{aggregateTypes}{a ReportSummaryType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{None} +#' } +#' } +#' \item{field}{a character} +#' \item{reverseColors}{a character either 'true' or 'false'} +#' \item{showChanges}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ReportCrossFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportcrossfilter.htm}{Salesforce Documentation for ReportCrossFilter} +#' \describe{ +#' \item{criteriaItems}{a ReportFilterItem} +#' \item{operation}{a ObjectFilterOperator - which is a character taking one of the following values: +#' \itemize{ +#' \item{with} +#' \item{without} +#' } +#' } +#' \item{primaryTableColumn}{a character} +#' \item{relatedTable}{a character} +#' \item{relatedTableJoinColumn}{a character} +#' } +#' +#' \strong{ReportDataCategoryFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportdatacategoryfilter.htm}{Salesforce Documentation for ReportDataCategoryFilter} +#' \describe{ +#' \item{dataCategory}{a character} +#' \item{dataCategoryGroup}{a character} +#' \item{operator}{a DataCategoryFilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{above} +#' \item{below} +#' \item{at} +#' \item{aboveOrBelow} +#' } +#' } +#' } +#' +#' \strong{ReportFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportfilter.htm}{Salesforce Documentation for ReportFilter} +#' \describe{ +#' \item{booleanFilter}{a character} +#' \item{criteriaItems}{a ReportFilterItem} +#' \item{language}{a Language - which is a character taking one of the following values: +#' \itemize{ +#' \item{en_US} +#' \item{de} +#' \item{es} +#' \item{fr} +#' \item{it} +#' \item{ja} +#' \item{sv} +#' \item{ko} +#' \item{zh_TW} +#' \item{zh_CN} +#' \item{pt_BR} +#' \item{nl_NL} +#' \item{da} +#' \item{th} +#' \item{fi} +#' \item{ru} +#' \item{es_MX} +#' \item{no} +#' \item{hu} +#' \item{pl} +#' \item{cs} +#' \item{tr} +#' \item{in} +#' \item{ro} +#' \item{vi} +#' \item{uk} +#' \item{iw} +#' \item{el} +#' \item{bg} +#' \item{en_GB} +#' \item{ar} +#' \item{sk} +#' \item{pt_PT} +#' \item{hr} +#' \item{sl} +#' \item{fr_CA} +#' \item{ka} +#' \item{sr} +#' \item{sh} +#' \item{en_AU} +#' \item{en_MY} +#' \item{en_IN} +#' \item{en_PH} +#' \item{en_CA} +#' \item{ro_MD} +#' \item{bs} +#' \item{mk} +#' \item{lv} +#' \item{lt} +#' \item{et} +#' \item{sq} +#' \item{sh_ME} +#' \item{mt} +#' \item{ga} +#' \item{eu} +#' \item{cy} +#' \item{is} +#' \item{ms} +#' \item{tl} +#' \item{lb} +#' \item{rm} +#' \item{hy} +#' \item{hi} +#' \item{ur} +#' \item{bn} +#' \item{de_AT} +#' \item{de_CH} +#' \item{ta} +#' \item{ar_DZ} +#' \item{ar_BH} +#' \item{ar_EG} +#' \item{ar_IQ} +#' \item{ar_JO} +#' \item{ar_KW} +#' \item{ar_LB} +#' \item{ar_LY} +#' \item{ar_MA} +#' \item{ar_OM} +#' \item{ar_QA} +#' \item{ar_SA} +#' \item{ar_SD} +#' \item{ar_SY} +#' \item{ar_TN} +#' \item{ar_AE} +#' \item{ar_YE} +#' \item{zh_SG} +#' \item{zh_HK} +#' \item{en_HK} +#' \item{en_IE} +#' \item{en_SG} +#' \item{en_ZA} +#' \item{fr_BE} +#' \item{fr_LU} +#' \item{fr_CH} +#' \item{de_BE} +#' \item{de_LU} +#' \item{it_CH} +#' \item{nl_BE} +#' \item{es_AR} +#' \item{es_BO} +#' \item{es_CL} +#' \item{es_CO} +#' \item{es_CR} +#' \item{es_DO} +#' \item{es_EC} +#' \item{es_SV} +#' \item{es_GT} +#' \item{es_HN} +#' \item{es_NI} +#' \item{es_PA} +#' \item{es_PY} +#' \item{es_PE} +#' \item{es_PR} +#' \item{es_US} +#' \item{es_UY} +#' \item{es_VE} +#' \item{ca} +#' \item{eo} +#' \item{iw_EO} +#' } +#' } +#' } +#' +#' \strong{ReportFilterItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportfilteritem.htm}{Salesforce Documentation for ReportFilterItem} +#' \describe{ +#' \item{column}{a character} +#' \item{columnToColumn}{a character either 'true' or 'false'} +#' \item{isUnlocked}{a character either 'true' or 'false'} +#' \item{operator}{a FilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{equals} +#' \item{notEqual} +#' \item{lessThan} +#' \item{greaterThan} +#' \item{lessOrEqual} +#' \item{greaterOrEqual} +#' \item{contains} +#' \item{notContain} +#' \item{startsWith} +#' \item{includes} +#' \item{excludes} +#' \item{within} +#' } +#' } +#' \item{snapshot}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{ReportFolder} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportfolder.htm}{Salesforce Documentation for ReportFolder} +#' \describe{ +#' \item{accessType}{a FolderAccessTypes (inherited from Folder)} +#' \item{folderShares}{a FolderShare (inherited from Folder)} +#' \item{name}{a character (inherited from Folder)} +#' \item{publicFolderAccess}{a PublicFolderAccess (inherited from Folder)} +#' \item{sharedTo}{a SharedTo (inherited from Folder)} +#' } +#' +#' \strong{ReportGrouping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportgrouping.htm}{Salesforce Documentation for ReportGrouping} +#' \describe{ +#' \item{aggregateType}{a ReportAggrType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Sum} +#' \item{Average} +#' \item{Maximum} +#' \item{Minimum} +#' \item{RowCount} +#' } +#' } +#' \item{dateGranularity}{a UserDateGranularity - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Day} +#' \item{Week} +#' \item{Month} +#' \item{Quarter} +#' \item{Year} +#' \item{FiscalQuarter} +#' \item{FiscalYear} +#' \item{MonthInYear} +#' \item{DayInMonth} +#' \item{FiscalPeriod} +#' \item{FiscalWeek} +#' } +#' } +#' \item{field}{a character} +#' \item{sortByName}{a character} +#' \item{sortOrder}{a SortOrder - which is a character taking one of the following values: +#' \itemize{ +#' \item{Asc} +#' \item{Desc} +#' } +#' } +#' \item{sortType}{a ReportSortType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Column} +#' \item{Aggregate} +#' \item{CustomSummaryFormula} +#' } +#' } +#' } +#' +#' \strong{ReportHistoricalSelector} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporthistoricalselector.htm}{Salesforce Documentation for ReportHistoricalSelector} +#' \describe{ +#' \item{snapshot}{a character} +#' } +#' +#' \strong{ReportLayoutSection} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportlayoutsection.htm}{Salesforce Documentation for ReportLayoutSection} +#' \describe{ +#' \item{columns}{a ReportTypeColumn} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{ReportParam} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reportparam.htm}{Salesforce Documentation for ReportParam} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{ReportTimeFrameFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttimeframefilter.htm}{Salesforce Documentation for ReportTimeFrameFilter} +#' \describe{ +#' \item{dateColumn}{a character} +#' \item{endDate}{a character formatted as 'yyyy-mm-dd'} +#' \item{interval}{a UserDateInterval - which is a character taking one of the following values: +#' \itemize{ +#' \item{INTERVAL_CURRENT} +#' \item{INTERVAL_CURNEXT1} +#' \item{INTERVAL_CURPREV1} +#' \item{INTERVAL_NEXT1} +#' \item{INTERVAL_PREV1} +#' \item{INTERVAL_CURNEXT3} +#' \item{INTERVAL_CURFY} +#' \item{INTERVAL_PREVFY} +#' \item{INTERVAL_PREV2FY} +#' \item{INTERVAL_AGO2FY} +#' \item{INTERVAL_NEXTFY} +#' \item{INTERVAL_PREVCURFY} +#' \item{INTERVAL_PREVCUR2FY} +#' \item{INTERVAL_CURNEXTFY} +#' \item{INTERVAL_CUSTOM} +#' \item{INTERVAL_YESTERDAY} +#' \item{INTERVAL_TODAY} +#' \item{INTERVAL_TOMORROW} +#' \item{INTERVAL_LASTWEEK} +#' \item{INTERVAL_THISWEEK} +#' \item{INTERVAL_NEXTWEEK} +#' \item{INTERVAL_LASTMONTH} +#' \item{INTERVAL_THISMONTH} +#' \item{INTERVAL_NEXTMONTH} +#' \item{INTERVAL_LASTTHISMONTH} +#' \item{INTERVAL_THISNEXTMONTH} +#' \item{INTERVAL_CURRENTQ} +#' \item{INTERVAL_CURNEXTQ} +#' \item{INTERVAL_CURPREVQ} +#' \item{INTERVAL_NEXTQ} +#' \item{INTERVAL_PREVQ} +#' \item{INTERVAL_CURNEXT3Q} +#' \item{INTERVAL_CURY} +#' \item{INTERVAL_PREVY} +#' \item{INTERVAL_PREV2Y} +#' \item{INTERVAL_AGO2Y} +#' \item{INTERVAL_NEXTY} +#' \item{INTERVAL_PREVCURY} +#' \item{INTERVAL_PREVCUR2Y} +#' \item{INTERVAL_CURNEXTY} +#' \item{INTERVAL_LAST7} +#' \item{INTERVAL_LAST30} +#' \item{INTERVAL_LAST60} +#' \item{INTERVAL_LAST90} +#' \item{INTERVAL_LAST120} +#' \item{INTERVAL_NEXT7} +#' \item{INTERVAL_NEXT30} +#' \item{INTERVAL_NEXT60} +#' \item{INTERVAL_NEXT90} +#' \item{INTERVAL_NEXT120} +#' \item{LAST_FISCALWEEK} +#' \item{THIS_FISCALWEEK} +#' \item{NEXT_FISCALWEEK} +#' \item{LAST_FISCALPERIOD} +#' \item{THIS_FISCALPERIOD} +#' \item{NEXT_FISCALPERIOD} +#' \item{LASTTHIS_FISCALPERIOD} +#' \item{THISNEXT_FISCALPERIOD} +#' \item{CURRENT_ENTITLEMENT_PERIOD} +#' \item{PREVIOUS_ENTITLEMENT_PERIOD} +#' \item{PREVIOUS_TWO_ENTITLEMENT_PERIODS} +#' \item{TWO_ENTITLEMENT_PERIODS_AGO} +#' \item{CURRENT_AND_PREVIOUS_ENTITLEMENT_PERIOD} +#' \item{CURRENT_AND_PREVIOUS_TWO_ENTITLEMENT_PERIODS} +#' } +#' } +#' \item{startDate}{a character formatted as 'yyyy-mm-dd'} +#' } +#' +#' \strong{ReportType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttype.htm}{Salesforce Documentation for ReportType} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{autogenerated}{a character either 'true' or 'false'} +#' \item{baseObject}{a character} +#' \item{category}{a ReportTypeCategory - which is a character taking one of the following values: +#' \itemize{ +#' \item{accounts} +#' \item{opportunities} +#' \item{forecasts} +#' \item{cases} +#' \item{leads} +#' \item{campaigns} +#' \item{activities} +#' \item{busop} +#' \item{products} +#' \item{admin} +#' \item{territory} +#' \item{other} +#' \item{content} +#' \item{usage_entitlement} +#' \item{wdc} +#' \item{calibration} +#' \item{territory2} +#' } +#' } +#' \item{deployed}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{join}{a ObjectRelationship} +#' \item{label}{a character} +#' \item{sections}{a ReportLayoutSection} +#' } +#' +#' \strong{ReportTypeColumn} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttypecolumn.htm}{Salesforce Documentation for ReportTypeColumn} +#' \describe{ +#' \item{checkedByDefault}{a character either 'true' or 'false'} +#' \item{displayNameOverride}{a character} +#' \item{field}{a character} +#' \item{table}{a character} +#' } +#' +#' \strong{ReportTypeColumnTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttypecolumntranslation.htm}{Salesforce Documentation for ReportTypeColumnTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{ReportTypeSectionTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttypesectiontranslation.htm}{Salesforce Documentation for ReportTypeSectionTranslation} +#' \describe{ +#' \item{columns}{a ReportTypeColumnTranslation} +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{ReportTypeTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reporttypetranslation.htm}{Salesforce Documentation for ReportTypeTranslation} +#' \describe{ +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{name}{a character} +#' \item{sections}{a ReportTypeSectionTranslation} +#' } +#' +#' \strong{ReputationBranding} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationbranding.htm}{Salesforce Documentation for ReputationBranding} +#' \describe{ +#' \item{smallImage}{a character} +#' } +#' +#' \strong{ReputationLevel} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationlevel.htm}{Salesforce Documentation for ReputationLevel} +#' \describe{ +#' \item{branding}{a ReputationBranding} +#' \item{label}{a character} +#' \item{lowerThreshold}{a numeric} +#' } +#' +#' \strong{ReputationLevelDefinitions} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationleveldefinitions.htm}{Salesforce Documentation for ReputationLevelDefinitions} +#' \describe{ +#' \item{level}{a ReputationLevel} +#' } +#' +#' \strong{ReputationLevels} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationlevels.htm}{Salesforce Documentation for ReputationLevels} +#' \describe{ +#' \item{chatterAnswersReputationLevels}{a ChatterAnswersReputationLevel} +#' \item{ideaReputationLevels}{a IdeaReputationLevel} +#' } +#' +#' \strong{ReputationPointsRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationpointsrule.htm}{Salesforce Documentation for ReputationPointsRule} +#' \describe{ +#' \item{eventType}{a character} +#' \item{points}{a integer} +#' } +#' +#' \strong{ReputationPointsRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_reputationpointsrules.htm}{Salesforce Documentation for ReputationPointsRules} +#' \describe{ +#' \item{pointsRule}{a ReputationPointsRule} +#' } +#' +#' \strong{RetrieveRequest} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_retrieverequest.htm}{Salesforce Documentation for RetrieveRequest} +#' \describe{ +#' \item{apiVersion}{a numeric} +#' \item{packageNames}{a character} +#' \item{singlePackage}{a character either 'true' or 'false'} +#' \item{specificFiles}{a character} +#' \item{unpackaged}{a Package} +#' } +#' +#' \strong{Role} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_role.htm}{Salesforce Documentation for Role} +#' \describe{ +#' \item{caseAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{contactAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{description}{a character (inherited from RoleOrTerritory)} +#' \item{mayForecastManagerShare}{a character either 'true' or 'false' (inherited from RoleOrTerritory)} +#' \item{name}{a character (inherited from RoleOrTerritory)} +#' \item{opportunityAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{parentRole}{a character} +#' } +#' +#' \strong{RoleAndSubordinates} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_roleandsubordinates.htm}{Salesforce Documentation for RoleAndSubordinates} +#' \describe{ +#' \item{roleAndSubordinate}{a character} +#' } +#' +#' \strong{RoleAndSubordinatesInternal} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_roleandsubordinatesinternal.htm}{Salesforce Documentation for RoleAndSubordinatesInternal} +#' \describe{ +#' \item{roleAndSubordinateInternal}{a character} +#' } +#' +#' \strong{RoleOrTerritory} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_roleorterritory.htm}{Salesforce Documentation for RoleOrTerritory} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{caseAccessLevel}{a character} +#' \item{contactAccessLevel}{a character} +#' \item{description}{a character} +#' \item{mayForecastManagerShare}{a character either 'true' or 'false'} +#' \item{name}{a character} +#' \item{opportunityAccessLevel}{a character} +#' } +#' +#' \strong{Roles} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_roles.htm}{Salesforce Documentation for Roles} +#' \describe{ +#' \item{role}{a character} +#' } +#' +#' \strong{RuleEntry} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_ruleentry.htm}{Salesforce Documentation for RuleEntry} +#' \describe{ +#' \item{assignedTo}{a character} +#' \item{assignedToType}{a AssignToLookupValueType - which is a character taking one of the following values: +#' \itemize{ +#' \item{User} +#' \item{Queue} +#' } +#' } +#' \item{booleanFilter}{a character} +#' \item{businessHours}{a character} +#' \item{businessHoursSource}{a BusinessHoursSourceType - which is a character taking one of the following values: +#' \itemize{ +#' \item{None} +#' \item{Case} +#' \item{Static} +#' } +#' } +#' \item{criteriaItems}{a FilterItem} +#' \item{disableEscalationWhenModified}{a character either 'true' or 'false'} +#' \item{escalationAction}{a EscalationAction} +#' \item{escalationStartTime}{a EscalationStartTimeType - which is a character taking one of the following values: +#' \itemize{ +#' \item{CaseCreation} +#' \item{CaseLastModified} +#' } +#' } +#' \item{formula}{a character} +#' \item{notifyCcRecipients}{a character either 'true' or 'false'} +#' \item{overrideExistingTeams}{a character either 'true' or 'false'} +#' \item{replyToEmail}{a character} +#' \item{senderEmail}{a character} +#' \item{senderName}{a character} +#' \item{team}{a character} +#' \item{template}{a character} +#' } +#' +#' \strong{SamlSsoConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_samlssoconfig.htm}{Salesforce Documentation for SamlSsoConfig} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{attributeName}{a character} +#' \item{attributeNameIdFormat}{a character} +#' \item{decryptionCertificate}{a character} +#' \item{errorUrl}{a character} +#' \item{executionUserId}{a character} +#' \item{identityLocation}{a SamlIdentityLocationType - which is a character taking one of the following values: +#' \itemize{ +#' \item{SubjectNameId} +#' \item{Attribute} +#' } +#' } +#' \item{identityMapping}{a SamlIdentityType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Username} +#' \item{FederationId} +#' \item{UserId} +#' } +#' } +#' \item{issuer}{a character} +#' \item{loginUrl}{a character} +#' \item{logoutUrl}{a character} +#' \item{name}{a character} +#' \item{oauthTokenEndpoint}{a character} +#' \item{redirectBinding}{a character either 'true' or 'false'} +#' \item{requestSignatureMethod}{a character} +#' \item{requestSigningCertId}{a character} +#' \item{salesforceLoginUrl}{a character} +#' \item{samlEntityId}{a character} +#' \item{samlJitHandlerId}{a character} +#' \item{samlVersion}{a SamlType - which is a character taking one of the following values: +#' \itemize{ +#' \item{SAML1_1} +#' \item{SAML2_0} +#' } +#' } +#' \item{singleLogoutBinding}{a SamlSpSLOBinding - which is a character taking one of the following values: +#' \itemize{ +#' \item{RedirectBinding} +#' \item{PostBinding} +#' } +#' } +#' \item{singleLogoutUrl}{a character} +#' \item{userProvisioning}{a character either 'true' or 'false'} +#' \item{validationCert}{a character} +#' } +#' +#' \strong{ScheduledRecommendation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_scheduledrecommendation.htm}{Salesforce Documentation for ScheduledRecommendation} +#' \describe{ +#' \item{scheduledRecommendationDetails}{a ScheduledRecommendationDetail} +#' } +#' +#' \strong{ScheduledRecommendationDetail} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_scheduledrecommendationdetail.htm}{Salesforce Documentation for ScheduledRecommendationDetail} +#' \describe{ +#' \item{channel}{a RecommendationChannel - which is a character taking one of the following values: +#' \itemize{ +#' \item{DefaultChannel} +#' \item{CustomChannel1} +#' \item{CustomChannel2} +#' \item{CustomChannel3} +#' \item{CustomChannel4} +#' \item{CustomChannel5} +#' } +#' } +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{rank}{a integer} +#' \item{recommendationAudience}{a character} +#' } +#' +#' \strong{Scontrol} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_scontrol.htm}{Salesforce Documentation for Scontrol} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{contentSource}{a SControlContentSource - which is a character taking one of the following values: +#' \itemize{ +#' \item{HTML} +#' \item{URL} +#' \item{Snippet} +#' } +#' } +#' \item{description}{a character} +#' \item{encodingKey}{a Encoding - which is a character taking one of the following values: +#' \itemize{ +#' \item{UTF-8} +#' \item{ISO-8859-1} +#' \item{Shift_JIS} +#' \item{ISO-2022-JP} +#' \item{EUC-JP} +#' \item{ks_c_5601-1987} +#' \item{Big5} +#' \item{GB2312} +#' \item{Big5-HKSCS} +#' \item{x-SJIS_0213} +#' } +#' } +#' \item{fileContent}{a character formed using RCurl::base64Encode} +#' \item{fileName}{a character} +#' \item{name}{a character} +#' \item{supportsCaching}{a character either 'true' or 'false'} +#' } +#' +#' \strong{ScontrolTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_scontroltranslation.htm}{Salesforce Documentation for ScontrolTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{SearchLayouts} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_searchlayouts.htm}{Salesforce Documentation for SearchLayouts} +#' \describe{ +#' \item{customTabListAdditionalFields}{a character} +#' \item{excludedStandardButtons}{a character} +#' \item{listViewButtons}{a character} +#' \item{lookupDialogsAdditionalFields}{a character} +#' \item{lookupFilterFields}{a character} +#' \item{lookupPhoneDialogsAdditionalFields}{a character} +#' \item{searchFilterFields}{a character} +#' \item{searchResultsAdditionalFields}{a character} +#' \item{searchResultsCustomButtons}{a character} +#' } +#' +#' \strong{SearchSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_searchsettings.htm}{Salesforce Documentation for SearchSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{documentContentSearchEnabled}{a character either 'true' or 'false'} +#' \item{optimizeSearchForCJKEnabled}{a character either 'true' or 'false'} +#' \item{recentlyViewedUsersForBlankLookupEnabled}{a character either 'true' or 'false'} +#' \item{searchSettingsByObject}{a SearchSettingsByObject} +#' \item{sidebarAutoCompleteEnabled}{a character either 'true' or 'false'} +#' \item{sidebarDropDownListEnabled}{a character either 'true' or 'false'} +#' \item{sidebarLimitToItemsIOwnCheckboxEnabled}{a character either 'true' or 'false'} +#' \item{singleSearchResultShortcutEnabled}{a character either 'true' or 'false'} +#' \item{spellCorrectKnowledgeSearchEnabled}{a character either 'true' or 'false'} +#' } +#' +#' \strong{SearchSettingsByObject} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_searchsettingsbyobject.htm}{Salesforce Documentation for SearchSettingsByObject} +#' \describe{ +#' \item{searchSettingsByObject}{a ObjectSearchSetting} +#' } +#' +#' \strong{SecuritySettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_securitysettings.htm}{Salesforce Documentation for SecuritySettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{networkAccess}{a NetworkAccess} +#' \item{passwordPolicies}{a PasswordPolicies} +#' \item{sessionSettings}{a SessionSettings} +#' } +#' +#' \strong{ServiceCloudConsoleConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_servicecloudconsoleconfig.htm}{Salesforce Documentation for ServiceCloudConsoleConfig} +#' \describe{ +#' \item{componentList}{a AppComponentList} +#' \item{detailPageRefreshMethod}{a character} +#' \item{footerColor}{a character} +#' \item{headerColor}{a character} +#' \item{keyboardShortcuts}{a KeyboardShortcuts} +#' \item{listPlacement}{a ListPlacement} +#' \item{listRefreshMethod}{a character} +#' \item{liveAgentConfig}{a LiveAgentConfig} +#' \item{primaryTabColor}{a character} +#' \item{pushNotifications}{a PushNotification} +#' \item{tabLimitConfig}{a TabLimitConfig} +#' \item{whitelistedDomains}{a character} +#' } +#' +#' \strong{SessionSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sessionsettings.htm}{Salesforce Documentation for SessionSettings} +#' \describe{ +#' \item{disableTimeoutWarning}{a character either 'true' or 'false'} +#' \item{enableCSPOnEmail}{a character either 'true' or 'false'} +#' \item{enableCSRFOnGet}{a character either 'true' or 'false'} +#' \item{enableCSRFOnPost}{a character either 'true' or 'false'} +#' \item{enableCacheAndAutocomplete}{a character either 'true' or 'false'} +#' \item{enableClickjackNonsetupSFDC}{a character either 'true' or 'false'} +#' \item{enableClickjackNonsetupUser}{a character either 'true' or 'false'} +#' \item{enableClickjackNonsetupUserHeaderless}{a character either 'true' or 'false'} +#' \item{enableClickjackSetup}{a character either 'true' or 'false'} +#' \item{enableContentSniffingProtection}{a character either 'true' or 'false'} +#' \item{enablePostForSessions}{a character either 'true' or 'false'} +#' \item{enableSMSIdentity}{a character either 'true' or 'false'} +#' \item{enableUpgradeInsecureRequests}{a character either 'true' or 'false'} +#' \item{enableXssProtection}{a character either 'true' or 'false'} +#' \item{enforceIpRangesEveryRequest}{a character either 'true' or 'false'} +#' \item{forceLogoutOnSessionTimeout}{a character either 'true' or 'false'} +#' \item{forceRelogin}{a character either 'true' or 'false'} +#' \item{hstsOnForcecomSites}{a character either 'true' or 'false'} +#' \item{identityConfirmationOnEmailChange}{a character either 'true' or 'false'} +#' \item{identityConfirmationOnTwoFactorRegistrationEnabled}{a character either 'true' or 'false'} +#' \item{lockSessionsToDomain}{a character either 'true' or 'false'} +#' \item{lockSessionsToIp}{a character either 'true' or 'false'} +#' \item{logoutURL}{a character} +#' \item{redirectionWarning}{a character either 'true' or 'false'} +#' \item{referrerPolicy}{a character either 'true' or 'false'} +#' \item{requireHttpOnly}{a character either 'true' or 'false'} +#' \item{requireHttps}{a character either 'true' or 'false'} +#' \item{securityCentralKillSession}{a character either 'true' or 'false'} +#' \item{sessionTimeout}{a SessionTimeout - which is a character taking one of the following values: +#' \itemize{ +#' \item{TwentyFourHours} +#' \item{TwelveHours} +#' \item{EightHours} +#' \item{FourHours} +#' \item{TwoHours} +#' \item{SixtyMinutes} +#' \item{ThirtyMinutes} +#' \item{FifteenMinutes} +#' } +#' } +#' } +#' +#' \strong{SFDCMobileSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sfdcmobilesettings.htm}{Salesforce Documentation for SFDCMobileSettings} +#' \describe{ +#' \item{enableMobileLite}{a character either 'true' or 'false'} +#' \item{enableUserToDeviceLinking}{a character either 'true' or 'false'} +#' } +#' +#' \strong{SharedTo} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharedto.htm}{Salesforce Documentation for SharedTo} +#' \describe{ +#' \item{allCustomerPortalUsers}{a character} +#' \item{allInternalUsers}{a character} +#' \item{allPartnerUsers}{a character} +#' \item{channelProgramGroup}{a character} +#' \item{channelProgramGroups}{a character} +#' \item{group}{a character} +#' \item{groups}{a character} +#' \item{managerSubordinates}{a character} +#' \item{managers}{a character} +#' \item{portalRole}{a character} +#' \item{portalRoleAndSubordinates}{a character} +#' \item{queue}{a character} +#' \item{role}{a character} +#' \item{roleAndSubordinates}{a character} +#' \item{roleAndSubordinatesInternal}{a character} +#' \item{roles}{a character} +#' \item{rolesAndSubordinates}{a character} +#' \item{territories}{a character} +#' \item{territoriesAndSubordinates}{a character} +#' \item{territory}{a character} +#' \item{territoryAndSubordinates}{a character} +#' } +#' +#' \strong{SharingBaseRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingbaserule.htm}{Salesforce Documentation for SharingBaseRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{accessLevel}{a character} +#' \item{accountSettings}{a AccountSharingRuleSettings} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{sharedTo}{a SharedTo} +#' } +#' +#' \strong{SharingCriteriaRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingcriteriarule.htm}{Salesforce Documentation for SharingCriteriaRule} +#' \describe{ +#' \item{accessLevel}{a character (inherited from SharingBaseRule)} +#' \item{accountSettings}{a AccountSharingRuleSettings (inherited from SharingBaseRule)} +#' \item{description}{a character (inherited from SharingBaseRule)} +#' \item{label}{a character (inherited from SharingBaseRule)} +#' \item{sharedTo}{a SharedTo (inherited from SharingBaseRule)} +#' \item{booleanFilter}{a character} +#' \item{criteriaItems}{a FilterItem} +#' } +#' +#' \strong{SharingOwnerRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingownerrule.htm}{Salesforce Documentation for SharingOwnerRule} +#' \describe{ +#' \item{accessLevel}{a character (inherited from SharingBaseRule)} +#' \item{accountSettings}{a AccountSharingRuleSettings (inherited from SharingBaseRule)} +#' \item{description}{a character (inherited from SharingBaseRule)} +#' \item{label}{a character (inherited from SharingBaseRule)} +#' \item{sharedTo}{a SharedTo (inherited from SharingBaseRule)} +#' \item{sharedFrom}{a SharedTo} +#' } +#' +#' \strong{SharingReason} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingreason.htm}{Salesforce Documentation for SharingReason} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{label}{a character} +#' } +#' +#' \strong{SharingReasonTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingreasontranslation.htm}{Salesforce Documentation for SharingReasonTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{SharingRecalculation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingrecalculation.htm}{Salesforce Documentation for SharingRecalculation} +#' \describe{ +#' \item{className}{a character} +#' } +#' +#' \strong{SharingRules} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingrules.htm}{Salesforce Documentation for SharingRules} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{sharingCriteriaRules}{a SharingCriteriaRule} +#' \item{sharingOwnerRules}{a SharingOwnerRule} +#' \item{sharingTerritoryRules}{a SharingTerritoryRule} +#' } +#' +#' \strong{SharingSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingset.htm}{Salesforce Documentation for SharingSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{accessMappings}{a AccessMapping} +#' \item{description}{a character} +#' \item{name}{a character} +#' \item{profiles}{a character} +#' } +#' +#' \strong{SharingTerritoryRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sharingterritoryrule.htm}{Salesforce Documentation for SharingTerritoryRule} +#' \describe{ +#' \item{sharedFrom}{a SharedTo (inherited from SharingOwnerRule)} +#' } +#' +#' \strong{SidebarComponent} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sidebarcomponent.htm}{Salesforce Documentation for SidebarComponent} +#' \describe{ +#' \item{componentType}{a character} +#' \item{createAction}{a character} +#' \item{enableLinking}{a character either 'true' or 'false'} +#' \item{height}{a integer} +#' \item{label}{a character} +#' \item{lookup}{a character} +#' \item{page}{a character} +#' \item{relatedLists}{a RelatedList} +#' \item{unit}{a character} +#' \item{updateAction}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{SiteDotCom} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sitedotcom.htm}{Salesforce Documentation for SiteDotCom} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{label}{a character} +#' \item{siteType}{a SiteType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Siteforce} +#' \item{Visualforce} +#' \item{User} +#' } +#' } +#' } +#' +#' \strong{SiteRedirectMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_siteredirectmapping.htm}{Salesforce Documentation for SiteRedirectMapping} +#' \describe{ +#' \item{action}{a SiteRedirect - which is a character taking one of the following values: +#' \itemize{ +#' \item{Permanent} +#' \item{Temporary} +#' } +#' } +#' \item{isActive}{a character either 'true' or 'false'} +#' \item{source}{a character} +#' \item{target}{a character} +#' } +#' +#' \strong{SiteWebAddress} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_sitewebaddress.htm}{Salesforce Documentation for SiteWebAddress} +#' \describe{ +#' \item{certificate}{a character} +#' \item{domainName}{a character} +#' \item{primary}{a character either 'true' or 'false'} +#' } +#' +#' \strong{Skill} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_skill.htm}{Salesforce Documentation for Skill} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assignments}{a SkillAssignments} +#' \item{description}{a character} +#' \item{label}{a character} +#' } +#' +#' \strong{SkillAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_skillassignments.htm}{Salesforce Documentation for SkillAssignments} +#' \describe{ +#' \item{profiles}{a SkillProfileAssignments} +#' \item{users}{a SkillUserAssignments} +#' } +#' +#' \strong{SkillProfileAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_skillprofileassignments.htm}{Salesforce Documentation for SkillProfileAssignments} +#' \describe{ +#' \item{profile}{a character} +#' } +#' +#' \strong{SkillUserAssignments} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_skilluserassignments.htm}{Salesforce Documentation for SkillUserAssignments} +#' \describe{ +#' \item{user}{a character} +#' } +#' +#' \strong{SocialCustomerServiceSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_socialcustomerservicesettings.htm}{Salesforce Documentation for SocialCustomerServiceSettings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{caseSubjectOption}{a CaseSubjectOption - which is a character taking one of the following values: +#' \itemize{ +#' \item{SocialPostSource} +#' \item{SocialPostContent} +#' \item{BuildCustom} +#' } +#' } +#' } +#' +#' \strong{StandardFieldTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_standardfieldtranslation.htm}{Salesforce Documentation for StandardFieldTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{StandardValue} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_standardvalue.htm}{Salesforce Documentation for StandardValue} +#' \describe{ +#' \item{color}{a character (inherited from CustomValue)} +#' \item{default}{a character either 'true' or 'false' (inherited from CustomValue)} +#' \item{description}{a character (inherited from CustomValue)} +#' \item{isActive}{a character either 'true' or 'false' (inherited from CustomValue)} +#' \item{label}{a character (inherited from CustomValue)} +#' \item{allowEmail}{a character either 'true' or 'false'} +#' \item{closed}{a character either 'true' or 'false'} +#' \item{converted}{a character either 'true' or 'false'} +#' \item{cssExposed}{a character either 'true' or 'false'} +#' \item{forecastCategory}{a ForecastCategories - which is a character taking one of the following values: +#' \itemize{ +#' \item{Omitted} +#' \item{Pipeline} +#' \item{BestCase} +#' \item{Forecast} +#' \item{Closed} +#' } +#' } +#' \item{groupingString}{a character} +#' \item{highPriority}{a character either 'true' or 'false'} +#' \item{probability}{a integer} +#' \item{reverseRole}{a character} +#' \item{reviewed}{a character either 'true' or 'false'} +#' \item{won}{a character either 'true' or 'false'} +#' } +#' +#' \strong{StandardValueSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_standardvalueset.htm}{Salesforce Documentation for StandardValueSet} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{groupingStringEnum}{a character} +#' \item{sorted}{a character either 'true' or 'false'} +#' \item{standardValue}{a StandardValue} +#' } +#' +#' \strong{StandardValueSetTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_standardvaluesettranslation.htm}{Salesforce Documentation for StandardValueSetTranslation} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{valueTranslation}{a ValueTranslation} +#' } +#' +#' \strong{State} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_state.htm}{Salesforce Documentation for State} +#' \describe{ +#' \item{active}{a character either 'true' or 'false'} +#' \item{integrationValue}{a character} +#' \item{isoCode}{a character} +#' \item{label}{a character} +#' \item{standard}{a character either 'true' or 'false'} +#' \item{visible}{a character either 'true' or 'false'} +#' } +#' +#' \strong{StaticResource} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_staticresource.htm}{Salesforce Documentation for StaticResource} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{cacheControl}{a StaticResourceCacheControl - which is a character taking one of the following values: +#' \itemize{ +#' \item{Private} +#' \item{Public} +#' } +#' } +#' \item{contentType}{a character} +#' \item{description}{a character} +#' } +#' +#' \strong{StrategyNode} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_strategynode.htm}{Salesforce Documentation for StrategyNode} +#' \describe{ +#' \item{definition}{a character} +#' \item{description}{a character} +#' \item{name}{a character} +#' \item{parentNode}{a character} +#' \item{type}{a integer} +#' } +#' +#' \strong{SubtabComponents} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_subtabcomponents.htm}{Salesforce Documentation for SubtabComponents} +#' \describe{ +#' \item{containers}{a Container} +#' } +#' +#' \strong{SummaryLayout} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_summarylayout.htm}{Salesforce Documentation for SummaryLayout} +#' \describe{ +#' \item{masterLabel}{a character} +#' \item{sizeX}{a integer} +#' \item{sizeY}{a integer} +#' \item{sizeZ}{a integer} +#' \item{summaryLayoutItems}{a SummaryLayoutItem} +#' \item{summaryLayoutStyle}{a SummaryLayoutStyle - which is a character taking one of the following values: +#' \itemize{ +#' \item{Default} +#' \item{QuoteTemplate} +#' \item{DefaultQuoteTemplate} +#' \item{ServiceReportTemplate} +#' \item{ChildServiceReportTemplateStyle} +#' \item{DefaultServiceReportTemplate} +#' \item{CaseInteraction} +#' \item{QuickActionLayoutLeftRight} +#' \item{QuickActionLayoutTopDown} +#' \item{PathAssistant} +#' } +#' } +#' } +#' +#' \strong{SummaryLayoutItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_summarylayoutitem.htm}{Salesforce Documentation for SummaryLayoutItem} +#' \describe{ +#' \item{customLink}{a character} +#' \item{field}{a character} +#' \item{posX}{a integer} +#' \item{posY}{a integer} +#' \item{posZ}{a integer} +#' } +#' +#' \strong{SupervisorAgentConfigSkills} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_supervisoragentconfigskills.htm}{Salesforce Documentation for SupervisorAgentConfigSkills} +#' \describe{ +#' \item{skill}{a character} +#' } +#' +#' \strong{SynonymDictionary} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_synonymdictionary.htm}{Salesforce Documentation for SynonymDictionary} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{groups}{a SynonymGroup} +#' \item{isProtected}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' } +#' +#' \strong{SynonymGroup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_synonymgroup.htm}{Salesforce Documentation for SynonymGroup} +#' \describe{ +#' \item{languages}{a Language - which is a character taking one of the following values: +#' \itemize{ +#' \item{en_US} +#' \item{de} +#' \item{es} +#' \item{fr} +#' \item{it} +#' \item{ja} +#' \item{sv} +#' \item{ko} +#' \item{zh_TW} +#' \item{zh_CN} +#' \item{pt_BR} +#' \item{nl_NL} +#' \item{da} +#' \item{th} +#' \item{fi} +#' \item{ru} +#' \item{es_MX} +#' \item{no} +#' \item{hu} +#' \item{pl} +#' \item{cs} +#' \item{tr} +#' \item{in} +#' \item{ro} +#' \item{vi} +#' \item{uk} +#' \item{iw} +#' \item{el} +#' \item{bg} +#' \item{en_GB} +#' \item{ar} +#' \item{sk} +#' \item{pt_PT} +#' \item{hr} +#' \item{sl} +#' \item{fr_CA} +#' \item{ka} +#' \item{sr} +#' \item{sh} +#' \item{en_AU} +#' \item{en_MY} +#' \item{en_IN} +#' \item{en_PH} +#' \item{en_CA} +#' \item{ro_MD} +#' \item{bs} +#' \item{mk} +#' \item{lv} +#' \item{lt} +#' \item{et} +#' \item{sq} +#' \item{sh_ME} +#' \item{mt} +#' \item{ga} +#' \item{eu} +#' \item{cy} +#' \item{is} +#' \item{ms} +#' \item{tl} +#' \item{lb} +#' \item{rm} +#' \item{hy} +#' \item{hi} +#' \item{ur} +#' \item{bn} +#' \item{de_AT} +#' \item{de_CH} +#' \item{ta} +#' \item{ar_DZ} +#' \item{ar_BH} +#' \item{ar_EG} +#' \item{ar_IQ} +#' \item{ar_JO} +#' \item{ar_KW} +#' \item{ar_LB} +#' \item{ar_LY} +#' \item{ar_MA} +#' \item{ar_OM} +#' \item{ar_QA} +#' \item{ar_SA} +#' \item{ar_SD} +#' \item{ar_SY} +#' \item{ar_TN} +#' \item{ar_AE} +#' \item{ar_YE} +#' \item{zh_SG} +#' \item{zh_HK} +#' \item{en_HK} +#' \item{en_IE} +#' \item{en_SG} +#' \item{en_ZA} +#' \item{fr_BE} +#' \item{fr_LU} +#' \item{fr_CH} +#' \item{de_BE} +#' \item{de_LU} +#' \item{it_CH} +#' \item{nl_BE} +#' \item{es_AR} +#' \item{es_BO} +#' \item{es_CL} +#' \item{es_CO} +#' \item{es_CR} +#' \item{es_DO} +#' \item{es_EC} +#' \item{es_SV} +#' \item{es_GT} +#' \item{es_HN} +#' \item{es_NI} +#' \item{es_PA} +#' \item{es_PY} +#' \item{es_PE} +#' \item{es_PR} +#' \item{es_US} +#' \item{es_UY} +#' \item{es_VE} +#' \item{ca} +#' \item{eo} +#' \item{iw_EO} +#' } +#' } +#' \item{terms}{a character} +#' } +#' +#' \strong{TabLimitConfig} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_tablimitconfig.htm}{Salesforce Documentation for TabLimitConfig} +#' \describe{ +#' \item{maxNumberOfPrimaryTabs}{a character} +#' \item{maxNumberOfSubTabs}{a character} +#' } +#' +#' \strong{Territory} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory.htm}{Salesforce Documentation for Territory} +#' \describe{ +#' \item{caseAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{contactAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{description}{a character (inherited from RoleOrTerritory)} +#' \item{mayForecastManagerShare}{a character either 'true' or 'false' (inherited from RoleOrTerritory)} +#' \item{name}{a character (inherited from RoleOrTerritory)} +#' \item{opportunityAccessLevel}{a character (inherited from RoleOrTerritory)} +#' \item{accountAccessLevel}{a character} +#' \item{parentTerritory}{a character} +#' } +#' +#' \strong{Territory2} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2.htm}{Salesforce Documentation for Territory2} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{accountAccessLevel}{a character} +#' \item{caseAccessLevel}{a character} +#' \item{contactAccessLevel}{a character} +#' \item{customFields}{a FieldValue} +#' \item{description}{a character} +#' \item{name}{a character} +#' \item{opportunityAccessLevel}{a character} +#' \item{parentTerritory}{a character} +#' \item{ruleAssociations}{a Territory2RuleAssociation} +#' \item{territory2Type}{a character} +#' } +#' +#' \strong{Territory2Model} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2model.htm}{Salesforce Documentation for Territory2Model} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customFields}{a FieldValue} +#' \item{description}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{Territory2Rule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2rule.htm}{Salesforce Documentation for Territory2Rule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{booleanFilter}{a character} +#' \item{name}{a character} +#' \item{objectType}{a character} +#' \item{ruleItems}{a Territory2RuleItem} +#' } +#' +#' \strong{Territory2RuleAssociation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2ruleassociation.htm}{Salesforce Documentation for Territory2RuleAssociation} +#' \describe{ +#' \item{inherited}{a character either 'true' or 'false'} +#' \item{ruleName}{a character} +#' } +#' +#' \strong{Territory2RuleItem} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2ruleitem.htm}{Salesforce Documentation for Territory2RuleItem} +#' \describe{ +#' \item{field}{a character} +#' \item{operation}{a FilterOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{equals} +#' \item{notEqual} +#' \item{lessThan} +#' \item{greaterThan} +#' \item{lessOrEqual} +#' \item{greaterOrEqual} +#' \item{contains} +#' \item{notContain} +#' \item{startsWith} +#' \item{includes} +#' \item{excludes} +#' \item{within} +#' } +#' } +#' \item{value}{a character} +#' } +#' +#' \strong{Territory2Settings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2settings.htm}{Salesforce Documentation for Territory2Settings} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{defaultAccountAccessLevel}{a character} +#' \item{defaultCaseAccessLevel}{a character} +#' \item{defaultContactAccessLevel}{a character} +#' \item{defaultOpportunityAccessLevel}{a character} +#' \item{opportunityFilterSettings}{a Territory2SettingsOpportunityFilter} +#' } +#' +#' \strong{Territory2SettingsOpportunityFilter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2settingsopportunityfilter.htm}{Salesforce Documentation for Territory2SettingsOpportunityFilter} +#' \describe{ +#' \item{apexClassName}{a character} +#' \item{enableFilter}{a character either 'true' or 'false'} +#' \item{runOnCreate}{a character either 'true' or 'false'} +#' } +#' +#' \strong{Territory2Type} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_territory2type.htm}{Salesforce Documentation for Territory2Type} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{name}{a character} +#' \item{priority}{a integer} +#' } +#' +#' \strong{TopicsForObjects} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_topicsforobjects.htm}{Salesforce Documentation for TopicsForObjects} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{enableTopics}{a character either 'true' or 'false'} +#' \item{entityApiName}{a character} +#' } +#' +#' \strong{TouchMobileSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_touchmobilesettings.htm}{Salesforce Documentation for TouchMobileSettings} +#' \describe{ +#' \item{enableTouchAppIPad}{a character either 'true' or 'false'} +#' \item{enableTouchAppIPhone}{a character either 'true' or 'false'} +#' \item{enableTouchBrowserIPad}{a character either 'true' or 'false'} +#' \item{enableTouchIosPhone}{a character either 'true' or 'false'} +#' \item{enableVisualforceInTouch}{a character either 'true' or 'false'} +#' } +#' +#' \strong{TransactionSecurityAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_transactionsecurityaction.htm}{Salesforce Documentation for TransactionSecurityAction} +#' \describe{ +#' \item{block}{a character either 'true' or 'false'} +#' \item{endSession}{a character either 'true' or 'false'} +#' \item{freezeUser}{a character either 'true' or 'false'} +#' \item{notifications}{a TransactionSecurityNotification} +#' \item{twoFactorAuthentication}{a character either 'true' or 'false'} +#' } +#' +#' \strong{TransactionSecurityNotification} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_transactionsecuritynotification.htm}{Salesforce Documentation for TransactionSecurityNotification} +#' \describe{ +#' \item{inApp}{a character either 'true' or 'false'} +#' \item{sendEmail}{a character either 'true' or 'false'} +#' \item{user}{a character} +#' } +#' +#' \strong{TransactionSecurityPolicy} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_transactionsecuritypolicy.htm}{Salesforce Documentation for TransactionSecurityPolicy} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{action}{a TransactionSecurityAction} +#' \item{active}{a character either 'true' or 'false'} +#' \item{apexClass}{a character} +#' \item{description}{a character} +#' \item{developerName}{a character} +#' \item{eventName}{a TransactionSecurityEventName - which is a character taking one of the following values: +#' \itemize{ +#' \item{ReportEvent} +#' \item{ApiEvent} +#' \item{AdminSetupEvent} +#' \item{LoginEvent} +#' } +#' } +#' \item{eventType}{a MonitoredEvents - which is a character taking one of the following values: +#' \itemize{ +#' \item{AuditTrail} +#' \item{Login} +#' \item{Entity} +#' \item{DataExport} +#' \item{AccessResource} +#' } +#' } +#' \item{executionUser}{a character} +#' \item{flow}{a character} +#' \item{masterLabel}{a character} +#' \item{resourceName}{a character} +#' \item{type}{a TxnSecurityPolicyType - which is a character taking one of the following values: +#' \itemize{ +#' \item{CustomApexPolicy} +#' \item{CustomConditionBuilderPolicy} +#' } +#' } +#' } +#' +#' \strong{Translations} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_translations.htm}{Salesforce Documentation for Translations} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{customApplications}{a CustomApplicationTranslation} +#' \item{customDataTypeTranslations}{a CustomDataTypeTranslation} +#' \item{customLabels}{a CustomLabelTranslation} +#' \item{customPageWebLinks}{a CustomPageWebLinkTranslation} +#' \item{customTabs}{a CustomTabTranslation} +#' \item{flowDefinitions}{a FlowDefinitionTranslation} +#' \item{quickActions}{a GlobalQuickActionTranslation} +#' \item{reportTypes}{a ReportTypeTranslation} +#' \item{scontrols}{a ScontrolTranslation} +#' } +#' +#' \strong{UiFormulaCriterion} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiformulacriterion.htm}{Salesforce Documentation for UiFormulaCriterion} +#' \describe{ +#' \item{leftValue}{a character} +#' \item{operator}{a character} +#' \item{rightValue}{a character} +#' } +#' +#' \strong{UiFormulaRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiformularule.htm}{Salesforce Documentation for UiFormulaRule} +#' \describe{ +#' \item{booleanFilter}{a character} +#' \item{criteria}{a UiFormulaCriterion} +#' } +#' +#' \strong{UiPlugin} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiplugin.htm}{Salesforce Documentation for UiPlugin} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{description}{a character} +#' \item{extensionPointIdentifier}{a character} +#' \item{isEnabled}{a character either 'true' or 'false'} +#' \item{language}{a character} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{UserCriteria} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_usercriteria.htm}{Salesforce Documentation for UserCriteria} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{creationAgeInSeconds}{a integer} +#' \item{description}{a character} +#' \item{lastChatterActivityAgeInSeconds}{a integer} +#' \item{masterLabel}{a character} +#' \item{profiles}{a character} +#' \item{userTypes}{a NetworkUserType - which is a character taking one of the following values: +#' \itemize{ +#' \item{Internal} +#' \item{Customer} +#' \item{Partner} +#' } +#' } +#' } +#' +#' \strong{Users} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_users.htm}{Salesforce Documentation for Users} +#' \describe{ +#' \item{user}{a character} +#' } +#' +#' \strong{ValidationRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_validationrule.htm}{Salesforce Documentation for ValidationRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{active}{a character either 'true' or 'false'} +#' \item{description}{a character} +#' \item{errorConditionFormula}{a character} +#' \item{errorDisplayField}{a character} +#' \item{errorMessage}{a character} +#' } +#' +#' \strong{ValidationRuleTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_validationruletranslation.htm}{Salesforce Documentation for ValidationRuleTranslation} +#' \describe{ +#' \item{errorMessage}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{ValueSet} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_valueset.htm}{Salesforce Documentation for ValueSet} +#' \describe{ +#' \item{controllingField}{a character} +#' \item{restricted}{a character either 'true' or 'false'} +#' \item{valueSetDefinition}{a ValueSetValuesDefinition} +#' \item{valueSetName}{a character} +#' \item{valueSettings}{a ValueSettings} +#' } +#' +#' \strong{ValueSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_valuesettings.htm}{Salesforce Documentation for ValueSettings} +#' \describe{ +#' \item{controllingFieldValue}{a character} +#' \item{valueName}{a character} +#' } +#' +#' \strong{ValueSetValuesDefinition} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_valuesetvaluesdefinition.htm}{Salesforce Documentation for ValueSetValuesDefinition} +#' \describe{ +#' \item{sorted}{a character either 'true' or 'false'} +#' \item{value}{a CustomValue} +#' } +#' +#' \strong{ValueTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_valuetranslation.htm}{Salesforce Documentation for ValueTranslation} +#' \describe{ +#' \item{masterLabel}{a character} +#' \item{translation}{a character} +#' } +#' +#' \strong{ValueTypeField} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_valuetypefield.htm}{Salesforce Documentation for ValueTypeField} +#' \describe{ +#' \item{fields}{a ValueTypeField} +#' \item{foreignKeyDomain}{a character} +#' \item{isForeignKey}{a character either 'true' or 'false'} +#' \item{isNameField}{a character either 'true' or 'false'} +#' \item{minOccurs}{a integer} +#' \item{name}{a character} +#' \item{picklistValues}{a PicklistEntry} +#' \item{soapType}{a character} +#' \item{valueRequired}{a character either 'true' or 'false'} +#' } +#' +#' \strong{VisualizationPlugin} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_visualizationplugin.htm}{Salesforce Documentation for VisualizationPlugin} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{description}{a character} +#' \item{developerName}{a character} +#' \item{icon}{a character} +#' \item{masterLabel}{a character} +#' \item{visualizationResources}{a VisualizationResource} +#' \item{visualizationTypes}{a VisualizationType} +#' } +#' +#' \strong{VisualizationResource} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_visualizationresource.htm}{Salesforce Documentation for VisualizationResource} +#' \describe{ +#' \item{description}{a character} +#' \item{file}{a character} +#' \item{rank}{a integer} +#' \item{type}{a VisualizationResourceType - which is a character taking one of the following values: +#' \itemize{ +#' \item{js} +#' \item{css} +#' } +#' } +#' } +#' +#' \strong{VisualizationType} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_visualizationtype.htm}{Salesforce Documentation for VisualizationType} +#' \describe{ +#' \item{description}{a character} +#' \item{developerName}{a character} +#' \item{icon}{a character} +#' \item{masterLabel}{a character} +#' \item{scriptBootstrapMethod}{a character} +#' } +#' +#' \strong{WaveApplication} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_waveapplication.htm}{Salesforce Documentation for WaveApplication} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assetIcon}{a character} +#' \item{description}{a character} +#' \item{folder}{a character} +#' \item{masterLabel}{a character} +#' \item{shares}{a FolderShare} +#' \item{templateOrigin}{a character} +#' \item{templateVersion}{a character} +#' } +#' +#' \strong{WaveDashboard} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavedashboard.htm}{Salesforce Documentation for WaveDashboard} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{application}{a character} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{templateAssetSourceName}{a character} +#' } +#' +#' \strong{WaveDataflow} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavedataflow.htm}{Salesforce Documentation for WaveDataflow} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{dataflowType}{a character} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' } +#' +#' \strong{WaveDataset} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavedataset.htm}{Salesforce Documentation for WaveDataset} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{application}{a character} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{templateAssetSourceName}{a character} +#' } +#' +#' \strong{WaveLens} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavelens.htm}{Salesforce Documentation for WaveLens} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{application}{a character} +#' \item{datasets}{a character} +#' \item{description}{a character} +#' \item{masterLabel}{a character} +#' \item{templateAssetSourceName}{a character} +#' \item{visualizationType}{a character} +#' } +#' +#' \strong{WaveRecipe} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_waverecipe.htm}{Salesforce Documentation for WaveRecipe} +#' \describe{ +#' \item{content}{a character formed using RCurl::base64Encode (inherited from MetadataWithContent)} +#' \item{dataflow}{a character} +#' \item{masterLabel}{a character} +#' \item{securityPredicate}{a character} +#' \item{targetDatasetAlias}{a character} +#' } +#' +#' \strong{WaveTemplateBundle} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavetemplatebundle.htm}{Salesforce Documentation for WaveTemplateBundle} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{assetIcon}{a character} +#' \item{assetVersion}{a numeric} +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{templateBadgeIcon}{a character} +#' \item{templateDetailIcon}{a character} +#' \item{templateType}{a character} +#' } +#' +#' \strong{WaveXmd} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmd.htm}{Salesforce Documentation for WaveXmd} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{application}{a character} +#' \item{dataset}{a character} +#' \item{datasetConnector}{a character} +#' \item{datasetFullyQualifiedName}{a character} +#' \item{dates}{a WaveXmdDate} +#' \item{dimensions}{a WaveXmdDimension} +#' \item{measures}{a WaveXmdMeasure} +#' \item{organizations}{a WaveXmdOrganization} +#' \item{origin}{a character} +#' \item{type}{a character} +#' \item{waveVisualization}{a character} +#' } +#' +#' \strong{WaveXmdDate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmddate.htm}{Salesforce Documentation for WaveXmdDate} +#' \describe{ +#' \item{alias}{a character} +#' \item{compact}{a character either 'true' or 'false'} +#' \item{dateFieldDay}{a character} +#' \item{dateFieldEpochDay}{a character} +#' \item{dateFieldEpochSecond}{a character} +#' \item{dateFieldFiscalMonth}{a character} +#' \item{dateFieldFiscalQuarter}{a character} +#' \item{dateFieldFiscalWeek}{a character} +#' \item{dateFieldFiscalYear}{a character} +#' \item{dateFieldFullYear}{a character} +#' \item{dateFieldHour}{a character} +#' \item{dateFieldMinute}{a character} +#' \item{dateFieldMonth}{a character} +#' \item{dateFieldQuarter}{a character} +#' \item{dateFieldSecond}{a character} +#' \item{dateFieldWeek}{a character} +#' \item{dateFieldYear}{a character} +#' \item{description}{a character} +#' \item{firstDayOfWeek}{a integer} +#' \item{fiscalMonthOffset}{a integer} +#' \item{isYearEndFiscalYear}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{showInExplorer}{a character either 'true' or 'false'} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdDimension} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmddimension.htm}{Salesforce Documentation for WaveXmdDimension} +#' \describe{ +#' \item{customActions}{a WaveXmdDimensionCustomAction} +#' \item{customActionsEnabled}{a character either 'true' or 'false'} +#' \item{dateFormat}{a character} +#' \item{description}{a character} +#' \item{field}{a character} +#' \item{fullyQualifiedName}{a character} +#' \item{imageTemplate}{a character} +#' \item{isDerived}{a character either 'true' or 'false'} +#' \item{isMultiValue}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{linkTemplate}{a character} +#' \item{linkTemplateEnabled}{a character either 'true' or 'false'} +#' \item{linkTooltip}{a character} +#' \item{members}{a WaveXmdDimensionMember} +#' \item{origin}{a character} +#' \item{recordDisplayFields}{a WaveXmdRecordDisplayLookup} +#' \item{recordIdField}{a character} +#' \item{recordOrganizationIdField}{a character} +#' \item{salesforceActions}{a WaveXmdDimensionSalesforceAction} +#' \item{salesforceActionsEnabled}{a character either 'true' or 'false'} +#' \item{showDetailsDefaultFieldIndex}{a integer} +#' \item{showInExplorer}{a character either 'true' or 'false'} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdDimensionCustomAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmddimensioncustomaction.htm}{Salesforce Documentation for WaveXmdDimensionCustomAction} +#' \describe{ +#' \item{customActionName}{a character} +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{icon}{a character} +#' \item{method}{a character} +#' \item{sortIndex}{a integer} +#' \item{target}{a character} +#' \item{tooltip}{a character} +#' \item{url}{a character} +#' } +#' +#' \strong{WaveXmdDimensionMember} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmddimensionmember.htm}{Salesforce Documentation for WaveXmdDimensionMember} +#' \describe{ +#' \item{color}{a character} +#' \item{label}{a character} +#' \item{member}{a character} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdDimensionSalesforceAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmddimensionsalesforceaction.htm}{Salesforce Documentation for WaveXmdDimensionSalesforceAction} +#' \describe{ +#' \item{enabled}{a character either 'true' or 'false'} +#' \item{salesforceActionName}{a character} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdMeasure} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmdmeasure.htm}{Salesforce Documentation for WaveXmdMeasure} +#' \describe{ +#' \item{dateFormat}{a character} +#' \item{description}{a character} +#' \item{field}{a character} +#' \item{formatCustomFormat}{a character} +#' \item{formatDecimalDigits}{a integer} +#' \item{formatIsNegativeParens}{a character either 'true' or 'false'} +#' \item{formatPrefix}{a character} +#' \item{formatSuffix}{a character} +#' \item{formatUnit}{a character} +#' \item{formatUnitMultiplier}{a numeric} +#' \item{fullyQualifiedName}{a character} +#' \item{isDerived}{a character either 'true' or 'false'} +#' \item{label}{a character} +#' \item{origin}{a character} +#' \item{showDetailsDefaultFieldIndex}{a integer} +#' \item{showInExplorer}{a character either 'true' or 'false'} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdOrganization} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmdorganization.htm}{Salesforce Documentation for WaveXmdOrganization} +#' \describe{ +#' \item{instanceUrl}{a character} +#' \item{label}{a character} +#' \item{organizationIdentifier}{a character} +#' \item{sortIndex}{a integer} +#' } +#' +#' \strong{WaveXmdRecordDisplayLookup} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_wavexmdrecorddisplaylookup.htm}{Salesforce Documentation for WaveXmdRecordDisplayLookup} +#' \describe{ +#' \item{recordDisplayField}{a character} +#' } +#' +#' \strong{WebLink} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_weblink.htm}{Salesforce Documentation for WebLink} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{availability}{a WebLinkAvailability - which is a character taking one of the following values: +#' \itemize{ +#' \item{online} +#' \item{offline} +#' } +#' } +#' \item{description}{a character} +#' \item{displayType}{a WebLinkDisplayType - which is a character taking one of the following values: +#' \itemize{ +#' \item{link} +#' \item{button} +#' \item{massActionButton} +#' } +#' } +#' \item{encodingKey}{a Encoding - which is a character taking one of the following values: +#' \itemize{ +#' \item{UTF-8} +#' \item{ISO-8859-1} +#' \item{Shift_JIS} +#' \item{ISO-2022-JP} +#' \item{EUC-JP} +#' \item{ks_c_5601-1987} +#' \item{Big5} +#' \item{GB2312} +#' \item{Big5-HKSCS} +#' \item{x-SJIS_0213} +#' } +#' } +#' \item{hasMenubar}{a character either 'true' or 'false'} +#' \item{hasScrollbars}{a character either 'true' or 'false'} +#' \item{hasToolbar}{a character either 'true' or 'false'} +#' \item{height}{a integer} +#' \item{isResizable}{a character either 'true' or 'false'} +#' \item{linkType}{a WebLinkType - which is a character taking one of the following values: +#' \itemize{ +#' \item{url} +#' \item{sControl} +#' \item{javascript} +#' \item{page} +#' \item{flow} +#' } +#' } +#' \item{masterLabel}{a character} +#' \item{openType}{a WebLinkWindowType - which is a character taking one of the following values: +#' \itemize{ +#' \item{newWindow} +#' \item{sidebar} +#' \item{noSidebar} +#' \item{replace} +#' \item{onClickJavaScript} +#' } +#' } +#' \item{page}{a character} +#' \item{position}{a WebLinkPosition - which is a character taking one of the following values: +#' \itemize{ +#' \item{fullScreen} +#' \item{none} +#' \item{topLeft} +#' } +#' } +#' \item{protected}{a character either 'true' or 'false'} +#' \item{requireRowSelection}{a character either 'true' or 'false'} +#' \item{scontrol}{a character} +#' \item{showsLocation}{a character either 'true' or 'false'} +#' \item{showsStatus}{a character either 'true' or 'false'} +#' \item{url}{a character} +#' \item{width}{a integer} +#' } +#' +#' \strong{WebLinkTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_weblinktranslation.htm}{Salesforce Documentation for WebLinkTranslation} +#' \describe{ +#' \item{label}{a character} +#' \item{name}{a character} +#' } +#' +#' \strong{WebToCaseSettings} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_webtocasesettings.htm}{Salesforce Documentation for WebToCaseSettings} +#' \describe{ +#' \item{caseOrigin}{a character} +#' \item{defaultResponseTemplate}{a character} +#' \item{enableWebToCase}{a character either 'true' or 'false'} +#' } +#' +#' \strong{WeightedSourceCategory} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_weightedsourcecategory.htm}{Salesforce Documentation for WeightedSourceCategory} +#' \describe{ +#' \item{sourceCategoryApiName}{a character} +#' \item{weight}{a numeric} +#' } +#' +#' \strong{Workflow} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflow.htm}{Salesforce Documentation for Workflow} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{alerts}{a WorkflowAlert} +#' \item{fieldUpdates}{a WorkflowFieldUpdate} +#' \item{flowActions}{a WorkflowFlowAction} +#' \item{knowledgePublishes}{a WorkflowKnowledgePublish} +#' \item{outboundMessages}{a WorkflowOutboundMessage} +#' \item{rules}{a WorkflowRule} +#' \item{send}{a WorkflowSend} +#' \item{tasks}{a WorkflowTask} +#' } +#' +#' \strong{WorkflowAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowaction.htm}{Salesforce Documentation for WorkflowAction} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' } +#' +#' \strong{WorkflowActionReference} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowactionreference.htm}{Salesforce Documentation for WorkflowActionReference} +#' \describe{ +#' \item{name}{a character} +#' \item{type}{a WorkflowActionType - which is a character taking one of the following values: +#' \itemize{ +#' \item{FieldUpdate} +#' \item{KnowledgePublish} +#' \item{Task} +#' \item{Alert} +#' \item{Send} +#' \item{OutboundMessage} +#' \item{FlowAction} +#' } +#' } +#' } +#' +#' \strong{WorkflowAlert} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowalert.htm}{Salesforce Documentation for WorkflowAlert} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{ccEmails}{a character} +#' \item{description}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' \item{recipients}{a WorkflowEmailRecipient} +#' \item{senderAddress}{a character} +#' \item{senderType}{a ActionEmailSenderType - which is a character taking one of the following values: +#' \itemize{ +#' \item{CurrentUser} +#' \item{OrgWideEmailAddress} +#' \item{DefaultWorkflowUser} +#' } +#' } +#' \item{template}{a character} +#' } +#' +#' \strong{WorkflowEmailRecipient} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowemailrecipient.htm}{Salesforce Documentation for WorkflowEmailRecipient} +#' \describe{ +#' \item{field}{a character} +#' \item{recipient}{a character} +#' \item{type}{a ActionEmailRecipientTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{group} +#' \item{role} +#' \item{user} +#' \item{opportunityTeam} +#' \item{accountTeam} +#' \item{roleSubordinates} +#' \item{owner} +#' \item{creator} +#' \item{partnerUser} +#' \item{accountOwner} +#' \item{customerPortalUser} +#' \item{portalRole} +#' \item{portalRoleSubordinates} +#' \item{contactLookup} +#' \item{userLookup} +#' \item{roleSubordinatesInternal} +#' \item{email} +#' \item{caseTeam} +#' \item{campaignMemberDerivedOwner} +#' } +#' } +#' } +#' +#' \strong{WorkflowFieldUpdate} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowfieldupdate.htm}{Salesforce Documentation for WorkflowFieldUpdate} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{description}{a character} +#' \item{field}{a character} +#' \item{formula}{a character} +#' \item{literalValue}{a character} +#' \item{lookupValue}{a character} +#' \item{lookupValueType}{a LookupValueType - which is a character taking one of the following values: +#' \itemize{ +#' \item{User} +#' \item{Queue} +#' \item{RecordType} +#' } +#' } +#' \item{name}{a character} +#' \item{notifyAssignee}{a character either 'true' or 'false'} +#' \item{operation}{a FieldUpdateOperation - which is a character taking one of the following values: +#' \itemize{ +#' \item{Formula} +#' \item{Literal} +#' \item{Null} +#' \item{NextValue} +#' \item{PreviousValue} +#' \item{LookupValue} +#' } +#' } +#' \item{protected}{a character either 'true' or 'false'} +#' \item{reevaluateOnChange}{a character either 'true' or 'false'} +#' \item{targetObject}{a character} +#' } +#' +#' \strong{WorkflowFlowAction} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowflowaction.htm}{Salesforce Documentation for WorkflowFlowAction} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{description}{a character} +#' \item{flow}{a character} +#' \item{flowInputs}{a WorkflowFlowActionParameter} +#' \item{label}{a character} +#' \item{language}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' } +#' +#' \strong{WorkflowFlowActionParameter} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowflowactionparameter.htm}{Salesforce Documentation for WorkflowFlowActionParameter} +#' \describe{ +#' \item{name}{a character} +#' \item{value}{a character} +#' } +#' +#' \strong{WorkflowKnowledgePublish} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowknowledgepublish.htm}{Salesforce Documentation for WorkflowKnowledgePublish} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{action}{a KnowledgeWorkflowAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{PublishAsNew} +#' \item{Publish} +#' } +#' } +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{language}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' } +#' +#' \strong{WorkflowRule} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowrule.htm}{Salesforce Documentation for WorkflowRule} +#' \describe{ +#' \item{fullName}{a character (inherited from Metadata)} +#' \item{actions}{a WorkflowActionReference} +#' \item{active}{a character either 'true' or 'false'} +#' \item{booleanFilter}{a character} +#' \item{criteriaItems}{a FilterItem} +#' \item{description}{a character} +#' \item{formula}{a character} +#' \item{triggerType}{a WorkflowTriggerTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{onCreateOnly} +#' \item{onCreateOrTriggeringUpdate} +#' \item{onAllChanges} +#' \item{OnRecursiveUpdate} +#' } +#' } +#' \item{workflowTimeTriggers}{a WorkflowTimeTrigger} +#' } +#' +#' \strong{WorkflowSend} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowsend.htm}{Salesforce Documentation for WorkflowSend} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{action}{a SendAction - which is a character taking one of the following values: +#' \itemize{ +#' \item{Send} +#' } +#' } +#' \item{description}{a character} +#' \item{label}{a character} +#' \item{language}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' } +#' +#' \strong{WorkflowTask} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowtask.htm}{Salesforce Documentation for WorkflowTask} +#' \describe{ +#' \item{extends WorkflowAction}{see documentation for WorkflowAction} +#' \item{assignedTo}{a character} +#' \item{assignedToType}{a ActionTaskAssignedToTypes - which is a character taking one of the following values: +#' \itemize{ +#' \item{user} +#' \item{role} +#' \item{opportunityTeam} +#' \item{accountTeam} +#' \item{owner} +#' \item{accountOwner} +#' \item{creator} +#' \item{accountCreator} +#' \item{partnerUser} +#' \item{portalRole} +#' } +#' } +#' \item{description}{a character} +#' \item{dueDateOffset}{a integer} +#' \item{notifyAssignee}{a character either 'true' or 'false'} +#' \item{offsetFromField}{a character} +#' \item{priority}{a character} +#' \item{protected}{a character either 'true' or 'false'} +#' \item{status}{a character} +#' \item{subject}{a character} +#' } +#' +#' \strong{WorkflowTaskTranslation} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowtasktranslation.htm}{Salesforce Documentation for WorkflowTaskTranslation} +#' \describe{ +#' \item{description}{a character} +#' \item{name}{a character} +#' \item{subject}{a character} +#' } +#' +#' \strong{WorkflowTimeTrigger} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflowtimetrigger.htm}{Salesforce Documentation for WorkflowTimeTrigger} +#' \describe{ +#' \item{actions}{a WorkflowActionReference} +#' \item{offsetFromField}{a character} +#' \item{timeLength}{a character} +#' \item{workflowTimeTriggerUnit}{a WorkflowTimeUnits - which is a character taking one of the following values: +#' \itemize{ +#' \item{Hours} +#' \item{Days} +#' } +#' } +#' } +#' +#' \strong{WorkspaceMapping} +#' +#' +#' \href{https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workspacemapping.htm}{Salesforce Documentation for WorkspaceMapping} +#' \describe{ +#' \item{fieldName}{a character} +#' \item{tab}{a character} +#' } +#' +#' @param obj_type a string from one of the object types described above +#' @param obj_data a \code{list} of \code{lists} or a \code{data.frame} with the required inputs to create the +#' the obj_type specified. +#' @return a \code{list} that can be used as input to one of the CRUD Metadata API +#' operations: \link{sf_create_metadata}, \link{sf_update_metadata}, \link{sf_update_metadata} +#' @export +metadata_type_validator <- function(obj_type, obj_data){ + + stopifnot(length(obj_data) > 0) + stopifnot(is.list(obj_data) | is.data.frame(obj_data)) + + if(is.data.frame(obj_data)) + obj_data <- split(obj_data, seq(nrow(obj_data))) + if(typeof(obj_data[[1]]) != "list") + obj_data <- list(obj_data) + + acceptable_inputs <- valid_metadata_list()[[obj_type]] + + if(length(acceptable_inputs) < 1) + stop(paste0("No input validation could be found for the obj_type specified: ", obj_type)) + + new_obj_data <- list() + counter <- 1 + for (e in 1:length(obj_data)){ + # pull out only the acceptable inputs, just ignore the rest + obj_data[[e]] <- obj_data[[e]][names(obj_data[[e]]) %in% acceptable_inputs] + # reorder according to WSDL since order matters + matched_order <- order(match(names(obj_data[[e]]), acceptable_inputs)) + + # if(all(is.na(matched_order))) + # warning(paste0("Some of the records were dropped because their inputs did not match the acceptable inputs for the specified data type:", obj_type)) + + obj_data[[e]] <- obj_data[[e]][matched_order[!is.na(matched_order)]] + + # add to the final formatted object if it is a record with some valid input elements + if(length(obj_data[[e]]) > 0){ + new_obj_data[[counter]] <- obj_data[[e]] + counter <- counter + 1 + } + } + + return(new_obj_data) +} + +#' List of Valid Data Types +#' +#' A list of data types that are valid for the Metadata API service. +#' +#' @return code{list}; contains name and valid inputs for data types +#' @export +valid_metadata_list <- function(){ + + reference_list <- list( + "AccessMapping"=c('accessLevel','object','objectField','userField'), + "AccountSettings"=c('fullName','enableAccountOwnerReport','enableAccountTeams','showViewHierarchyLink'), + "AccountSharingRuleSettings"=c('caseAccessLevel','contactAccessLevel','opportunityAccessLevel'), + "ActionLinkGroupTemplate"=c('fullName','actionLinkTemplates','category','executionsAllowed','hoursUntilExpiration','isPublished','name'), + "ActionLinkTemplate"=c('actionUrl','headers','isConfirmationRequired','isGroupDefault','label','labelKey','linkType','method','position','requestBody','userAlias','userVisibility'), + "ActionOverride"=c('actionName','comment','content','formFactor','skipRecordTypeSelect','type'), + "ActivitiesSettings"=c('fullName','allowUsersToRelateMultipleContactsToTasksAndEvents','autoRelateEventAttendees','enableActivityReminders','enableClickCreateEvents','enableDragAndDropScheduling','enableEmailTracking','enableGroupTasks','enableListViewScheduling','enableLogNote','enableMultidayEvents','enableRecurringEvents','enableRecurringTasks','enableSidebarCalendarShortcut','enableSimpleTaskCreateUI','enableUNSTaskDelegatedToNotifications','meetingRequestsLogo','showCustomLogoMeetingRequests','showEventDetailsMultiUserCalendar','showHomePageHoverLinksForEvents','showMyTasksHoverLinks'), + "AddressSettings"=c('fullName','countriesAndStates'), + "AdjustmentsSettings"=c('enableAdjustments','enableOwnerAdjustments'), + "AgentConfigAssignments"=c('profiles','users'), + "AgentConfigButtons"=c('button'), + "AgentConfigProfileAssignments"=c('profile'), + "AgentConfigSkills"=c('skill'), + "AgentConfigUserAssignments"=c('user'), + "AnalyticsCloudComponentLayoutItem"=c('assetType','devName','error','filter','height','hideOnError','showHeader','showSharing','showTitle','width'), + "AnalyticSnapshot"=c('fullName','description','groupColumn','mappings','name','runningUser','sourceReport','targetObject'), + "AnalyticSnapshotMapping"=c('aggregateType','sourceField','sourceType','targetField'), + "ApexClass"=c('content','apiVersion','packageVersions','status'), + "ApexComponent"=c('content','apiVersion','description','label','packageVersions'), + "ApexPage"=c('content','apiVersion','availableInTouch','confirmationTokenRequired','description','label','packageVersions'), + "ApexTestSuite"=c('fullName','testClassName'), + "ApexTrigger"=c('content','apiVersion','packageVersions','status'), + "AppActionOverride"=c('actionName','comment','content','formFactor','skipRecordTypeSelect','type','pageOrSobjectType'), + "AppBrand"=c('footerColor','headerColor','logo','logoVersion','shouldOverrideOrgTheme'), + "AppComponentList"=c('alignment','components'), + "AppMenu"=c('fullName','appMenuItems'), + "AppMenuItem"=c('name','type'), + "AppPreferences"=c('enableCustomizeMyTabs','enableKeyboardShortcuts','enableListViewHover','enableListViewReskin','enableMultiMonitorComponents','enablePinTabs','enableTabHover','enableTabLimits','saveUserSessions'), + "AppProfileActionOverride"=c('actionName','content','formFactor','pageOrSobjectType','recordType','type','profile'), + "ApprovalAction"=c('action'), + "ApprovalEntryCriteria"=c('booleanFilter','criteriaItems','formula'), + "ApprovalPageField"=c('field'), + "ApprovalProcess"=c('fullName','active','allowRecall','allowedSubmitters','approvalPageFields','approvalStep','description','emailTemplate','enableMobileDeviceAccess','entryCriteria','finalApprovalActions','finalApprovalRecordLock','finalRejectionActions','finalRejectionRecordLock','initialSubmissionActions','label','nextAutomatedApprover','postTemplate','recallActions','recordEditability','showApprovalHistory'), + "ApprovalStep"=c('allowDelegate','approvalActions','assignedApprover','description','entryCriteria','ifCriteriaNotMet','label','name','rejectBehavior','rejectionActions'), + "ApprovalStepApprover"=c('approver','whenMultipleApprovers'), + "ApprovalStepRejectBehavior"=c('type'), + "ApprovalSubmitter"=c('submitter','type'), + "Approver"=c('name','type'), + "AppWorkspaceConfig"=c('mappings'), + "ArticleTypeChannelDisplay"=c('articleTypeTemplates'), + "ArticleTypeTemplate"=c('channel','page','template'), + "AssignmentRule"=c('fullName','active','ruleEntry'), + "AssignmentRules"=c('fullName','assignmentRule'), + "AssistantRecommendationType"=c('fullName','description','masterLabel','platformActionlist','sobjectType','title'), + "Attachment"=c('content','name'), + "AuraDefinitionBundle"=c('fullName','SVGContent','apiVersion','controllerContent','description','designContent','documentationContent','helperContent','markup','modelContent','packageVersions','rendererContent','styleContent','testsuiteContent','type'), + "AuthProvider"=c('fullName','authorizeUrl','consumerKey','consumerSecret','customMetadataTypeRecord','defaultScopes','errorUrl','executionUser','friendlyName','iconUrl','idTokenIssuer','includeOrgIdInIdentifier','logoutUrl','plugin','portal','providerType','registrationHandler','sendAccessTokenInHeader','sendClientCredentialsInHeader','tokenUrl','userInfoUrl'), + "AutoResponseRule"=c('fullName','active','ruleEntry'), + "AutoResponseRules"=c('fullName','autoResponseRule'), + "BrandingSet"=c('fullName','brandingSetProperty','description','masterLabel','type'), + "BrandingSetProperty"=c('propertyName','propertyValue'), + "BusinessHoursEntry"=c('fullName','active','default','fridayEndTime','fridayStartTime','mondayEndTime','mondayStartTime','name','saturdayEndTime','saturdayStartTime','sundayEndTime','sundayStartTime','thursdayEndTime','thursdayStartTime','timeZoneId','tuesdayEndTime','tuesdayStartTime','wednesdayEndTime','wednesdayStartTime'), + "BusinessHoursSettings"=c('fullName','businessHours','holidays'), + "BusinessProcess"=c('fullName','description','isActive','values'), + "CallCenter"=c('fullName','adapterUrl','customSettings','displayName','displayNameLabel','internalNameLabel','sections','version'), + "CallCenterItem"=c('label','name','value'), + "CallCenterSection"=c('items','label','name'), + "CampaignInfluenceModel"=c('fullName','isActive','isDefaultModel','isModelLocked','modelDescription','name','recordPreference'), + "CaseSettings"=c('fullName','caseAssignNotificationTemplate','caseCloseNotificationTemplate','caseCommentNotificationTemplate','caseCreateNotificationTemplate','caseFeedItemSettings','closeCaseThroughStatusChange','defaultCaseOwner','defaultCaseOwnerType','defaultCaseUser','emailActionDefaultsHandlerClass','emailToCase','enableCaseFeed','enableDraftEmails','enableEarlyEscalationRuleTriggers','enableEmailActionDefaultsHandler','enableSuggestedArticlesApplication','enableSuggestedArticlesCustomerPortal','enableSuggestedArticlesPartnerPortal','enableSuggestedSolutions','keepRecordTypeOnAssignmentRule','notifyContactOnCaseComment','notifyDefaultCaseOwner','notifyOwnerOnCaseComment','notifyOwnerOnCaseOwnerChange','showEmailAttachmentsInCaseAttachmentsRL','showFewerCloseActions','systemUserEmail','useSystemEmailAddress','useSystemUserAsDefaultCaseUser','webToCase'), + "CaseSubjectParticle"=c('fullName','index','textField','type'), + "Certificate"=c('content','caSigned','encryptedWithPlatformEncryption','expirationDate','keySize','masterLabel','privateKeyExportable'), + "ChannelLayout"=c('fullName','enabledChannels','label','layoutItems','recordType'), + "ChannelLayoutItem"=c('field'), + "ChartSummary"=c('aggregate','axisBinding','column'), + "ChatterAnswersReputationLevel"=c('name','value'), + "ChatterAnswersSettings"=c('fullName','emailFollowersOnBestAnswer','emailFollowersOnReply','emailOwnerOnPrivateReply','emailOwnerOnReply','enableAnswerViaEmail','enableChatterAnswers','enableFacebookSSO','enableInlinePublisher','enableReputation','enableRichTextEditor','facebookAuthProvider','showInPortals'), + "ChatterExtension"=c('fullName','compositionComponent','description','extensionName','headerText','hoverText','icon','isProtected','masterLabel','renderComponent','type'), + "ChatterMobileSettings"=c('enablePushNotifications'), + "CleanDataService"=c('fullName','cleanRules','description','masterLabel','matchEngine'), + "CleanRule"=c('bulkEnabled','bypassTriggers','bypassWorkflow','description','developerName','fieldMappings','masterLabel','matchRule','sourceSobjectType','status','targetSobjectType'), + "CodeLocation"=c('column','line','numExecutions','time'), + "Community"=c('fullName','active','chatterAnswersFacebookSsoUrl','communityFeedPage','dataCategoryName','description','emailFooterDocument','emailHeaderDocument','emailNotificationUrl','enableChatterAnswers','enablePrivateQuestions','expertsGroup','portal','reputationLevels','showInPortal','site'), + "CommunityCustomThemeLayoutType"=c('description','label'), + "CommunityRoles"=c('customerUserRole','employeeUserRole','partnerUserRole'), + "CommunityTemplateBundleInfo"=c('description','image','order','title','type'), + "CommunityTemplateDefinition"=c('fullName','baseTemplate','bundlesInfo','category','defaultBrandingSet','defaultThemeDefinition','description','enableExtendedCleanUpOnDelete','masterLabel','navigationLinkSet','pageSetting'), + "CommunityTemplatePageSetting"=c('page','themeLayout'), + "CommunityThemeDefinition"=c('fullName','customThemeLayoutType','description','enableExtendedCleanUpOnDelete','masterLabel','themeSetting'), + "CommunityThemeSetting"=c('customThemeLayoutType','themeLayout','themeLayoutType'), + "CompactLayout"=c('fullName','fields','label'), + "CompanySettings"=c('fullName','fiscalYear'), + "ComponentInstance"=c('componentInstanceProperties','componentName','visibilityRule'), + "ComponentInstanceProperty"=c('name','type','value'), + "ConnectedApp"=c('fullName','attributes','canvasConfig','contactEmail','contactPhone','description','iconUrl','infoUrl','ipRanges','label','logoUrl','mobileAppConfig','mobileStartUrl','oauthConfig','plugin','samlConfig','startUrl'), + "ConnectedAppAttribute"=c('formula','key'), + "ConnectedAppCanvasConfig"=c('accessMethod','canvasUrl','lifecycleClass','locations','options','samlInitiationMethod'), + "ConnectedAppIpRange"=c('description','end','start'), + "ConnectedAppMobileDetailConfig"=c('applicationBinaryFile','applicationBinaryFileName','applicationBundleIdentifier','applicationFileLength','applicationIconFile','applicationIconFileName','applicationInstallUrl','devicePlatform','deviceType','minimumOsVersion','privateApp','version'), + "ConnectedAppOauthConfig"=c('callbackUrl','certificate','consumerKey','consumerSecret','scopes','singleLogoutUrl'), + "ConnectedAppSamlConfig"=c('acsUrl','certificate','encryptionCertificate','encryptionType','entityUrl','issuer','samlIdpSLOBindingEnum','samlNameIdFormat','samlSloUrl','samlSubjectCustomAttr','samlSubjectType'), + "Container"=c('height','isContainerAutoSizeEnabled','region','sidebarComponents','style','unit','width'), + "ContentAsset"=c('content','format','language','masterLabel','originNetwork','relationships','versions'), + "ContentAssetLink"=c('access','isManagingWorkspace','name'), + "ContentAssetRelationships"=c('insightsApplication','network','organization','workspace'), + "ContentAssetVersion"=c('number','pathOnClient','zipEntry'), + "ContentAssetVersions"=c('version'), + "ContractSettings"=c('fullName','autoCalculateEndDate','autoExpirationDelay','autoExpirationRecipient','autoExpireContracts','enableContractHistoryTracking','notifyOwnersOnContractExpiration'), + "CorsWhitelistOrigin"=c('fullName','urlPattern'), + "CountriesAndStates"=c('countries'), + "Country"=c('active','integrationValue','isoCode','label','orgDefault','standard','states','visible'), + "CspTrustedSite"=c('fullName','description','endpointUrl','isActive'), + "CustomApplication"=c('fullName','actionOverrides','brand','consoleConfig','defaultLandingTab','description','formFactors','isServiceCloudConsole','label','logo','navType','preferences','profileActionOverrides','setupExperience','subscriberTabs','tabs','uiType','utilityBar','workspaceConfig'), + "CustomApplicationComponent"=c('fullName','buttonIconUrl','buttonStyle','buttonText','buttonWidth','height','isHeightFixed','isHidden','isWidthFixed','visualforcePage','width'), + "CustomApplicationTranslation"=c('label','name'), + "CustomConsoleComponents"=c('primaryTabComponents','subtabComponents'), + "CustomDataType"=c('fullName','customDataTypeComponents','description','displayFormula','editComponentsOnSeparateLines','label','rightAligned','supportComponentsInReports'), + "CustomDataTypeComponent"=c('developerSuffix','enforceFieldRequiredness','label','length','precision','scale','sortOrder','sortPriority','type'), + "CustomDataTypeComponentTranslation"=c('developerSuffix','label'), + "CustomDataTypeTranslation"=c('components','customDataTypeName','description','label'), + "CustomExperience"=c('fullName','allowInternalUserLogin','branding','changePasswordEmailTemplate','emailFooterLogo','emailFooterText','emailSenderAddress','emailSenderName','enableErrorPageOverridesForVisualforce','forgotPasswordEmailTemplate','picassoSite','sObjectType','sendWelcomeEmail','site','siteAsContainerEnabled','tabs','urlPathPrefix','welcomeEmailTemplate'), + "CustomExperienceBranding"=c('loginFooterText','loginLogo','pageFooter','pageHeader','primaryColor','primaryComplementColor','quaternaryColor','quaternaryComplementColor','secondaryColor','tertiaryColor','tertiaryComplementColor','zeronaryColor','zeronaryComplementColor'), + "CustomExperienceTabSet"=c('customTab','defaultTab','standardTab'), + "CustomFeedFilter"=c('fullName','criteria','description','isProtected','label'), + "CustomField"=c('fullName','businessOwnerGroup','businessOwnerUser','businessStatus','caseSensitive','customDataType','defaultValue','deleteConstraint','deprecated','description','displayFormat','encrypted','escapeMarkup','externalDeveloperName','externalId','fieldManageability','formula','formulaTreatBlanksAs','inlineHelpText','isConvertLeadDisabled','isFilteringDisabled','isNameField','isSortingDisabled','label','length','lookupFilter','maskChar','maskType','metadataRelationshipControllingField','populateExistingRows','precision','referenceTargetField','referenceTo','relationshipLabel','relationshipName','relationshipOrder','reparentableMasterDetail','required','restrictedAdminField','scale','securityClassification','startingNumber','stripMarkup','summarizedField','summaryFilterItems','summaryForeignKey','summaryOperation','trackFeedHistory','trackHistory','trackTrending','type','unique','valueSet','visibleLines','writeRequiresMasterRead'), + "CustomFieldTranslation"=c('caseValues','gender','help','label','lookupFilter','name','picklistValues','relationshipLabel','startsWith'), + "CustomLabel"=c('fullName','categories','language','protected','shortDescription','value'), + "CustomLabels"=c('fullName','labels'), + "CustomLabelTranslation"=c('label','name'), + "CustomMetadata"=c('fullName','description','label','protected','values'), + "CustomMetadataValue"=c('field','value'), + "CustomNotificationType"=c('fullName','customNotifTypeName','description','desktop','email','masterLabel','mobile'), + "CustomObject"=c('fullName','actionOverrides','allowInChatterGroups','articleTypeChannelDisplay','businessProcesses','compactLayoutAssignment','compactLayouts','customHelp','customHelpPage','customSettingsType','dataStewardGroup','dataStewardUser','deploymentStatus','deprecated','description','enableActivities','enableBulkApi','enableChangeDataCapture','enableDivisions','enableEnhancedLookup','enableFeeds','enableHistory','enableReports','enableSearch','enableSharing','enableStreamingApi','eventType','externalDataSource','externalName','externalRepository','externalSharingModel','fieldSets','fields','gender','historyRetentionPolicy','household','indexes','label','listViews','nameField','pluralLabel','recordTypeTrackFeedHistory','recordTypeTrackHistory','recordTypes','searchLayouts','sharingModel','sharingReasons','sharingRecalculations','startsWith','validationRules','visibility','webLinks'), + "CustomObjectTranslation"=c('fullName','caseValues','fieldSets','fields','gender','layouts','nameFieldLabel','quickActions','recordTypes','sharingReasons','standardFields','startsWith','validationRules','webLinks','workflowTasks'), + "CustomPageWebLink"=c('fullName','availability','description','displayType','encodingKey','hasMenubar','hasScrollbars','hasToolbar','height','isResizable','linkType','masterLabel','openType','page','position','protected','requireRowSelection','scontrol','showsLocation','showsStatus','url','width'), + "CustomPageWebLinkTranslation"=c('label','name'), + "CustomPermission"=c('fullName','connectedApp','description','label','requiredPermission'), + "CustomPermissionDependencyRequired"=c('customPermission','dependency'), + "CustomShortcut"=c('action','active','keyCommand','description','eventName'), + "CustomSite"=c('fullName','active','allowHomePage','allowStandardAnswersPages','allowStandardIdeasPages','allowStandardLookups','allowStandardPortalPages','allowStandardSearch','analyticsTrackingCode','authorizationRequiredPage','bandwidthExceededPage','browserXssProtection','changePasswordPage','chatterAnswersForgotPasswordConfirmPage','chatterAnswersForgotPasswordPage','chatterAnswersHelpPage','chatterAnswersLoginPage','chatterAnswersRegistrationPage','clickjackProtectionLevel','contentSniffingProtection','cspUpgradeInsecureRequests','customWebAddresses','description','favoriteIcon','fileNotFoundPage','forgotPasswordPage','genericErrorPage','guestProfile','inMaintenancePage','inactiveIndexPage','indexPage','masterLabel','myProfilePage','portal','referrerPolicyOriginWhenCrossOrigin','requireHttps','requireInsecurePortalAccess','robotsTxtPage','rootComponent','selfRegPage','serverIsDown','siteAdmin','siteRedirectMappings','siteTemplate','siteType','subdomain','urlPathPrefix'), + "CustomTab"=c('fullName','actionOverrides','auraComponent','customObject','description','flexiPage','frameHeight','hasSidebar','icon','label','mobileReady','motif','page','scontrol','splashPageLink','url','urlEncodingKey'), + "CustomTabTranslation"=c('label','name'), + "CustomValue"=c('fullName','color','default','description','isActive','label'), + "Dashboard"=c('fullName','backgroundEndColor','backgroundFadeDirection','backgroundStartColor','chartTheme','colorPalette','dashboardChartTheme','dashboardColorPalette','dashboardFilters','dashboardGridLayout','dashboardResultRefreshedDate','dashboardResultRunningUser','dashboardType','description','folderName','isGridLayout','leftSection','middleSection','numSubscriptions','rightSection','runningUser','textColor','title','titleColor','titleSize'), + "DashboardComponent"=c('autoselectColumnsFromReport','chartAxisRange','chartAxisRangeMax','chartAxisRangeMin','chartSummary','componentChartTheme','componentType','dashboardFilterColumns','dashboardTableColumn','displayUnits','drillDownUrl','drillEnabled','drillToDetailEnabled','enableHover','expandOthers','flexComponentProperties','footer','gaugeMax','gaugeMin','groupingColumn','header','indicatorBreakpoint1','indicatorBreakpoint2','indicatorHighColor','indicatorLowColor','indicatorMiddleColor','legendPosition','maxValuesDisplayed','metricLabel','page','pageHeightInPixels','report','scontrol','scontrolHeightInPixels','showPercentage','showPicturesOnCharts','showPicturesOnTables','showRange','showTotal','showValues','sortBy','title','useReportChart'), + "DashboardComponentColumn"=c('breakPoint1','breakPoint2','breakPointOrder','highRangeColor','lowRangeColor','midRangeColor','reportColumn','showTotal','type'), + "DashboardComponentSection"=c('columnSize','components'), + "DashboardComponentSortInfo"=c('sortColumn','sortOrder'), + "DashboardFilter"=c('dashboardFilterOptions','name'), + "DashboardFilterColumn"=c('column'), + "DashboardFilterOption"=c('operator','values'), + "DashboardFlexTableComponentProperties"=c('flexTableColumn','flexTableSortInfo','hideChatterPhotos'), + "DashboardFolder"=c('accessType','folderShares','name','publicFolderAccess','sharedTo'), + "DashboardGridComponent"=c('colSpan','columnIndex','dashboardComponent','rowIndex','rowSpan'), + "DashboardGridLayout"=c('dashboardGridComponents','numberOfColumns','rowHeight'), + "DashboardMobileSettings"=c('enableDashboardIPadApp'), + "DashboardTableColumn"=c('aggregateType','calculatePercent','column','decimalPlaces','showTotal','sortBy'), + "DataCategory"=c('dataCategory','label','name'), + "DataCategoryGroup"=c('fullName','active','dataCategory','description','label','objectUsage'), + "DataPipeline"=c('content','apiVersion','label','scriptType'), + "DefaultShortcut"=c('action','active','keyCommand'), + "DelegateGroup"=c('fullName','customObjects','groups','label','loginAccess','permissionSets','profiles','roles'), + "DeployDetails"=c('componentFailures','componentSuccesses','retrieveResult','runTestResult'), + "DeployOptions"=c('allowMissingFiles','autoUpdatePackage','checkOnly','ignoreWarnings','performRetrieve','purgeOnDelete','rollbackOnError','runTests','singlePackage','testLevel'), + "DescribeMetadataObject"=c('childXmlNames','directoryName','inFolder','metaFile','suffix','xmlName'), + "Document"=c('content','description','internalUseOnly','keywords','name','public'), + "DocumentFolder"=c('accessType','folderShares','name','publicFolderAccess','sharedTo'), + "DuplicateRule"=c('fullName','actionOnInsert','actionOnUpdate','alertText','description','duplicateRuleFilter','duplicateRuleMatchRules','isActive','masterLabel','operationsOnInsert','operationsOnUpdate','securityOption','sortOrder'), + "DuplicateRuleFilter"=c('booleanFilter','duplicateRuleFilterItems'), + "DuplicateRuleFilterItem"=c('field','operation','value','valueField','sortOrder','table'), + "DuplicateRuleMatchRule"=c('matchRuleSObjectType','matchingRule','objectMapping'), + "EclairGeoData"=c('content','maps','masterLabel'), + "EclairMap"=c('boundingBoxBottom','boundingBoxLeft','boundingBoxRight','boundingBoxTop','mapLabel','mapName','projection'), + "EmailFolder"=c('accessType','folderShares','name','publicFolderAccess','sharedTo'), + "EmailServicesAddress"=c('authorizedSenders','developerName','isActive','localPart','runAsUser'), + "EmailServicesFunction"=c('fullName','apexClass','attachmentOption','authenticationFailureAction','authorizationFailureAction','authorizedSenders','emailServicesAddresses','errorRoutingAddress','functionInactiveAction','functionName','isActive','isAuthenticationRequired','isErrorRoutingEnabled','isTextAttachmentsAsBinary','isTlsRequired','overLimitAction'), + "EmailTemplate"=c('content','apiVersion','attachedDocuments','attachments','available','description','encodingKey','letterhead','name','packageVersions','relatedEntityType','style','subject','textOnly','type','uiType'), + "EmailToCaseRoutingAddress"=c('addressType','authorizedSenders','caseOrigin','caseOwner','caseOwnerType','casePriority','createTask','emailAddress','emailServicesAddress','isVerified','routingName','saveEmailHeaders','taskStatus'), + "EmailToCaseSettings"=c('enableE2CSourceTracking','enableEmailToCase','enableHtmlEmail','enableOnDemandEmailToCase','enableThreadIDInBody','enableThreadIDInSubject','notifyOwnerOnNewCaseEmail','overEmailLimitAction','preQuoteSignature','routingAddresses','unauthorizedSenderAction'), + "EmbeddedServiceBranding"=c('fullName','contrastInvertedColor','contrastPrimaryColor','embeddedServiceConfig','font','masterLabel','navBarColor','primaryColor','secondaryColor'), + "EmbeddedServiceConfig"=c('fullName','masterLabel','site'), + "EmbeddedServiceFieldService"=c('fullName','appointmentBookingFlowName','cancelApptBookingFlowName','embeddedServiceConfig','enabled','fieldServiceConfirmCardImg','fieldServiceHomeImg','fieldServiceLogoImg','masterLabel','modifyApptBookingFlowName','shouldShowExistingAppointment','shouldShowNewAppointment'), + "EmbeddedServiceLiveAgent"=c('fullName','avatarImg','customPrechatComponent','embeddedServiceConfig','embeddedServiceQuickActions','enabled','fontSize','headerBackgroundImg','liveAgentChatUrl','liveAgentContentUrl','liveChatButton','liveChatDeployment','masterLabel','prechatBackgroundImg','prechatEnabled','prechatJson','scenario','smallCompanyLogoImg','waitingStateBackgroundImg'), + "EmbeddedServiceQuickAction"=c('embeddedServiceLiveAgent','order','quickActionDefinition'), + "EntitlementProcess"=c('fullName','SObjectType','active','businessHours','description','entryStartDateField','exitCriteriaBooleanFilter','exitCriteriaFilterItems','exitCriteriaFormula','isRecordTypeApplied','isVersionDefault','milestones','name','recordType','versionMaster','versionNotes','versionNumber'), + "EntitlementProcessMilestoneItem"=c('businessHours','criteriaBooleanFilter','milestoneCriteriaFilterItems','milestoneCriteriaFormula','milestoneName','minutesCustomClass','minutesToComplete','successActions','timeTriggers','useCriteriaStartTime'), + "EntitlementProcessMilestoneTimeTrigger"=c('actions','timeLength','workflowTimeTriggerUnit'), + "EntitlementSettings"=c('fullName','assetLookupLimitedToActiveEntitlementsOnAccount','assetLookupLimitedToActiveEntitlementsOnContact','assetLookupLimitedToSameAccount','assetLookupLimitedToSameContact','enableEntitlementVersioning','enableEntitlements','entitlementLookupLimitedToActiveStatus','entitlementLookupLimitedToSameAccount','entitlementLookupLimitedToSameAsset','entitlementLookupLimitedToSameContact'), + "EntitlementTemplate"=c('fullName','businessHours','casesPerEntitlement','entitlementProcess','isPerIncident','term','type'), + "EscalationAction"=c('assignedTo','assignedToTemplate','assignedToType','minutesToEscalation','notifyCaseOwner','notifyEmail','notifyTo','notifyToTemplate'), + "EscalationRule"=c('fullName','active','ruleEntry'), + "EscalationRules"=c('fullName','escalationRule'), + "EventDelivery"=c('fullName','eventParameters','eventSubscription','referenceData','type'), + "EventParameterMap"=c('parameterName','parameterValue'), + "EventSubscription"=c('fullName','active','eventParameters','eventType','referenceData'), + "ExtendedErrorDetails"=c('extendedErrorCode'), + "ExternalDataSource"=c('fullName','authProvider','certificate','customConfiguration','endpoint','isWritable','label','oauthRefreshToken','oauthScope','oauthToken','password','principalType','protocol','repository','type','username','version'), + "ExternalServiceRegistration"=c('fullName','description','label','namedCredential','schema','schemaType','schemaUrl','status'), + "FeedFilterCriterion"=c('feedItemType','feedItemVisibility','relatedSObjectType'), + "FeedItemSettings"=c('characterLimit','collapseThread','displayFormat','feedItemType'), + "FeedLayout"=c('autocollapsePublisher','compactFeed','feedFilterPosition','feedFilters','fullWidthFeed','hideSidebar','highlightExternalFeedItems','leftComponents','rightComponents','useInlineFiltersInConsole'), + "FeedLayoutComponent"=c('componentType','height','page'), + "FeedLayoutFilter"=c('feedFilterName','feedFilterType','feedItemType'), + "FieldMapping"=c('SObjectType','developerName','fieldMappingRows','masterLabel'), + "FieldMappingField"=c('dataServiceField','dataServiceObjectName','priority'), + "FieldMappingRow"=c('SObjectType','fieldMappingFields','fieldName','mappingOperation'), + "FieldOverride"=c('field','formula','literalValue'), + "FieldServiceSettings"=c('fullName','fieldServiceNotificationsOrgPref','fieldServiceOrgPref','serviceAppointmentsDueDateOffsetOrgValue','workOrderLineItemSearchFields','workOrderSearchFields'), + "FieldSet"=c('fullName','availableFields','description','displayedFields','label'), + "FieldSetItem"=c('field','isFieldManaged','isRequired'), + "FieldSetTranslation"=c('label','name'), + "FieldValue"=c('name','value'), + "FileProperties"=c('createdById','createdByName','createdDate','fileName','fullName','id','lastModifiedById','lastModifiedByName','lastModifiedDate','manageableState','namespacePrefix','type'), + "FileTypeDispositionAssignmentBean"=c('behavior','fileType','securityRiskFileType'), + "FileUploadAndDownloadSecuritySettings"=c('fullName','dispositions','noHtmlUploadAsAttachment'), + "FilterItem"=c('field','operation','value','valueField'), + "FindSimilarOppFilter"=c('similarOpportunitiesDisplayColumns','similarOpportunitiesMatchFields'), + "FiscalYearSettings"=c('fiscalYearNameBasedOn','startMonth'), + "FlexiPage"=c('fullName','description','flexiPageRegions','masterLabel','parentFlexiPage','platformActionlist','quickActionList','sobjectType','template','type'), + "FlexiPageRegion"=c('appendable','componentInstances','mode','name','prependable','replaceable','type'), + "FlexiPageTemplateInstance"=c('name','properties'), + "Flow"=c('fullName','actionCalls','apexPluginCalls','assignments','choices','constants','decisions','description','dynamicChoiceSets','formulas','interviewLabel','label','loops','processMetadataValues','processType','recordCreates','recordDeletes','recordLookups','recordUpdates','screens','stages','startElementReference','steps','subflows','textTemplates','variables','waits'), + "FlowActionCall"=c('label','locationX','locationY','actionName','actionType','connector','faultConnector','inputParameters','outputParameters'), + "FlowActionCallInputParameter"=c('processMetadataValues','name','value'), + "FlowActionCallOutputParameter"=c('processMetadataValues','assignToReference','name'), + "FlowApexPluginCall"=c('label','locationX','locationY','apexClass','connector','faultConnector','inputParameters','outputParameters'), + "FlowApexPluginCallInputParameter"=c('processMetadataValues','name','value'), + "FlowApexPluginCallOutputParameter"=c('processMetadataValues','assignToReference','name'), + "FlowAssignment"=c('label','locationX','locationY','assignmentItems','connector'), + "FlowAssignmentItem"=c('processMetadataValues','assignToReference','operator','value'), + "FlowBaseElement"=c('processMetadataValues'), + "FlowCategory"=c('fullName','description','flowCategoryItems','masterLabel'), + "FlowCategoryItems"=c('flow'), + "FlowChoice"=c('description','name','choiceText','dataType','userInput','value'), + "FlowChoiceTranslation"=c('choiceText','name','userInput'), + "FlowChoiceUserInput"=c('processMetadataValues','isRequired','promptText','validationRule'), + "FlowChoiceUserInputTranslation"=c('promptText','validationRule'), + "FlowCondition"=c('processMetadataValues','leftValueReference','operator','rightValue'), + "FlowConnector"=c('processMetadataValues','targetReference'), + "FlowConstant"=c('description','name','dataType','value'), + "FlowDecision"=c('label','locationX','locationY','defaultConnector','defaultConnectorLabel','rules'), + "FlowDefinition"=c('fullName','activeVersionNumber','description','masterLabel'), + "FlowDefinitionTranslation"=c('flows','fullName','label'), + "FlowDynamicChoiceSet"=c('description','name','dataType','displayField','filters','limit','object','outputAssignments','picklistField','picklistObject','sortField','sortOrder','valueField'), + "FlowElement"=c('processMetadataValues','description','name'), + "FlowElementReferenceOrValue"=c('booleanValue','dateTimeValue','dateValue','elementReference','numberValue','stringValue'), + "FlowFormula"=c('description','name','dataType','expression','scale'), + "FlowInputFieldAssignment"=c('processMetadataValues','field','value'), + "FlowInputValidationRule"=c('errorMessage','formulaExpression'), + "FlowInputValidationRuleTranslation"=c('errorMessage'), + "FlowLoop"=c('label','locationX','locationY','assignNextValueToReference','collectionReference','iterationOrder','nextValueConnector','noMoreValuesConnector'), + "FlowMetadataValue"=c('name','value'), + "FlowNode"=c('description','name','label','locationX','locationY'), + "FlowOutputFieldAssignment"=c('processMetadataValues','assignToReference','field'), + "FlowRecordCreate"=c('label','locationX','locationY','assignRecordIdToReference','connector','faultConnector','inputAssignments','inputReference','object'), + "FlowRecordDelete"=c('label','locationX','locationY','connector','faultConnector','filters','inputReference','object'), + "FlowRecordFilter"=c('processMetadataValues','field','operator','value'), + "FlowRecordLookup"=c('label','locationX','locationY','assignNullValuesIfNoRecordsFound','connector','faultConnector','filters','object','outputAssignments','outputReference','queriedFields','sortField','sortOrder'), + "FlowRecordUpdate"=c('label','locationX','locationY','connector','faultConnector','filters','inputAssignments','inputReference','object'), + "FlowRule"=c('description','name','conditionLogic','conditions','connector','label'), + "FlowScreen"=c('label','locationX','locationY','allowBack','allowFinish','allowPause','connector','fields','helpText','pausedText','rules','showFooter','showHeader'), + "FlowScreenField"=c('description','name','choiceReferences','dataType','defaultSelectedChoiceReference','defaultValue','extensionName','fieldText','fieldType','helpText','inputParameters','isRequired','isVisible','outputParameters','scale','validationRule'), + "FlowScreenFieldInputParameter"=c('processMetadataValues','name','value'), + "FlowScreenFieldOutputParameter"=c('processMetadataValues','assignToReference','name'), + "FlowScreenFieldTranslation"=c('fieldText','helpText','name','validationRule'), + "FlowScreenRule"=c('processMetadataValues','conditionLogic','conditions','label','ruleActions'), + "FlowScreenRuleAction"=c('processMetadataValues','attribute','fieldReference','value'), + "FlowScreenTranslation"=c('fields','helpText','name','pausedText'), + "FlowStage"=c('description','name','isActive','label','stageOrder'), + "FlowStep"=c('label','locationX','locationY','connectors'), + "FlowSubflow"=c('label','locationX','locationY','connector','flowName','inputAssignments','outputAssignments'), + "FlowSubflowInputAssignment"=c('processMetadataValues','name','value'), + "FlowSubflowOutputAssignment"=c('processMetadataValues','assignToReference','name'), + "FlowTextTemplate"=c('description','name','text'), + "FlowTranslation"=c('choices','fullName','label','screens'), + "FlowVariable"=c('description','name','dataType','isCollection','isInput','isOutput','objectType','scale','value'), + "FlowWait"=c('label','locationX','locationY','defaultConnector','defaultConnectorLabel','faultConnector','waitEvents'), + "FlowWaitEvent"=c('description','name','conditionLogic','conditions','connector','eventType','inputParameters','label','outputParameters'), + "FlowWaitEventInputParameter"=c('processMetadataValues','name','value'), + "FlowWaitEventOutputParameter"=c('processMetadataValues','assignToReference','name'), + "Folder"=c('fullName','accessType','folderShares','name','publicFolderAccess','sharedTo'), + "FolderShare"=c('accessLevel','sharedTo','sharedToType'), + "ForecastingCategoryMapping"=c('forecastingItemCategoryApiName','weightedSourceCategories'), + "ForecastingDisplayedFamilySettings"=c('productFamily'), + "ForecastingSettings"=c('fullName','displayCurrency','enableForecasts','forecastingCategoryMappings','forecastingDisplayedFamilySettings','forecastingTypeSettings'), + "ForecastingTypeSettings"=c('active','adjustmentsSettings','displayedCategoryApiNames','forecastRangeSettings','forecastedCategoryApiNames','forecastingDateType','hasProductFamily','isAmount','isAvailable','isQuantity','managerAdjustableCategoryApiNames','masterLabel','name','opportunityListFieldsLabelMappings','opportunityListFieldsSelectedSettings','opportunityListFieldsUnselectedSettings','opportunitySplitName','ownerAdjustableCategoryApiNames','quotasSettings','territory2ModelName'), + "ForecastRangeSettings"=c('beginning','displaying','periodType'), + "GlobalPicklistValue"=c('fullName','color','default','description','isActive'), + "GlobalQuickActionTranslation"=c('label','name'), + "GlobalValueSet"=c('fullName','customValue','description','masterLabel','sorted'), + "GlobalValueSetTranslation"=c('fullName','valueTranslation'), + "Group"=c('fullName','doesIncludeBosses','name'), + "HistoryRetentionPolicy"=c('archiveAfterMonths','archiveRetentionYears','description'), + "Holiday"=c('activityDate','businessHours','description','endTime','isRecurring','name','recurrenceDayOfMonth','recurrenceDayOfWeek','recurrenceDayOfWeekMask','recurrenceEndDate','recurrenceInstance','recurrenceInterval','recurrenceMonthOfYear','recurrenceStartDate','recurrenceType','startTime'), + "HomePageComponent"=c('fullName','body','height','links','page','pageComponentType','showLabel','showScrollbars','width'), + "HomePageLayout"=c('fullName','narrowComponents','wideComponents'), + "IdeaReputationLevel"=c('name','value'), + "IdeasSettings"=c('fullName','enableChatterProfile','enableIdeaThemes','enableIdeas','enableIdeasReputation','halfLife','ideasProfilePage'), + "Index"=c('fullName','fields','label'), + "IndexField"=c('name','sortDirection'), + "InsightType"=c('fullName','defaultTrendType','description','isProtected','masterLabel','parentType','title'), + "InstalledPackage"=c('fullName','password','versionNumber'), + "IntegrationHubSettings"=c('fullName','canonicalName','canonicalNameBindingChar','description','isEnabled','isProtected','masterLabel','setupData','setupDefinition','setupNamespace','setupSimpleName','uUID','version','versionBuild','versionMajor','versionMinor'), + "IntegrationHubSettingsType"=c('fullName','canonicalName','canonicalNameBindingChar','description','isEnabled','isProtected','masterLabel','setupNamespace','setupSimpleName','uUID','version','versionBuild','versionMajor','versionMinor'), + "IpRange"=c('description','end','start'), + "KeyboardShortcuts"=c('customShortcuts','defaultShortcuts'), + "Keyword"=c('keyword'), + "KeywordList"=c('fullName','description','keywords','masterLabel'), + "KnowledgeAnswerSettings"=c('assignTo','defaultArticleType','enableArticleCreation'), + "KnowledgeCaseField"=c('name'), + "KnowledgeCaseFieldsSettings"=c('field'), + "KnowledgeCaseSettings"=c('articlePDFCreationProfile','articlePublicSharingCommunities','articlePublicSharingSites','articlePublicSharingSitesChatterAnswers','assignTo','customizationClass','defaultContributionArticleType','editor','enableArticleCreation','enableArticlePublicSharingSites','enableCaseDataCategoryMapping','useProfileForPDFCreation'), + "KnowledgeCommunitiesSettings"=c('community'), + "KnowledgeLanguage"=c('active','defaultAssignee','defaultAssigneeType','defaultReviewer','defaultReviewerType','name'), + "KnowledgeLanguageSettings"=c('language'), + "KnowledgeSettings"=c('fullName','answers','cases','defaultLanguage','enableChatterQuestionKBDeflection','enableCreateEditOnArticlesTab','enableExternalMediaContent','enableKnowledge','enableLightningKnowledge','languages','showArticleSummariesCustomerPortal','showArticleSummariesInternalApp','showArticleSummariesPartnerPortal','showValidationStatusField','suggestedArticles'), + "KnowledgeSitesSettings"=c('site'), + "KnowledgeSuggestedArticlesSettings"=c('caseFields','useSuggestedArticlesForCase','workOrderFields','workOrderLineItemFields'), + "KnowledgeWorkOrderField"=c('name'), + "KnowledgeWorkOrderFieldsSettings"=c('field'), + "KnowledgeWorkOrderLineItemField"=c('name'), + "KnowledgeWorkOrderLineItemFieldsSettings"=c('field'), + "Layout"=c('fullName','customButtons','customConsoleComponents','emailDefault','excludeButtons','feedLayout','headers','layoutSections','miniLayout','multilineLayoutFields','platformActionList','quickActionList','relatedContent','relatedLists','relatedObjects','runAssignmentRulesDefault','showEmailCheckbox','showHighlightsPanel','showInteractionLogPanel','showKnowledgeComponent','showRunAssignmentRulesCheckbox','showSolutionSection','showSubmitAndAttachButton','summaryLayout'), + "LayoutColumn"=c('layoutItems','reserved'), + "LayoutItem"=c('analyticsCloudComponent','behavior','canvas','component','customLink','emptySpace','field','height','page','reportChartComponent','scontrol','showLabel','showScrollbars','width'), + "LayoutSection"=c('customLabel','detailHeading','editHeading','label','layoutColumns','style'), + "LayoutSectionTranslation"=c('label','section'), + "LayoutTranslation"=c('layout','layoutType','sections'), + "LeadConvertSettings"=c('fullName','allowOwnerChange','objectMapping','opportunityCreationOptions'), + "Letterhead"=c('fullName','available','backgroundColor','bodyColor','bottomLine','description','footer','header','middleLine','name','topLine'), + "LetterheadHeaderFooter"=c('backgroundColor','height','horizontalAlignment','logo','verticalAlignment'), + "LetterheadLine"=c('color','height'), + "LicensedCustomPermissions"=c('customPermission','licenseDefinition'), + "LicenseDefinition"=c('fullName','aggregationGroup','description','isPublished','label','licensedCustomPermissions','licensingAuthority','licensingAuthorityProvider','minPlatformVersion','origin','revision','trialLicenseDuration','trialLicenseQuantity'), + "LightningBolt"=c('fullName','category','lightningBoltFeatures','lightningBoltImages','lightningBoltItems','masterLabel','publisher','summary'), + "LightningBoltFeatures"=c('description','order','title'), + "LightningBoltImages"=c('image','order'), + "LightningBoltItems"=c('name','type'), + "LightningComponentBundle"=c('fullName','apiVersion','isExposed'), + "LightningExperienceTheme"=c('fullName','defaultBrandingSet','description','masterLabel','shouldOverrideLoadingImage'), + "ListMetadataQuery"=c('folder','type'), + "ListPlacement"=c('height','location','units','width'), + "ListView"=c('fullName','booleanFilter','columns','division','filterScope','filters','label','language','queue','sharedTo'), + "ListViewFilter"=c('field','operation','value'), + "LiveAgentConfig"=c('enableLiveChat','openNewAccountSubtab','openNewCaseSubtab','openNewContactSubtab','openNewLeadSubtab','openNewVFPageSubtab','pageNamesToOpen','showKnowledgeArticles'), + "LiveAgentSettings"=c('fullName','enableLiveAgent'), + "LiveChatAgentConfig"=c('fullName','assignments','autoGreeting','capacity','criticalWaitTime','customAgentName','enableAgentFileTransfer','enableAgentSneakPeek','enableAssistanceFlag','enableAutoAwayOnDecline','enableAutoAwayOnPushTimeout','enableChatConferencing','enableChatMonitoring','enableChatTransferToAgent','enableChatTransferToButton','enableChatTransferToSkill','enableLogoutSound','enableNotifications','enableRequestSound','enableSneakPeek','enableVisitorBlocking','enableWhisperMessage','label','supervisorDefaultAgentStatusFilter','supervisorDefaultButtonFilter','supervisorDefaultSkillFilter','supervisorSkills','transferableButtons','transferableSkills'), + "LiveChatButton"=c('fullName','animation','autoGreeting','chasitorIdleTimeout','chasitorIdleTimeoutWarning','chatPage','customAgentName','deployments','enableQueue','inviteEndPosition','inviteImage','inviteStartPosition','isActive','label','numberOfReroutingAttempts','offlineImage','onlineImage','optionsCustomRoutingIsEnabled','optionsHasChasitorIdleTimeout','optionsHasInviteAfterAccept','optionsHasInviteAfterReject','optionsHasRerouteDeclinedRequest','optionsIsAutoAccept','optionsIsInviteAutoRemove','overallQueueLength','perAgentQueueLength','postChatPage','postChatUrl','preChatFormPage','preChatFormUrl','pushTimeOut','routingType','site','skills','timeToRemoveInvite','type','windowLanguage'), + "LiveChatButtonDeployments"=c('deployment'), + "LiveChatButtonSkills"=c('skill'), + "LiveChatDeployment"=c('fullName','brandingImage','connectionTimeoutDuration','connectionWarningDuration','displayQueuePosition','domainWhiteList','enablePrechatApi','enableTranscriptSave','label','mobileBrandingImage','site','windowTitle'), + "LiveChatDeploymentDomainWhitelist"=c('domain'), + "LiveChatSensitiveDataRule"=c('fullName','actionType','description','enforceOn','isEnabled','pattern','replacement'), + "LiveMessageSettings"=c('fullName','enableLiveMessage'), + "LogInfo"=c('category','level'), + "LookupFilter"=c('active','booleanFilter','description','errorMessage','filterItems','infoMessage','isOptional'), + "LookupFilterTranslation"=c('errorMessage','informationalMessage'), + "MacroSettings"=c('fullName','enableAdvancedSearch'), + "ManagedTopic"=c('fullName','managedTopicType','name','parentName','position','topicDescription'), + "ManagedTopics"=c('fullName','managedTopic'), + "MarketingActionSettings"=c('fullName','enableMarketingAction'), + "MarketingResourceType"=c('fullName','description','masterLabel','object','provider'), + "MatchingRule"=c('fullName','booleanFilter','description','label','matchingRuleItems','ruleStatus'), + "MatchingRuleItem"=c('blankValueBehavior','fieldName','matchingMethod'), + "MatchingRules"=c('fullName','matchingRules'), + "Metadata"=c('fullName'), + "MetadataWithContent"=c('fullName','content'), + "MilestoneType"=c('fullName','description','recurrenceType'), + "MiniLayout"=c('fields','relatedLists'), + "MobileSettings"=c('fullName','chatterMobile','dashboardMobile','salesforceMobile','touchMobile'), + "ModeratedEntityField"=c('entityName','fieldName','keywordList'), + "ModerationRule"=c('fullName','action','actionLimit','active','description','entitiesAndFields','masterLabel','notifyLimit','timePeriod','type','userCriteria','userMessage'), + "NamedCredential"=c('fullName','allowMergeFieldsInBody','allowMergeFieldsInHeader','authProvider','certificate','endpoint','generateAuthorizationHeader','label','oauthRefreshToken','oauthScope','oauthToken','password','principalType','protocol','username'), + "NameSettings"=c('fullName','enableMiddleName','enableNameSuffix'), + "NavigationLinkSet"=c('navigationMenuItem'), + "NavigationMenuItem"=c('defaultListViewId','label','position','publiclyAvailable','subMenu','target','targetPreference','type'), + "NavigationSubMenu"=c('navigationMenuItem'), + "Network"=c('fullName','allowInternalUserLogin','allowMembersToFlag','allowedExtensions','caseCommentEmailTemplate','changePasswordTemplate','communityRoles','description','disableReputationRecordConversations','emailFooterLogo','emailFooterText','emailSenderAddress','emailSenderName','enableCustomVFErrorPageOverrides','enableDirectMessages','enableGuestChatter','enableGuestFileAccess','enableInvitation','enableKnowledgeable','enableNicknameDisplay','enablePrivateMessages','enableReputation','enableShowAllNetworkSettings','enableSiteAsContainer','enableTalkingAboutStats','enableTopicAssignmentRules','enableTopicSuggestions','enableUpDownVote','feedChannel','forgotPasswordTemplate','gatherCustomerSentimentData','logoutUrl','maxFileSizeKb','navigationLinkSet','networkMemberGroups','networkPageOverrides','newSenderAddress','picassoSite','recommendationAudience','recommendationDefinition','reputationLevels','reputationPointsRules','selfRegProfile','selfRegistration','sendWelcomeEmail','site','status','tabs','urlPathPrefix','welcomeTemplate'), + "NetworkAccess"=c('ipRanges'), + "NetworkBranding"=c('content','loginFooterText','loginLogo','loginLogoName','loginPrimaryColor','loginQuaternaryColor','loginRightFrameUrl','network','pageFooter','pageHeader','primaryColor','primaryComplementColor','quaternaryColor','quaternaryComplementColor','secondaryColor','staticLogoImageUrl','tertiaryColor','tertiaryComplementColor','zeronaryColor','zeronaryComplementColor'), + "NetworkMemberGroup"=c('permissionSet','profile'), + "NetworkPageOverride"=c('changePasswordPageOverrideSetting','forgotPasswordPageOverrideSetting','homePageOverrideSetting','loginPageOverrideSetting','selfRegProfilePageOverrideSetting'), + "NetworkTabSet"=c('customTab','defaultTab','standardTab'), + "NextAutomatedApprover"=c('useApproverFieldOfRecordOwner','userHierarchyField'), + "ObjectMapping"=c('inputObject','mappingFields','outputObject'), + "ObjectMappingField"=c('inputField','outputField'), + "ObjectNameCaseValue"=c('article','caseType','plural','possessive','value'), + "ObjectRelationship"=c('join','outerJoin','relationship'), + "ObjectSearchSetting"=c('enhancedLookupEnabled','lookupAutoCompleteEnabled','name','resultsPerPageCount'), + "ObjectUsage"=c('object'), + "OpportunityListFieldsLabelMapping"=c('field','label'), + "OpportunityListFieldsSelectedSettings"=c('field'), + "OpportunityListFieldsUnselectedSettings"=c('field'), + "OpportunitySettings"=c('fullName','autoActivateNewReminders','enableFindSimilarOpportunities','enableOpportunityTeam','enableUpdateReminders','findSimilarOppFilter','promptToAddProducts'), + "Orchestration"=c('content','context','masterLabel'), + "OrchestrationContext"=c('fullName','description','events','masterLabel','runtimeType','salesforceObject','salesforceObjectPrimaryKey'), + "OrchestrationContextEvent"=c('eventType','orchestrationEvent','platformEvent','platformEventPrimaryKey'), + "OrderSettings"=c('fullName','enableNegativeQuantity','enableOrders','enableReductionOrders','enableZeroQuantity'), + "OrganizationSettingsDetail"=c('settingName','settingValue'), + "OrgPreferenceSettings"=c('fullName','preferences'), + "Package"=c('fullName','apiAccessLevel','description','namespacePrefix','objectPermissions','packageType','postInstallClass','setupWeblink','types','uninstallClass','version'), + "PackageTypeMembers"=c('members','name'), + "PackageVersion"=c('majorNumber','minorNumber','namespace'), + "PasswordPolicies"=c('apiOnlyUserHomePageURL','complexity','expiration','historyRestriction','lockoutInterval','maxLoginAttempts','minimumPasswordLength','minimumPasswordLifetime','obscureSecretAnswer','passwordAssistanceMessage','passwordAssistanceURL','questionRestriction'), + "PathAssistant"=c('fullName','active','entityName','fieldName','masterLabel','pathAssistantSteps','recordTypeName'), + "PathAssistantSettings"=c('fullName','pathAssistantEnabled'), + "PathAssistantStep"=c('fieldNames','info','picklistValueName'), + "PermissionSet"=c('fullName','applicationVisibilities','classAccesses','customPermissions','description','externalDataSourceAccesses','fieldPermissions','hasActivationRequired','label','license','objectPermissions','pageAccesses','recordTypeVisibilities','tabSettings','userPermissions'), + "PermissionSetApexClassAccess"=c('apexClass','enabled'), + "PermissionSetApexPageAccess"=c('apexPage','enabled'), + "PermissionSetApplicationVisibility"=c('application','visible'), + "PermissionSetCustomPermissions"=c('enabled','name'), + "PermissionSetExternalDataSourceAccess"=c('enabled','externalDataSource'), + "PermissionSetFieldPermissions"=c('editable','field','readable'), + "PermissionSetGroup"=c('fullName','description','isCalculatingChanges','label','permissionSets'), + "PermissionSetObjectPermissions"=c('allowCreate','allowDelete','allowEdit','allowRead','modifyAllRecords','object','viewAllRecords'), + "PermissionSetRecordTypeVisibility"=c('recordType','visible'), + "PermissionSetTabSetting"=c('tab','visibility'), + "PermissionSetUserPermission"=c('enabled','name'), + "PersonalJourneySettings"=c('fullName','enableExactTargetForSalesforceApps'), + "PersonListSettings"=c('fullName','enablePersonList'), + "PicklistEntry"=c('active','defaultValue','label','validFor','value'), + "PicklistValue"=c('color','default','description','isActive','allowEmail','closed','controllingFieldValues','converted','cssExposed','forecastCategory','highPriority','probability','reverseRole','reviewed','won'), + "PicklistValueTranslation"=c('masterLabel','translation'), + "PlatformActionList"=c('fullName','actionListContext','platformActionListItems','relatedSourceEntity'), + "PlatformActionListItem"=c('actionName','actionType','sortOrder','subtype'), + "PlatformCachePartition"=c('fullName','description','isDefaultPartition','masterLabel','platformCachePartitionTypes'), + "PlatformCachePartitionType"=c('allocatedCapacity','allocatedPurchasedCapacity','allocatedTrialCapacity','cacheType'), + "Portal"=c('fullName','active','admin','defaultLanguage','description','emailSenderAddress','emailSenderName','enableSelfCloseCase','footerDocument','forgotPassTemplate','headerDocument','isSelfRegistrationActivated','loginHeaderDocument','logoDocument','logoutUrl','newCommentTemplate','newPassTemplate','newUserTemplate','ownerNotifyTemplate','selfRegNewUserUrl','selfRegUserDefaultProfile','selfRegUserDefaultRole','selfRegUserTemplate','showActionConfirmation','stylesheetDocument','type'), + "PostTemplate"=c('fullName','default','description','fields','label'), + "PrimaryTabComponents"=c('containers'), + "ProductSettings"=c('fullName','enableCascadeActivateToRelatedPrices','enableQuantitySchedule','enableRevenueSchedule'), + "Profile"=c('fullName','applicationVisibilities','categoryGroupVisibilities','classAccesses','custom','customPermissions','description','externalDataSourceAccesses','fieldPermissions','layoutAssignments','loginHours','loginIpRanges','objectPermissions','pageAccesses','profileActionOverrides','recordTypeVisibilities','tabVisibilities','userLicense','userPermissions'), + "ProfileActionOverride"=c('actionName','content','formFactor','pageOrSobjectType','recordType','type'), + "ProfileApexClassAccess"=c('apexClass','enabled'), + "ProfileApexPageAccess"=c('apexPage','enabled'), + "ProfileApplicationVisibility"=c('application','default','visible'), + "ProfileCategoryGroupVisibility"=c('dataCategories','dataCategoryGroup','visibility'), + "ProfileCustomPermissions"=c('enabled','name'), + "ProfileExternalDataSourceAccess"=c('enabled','externalDataSource'), + "ProfileFieldLevelSecurity"=c('editable','field','readable'), + "ProfileLayoutAssignment"=c('layout','recordType'), + "ProfileLoginHours"=c('fridayEnd','fridayStart','mondayEnd','mondayStart','saturdayEnd','saturdayStart','sundayEnd','sundayStart','thursdayEnd','thursdayStart','tuesdayEnd','tuesdayStart','wednesdayEnd','wednesdayStart'), + "ProfileLoginIpRange"=c('description','endAddress','startAddress'), + "ProfileObjectPermissions"=c('allowCreate','allowDelete','allowEdit','allowRead','modifyAllRecords','object','viewAllRecords'), + "ProfilePasswordPolicy"=c('fullName','lockoutInterval','maxLoginAttempts','minimumPasswordLength','minimumPasswordLifetime','obscure','passwordComplexity','passwordExpiration','passwordHistory','passwordQuestion','profile'), + "ProfileRecordTypeVisibility"=c('default','personAccountDefault','recordType','visible'), + "ProfileSessionSetting"=c('fullName','externalCommunityUserIdentityVerif','forceLogout','profile','requiredSessionLevel','sessionPersistence','sessionTimeout','sessionTimeoutWarning'), + "ProfileTabVisibility"=c('tab','visibility'), + "ProfileUserPermission"=c('enabled','name'), + "PublicGroups"=c('publicGroup'), + "PushNotification"=c('fieldNames','objectName'), + "Queue"=c('fullName','doesSendEmailToMembers','email','name','queueMembers','queueRoutingConfig','queueSobject'), + "QueueMembers"=c('publicGroups','roleAndSubordinates','roleAndSubordinatesInternal','roles','users'), + "QueueSobject"=c('sobjectType'), + "QuickAction"=c('fullName','canvas','description','fieldOverrides','flowDefinition','height','icon','isProtected','label','lightningComponent','optionsCreateFeedItem','page','quickActionLayout','quickActionSendEmailOptions','standardLabel','successMessage','targetObject','targetParentField','targetRecordType','type','width'), + "QuickActionLayout"=c('layoutSectionStyle','quickActionLayoutColumns'), + "QuickActionLayoutColumn"=c('quickActionLayoutItems'), + "QuickActionLayoutItem"=c('emptySpace','field','uiBehavior'), + "QuickActionList"=c('quickActionListItems'), + "QuickActionListItem"=c('quickActionName'), + "QuickActionSendEmailOptions"=c('defaultEmailTemplateName','ignoreDefaultEmailTemplateSubject'), + "QuickActionTranslation"=c('label','name'), + "QuotasSettings"=c('showQuotas'), + "QuoteSettings"=c('fullName','enableQuote'), + "RecommendationAudience"=c('recommendationAudienceDetails'), + "RecommendationAudienceDetail"=c('audienceCriteriaType','audienceCriteriaValue','setupName'), + "RecommendationDefinition"=c('recommendationDefinitionDetails'), + "RecommendationDefinitionDetail"=c('actionUrl','description','linkText','scheduledRecommendations','setupName','title'), + "RecommendationStrategy"=c('fullName','description','masterLabel','recommendationStrategyName','strategyNode'), + "RecordType"=c('fullName','active','businessProcess','compactLayoutAssignment','description','label','picklistValues'), + "RecordTypePicklistValue"=c('picklist','values'), + "RecordTypeTranslation"=c('description','label','name'), + "RelatedContent"=c('relatedContentItems'), + "RelatedContentItem"=c('layoutItem'), + "RelatedList"=c('hideOnDetail','name'), + "RelatedListItem"=c('customButtons','excludeButtons','fields','relatedList','sortField','sortOrder'), + "RemoteSiteSetting"=c('fullName','description','disableProtocolSecurity','isActive','url'), + "Report"=c('fullName','aggregates','block','blockInfo','buckets','chart','colorRanges','columns','crossFilters','currency','dataCategoryFilters','description','division','filter','folderName','format','groupingsAcross','groupingsDown','historicalSelector','name','numSubscriptions','params','reportType','roleHierarchyFilter','rowLimit','scope','showCurrentDate','showDetails','sortColumn','sortOrder','territoryHierarchyFilter','timeFrameFilter','userFilter'), + "ReportAggregate"=c('acrossGroupingContext','calculatedFormula','datatype','description','developerName','downGroupingContext','isActive','isCrossBlock','masterLabel','reportType','scale'), + "ReportAggregateReference"=c('aggregate'), + "ReportBlockInfo"=c('aggregateReferences','blockId','joinTable'), + "ReportBucketField"=c('bucketType','developerName','masterLabel','nullTreatment','otherBucketLabel','sourceColumnName','useOther','values'), + "ReportBucketFieldSourceValue"=c('from','sourceValue','to'), + "ReportBucketFieldValue"=c('sourceValues','value'), + "ReportChart"=c('backgroundColor1','backgroundColor2','backgroundFadeDir','chartSummaries','chartType','enableHoverLabels','expandOthers','groupingColumn','legendPosition','location','secondaryGroupingColumn','showAxisLabels','showPercentage','showTotal','showValues','size','summaryAxisManualRangeEnd','summaryAxisManualRangeStart','summaryAxisRange','textColor','textSize','title','titleColor','titleSize'), + "ReportChartComponentLayoutItem"=c('cacheData','contextFilterableField','error','hideOnError','includeContext','reportName','showTitle','size'), + "ReportColorRange"=c('aggregate','columnName','highBreakpoint','highColor','lowBreakpoint','lowColor','midColor'), + "ReportColumn"=c('aggregateTypes','field','reverseColors','showChanges'), + "ReportCrossFilter"=c('criteriaItems','operation','primaryTableColumn','relatedTable','relatedTableJoinColumn'), + "ReportDataCategoryFilter"=c('dataCategory','dataCategoryGroup','operator'), + "ReportFilter"=c('booleanFilter','criteriaItems','language'), + "ReportFilterItem"=c('column','columnToColumn','isUnlocked','operator','snapshot','value'), + "ReportFolder"=c('accessType','folderShares','name','publicFolderAccess','sharedTo'), + "ReportGrouping"=c('aggregateType','dateGranularity','field','sortByName','sortOrder','sortType'), + "ReportHistoricalSelector"=c('snapshot'), + "ReportLayoutSection"=c('columns','masterLabel'), + "ReportParam"=c('name','value'), + "ReportTimeFrameFilter"=c('dateColumn','endDate','interval','startDate'), + "ReportType"=c('fullName','autogenerated','baseObject','category','deployed','description','join','label','sections'), + "ReportTypeColumn"=c('checkedByDefault','displayNameOverride','field','table'), + "ReportTypeColumnTranslation"=c('label','name'), + "ReportTypeSectionTranslation"=c('columns','label','name'), + "ReportTypeTranslation"=c('description','label','name','sections'), + "ReputationBranding"=c('smallImage'), + "ReputationLevel"=c('branding','label','lowerThreshold'), + "ReputationLevelDefinitions"=c('level'), + "ReputationLevels"=c('chatterAnswersReputationLevels','ideaReputationLevels'), + "ReputationPointsRule"=c('eventType','points'), + "ReputationPointsRules"=c('pointsRule'), + "RetrieveRequest"=c('apiVersion','packageNames','singlePackage','specificFiles','unpackaged'), + "Role"=c('caseAccessLevel','contactAccessLevel','description','mayForecastManagerShare','name','opportunityAccessLevel','parentRole'), + "RoleAndSubordinates"=c('roleAndSubordinate'), + "RoleAndSubordinatesInternal"=c('roleAndSubordinateInternal'), + "RoleOrTerritory"=c('fullName','caseAccessLevel','contactAccessLevel','description','mayForecastManagerShare','name','opportunityAccessLevel'), + "Roles"=c('role'), + "RuleEntry"=c('assignedTo','assignedToType','booleanFilter','businessHours','businessHoursSource','criteriaItems','disableEscalationWhenModified','escalationAction','escalationStartTime','formula','notifyCcRecipients','overrideExistingTeams','replyToEmail','senderEmail','senderName','team','template'), + "SamlSsoConfig"=c('fullName','attributeName','attributeNameIdFormat','decryptionCertificate','errorUrl','executionUserId','identityLocation','identityMapping','issuer','loginUrl','logoutUrl','name','oauthTokenEndpoint','redirectBinding','requestSignatureMethod','requestSigningCertId','salesforceLoginUrl','samlEntityId','samlJitHandlerId','samlVersion','singleLogoutBinding','singleLogoutUrl','userProvisioning','validationCert'), + "ScheduledRecommendation"=c('scheduledRecommendationDetails'), + "ScheduledRecommendationDetail"=c('channel','enabled','rank','recommendationAudience'), + "Scontrol"=c('content','contentSource','description','encodingKey','fileContent','fileName','name','supportsCaching'), + "ScontrolTranslation"=c('label','name'), + "SearchLayouts"=c('customTabListAdditionalFields','excludedStandardButtons','listViewButtons','lookupDialogsAdditionalFields','lookupFilterFields','lookupPhoneDialogsAdditionalFields','searchFilterFields','searchResultsAdditionalFields','searchResultsCustomButtons'), + "SearchSettings"=c('fullName','documentContentSearchEnabled','optimizeSearchForCJKEnabled','recentlyViewedUsersForBlankLookupEnabled','searchSettingsByObject','sidebarAutoCompleteEnabled','sidebarDropDownListEnabled','sidebarLimitToItemsIOwnCheckboxEnabled','singleSearchResultShortcutEnabled','spellCorrectKnowledgeSearchEnabled'), + "SearchSettingsByObject"=c('searchSettingsByObject'), + "SecuritySettings"=c('fullName','networkAccess','passwordPolicies','sessionSettings'), + "ServiceCloudConsoleConfig"=c('componentList','detailPageRefreshMethod','footerColor','headerColor','keyboardShortcuts','listPlacement','listRefreshMethod','liveAgentConfig','primaryTabColor','pushNotifications','tabLimitConfig','whitelistedDomains'), + "SessionSettings"=c('disableTimeoutWarning','enableCSPOnEmail','enableCSRFOnGet','enableCSRFOnPost','enableCacheAndAutocomplete','enableClickjackNonsetupSFDC','enableClickjackNonsetupUser','enableClickjackNonsetupUserHeaderless','enableClickjackSetup','enableContentSniffingProtection','enablePostForSessions','enableSMSIdentity','enableUpgradeInsecureRequests','enableXssProtection','enforceIpRangesEveryRequest','forceLogoutOnSessionTimeout','forceRelogin','hstsOnForcecomSites','identityConfirmationOnEmailChange','identityConfirmationOnTwoFactorRegistrationEnabled','lockSessionsToDomain','lockSessionsToIp','logoutURL','redirectionWarning','referrerPolicy','requireHttpOnly','requireHttps','securityCentralKillSession','sessionTimeout'), + "SFDCMobileSettings"=c('enableMobileLite','enableUserToDeviceLinking'), + "SharedTo"=c('allCustomerPortalUsers','allInternalUsers','allPartnerUsers','channelProgramGroup','channelProgramGroups','group','groups','managerSubordinates','managers','portalRole','portalRoleAndSubordinates','queue','role','roleAndSubordinates','roleAndSubordinatesInternal','roles','rolesAndSubordinates','territories','territoriesAndSubordinates','territory','territoryAndSubordinates'), + "SharingBaseRule"=c('fullName','accessLevel','accountSettings','description','label','sharedTo'), + "SharingCriteriaRule"=c('accessLevel','accountSettings','description','label','sharedTo','booleanFilter','criteriaItems'), + "SharingOwnerRule"=c('accessLevel','accountSettings','description','label','sharedTo','sharedFrom'), + "SharingReason"=c('fullName','label'), + "SharingReasonTranslation"=c('label','name'), + "SharingRecalculation"=c('className'), + "SharingRules"=c('fullName','sharingCriteriaRules','sharingOwnerRules','sharingTerritoryRules'), + "SharingSet"=c('fullName','accessMappings','description','name','profiles'), + "SharingTerritoryRule"=c('sharedFrom'), + "SidebarComponent"=c('componentType','createAction','enableLinking','height','label','lookup','page','relatedLists','unit','updateAction','width'), + "SiteDotCom"=c('content','label','siteType'), + "SiteRedirectMapping"=c('action','isActive','source','target'), + "SiteWebAddress"=c('certificate','domainName','primary'), + "Skill"=c('fullName','assignments','description','label'), + "SkillAssignments"=c('profiles','users'), + "SkillProfileAssignments"=c('profile'), + "SkillUserAssignments"=c('user'), + "SocialCustomerServiceSettings"=c('fullName','caseSubjectOption'), + "StandardFieldTranslation"=c('label','name'), + "StandardValue"=c('color','default','description','isActive','label','allowEmail','closed','converted','cssExposed','forecastCategory','groupingString','highPriority','probability','reverseRole','reviewed','won'), + "StandardValueSet"=c('fullName','groupingStringEnum','sorted','standardValue'), + "StandardValueSetTranslation"=c('fullName','valueTranslation'), + "State"=c('active','integrationValue','isoCode','label','standard','visible'), + "StaticResource"=c('content','cacheControl','contentType','description'), + "StrategyNode"=c('definition','description','name','parentNode','type'), + "SubtabComponents"=c('containers'), + "SummaryLayout"=c('masterLabel','sizeX','sizeY','sizeZ','summaryLayoutItems','summaryLayoutStyle'), + "SummaryLayoutItem"=c('customLink','field','posX','posY','posZ'), + "SupervisorAgentConfigSkills"=c('skill'), + "SynonymDictionary"=c('fullName','groups','isProtected','label'), + "SynonymGroup"=c('languages','terms'), + "TabLimitConfig"=c('maxNumberOfPrimaryTabs','maxNumberOfSubTabs'), + "Territory"=c('caseAccessLevel','contactAccessLevel','description','mayForecastManagerShare','name','opportunityAccessLevel','accountAccessLevel','parentTerritory'), + "Territory2"=c('fullName','accountAccessLevel','caseAccessLevel','contactAccessLevel','customFields','description','name','opportunityAccessLevel','parentTerritory','ruleAssociations','territory2Type'), + "Territory2Model"=c('fullName','customFields','description','name'), + "Territory2Rule"=c('fullName','active','booleanFilter','name','objectType','ruleItems'), + "Territory2RuleAssociation"=c('inherited','ruleName'), + "Territory2RuleItem"=c('field','operation','value'), + "Territory2Settings"=c('fullName','defaultAccountAccessLevel','defaultCaseAccessLevel','defaultContactAccessLevel','defaultOpportunityAccessLevel','opportunityFilterSettings'), + "Territory2SettingsOpportunityFilter"=c('apexClassName','enableFilter','runOnCreate'), + "Territory2Type"=c('fullName','description','name','priority'), + "TopicsForObjects"=c('fullName','enableTopics','entityApiName'), + "TouchMobileSettings"=c('enableTouchAppIPad','enableTouchAppIPhone','enableTouchBrowserIPad','enableTouchIosPhone','enableVisualforceInTouch'), + "TransactionSecurityAction"=c('block','endSession','freezeUser','notifications','twoFactorAuthentication'), + "TransactionSecurityNotification"=c('inApp','sendEmail','user'), + "TransactionSecurityPolicy"=c('fullName','action','active','apexClass','description','developerName','eventName','eventType','executionUser','flow','masterLabel','resourceName','type'), + "Translations"=c('fullName','customApplications','customDataTypeTranslations','customLabels','customPageWebLinks','customTabs','flowDefinitions','quickActions','reportTypes','scontrols'), + "UiFormulaCriterion"=c('leftValue','operator','rightValue'), + "UiFormulaRule"=c('booleanFilter','criteria'), + "UiPlugin"=c('content','description','extensionPointIdentifier','isEnabled','language','masterLabel'), + "UserCriteria"=c('fullName','creationAgeInSeconds','description','lastChatterActivityAgeInSeconds','masterLabel','profiles','userTypes'), + "Users"=c('user'), + "ValidationRule"=c('fullName','active','description','errorConditionFormula','errorDisplayField','errorMessage'), + "ValidationRuleTranslation"=c('errorMessage','name'), + "ValueSet"=c('controllingField','restricted','valueSetDefinition','valueSetName','valueSettings'), + "ValueSettings"=c('controllingFieldValue','valueName'), + "ValueSetValuesDefinition"=c('sorted','value'), + "ValueTranslation"=c('masterLabel','translation'), + "ValueTypeField"=c('fields','foreignKeyDomain','isForeignKey','isNameField','minOccurs','name','picklistValues','soapType','valueRequired'), + "VisualizationPlugin"=c('fullName','description','developerName','icon','masterLabel','visualizationResources','visualizationTypes'), + "VisualizationResource"=c('description','file','rank','type'), + "VisualizationType"=c('description','developerName','icon','masterLabel','scriptBootstrapMethod'), + "WaveApplication"=c('fullName','assetIcon','description','folder','masterLabel','shares','templateOrigin','templateVersion'), + "WaveDashboard"=c('content','application','description','masterLabel','templateAssetSourceName'), + "WaveDataflow"=c('content','dataflowType','description','masterLabel'), + "WaveDataset"=c('fullName','application','description','masterLabel','templateAssetSourceName'), + "WaveLens"=c('content','application','datasets','description','masterLabel','templateAssetSourceName','visualizationType'), + "WaveRecipe"=c('content','dataflow','masterLabel','securityPredicate','targetDatasetAlias'), + "WaveTemplateBundle"=c('fullName','assetIcon','assetVersion','description','label','templateBadgeIcon','templateDetailIcon','templateType'), + "WaveXmd"=c('fullName','application','dataset','datasetConnector','datasetFullyQualifiedName','dates','dimensions','measures','organizations','origin','type','waveVisualization'), + "WaveXmdDate"=c('alias','compact','dateFieldDay','dateFieldEpochDay','dateFieldEpochSecond','dateFieldFiscalMonth','dateFieldFiscalQuarter','dateFieldFiscalWeek','dateFieldFiscalYear','dateFieldFullYear','dateFieldHour','dateFieldMinute','dateFieldMonth','dateFieldQuarter','dateFieldSecond','dateFieldWeek','dateFieldYear','description','firstDayOfWeek','fiscalMonthOffset','isYearEndFiscalYear','label','showInExplorer','sortIndex'), + "WaveXmdDimension"=c('customActions','customActionsEnabled','dateFormat','description','field','fullyQualifiedName','imageTemplate','isDerived','isMultiValue','label','linkTemplate','linkTemplateEnabled','linkTooltip','members','origin','recordDisplayFields','recordIdField','recordOrganizationIdField','salesforceActions','salesforceActionsEnabled','showDetailsDefaultFieldIndex','showInExplorer','sortIndex'), + "WaveXmdDimensionCustomAction"=c('customActionName','enabled','icon','method','sortIndex','target','tooltip','url'), + "WaveXmdDimensionMember"=c('color','label','member','sortIndex'), + "WaveXmdDimensionSalesforceAction"=c('enabled','salesforceActionName','sortIndex'), + "WaveXmdMeasure"=c('dateFormat','description','field','formatCustomFormat','formatDecimalDigits','formatIsNegativeParens','formatPrefix','formatSuffix','formatUnit','formatUnitMultiplier','fullyQualifiedName','isDerived','label','origin','showDetailsDefaultFieldIndex','showInExplorer','sortIndex'), + "WaveXmdOrganization"=c('instanceUrl','label','organizationIdentifier','sortIndex'), + "WaveXmdRecordDisplayLookup"=c('recordDisplayField'), + "WebLink"=c('fullName','availability','description','displayType','encodingKey','hasMenubar','hasScrollbars','hasToolbar','height','isResizable','linkType','masterLabel','openType','page','position','protected','requireRowSelection','scontrol','showsLocation','showsStatus','url','width'), + "WebLinkTranslation"=c('label','name'), + "WebToCaseSettings"=c('caseOrigin','defaultResponseTemplate','enableWebToCase'), + "WeightedSourceCategory"=c('sourceCategoryApiName','weight'), + "Workflow"=c('fullName','alerts','fieldUpdates','flowActions','knowledgePublishes','outboundMessages','rules','send','tasks'), + "WorkflowAction"=c('fullName'), + "WorkflowActionReference"=c('name','type'), + "WorkflowAlert"=c('ccEmails','description','protected','recipients','senderAddress','senderType','template'), + "WorkflowEmailRecipient"=c('field','recipient','type'), + "WorkflowFieldUpdate"=c('description','field','formula','literalValue','lookupValue','lookupValueType','name','notifyAssignee','operation','protected','reevaluateOnChange','targetObject'), + "WorkflowFlowAction"=c('description','flow','flowInputs','label','language','protected'), + "WorkflowFlowActionParameter"=c('name','value'), + "WorkflowKnowledgePublish"=c('action','description','label','language','protected'), + "WorkflowRule"=c('fullName','actions','active','booleanFilter','criteriaItems','description','formula','triggerType','workflowTimeTriggers'), + "WorkflowSend"=c('action','description','label','language','protected'), + "WorkflowTask"=c('assignedTo','assignedToType','description','dueDateOffset','notifyAssignee','offsetFromField','priority','protected','status','subject'), + "WorkflowTaskTranslation"=c('description','name','subject'), + "WorkflowTimeTrigger"=c('actions','offsetFromField','timeLength','workflowTimeTriggerUnit'), + "WorkspaceMapping"=c('fieldName','tab') + ) + + return(reference_list) +} diff --git a/R/utils-org.R b/R/utils-org.R new file mode 100644 index 0000000..ccc4b53 --- /dev/null +++ b/R/utils-org.R @@ -0,0 +1,167 @@ +#' Return Current User Info +#' +#' Retrieves personal information for the user associated with the current session. +#' +#' @importFrom httr content +#' @return \code{list} +#' @examples +#' \dontrun{ +#' sf_user_info() +#' } +#' @export +sf_user_info <- function(){ + # ensure we are authenticated first so the url can be formed + chatter_url <- make_chatter_users_url() + httr_response <- rGET(sprintf("%s%s", chatter_url, "me")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + return(response_parsed) +} + +#' Salesforce Server Timestamp +#' +#' Retrieves the current system timestamp from the API. +#' +#' @importFrom httr headers +#' @importFrom lubridate dmy_hms +#' @return \code{POSIXct} formatted timestamp +#' @examples +#' \dontrun{ +#' sf_server_timestamp() +#' } +#' @export +sf_server_timestamp <- function(){ + base_rest_url <- make_base_rest_url() + httr_response <- rGET(base_rest_url, + headers = c("Accept"="application/xml", + "X-PrettyPrint"="1")) + catch_errors(httr_response) + response_parsed <- headers(httr_response)$date + timestamp <- dmy_hms(response_parsed) + return(timestamp) +} + +#' List REST API Versions +#' +#' Lists summary information about each Salesforce version currently available, +#' including the version, label, and a link to each version\'s root +#' +#' @importFrom httr content +#' @return \code{list} +#' @examples +#' \dontrun{ +#' sf_list_rest_api_versions() +#' } +#' @export +sf_list_rest_api_versions <- function(){ + sf_auth_check() + httr_response <- rGET(sprintf("%s/services/data/", salesforcer_state()$instance_url)) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + return(response_parsed) +} + +#' List the Resources for an API +#' +#' Lists available resources for the specified API version, including resource +#' name and URI. +#' +#' @importFrom httr content +#' @return \code{list} +#' @examples +#' \dontrun{ +#' sf_list_resources() +#' } +#' @export +sf_list_resources <- function(){ + base_rest_url <- make_base_rest_url() + httr_response <- rGET(base_rest_url) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + return(response_parsed) +} + +#' List the Limits for an API +#' +#' Lists information about limits in your org. +#' +#' @importFrom httr content +#' @note This resource is available in REST API version 29.0 and later for API +#' users with the View Setup and Configuration permission. The resource returns +#' these limits: +#' \itemize{ +#' \item Daily API calls +#' \item Daily asynchronous Apex method executions (batch Apex, future methods, queueable Apex, and scheduled Apex) +#' \item Daily Bulk API calls +#' \item Daily Streaming API events (API version 36.0 and earlier) +#' \item Daily durable Streaming API events (API version 37.0 and later) +#' \item Streaming API concurrent clients (API version 36.0 and earlier) +#' \item Durable Streaming API concurrent clients (API version 37.0 and later) +#' \item Daily generic streaming events (API version 36.0 and earlier) +#' \item Daily durable generic streaming events (API version 37.0 and later) +#' \item Daily number of mass emails that are sent to external email addresses by using Apex or APIs +#' \item Daily number of single emails that are sent to external email addresses by using Apex or APIs +#' \item Concurrent REST API requests for results of asynchronous report runs +#' \item Concurrent synchronous report runs via REST API +#' \item Hourly asynchronous report runs via REST API +#' \item Hourly synchronous report runs via REST API +#' \item Hourly dashboard refreshes via REST API +#' \item Hourly REST API requests for dashboard results +#' \item Hourly dashboard status requests via REST API +#' \item Daily workflow emails +#' \item Hourly workflow time triggers +#' \item Hourly OData callouts +#' \item Daily and active scratch org counts +#' \item Data storage (MB) +#' \item File storage (MB) +#' } +#' @return \code{list} +#' @examples +#' \dontrun{ +#' sf_list_api_limits() +#' } +#' @export +sf_list_api_limits <- function(){ + base_rest_url <- make_base_rest_url() + httr_response <- rGET(sprintf("%s%s", base_rest_url, "limits/")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + return(response_parsed) +} + +#' List Organization Objects and their Metadata +#' +#' Lists the available objects and their metadata for your organization’s data. +#' +#' @importFrom httr content +#' @return \code{list} +#' @examples +#' \dontrun{ +#' sf_list_objects() +#' } +#' @export +sf_list_objects <- function(){ + base_rest_url <- make_base_rest_url() + httr_response <- rGET(sprintf("%s%s", base_rest_url, "sobjects/")) + catch_errors(httr_response) + response_parsed <- content(httr_response, encoding='UTF-8') + return(response_parsed) +} + +#' #' Delete from Recycle Bin +#' #' +#' #' Delete records from the recycle bin immediately. +#' #' +#' #' @importFrom httr content +#' #' @return \code{list} +#' #' @examples +#' #' \dontrun{ +#' #' sf_empty_trash() +#' #' } +#' #' @export +#' sf_empty_trash <- function(){ +#' httr_response <- rGET("https://login.salesforce.com/services/oauth2/userinfo") +#' catch_errors(httr_response) +#' response_parsed <- content(httr_response, encoding='UTF-8') +#' return(response_parsed) +#' } \ No newline at end of file diff --git a/R/utils-xml.R b/R/utils-xml.R new file mode 100644 index 0000000..8034e0c --- /dev/null +++ b/R/utils-xml.R @@ -0,0 +1,309 @@ +#' xmlToList2 +#' +#' This function is an early and simple approach to converting an +#' XML node or document into a more typical R list containing the data values. +#' It differs from xmlToList by not including attributes at all in the output. +#' +#' @importFrom XML xmlApply xmlSApply xmlValue xmlAttrs xmlParse xmlSize xmlRoot +#' @param node the XML node or document to be converted to an R list +#' @return \code{list} parsed from the supplied node +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +xmlToList2 <- function(node){ + if (is.character(node)) { + node <- xmlParse(node) + } + if (inherits(node, "XMLAbstractDocument")) { + node <- xmlRoot(node) + } + if (any(inherits(node, c("XMLTextNode", "XMLInternalTextNode")))) { + xmlValue(node) + } else if (xmlSize(node) == 0) { + x <- xmlAttrs(node) + if(length(names(x)) == 0){ + NA + } else if(names(x) == "xsi:nil" & x == "true"){ + NA + } else { + x + } + } else { + if (is.list(node)) { + tmp = vals = xmlSApply(node, xmlToList2) + tt = xmlSApply(node, inherits, c("XMLTextNode", "XMLInternalTextNode")) + } + else { + tmp = vals = xmlApply(node, xmlToList2) + tt = xmlSApply(node, inherits, c("XMLTextNode", "XMLInternalTextNode")) + } + vals[tt] = lapply(vals[tt], function(x) x[[1]]) + if (any(tt) && length(vals) == 1) { + vals[[1]] + } else { + vals + } + } +} + +#' xml_nodeset_to_df +#' +#' A function specifically for parsing an XML node into a \code{data.frame} +#' +#' @importFrom dplyr as_tibble +#' @importFrom utils capture.output +#' @param this_node \code{xml_node}; to be parsed out +#' @return \code{data.frame} parsed from the supplied xml +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +xml_nodeset_to_df <- function(this_node){ + # capture any xmlToList grumblings about Namespace prefix + invisible(capture.output(node_vals <- unlist(xmlToList2(as.character(this_node))))) + return(as_tibble(t(node_vals))) +} + +#' Make SOAP XML Request Skeleton +#' +#' Create XML in preparate for sending to the SOAP API +#' +#' @importFrom XML newXMLNode xmlValue<- +#' @param soap_headers \code{list}; any number of SOAP headers +#' @return a XML document +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/soap_headers.htm} +#' @note This function is meant to be used internally. Only use when debugging. +#' Any of the following SOAP headers are allowed: +#' \itemize{ +#' \item AllorNoneHeader +#' \item AllowFieldTruncationHeader +#' \item AssignmentRuleHeader +#' \item CallOptions +#' \item DisableFeedTrackingHeader +#' \item EmailHeader +#' \item LimitInfoHeader +#' \item LocaleOptions +#' \item LoginScopeHeader +#' \item MruHeader +#' \item OwnerChangeOptions +#' \item PackageVersionHeader +#' \item QueryOptions +#' \item UserTerritoryDeleteHeader +#' } +#' Additionally, Bulk API can't access or query compound address or compound geolocation fields. +#' @references \url{https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/} +#' @keywords internal +#' @export +make_soap_xml_skeleton <- function(soap_headers=list(), metadata_ns=FALSE){ + + sf_auth_check() + + if(metadata_ns){ + these_ns = c("soapenv" = "http://schemas.xmlsoap.org/soap/envelope/", + "xsi" = "http://www.w3.org/2001/XMLSchema-instance", + "ns1" = "http://soap.sforce.com/2006/04/metadata") + ns_prefix <- "ns1" + } else { + these_ns <- c("soapenv" = "http://schemas.xmlsoap.org/soap/envelope/", + "xsi" = "http://www.w3.org/2001/XMLSchema-instance", + "urn" = "urn:partner.soap.sforce.com", + "urn1" = "urn:sobject.partner.soap.sforce.com") + ns_prefix <- "urn" + } + + root <- newXMLNode("soapenv:Envelope", namespaceDefinitions = these_ns) + header_node <- newXMLNode("soapenv:Header", parent=root) + sheader_node <- newXMLNode(paste0(ns_prefix, ":", "SessionHeader"), + parent=header_node) + #namespaceDefinitions = c("")) + + # get the current session id + this_session_id <- sf_access_token() + if(is.null(this_session_id)){ + this_session_id <- sf_session_id() + } + if(is.null(this_session_id)){ + stop("Could not find a session id in the environment. Try reauthenticating with sf_auth().") + } + + sid_node <- newXMLNode(paste0(ns_prefix, ":", "sessionId"), + this_session_id, + parent=sheader_node) + + if(length(soap_headers)>0){ + for(i in 1:length(soap_headers)){ + opt_node <- newXMLNode(paste0(ns_prefix, ":", names(soap_headers)[i]), + as.character(soap_headers[[i]]), + parent=header_node) + } + } + return(root) +} + +#' Build XML Request Body +#' +#' Parse data into XML format +#' +#' @importFrom XML newXMLNode xmlValue<- +#' @param input_data a \code{data.frame} of data to fill the XML body +#' @template operation +#' @template object_name +#' @param fields character; one or more strings indicating the fields to be returned +#' on the records +#' @template external_id_fieldname +#' @param root_name character; the name of the root node if created +#' @param ns named vector; a collection of character strings indicating the namespace +#' definitions of the root node if created +#' @param root \code{XMLNode}; a node to be used as the root +#' @return a XML document +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +build_soap_xml_from_list <- function(input_data, + operation = c("create", "retrieve", + "update", "upsert", + "delete", "search", + "query", "queryMore", + "describeSObjects"), + object_name=NULL, + fields=NULL, + external_id_fieldname=NULL, + root_name = NULL, + ns = c(character(0)), + root = NULL){ + + # ensure that if root is NULL that root_name is not also NULL + # this is so we have something to create the root node + stopifnot(!is.null(root_name) | !is.null(root)) + which_operation <- match.arg(operation) + input_data <- sf_input_data_validation(input_data, operation=which_operation) + + if (is.null(root)) + root <- newXMLNode(root_name, namespaceDefinitions = ns) + + body_node <- newXMLNode("soapenv:Body", parent=root) + operation_node <- newXMLNode(sprintf("urn:%s", which_operation), + parent=body_node) + + if(which_operation == "upsert"){ + stopifnot(!is.null(external_id_fieldname)) + external_field_node <- newXMLNode("urn:externalIDFieldName", + external_id_fieldname, + parent=operation_node) + } + + if(which_operation == "retrieve"){ + stopifnot(!is.null(object_name)) + stopifnot(!is.null(fields)) + field_list_node <- newXMLNode("urn:fieldList", + paste0(fields, collapse=","), + parent=operation_node) + sobject_type_node <- newXMLNode("urn:sObjectType", + object_name, + parent=operation_node) + } + + if(which_operation %in% c("search", "query")){ + + element_name <- if(which_operation == "search") "urn:searchString" else "urn:queryString" + this_node <- newXMLNode(element_name, + input_data[1,1], + parent=operation_node) + + } else if(which_operation == "queryMore"){ + + this_node <- newXMLNode("urn:queryLocator", + input_data[1,1], + parent=operation_node) + + } else if(which_operation %in% c("delete","retrieve")){ + + for(i in 1:nrow(input_data)){ + this_node <- newXMLNode("urn:ids", + input_data[i,"Id"], + parent=operation_node) + } + + } else if(which_operation == "describeSObjects"){ + + for(i in 1:nrow(input_data)){ + this_node <- newXMLNode("urn:sObjectType", + input_data[i,"sObjectType"], + parent=operation_node) + } + + } else { + + for(i in 1:nrow(input_data)){ + list <- as.list(input_data[i,,drop=FALSE]) + this_row_node <- newXMLNode("urn:sObjects", parent=operation_node) + # if the body elements are objects we must list the type of object_name + # under each block of XML for the row + type_node <- newXMLNode("urn1:type", parent=this_row_node) + xmlValue(type_node) <- object_name + + if(length(list) > 0){ + for (i in 1:length(list)){ + if (typeof(list[[i]]) == "list") { + this_node <- newXMLNode(names(list)[i], parent=this_row_node) + build_soap_xml_from_list(list[[i]], + operation = operation, + object_name = object_name, + external_id_fieldname = external_id_fieldname, + root = this_node) + } else { + if (!is.null(list[[i]])){ + this_node <- newXMLNode(names(list)[i], parent=this_row_node) + xmlValue(this_node) <- list[[i]] + } + } + } + } + } + } + return(root) +} + +#' Metadata List to XML Converter +#' +#' This function converts a list of metadata to XML +#' +#' @concept metadata salesforce api +#' @importFrom XML newXMLNode xmlValue<- +#' @param input_data XML document serving as the basis upon which to add the list +#' @param metatype a character indicating the element name of each record in the list +#' @param root_name character; the name of the root node if created +#' @param ns named vector; a collection of character strings indicating the namespace +#' definitions of the root node if created +#' @param root \code{XMLNode}; a node to be used as the root +#' @return A XML document with the sublist data added +build_metadata_xml_from_list <- function(input_data, + metatype = NULL, + root_name = NULL, + ns = c(character(0)), + root = NULL){ + + # ensure that if root is NULL that root_name is not also NULL + # this is so we have something to create the root node + stopifnot(!is.null(root_name) | !is.null(root)) + + if (is.null(root)) + root <- newXMLNode(root_name, namespaceDefinitions = ns) + + for(i in 1:length(input_data)){ + if (!is.null(metatype)){ + this <- newXMLNode("Metadata", attrs = c(`xsi:type`=paste0("ns2:", metatype)), parent=root, + namespaceDefinitions = c("ns2"="http://soap.sforce.com/2006/04/metadata"), + suppressNamespaceWarning = TRUE) + } else { + this <- newXMLNode(names(input_data)[i], parent=root, + suppressNamespaceWarning = TRUE) + } + if (typeof(input_data[[i]]) == "list"){ + build_metadata_xml_from_list(input_data=input_data[[i]], root=this, metatype=NULL) + } + else{ + xmlValue(this) <- input_data[[i]] + } + } + return(root) +} diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..84ba27f --- /dev/null +++ b/R/utils.R @@ -0,0 +1,93 @@ +#' Return the package's .state environment variable +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +salesforcer_state <- function(){ + .state +} + +#' Write a CSV file in format acceptable to Salesforce APIs +#' +#' @importFrom readr write_csv +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_write_csv <- function(x, path){ + write_csv(x=x, path=path, na="#N/A") +} + +#' Determine the host operating system +#' +#' This function determines whether the system running the R code +#' is Windows, Mac, or Linux +#' +#' @return A character string +#' @examples +#' \dontrun{ +#' get_os() +#' } +#' @seealso \url{http://conjugateprior.org/2015/06/identifying-the-os-from-r} +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +get_os <- function(){ + sysinf <- Sys.info() + if (!is.null(sysinf)){ + os <- sysinf['sysname'] + if (os == 'Darwin'){ + os <- "osx" + } + } else { + os <- .Platform$OS.type + if (grepl("^darwin", R.version$os)){ + os <- "osx" + } + if (grepl("linux-gnu", R.version$os)){ + os <- "linux" + } + } + unname(tolower(os)) +} + +#' Validate the input for an operation +#' +#' @note This function is meant to be used internally. Only use when debugging. +#' @keywords internal +#' @export +sf_input_data_validation <- function(input_data, operation=''){ + + # TODO: Automatic date validation + # https://developer.salesforce.com/docs/atlas.en-us.api_bulk_v2.meta/api_bulk_v2/datafiles_date_format.htm + + # put everything into a data.frame format if it's not already + if(!is.data.frame(input_data)){ + if(is.null(names(input_data))){ + if(!is.list(input_data)){ + input_data <- as.data.frame(list(input_data), stringsAsFactors = FALSE) + } else { + input_data <- as.data.frame(unlist(input_data), stringsAsFactors = FALSE) + } + } else { + input_data <- as.data.frame(as.list(input_data), stringsAsFactors = FALSE) + } + } + + if(operation %in% c("describeSObjects") & ncol(input_data) == 1){ + names(input_data) <- "sObjectType" + } + + if(operation %in% c("delete", "retrieve") & ncol(input_data) == 1){ + names(input_data) <- "Id" + } + + if(operation %in% c("delete", "update")){ + if(any(grepl("^ID$|^IDS$", names(input_data), ignore.case=TRUE))){ + idx <- grep("^ID$|^IDS$", names(input_data), ignore.case=TRUE) + names(input_data)[idx] <- "Id" + } + stopifnot("Id" %in% names(input_data)) + } + + return(input_data) +} \ No newline at end of file diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..14595b2 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,23 @@ +.onLoad <- function(libname, pkgname) { + + op <- options() + op.salesforcer <- list( + salesforcer.api_version = "42.0", + salesforcer.login_url = "https://login.salesforce.com", + salesforcer.consumer_key = "3MVG9CEn_O3jvv0yRMQezJ8PwesiIknRU9v9j778rv78UvJ2JTQzSG.QduxyMxYaldoNEhO0eVvw4ogCT58c5", + salesforcer.consumer_secret = "3471656211653393546", + salesforcer.callback_url = "http://localhost:1410/", + salesforcer.httr_oauth_cache = ".httr-oauth-salesforcer" + ) + toset <- !(names(op.salesforcer) %in% names(op)) + if(any(toset)) options(op.salesforcer[toset]) + + invisible() + +} + +# store state variables in the '.state' internal environment (created in sf_auth.R) +.state$auth_method <- NULL +.state$token <- NULL +.state$session_id <- NULL +.state$instance_url <- NULL diff --git a/README.md b/README.md new file mode 100644 index 0000000..adae6a8 --- /dev/null +++ b/README.md @@ -0,0 +1,293 @@ + +salesforcer +================================================================================ + +[![Build Status](https://travis-ci.org/StevenMMortimer/salesforcer.svg?branch=master)](https://travis-ci.org/StevenMMortimer/salesforcer) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/StevenMMortimer/salesforcer?branch=master&svg=true)](https://ci.appveyor.com/project/StevenMMortimer/salesforcer) [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/salesforcer)](http://cran.r-project.org/package=salesforcer) [![Coverage Status](https://codecov.io/gh/StevenMMortimer/salesforcer/branch/master/graph/badge.svg)](https://codecov.io/gh/StevenMMortimer/salesforcer?branch=master) + +**salesforcer** is an R package that connects to Salesforce Platform APIs using tidy principles. The package implements most actions from the SOAP, REST, Bulk 1.0, Bulk 2.0, and Metadata APIs. Package features include: + +- OAuth 2.0 (Single Sign On) and Basic (Username-Password) Authentication methods (`sf_auth()`) +- CRUD (Create, Retrieve, Update, Delete) methods for records using the SOAP, REST, and Bulk APIs +- Query records via the SOAP, REST, and Bulk 1.0 APIs using `sf_query()` +- Retrieve and modify metadata (Custom Objects, Fields, etc.) using the Metadata API with: + - `sf_describe_objects()`, `sf_create_metadata()`, `sf_update_metadata()` +- Utilize backwards compatible functions for the **RForcecom** package, such as: + - `rforcecom.login()`, `rforcecom.query()`, `rforcecom.create()`, `rforcecom.update()` +- Basic utility calls (`sf_user_info()`, `sf_server_timestamp()`, `sf_list_objects()`) + +Table of Contents +----------------- + +- [Installation](#installation) +- [Usage](#usage) + - [Authenticate](#authenticate) + - [Create](#create) + - [Query](#query) + - [Update](#update) + - [Bulk Operations](#bulk-operations) + - [Using the Metadata API](#using-the-metadata-api) +- [Future](#future) +- [Credits](#credits) +- [More Information](#more-information) + +Installation +------------ + +``` r +# this package is currently not on CRAN, so it should be installed from GitHub +# install.packages("devtools") +devtools::install_github("StevenMMortimer/salesforcer") +``` + +If you encounter a clear bug, please file a minimal reproducible example on [GitHub](https://github.com/StevenMMortimer/salesforcer/issues). + +Usage +----- + +### Authenticate + +First, load the **salesforcer** package and login. There are two ways to authenticate: + +1. OAuth 2.0 +2. Basic Username-Password + +It is recommended to use OAuth 2.0 so that passwords do not have to be shared or embedded within scripts. User credentials will be stored in locally cached file entitled ".httr-oauth-salesforcer" in the current working directory. + +``` r +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(purrr))) +library(salesforcer) + +# Using OAuth 2.0 authentication +sf_auth() + +# Using Basic Username-Password authentication +sf_auth(username = "test@gmail.com", + password = "{PASSWORD_HERE}", + security_token = "{SECURITY_TOKEN_HERE}") +``` + +After logging in with `sf_auth()`, you can check your connectivity by looking at the information returned about the current user. It should be information about you! + +``` r +# pull down information of person logged in +# it's a simple easy call to get started +# and confirm a connection to the APIs +user_info <- sf_user_info() +sprintf("User Id: %s", user_info$id) +#> [1] "User Id: 0056A000000MPRjQAO" +sprintf("User Active?: %s", user_info$isActive) +#> [1] "User Active?: TRUE" +``` + +### Create + +Salesforce has objects and those objects contain records. One default object is the "Contact" object. This example shows how to create two records in the Contact object. + +``` r +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, object_name="Contact") +created_records +#> # A tibble: 2 x 2 +#> id success +#> +#> 1 0036A00000SnhbfQAB true +#> 2 0036A00000SnhbgQAB true +``` + +### Query + +Salesforce has proprietary form of SQL called SOQL (Salesforce Object Query Language). SOQL is a powerful tool that allows you to return the attributes of records on almost any object in Salesforce including Accounts, Contacts, Tasks, Opportunities, even Attachments! Below is an example where we grab the data we just created including Account object information for which the Contact record is associated with. The Account column is all `NA` since we have yet to provide information to link these Contacts with Accounts. + +``` r +my_soql <- sprintf("SELECT Id, + Account.Name, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + +queried_records <- sf_query(my_soql) +queried_records +#> # A tibble: 2 x 4 +#> Id Account FirstName LastName +#> * +#> 1 0036A00000SnhbfQAB NA Test Contact-Create-1 +#> 2 0036A00000SnhbgQAB NA Test Contact-Create-2 +``` + +### Update + +After creating records you can update them using `sf_update()`. Updating a record requires you to pass the Salesforce `Id` of the record. Salesforce creates a unique 18-character identifier on each record and uses that to know which record to attach the update information you provide. Simply include a field or column in your update dataset called "Id" and the information will be matched. Here is an example where we update each of the records we created earlier with a new first name called "TestTest". + +``` r +# Update some of those records +queried_records <- queried_records %>% + mutate(FirstName = "TestTest") %>% + select(-Account) + +updated_records <- sf_update(queried_records, object_name="Contact") +updated_records +#> # A tibble: 2 x 2 +#> id success +#> +#> 1 0036A00000SnhbfQAB true +#> 2 0036A00000SnhbgQAB true +``` + +### Bulk Operations + +For really large operations (inserts, updates, upserts, deletes, and queries) Salesforce provides the [Bulk 1.0](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/asynch_api_intro.htm) and [Bulk 2.0](https://developer.salesforce.com/docs/atlas.en-us.api_bulk_v2.meta/api_bulk_v2/introduction_bulk_api_2.htm) APIs. In order to use the Bulk APIs in **salesforcer** you can just add `api_type = "Bulk 1.0"` or `api_type = "Bulk 2.0"` to your functions and the operation will be executed using the Bulk APIs. It's that simple. + +The benefits of using the Bulk API for larger datasets is that the operation will reduce the number of individual API calls (organization usually have a limit on total calls) and batching the requests in bulk is usually quicker than running thousands of individuals calls when your data is large. **Note:** the Bulk 2.0 API does **NOT** guarantee the order of the data submitted is preserved in the output. This means that you must join on other data columns to match up the Ids that are returned in the output with the data you submitted. For this reason, Bulk 2.0 may not be a good solution for creating, updating, or upserting records where you need to keep track of the created Ids. The Bulk 2.0 API would be fine for deleting records where you only need to know which Ids were successfully deleted. + +``` r +# create contacts using the Bulk API +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 1.0") + +# query large recordsets using the Bulk API +my_soql <- sprintf("SELECT Id, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$Id , collapse="','")) + +queried_records <- sf_query(my_soql, object_name="Contact", api_type="Bulk 1.0") + +# delete these records using the Bulk API +deleted_records <- sf_delete(queried_records$Id, object_name="Contact", api_type="Bulk 1.0") +``` + +### Using the Metadata API + +Salesforce is a very flexible platform. Salesforce provides the [Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_intro.htm) for users to create, read, update and delete the objects, page layouts, and more. This makes it very easy to programmatically setup and teardown the Salesforce environment. One common use case for the Metadata API is retrieving information about an object (fields, permissions, etc.). You can use the `sf_read_metadata()` function to return a list of objects and their metadata. In the example below we retrieve the metadata for the Account and Contact objects. Note that the `metadata_type` argument is "CustomObject". Standard Objects are an implementation of CustomObjects, so they are returned using that metadata type. + +``` r +read_obj_result <- sf_read_metadata(metadata_type='CustomObject', + object_names=c('Account', 'Contact')) +read_obj_result[[1]][c('fullName', 'label', 'sharingModel', 'enableHistory')] +#> $fullName +#> [1] "Account" +#> +#> $label +#> [1] "Account" +#> +#> $sharingModel +#> [1] "ReadWrite" +#> +#> $enableHistory +#> [1] "false" +first_two_fields_idx <- head(which(names(read_obj_result[[1]]) == 'fields'), 2) +# show the first two returned fields of the Account object +read_obj_result[[1]][first_two_fields_idx] +#> $fields +#> $fields$fullName +#> [1] "AccountNumber" +#> +#> $fields$trackFeedHistory +#> [1] "false" +#> +#> +#> $fields +#> $fields$fullName +#> [1] "AccountSource" +#> +#> $fields$trackFeedHistory +#> [1] "false" +#> +#> $fields$type +#> [1] "Picklist" +``` + +The data is returned as a list because object definitions are highly nested representations. You may notice that we are missing some really specific details, such as, the picklist values of a field with type "Picklist". You can get that information using the function `sf_describe_object()` function which is actually part of the REST and SOAP APIs. It is recommended that you try out the various metadata functions `sf_read_metadata()`, `sf_list_metadata()`, `sf_describe_metadata()`, and `sf_describe_objects()` in order to see which information best suits your use case. + +``` r +describe_obj_result <- sf_describe_objects(object_names=c('Account', 'Contact')) +describe_obj_result[[1]][c('label', 'queryable')] +#> $label +#> [1] "Account" +#> +#> $queryable +#> [1] "true" +# show the first two returned fields of the Account object +the_type_field <- describe_obj_result[[1]][[58]] +the_type_field$name +#> [1] "Type" +map_df(the_type_field[which(names(the_type_field) == "picklistValues")], as_tibble) +#> # A tibble: 7 x 4 +#> active defaultValue label value +#> +#> 1 true false Prospect Prospect +#> 2 true false Customer - Direct Customer - Direct +#> 3 true false Customer - Channel Customer - Channel +#> 4 true false Channel Partner / Reseller Channel Partner / Resell… +#> 5 true false Installation Partner Installation Partner +#> 6 true false Technology Partner Technology Partner +#> 7 true false Other Other +``` + +Where the Metadata API really shines is when it comes to CRUD operations on metadata. In this example we will create an object, add fields to it, then delete that object. + +``` r +# create an object +base_obj_name <- "Custom_Account1" +custom_object <- list() +custom_object$fullName <- paste0(base_obj_name, "__c") +custom_object$label <- paste0(gsub("_", " ", base_obj_name)) +custom_object$pluralLabel <- paste0(base_obj_name, "s") +custom_object$nameField <- list(displayFormat = 'AN-{0000}', + label = paste0(base_obj_name, ' Number'), + type = 'AutoNumber') +custom_object$deploymentStatus <- 'Deployed' +custom_object$sharingModel <- 'ReadWrite' +custom_object$enableActivities <- 'true' +custom_object$description <- paste0(base_obj_name, " created by the Metadata API") +custom_object_result <- sf_create_metadata(metadata_type = 'CustomObject', + metadata = custom_object) + +# add fields to the object +custom_fields <- tibble(fullName=c(paste0(base_obj_name, '__c.CustomField3__c'), + paste0(base_obj_name, '__c.CustomField4__c')), + label=c('Test Field3', 'Test Field4'), + length=c(100, 100), + type=c('Text', 'Text')) +create_fields_result <- sf_create_metadata(metadata_type = 'CustomField', + metadata = custom_fields) + +# delete the object +deleted_custom_object_result <- sf_delete_metadata(metadata_type = 'CustomObject', + object_names = c('Custom_Account1__c')) +``` + +Future +------ + +Future APIs to support: + +- [Reports and Dashboards REST API](https://developer.salesforce.com/docs/atlas.en-us.api_analytics.meta/api_analytics/sforce_analytics_rest_api_intro.htm) +- [Analytics REST API](https://developer.salesforce.com/docs/atlas.en-us.bi_dev_guide_rest.meta/bi_dev_guide_rest/bi_rest_overview.htm) + +Credits +------- + +This application uses other open source software components. The authentication components are mostly verbatim copies of the routines established in the **googlesheets** package (). Methods are inspired by the **RForcecom** package (). We acknowledge and are grateful to these developers for their contributions to open source. + +More Information +---------------- + +Salesforce provides client libraries and examples in many programming langauges (Java, Python, Ruby, and PhP) but unfortunately R is not a supported language. However, most all operations supported by the Salesforce APIs are available via this package. This package makes requests best formatted to match what the APIs require as input. This articulation is not perfect and continued progress will be made to add and improve functionality. For details on formatting, attributes, and methods please refer to [Salesforce's documentation](https://developer.salesforce.com/page/Salesforce_APIs) as they are explained better there. + +More information is also available on the `pkgdown` site at . + +[Top](#salesforcer) + +------------------------------------------------------------------------ + +Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms. diff --git a/build/vignette.rds b/build/vignette.rds new file mode 100644 index 0000000000000000000000000000000000000000..e4becb63ab9b1d2a6a48954cfdaf2b13259eff84 GIT binary patch literal 305 zcmV-10nYv(iwFP!000001BH@NOT#b_$FsIhHxQL6qKL!~(0&JHRK%At2l^V@Yzu3e zkw%JdesNbX?RB(u&WBubcmMWxcgfq35aJNmbBW`^(H(*5!#cGN@yG!7(SjQz(uJQH zrVWpSsf;m2jb>>kj8Lf+%(asKG*mj`k&+GFRj%~PDso|#{`*I=^4VIHf;Q{qv0~Ae ziiP2uS(8I8hi*Bjxp=J@)H3J;FzEf{sq_EyZZAtC6U^Q1ZKff--rY^9XyeX)jSdsH z`v-@r%Rk0uFQueZG_qs=C+|66dWbnlndBKJ`xx{>k?>kD6K3nUlW~a0UR~(nn6G&n zXXqY1^G_%p{5EKyRUXu^WBc^Jz!XLC-K{7}SXNh52Zu2;ESPKf9=y#D|I%)YyaE6K Dk}sFp literal 0 HcmV?d00001 diff --git a/inst/doc/getting-started.R b/inst/doc/getting-started.R new file mode 100644 index 0000000..46c593f --- /dev/null +++ b/inst/doc/getting-started.R @@ -0,0 +1,96 @@ +## ---- echo = FALSE------------------------------------------------------- +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) + +## ----auth, include = FALSE----------------------------------------------- +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) + +## ----load-package, eval=FALSE-------------------------------------------- +# suppressWarnings(suppressMessages(library(dplyr))) +# library(salesforcer) +# sf_auth() + +## ----other-params, eval=FALSE-------------------------------------------- +# options(salesforcer.consumer_key = "012345678901-99thisisatest99connected33app22key") +# options(salesforcer.consumer_secret = "Th1s1sMyConsumerS3cr3t") +# +# sf_auth() + +## ------------------------------------------------------------------------ +# pull down information of person logged in +# it's a simple easy call to get started +# and confirm a connection to the APIs +user_info <- sf_user_info() +sprintf("User Id: %s", user_info$id) +sprintf("User Active?: %s", user_info$isActive) + +## ------------------------------------------------------------------------ +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, "Contact") +created_records + +## ------------------------------------------------------------------------ +retrieved_records <- sf_retrieve(ids=created_records$id, + fields=c("FirstName", "LastName"), + object_name="Contact") +retrieved_records + +## ----query-records------------------------------------------------------- +my_soql <- sprintf("SELECT Id, + Account.Name, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + +queried_records <- sf_query(my_soql) +queried_records + +## ----update-records------------------------------------------------------ +# Update some of those records +queried_records <- queried_records %>% + mutate(FirstName = "TestTest") %>% + select(-Account) + +updated_records <- sf_update(queried_records, object_name="Contact") +updated_records + +## ------------------------------------------------------------------------ +deleted_records <- sf_delete(updated_records$id) +deleted_records + +## ------------------------------------------------------------------------ +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=letters[1:n]) +created_records <- sf_create(new_contacts, "Contact") + +upserted_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Upsert-", 1:n), + My_External_Id__c=letters[1:n]) +new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=letters[n+1]) +upserted_contacts <- bind_rows(upserted_contacts, new_record) + +upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c") +upserted_records + +## ---- include = FALSE---------------------------------------------------- +deleted_records <- sf_delete(upserted_records$id) + diff --git a/inst/doc/getting-started.Rmd b/inst/doc/getting-started.Rmd new file mode 100644 index 0000000..3826de6 --- /dev/null +++ b/inst/doc/getting-started.Rmd @@ -0,0 +1,189 @@ +--- +title: "Getting Started" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Getting Started} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +First, load the `salesforcer` package and login. There are two ways to authenticate: +1) OAuth 2.0 and 2) Basic Username-Password. It is recommended to use OAuth 2.0 so that +passwords do not have to be shared/embedded within scripts. User credentials will +be stored in locally cached file entitled ".httr-oauth-salesforcer" in the current working +directory. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) +``` + +```{r load-package, eval=FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +library(salesforcer) +sf_auth() +``` + +Just a note, that it's not necessary to setup your own Connected App in Salesforce +to use OAuth 2.0 authentication. The only difference is that the authentication +will be run through the client created and associated with the `salesforcer` +package. By using the package client, you will *NOT* be giving access to Salesforce +to anyone, the package is just the medium for you to connect to your own data. +If you wanted more control you would specify those options like so: + +```{r other-params, eval=FALSE} +options(salesforcer.consumer_key = "012345678901-99thisisatest99connected33app22key") +options(salesforcer.consumer_secret = "Th1s1sMyConsumerS3cr3t") + +sf_auth() +``` + +After logging in with `sf_auth()`, you can check your connectivity by looking at +the information returned about the current user. It should be information about you! + +```{r} +# pull down information of person logged in +# it's a simple easy call to get started +# and confirm a connection to the APIs +user_info <- sf_user_info() +sprintf("User Id: %s", user_info$id) +sprintf("User Active?: %s", user_info$isActive) +``` + +### Create +Salesforce has objects and those objects contain records. One default object is the +"Contact" object. This example shows how to create two records in the Contact object. + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, "Contact") +created_records +``` + +### Retrieve +Retrieve pulls down a specific set of records and fields. It's very similar to +running a query, but doesn't use SOQL. Here is an example where we retrieve the +data we just created. + +```{r} +retrieved_records <- sf_retrieve(ids=created_records$id, + fields=c("FirstName", "LastName"), + object_name="Contact") +retrieved_records +``` + + +### Query + +Salesforce has proprietary form of SQL called SOQL (Salesforce Object Query +Language). SOQL is a powerful tool that allows you to return the attributes of records +on almost any object in Salesforce including Accounts, Contacts, Tasks, Opportunities, +even Attachments! Below is an example where we grab the data we just created +including Account object information for which the Contact record is associated +with. The Account column is all `NA` since we have yet to provide information to +link these Contacts with Accounts. + +```{r query-records} +my_soql <- sprintf("SELECT Id, + Account.Name, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + +queried_records <- sf_query(my_soql) +queried_records +``` + +### Update + +After creating records you can update them using `sf_update()`. Updating a record +requires you to pass the Salesforce `Id` of the record. Salesforce creates a unique +18-character identifier on each record and uses that to know which record to +attach the update information you provide. Simply include a field or column in your +update dataset called "Id" and the information will be matched. Here is an example +where we update each of the records we created earlier with a new first name +called "TestTest". + +```{r update-records} +# Update some of those records +queried_records <- queried_records %>% + mutate(FirstName = "TestTest") %>% + select(-Account) + +updated_records <- sf_update(queried_records, object_name="Contact") +updated_records +``` + +### Delete +You can also delete records in Salesforce. The method implements a "soft" delete +meaning that the deleted records go to the Recycle Bin which can be emptied or +queried against later in the event that the record needed. + +```{r} +deleted_records <- sf_delete(updated_records$id) +deleted_records +``` + +### Upsert +Finally, Salesforce has a unique method called "upsert" that allows you to +create and/or update records at the same time. More specifically, if the record +is not found based an an "External Id" field, then Salesforce will create the +record instead of updating one. Below is an example where we create 2 records, +then upsert 3, where 2 are matched and updated and one is created. **NOTE**: You +will need to create a custom field on the target object and ensure it is labeled as +an "External Id" field. Read more at http://blog.jeffdouglas.com/2010/05/07/using-exernal-id-fields-in-salesforce/. + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=letters[1:n]) +created_records <- sf_create(new_contacts, "Contact") + +upserted_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Upsert-", 1:n), + My_External_Id__c=letters[1:n]) +new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=letters[n+1]) +upserted_contacts <- bind_rows(upserted_contacts, new_record) + +upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c") +upserted_records +``` + +```{r, include = FALSE} +deleted_records <- sf_delete(upserted_records$id) +``` + +### Check out the Tests + +The **salesforcer** package has quite a bit of unit test coverage to track any +changes made between newly released versions of the Salesforce API (typically 4 each year). +These tests are an excellent source of examples because they cover most all cases of +utilizing the package functions. diff --git a/inst/doc/getting-started.html b/inst/doc/getting-started.html new file mode 100644 index 0000000..22233c0 --- /dev/null +++ b/inst/doc/getting-started.html @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + +Getting Started + + + + + + + + + + + + + + + + + +

Getting Started

+

Steven M. Mortimer

+

2018-03-12

+ + + + +

First, load the salesforcer package and login. There are two ways to authenticate: 1) OAuth 2.0 and 2) Basic Username-Password. It is recommended to use OAuth 2.0 so that passwords do not have to be shared/embedded within scripts. User credentials will be stored in locally cached file entitled “.httr-oauth-salesforcer” in the current working directory.

+
suppressWarnings(suppressMessages(library(dplyr)))
+library(salesforcer)
+sf_auth()
+

Just a note, that it’s not necessary to setup your own Connected App in Salesforce to use OAuth 2.0 authentication. The only difference is that the authentication will be run through the client created and associated with the salesforcer package. By using the package client, you will NOT be giving access to Salesforce to anyone, the package is just the medium for you to connect to your own data. If you wanted more control you would specify those options like so:

+
options(salesforcer.consumer_key = "012345678901-99thisisatest99connected33app22key")
+options(salesforcer.consumer_secret = "Th1s1sMyConsumerS3cr3t")
+
+sf_auth()
+

After logging in with sf_auth(), you can check your connectivity by looking at the information returned about the current user. It should be information about you!

+
# pull down information of person logged in
+# it's a simple easy call to get started 
+# and confirm a connection to the APIs
+user_info <- sf_user_info()
+sprintf("User Id: %s", user_info$id)
+#> [1] "User Id: 0056A000000MPRjQAO"
+sprintf("User Active?: %s", user_info$isActive)
+#> [1] "User Active?: TRUE"
+
+

Create

+

Salesforce has objects and those objects contain records. One default object is the “Contact” object. This example shows how to create two records in the Contact object.

+
n <- 2
+new_contacts <- tibble(FirstName = rep("Test", n),
+                       LastName = paste0("Contact-Create-", 1:n))
+created_records <- sf_create(new_contacts, "Contact")
+created_records
+#> # A tibble: 2 x 2
+#>   id                 success
+#>   <chr>              <chr>  
+#> 1 0036A00000SnwvEQAR true   
+#> 2 0036A00000SnwvFQAR true
+
+
+

Retrieve

+

Retrieve pulls down a specific set of records and fields. It’s very similar to running a query, but doesn’t use SOQL. Here is an example where we retrieve the data we just created.

+
retrieved_records <- sf_retrieve(ids=created_records$id, 
+                                 fields=c("FirstName", "LastName"), 
+                                 object_name="Contact")
+retrieved_records
+#> # A tibble: 2 x 3
+#>   Id                 FirstName LastName        
+#>   <chr>              <chr>     <chr>           
+#> 1 0036A00000SnwvEQAR Test      Contact-Create-1
+#> 2 0036A00000SnwvFQAR Test      Contact-Create-2
+
+
+

Query

+

Salesforce has proprietary form of SQL called SOQL (Salesforce Object Query Language). SOQL is a powerful tool that allows you to return the attributes of records on almost any object in Salesforce including Accounts, Contacts, Tasks, Opportunities, even Attachments! Below is an example where we grab the data we just created including Account object information for which the Contact record is associated with. The Account column is all NA since we have yet to provide information to link these Contacts with Accounts.

+
my_soql <- sprintf("SELECT Id, 
+                           Account.Name, 
+                           FirstName, 
+                           LastName 
+                    FROM Contact 
+                    WHERE Id in ('%s')", 
+                   paste0(created_records$id , collapse="','"))
+
+queried_records <- sf_query(my_soql)
+queried_records
+#> # A tibble: 2 x 4
+#>   Id                 Account FirstName LastName        
+#> * <chr>              <lgl>   <chr>     <chr>           
+#> 1 0036A00000SnwvEQAR NA      Test      Contact-Create-1
+#> 2 0036A00000SnwvFQAR NA      Test      Contact-Create-2
+
+
+

Update

+

After creating records you can update them using sf_update(). Updating a record requires you to pass the Salesforce Id of the record. Salesforce creates a unique 18-character identifier on each record and uses that to know which record to attach the update information you provide. Simply include a field or column in your update dataset called “Id” and the information will be matched. Here is an example where we update each of the records we created earlier with a new first name called “TestTest”.

+
# Update some of those records
+queried_records <- queried_records %>%
+  mutate(FirstName = "TestTest") %>% 
+  select(-Account)
+
+updated_records <- sf_update(queried_records, object_name="Contact")
+updated_records
+#> # A tibble: 2 x 2
+#>   id                 success
+#>   <chr>              <chr>  
+#> 1 0036A00000SnwvEQAR true   
+#> 2 0036A00000SnwvFQAR true
+
+
+

Delete

+

You can also delete records in Salesforce. The method implements a “soft” delete meaning that the deleted records go to the Recycle Bin which can be emptied or queried against later in the event that the record needed.

+
deleted_records <- sf_delete(updated_records$id)
+deleted_records
+#> # A tibble: 2 x 3
+#>   id                 success errors    
+#>   <chr>              <lgl>   <list>    
+#> 1 0036A00000SnwvEQAR TRUE    <list [0]>
+#> 2 0036A00000SnwvFQAR TRUE    <list [0]>
+
+
+

Upsert

+

Finally, Salesforce has a unique method called “upsert” that allows you to create and/or update records at the same time. More specifically, if the record is not found based an an “External Id” field, then Salesforce will create the record instead of updating one. Below is an example where we create 2 records, then upsert 3, where 2 are matched and updated and one is created. NOTE: You will need to create a custom field on the target object and ensure it is labeled as an “External Id” field. Read more at http://blog.jeffdouglas.com/2010/05/07/using-exernal-id-fields-in-salesforce/.

+
n <- 2
+new_contacts <- tibble(FirstName = rep("Test", n),
+                       LastName = paste0("Contact-Create-", 1:n), 
+                       My_External_Id__c=letters[1:n])
+created_records <- sf_create(new_contacts, "Contact")
+
+upserted_contacts <- tibble(FirstName = rep("Test", n),
+                            LastName = paste0("Contact-Upsert-", 1:n), 
+                            My_External_Id__c=letters[1:n])
+new_record <- tibble(FirstName = "Test",
+                     LastName = paste0("Contact-Upsert-", n+1), 
+                     My_External_Id__c=letters[n+1])
+upserted_contacts <- bind_rows(upserted_contacts, new_record)
+
+upserted_records <- sf_upsert(input_data=upserted_contacts, 
+                              object_name="Contact", 
+                              external_id_fieldname="My_External_Id__c")
+upserted_records
+#> # A tibble: 3 x 3
+#>   created id                 success
+#>   <chr>   <chr>              <chr>  
+#> 1 false   0036A00000SnwvJQAR true   
+#> 2 false   0036A00000SnwvKQAR true   
+#> 3 true    0036A00000SnwvOQAR true
+
+
+

Check out the Tests

+

The salesforcer package has quite a bit of unit test coverage to track any changes made between newly released versions of the Salesforce API (typically 4 each year). These tests are an excellent source of examples because they cover most all cases of utilizing the package functions.

+
+ + + + + + + + diff --git a/inst/doc/transitioning-from-RForcecom.R b/inst/doc/transitioning-from-RForcecom.R new file mode 100644 index 0000000..a966e4b --- /dev/null +++ b/inst/doc/transitioning-from-RForcecom.R @@ -0,0 +1,83 @@ +## ---- echo = FALSE------------------------------------------------------- +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) + +## ----auth, include = FALSE----------------------------------------------- +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +options_path <- here::here("tests", "testthat", "salesforcer_test_settings.rds") +salesforcer_test_settings <- readRDS(options_path) +username <- salesforcer_test_settings$username +password <- salesforcer_test_settings$password +security_token <- salesforcer_test_settings$security_token + +## ---- warning=FALSE------------------------------------------------------ +# the RForcecom way +session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session1['sessionID'] <- "{MASKED}" +session1 + +# replicated in salesforcer package +session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session2['sessionID'] <- "{MASKED}" +session2 + +## ---- include=FALSE------------------------------------------------------ +# keep using the session, just rename it to "session" +session <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) + +## ---- warning=FALSE------------------------------------------------------ +object <- "Contact" +fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility") + +# the RForcecom way +result1 <- RForcecom::rforcecom.create(session, objectName=object, fields) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.create(session, objectName=object, fields) +result2 + +## ---- warning=FALSE------------------------------------------------------ +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) + +# the RForcecom way +rforcecom_results <- NULL +for(i in 1:nrow(new_contacts)){ + temp <- RForcecom::rforcecom.create(session, + objectName = "Contact", + fields = unlist(slice(new_contacts,i))) + rforcecom_results <- bind_rows(rforcecom_results, temp) +} +rforcecom_results + +# the better way in salesforcer to do multiple records +salesforcer_results <- sf_create(new_contacts, object_name="Contact") +salesforcer_results + +## ---- warning=FALSE------------------------------------------------------ +this_soql <- "SELECT Id, Email FROM Contact LIMIT 5" + +# the RForcecom way +result1 <- RForcecom::rforcecom.query(session, soqlQuery = this_soql) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql) +result2 + +# the better way in salesforcer to query +salesforcer_results <- sf_query(this_soql) +salesforcer_results + diff --git a/inst/doc/transitioning-from-RForcecom.Rmd b/inst/doc/transitioning-from-RForcecom.Rmd new file mode 100644 index 0000000..59cbc4e --- /dev/null +++ b/inst/doc/transitioning-from-RForcecom.Rmd @@ -0,0 +1,142 @@ +--- +title: "Transitioning from RForcecom" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Transitioning from RForcecom} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +While writing the **salesforcer** package we were keenly aware that many folks +are already using the **RForcecom** package to connect to Salesforce. In order +to foster adoption and switching between the packages **salesforcer** replicates +the functionality of many **RForcecom** functions so that you will only need to swap +out `library(RForcecom)` for `library(salesforcer)` and still have your production +tested scripts perform as usual. + +### Authentication + +**salesforcer** supports OAuth 2.0 authentication which is preferred, but for +backward compatibility provides the username-password authentication routine +implemented by **RForcecom**. Here is an example running the function from +each of the packages side-by-side and producing the same result. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +options_path <- here::here("tests", "testthat", "salesforcer_test_settings.rds") +salesforcer_test_settings <- readRDS(options_path) +username <- salesforcer_test_settings$username +password <- salesforcer_test_settings$password +security_token <- salesforcer_test_settings$security_token +``` + +```{r, warning=FALSE} +# the RForcecom way +session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session1['sessionID'] <- "{MASKED}" +session1 + +# replicated in salesforcer package +session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session2['sessionID'] <- "{MASKED}" +session2 +``` + +```{r, include=FALSE} +# keep using the session, just rename it to "session" +session <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +``` + +Note that we must set the API version here because calls to session will not create +a new sessionId and then we are stuck with version 35.0 (the default from +RForcecom::rforcecom.login). Some functions in **salesforcer** implement API calls +that are only available after version 35.0. + +### CRUD Operations + +"CRUD" operations (Create, Retrieve, Update, Delete) in the **RForcecom** package +only operate on one record at a time. One benefit to using the **salesforcer** package +is that these operations will accept a named vector (one record) or an entire `data.frame` +or `tbl_df` of records to churn through. However, rest assured that the replicated +functions behave exactly the same way if you are hesitant to making the switch. + +```{r, warning=FALSE} +object <- "Contact" +fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility") + +# the RForcecom way +result1 <- RForcecom::rforcecom.create(session, objectName=object, fields) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.create(session, objectName=object, fields) +result2 +``` + +Here is an example showing the reduction in code of using **salesforcer** if you +would like to create multiple records. + +```{r, warning=FALSE} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) + +# the RForcecom way +rforcecom_results <- NULL +for(i in 1:nrow(new_contacts)){ + temp <- RForcecom::rforcecom.create(session, + objectName = "Contact", + fields = unlist(slice(new_contacts,i))) + rforcecom_results <- bind_rows(rforcecom_results, temp) +} +rforcecom_results + +# the better way in salesforcer to do multiple records +salesforcer_results <- sf_create(new_contacts, object_name="Contact") +salesforcer_results +``` + +### Query + +**salesforcer** also has better printing and type-casting when returning query result +thanks to features of the readr package. + +```{r, warning=FALSE} +this_soql <- "SELECT Id, Email FROM Contact LIMIT 5" + +# the RForcecom way +result1 <- RForcecom::rforcecom.query(session, soqlQuery = this_soql) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql) +result2 + +# the better way in salesforcer to query +salesforcer_results <- sf_query(this_soql) +salesforcer_results +``` + +In the future more features will be migrated from **RForcecom** to make the +transition as seamless as possible. diff --git a/inst/doc/transitioning-from-RForcecom.html b/inst/doc/transitioning-from-RForcecom.html new file mode 100644 index 0000000..20b3dab --- /dev/null +++ b/inst/doc/transitioning-from-RForcecom.html @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + +Transitioning from RForcecom + + + + + + + + + + + + + + + + + +

Transitioning from RForcecom

+

Steven M. Mortimer

+

2018-03-12

+ + + + +

While writing the salesforcer package we were keenly aware that many folks are already using the RForcecom package to connect to Salesforce. In order to foster adoption and switching between the packages salesforcer replicates the functionality of many RForcecom functions so that you will only need to swap out library(RForcecom) for library(salesforcer) and still have your production tested scripts perform as usual.

+
+

Authentication

+

salesforcer supports OAuth 2.0 authentication which is preferred, but for backward compatibility provides the username-password authentication routine implemented by RForcecom. Here is an example running the function from each of the packages side-by-side and producing the same result.

+
# the RForcecom way
+session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token), 
+                                       apiVersion=getOption("salesforcer.api_version"))
+session1['sessionID'] <- "{MASKED}"
+session1
+#>                      sessionID                    instanceURL 
+#>                     "{MASKED}" "https://na50.salesforce.com/" 
+#>                     apiVersion 
+#>                         "42.0"
+
+# replicated in salesforcer package
+session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token), 
+                                         apiVersion=getOption("salesforcer.api_version"))
+session2['sessionID'] <- "{MASKED}"
+session2
+#>                      sessionID                    instanceURL 
+#>                     "{MASKED}" "https://na50.salesforce.com/" 
+#>                     apiVersion 
+#>                         "42.0"
+

Note that we must set the API version here because calls to session will not create a new sessionId and then we are stuck with version 35.0 (the default from RForcecom::rforcecom.login). Some functions in salesforcer implement API calls that are only available after version 35.0.

+
+
+

CRUD Operations

+

“CRUD” operations (Create, Retrieve, Update, Delete) in the RForcecom package only operate on one record at a time. One benefit to using the salesforcer package is that these operations will accept a named vector (one record) or an entire data.frame or tbl_df of records to churn through. However, rest assured that the replicated functions behave exactly the same way if you are hesitant to making the switch.

+
object <- "Contact"
+fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility")
+
+# the RForcecom way
+result1 <- RForcecom::rforcecom.create(session, objectName=object, fields)
+result1
+#>                   id success
+#> 1 0036A00000SnwvTQAR    true
+
+# replicated in salesforcer package
+result2 <- salesforcer::rforcecom.create(session, objectName=object, fields)
+result2
+#>                   id success
+#> 1 0036A00000SnwvYQAR    true
+

Here is an example showing the reduction in code of using salesforcer if you would like to create multiple records.

+
n <- 2
+new_contacts <- tibble(FirstName = rep("Test", n),
+                       LastName = paste0("Contact-Create-", 1:n))
+
+# the RForcecom way
+rforcecom_results <- NULL
+for(i in 1:nrow(new_contacts)){
+  temp <- RForcecom::rforcecom.create(session, 
+                                      objectName = "Contact", 
+                                      fields = unlist(slice(new_contacts,i)))
+  rforcecom_results <- bind_rows(rforcecom_results, temp)
+}
+rforcecom_results
+#>                   id success
+#> 1 0036A00000SnwvdQAB    true
+#> 2 0036A00000SnwviQAB    true
+
+# the better way in salesforcer to do multiple records
+salesforcer_results <- sf_create(new_contacts, object_name="Contact")
+salesforcer_results
+#> # A tibble: 2 x 2
+#>   id                 success
+#>   <chr>              <chr>  
+#> 1 0036A00000SnwvnQAB true   
+#> 2 0036A00000SnwvoQAB true
+
+
+

Query

+

salesforcer also has better printing and type-casting when returning query result thanks to features of the readr package.

+
this_soql <- "SELECT Id, Email FROM Contact LIMIT 5"
+
+# the RForcecom way
+result1 <- RForcecom::rforcecom.query(session, soqlQuery = this_soql)
+result1
+#>                   Id
+#> 1 0036A00000SncIGQAZ
+#> 2 0036A00000SncIHQAZ
+#> 3 0036A00000RUqb0QAD
+#> 4 0036A00000RUqedQAD
+#> 5 0036A00000RUqeeQAD
+
+# replicated in salesforcer package
+result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql)
+result2
+#> # A tibble: 5 x 2
+#>   Id                 Email
+#> * <chr>              <lgl>
+#> 1 0036A00000SncIGQAZ NA   
+#> 2 0036A00000SncIHQAZ NA   
+#> 3 0036A00000RUqb0QAD NA   
+#> 4 0036A00000RUqedQAD NA   
+#> 5 0036A00000RUqeeQAD NA
+
+# the better way in salesforcer to query
+salesforcer_results <- sf_query(this_soql)
+salesforcer_results
+#> # A tibble: 5 x 2
+#>   Id                 Email
+#> * <chr>              <lgl>
+#> 1 0036A00000SncIGQAZ NA   
+#> 2 0036A00000SncIHQAZ NA   
+#> 3 0036A00000RUqb0QAD NA   
+#> 4 0036A00000RUqedQAD NA   
+#> 5 0036A00000RUqeeQAD NA
+

In the future more features will be migrated from RForcecom to make the transition as seamless as possible.

+
+ + + + + + + + diff --git a/inst/doc/working-with-bulk-api.R b/inst/doc/working-with-bulk-api.R new file mode 100644 index 0000000..5d9d744 --- /dev/null +++ b/inst/doc/working-with-bulk-api.R @@ -0,0 +1,57 @@ +## ---- echo = FALSE------------------------------------------------------- +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) + +## ----auth, include = FALSE----------------------------------------------- +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) + +## ----load-package, eval=FALSE-------------------------------------------- +# suppressWarnings(suppressMessages(library(dplyr))) +# library(salesforcer) +# sf_auth() + +## ------------------------------------------------------------------------ +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +# REST +rest_created_records <- sf_create(new_contacts, object_name="Contact", api_type="REST") +rest_created_records +# Bulk +bulk_created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 1.0") +bulk_created_records + +## ------------------------------------------------------------------------ +# just add api_type="Bulk" to most calls! +# create bulk +object <- "Contact" +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, object_name=object, api_type="Bulk 1.0") +created_records + +# query bulk +my_soql <- sprintf("SELECT Id, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$Id , collapse="','")) + +queried_records <- sf_query(my_soql, object_name=object, api_type="Bulk 1.0") +queried_records + +# delete bulk +deleted_records <- sf_delete(queried_records$Id, object_name=object, api_type="Bulk 1.0") +deleted_records + diff --git a/inst/doc/working-with-bulk-api.Rmd b/inst/doc/working-with-bulk-api.Rmd new file mode 100644 index 0000000..161b212 --- /dev/null +++ b/inst/doc/working-with-bulk-api.Rmd @@ -0,0 +1,92 @@ +--- +title: "Working with Bulk API" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Working with Bulk API} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +### Using the Bulk API + +First, load the `salesforcer` package and login. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) +``` + +```{r load-package, eval=FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +library(salesforcer) +sf_auth() +``` + +For really large inserts, updates, deletes, upserts, queries you can just add +"api_type" = "Bulk" to most functions to get the benefits of using the Bulk API +instead of the SOAP or REST APIs. Here is the difference in using the REST API vs. +the Bulk API to do an insert: + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +# REST +rest_created_records <- sf_create(new_contacts, object_name="Contact", api_type="REST") +rest_created_records +# Bulk +bulk_created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 1.0") +bulk_created_records +``` + +There are some differences in the way each API returns response information; however, +the end result is exactly the same for these two calls. Also, note that this +package utilizes the Bulk 2.0 API for most bulk calls except for bulk queries +since Salesforce has not yet implemented it in 2.0. + +Here is a simple workflow of adding, querying, and deleting records using the Bulk API. + +```{r} +# just add api_type="Bulk" to most calls! +# create bulk +object <- "Contact" +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, object_name=object, api_type="Bulk 1.0") +created_records + +# query bulk +my_soql <- sprintf("SELECT Id, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$Id , collapse="','")) + +queried_records <- sf_query(my_soql, object_name=object, api_type="Bulk 1.0") +queried_records + +# delete bulk +deleted_records <- sf_delete(queried_records$Id, object_name=object, api_type="Bulk 1.0") +deleted_records +``` diff --git a/inst/doc/working-with-bulk-api.html b/inst/doc/working-with-bulk-api.html new file mode 100644 index 0000000..d5cf3c9 --- /dev/null +++ b/inst/doc/working-with-bulk-api.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + +Working with Bulk API + + + + + + + + + + + + + + + + + +

Working with Bulk API

+

Steven M. Mortimer

+

2018-03-12

+ + + + +
+

Using the Bulk API

+

First, load the salesforcer package and login.

+
suppressWarnings(suppressMessages(library(dplyr)))
+library(salesforcer)
+sf_auth()
+

For really large inserts, updates, deletes, upserts, queries you can just add “api_type” = “Bulk” to most functions to get the benefits of using the Bulk API instead of the SOAP or REST APIs. Here is the difference in using the REST API vs. the Bulk API to do an insert:

+
n <- 2
+new_contacts <- tibble(FirstName = rep("Test", n),
+                       LastName = paste0("Contact-Create-", 1:n))
+# REST
+rest_created_records <- sf_create(new_contacts, object_name="Contact", api_type="REST")
+rest_created_records
+#> # A tibble: 2 x 3
+#>   id                 success errors    
+#>   <chr>              <lgl>   <list>    
+#> 1 0036A00000SnwvsQAB TRUE    <list [0]>
+#> 2 0036A00000SnwvtQAB TRUE    <list [0]>
+# Bulk
+bulk_created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 1.0")
+bulk_created_records
+#> # A tibble: 2 x 4
+#>   Id                 Success Created Error
+#>   <chr>              <chr>   <chr>   <lgl>
+#> 1 0036A00000SnwvjQAB true    true    NA   
+#> 2 0036A00000SnwvkQAB true    true    NA
+

There are some differences in the way each API returns response information; however, the end result is exactly the same for these two calls. Also, note that this package utilizes the Bulk 2.0 API for most bulk calls except for bulk queries since Salesforce has not yet implemented it in 2.0.

+

Here is a simple workflow of adding, querying, and deleting records using the Bulk API.

+
# just add api_type="Bulk" to most calls!
+# create bulk
+object <- "Contact"
+n <- 2
+new_contacts <- tibble(FirstName = rep("Test", n),
+                       LastName = paste0("Contact-Create-", 1:n))
+created_records <- sf_create(new_contacts, object_name=object, api_type="Bulk 1.0")
+created_records
+#> # A tibble: 2 x 4
+#>   Id                 Success Created Error
+#>   <chr>              <chr>   <chr>   <lgl>
+#> 1 0036A00000SnwvxQAB true    true    NA   
+#> 2 0036A00000SnwvyQAB true    true    NA
+
+# query bulk
+my_soql <- sprintf("SELECT Id,
+                           FirstName, 
+                           LastName
+                    FROM Contact 
+                    WHERE Id in ('%s')", 
+                   paste0(created_records$Id , collapse="','"))
+
+queried_records <- sf_query(my_soql, object_name=object, api_type="Bulk 1.0")
+queried_records
+#> # A tibble: 2 x 3
+#>   Id                 FirstName LastName        
+#>   <chr>              <chr>     <chr>           
+#> 1 0036A00000SnwvxQAB Test      Contact-Create-1
+#> 2 0036A00000SnwvyQAB Test      Contact-Create-2
+
+# delete bulk
+deleted_records <- sf_delete(queried_records$Id, object_name=object, api_type="Bulk 1.0")
+deleted_records
+#> # A tibble: 2 x 4
+#>   Id                 Success Created Error
+#>   <chr>              <chr>   <chr>   <lgl>
+#> 1 0036A00000SnwvxQAB true    false   NA   
+#> 2 0036A00000SnwvyQAB true    false   NA
+
+ + + + + + + + diff --git a/man/VERB_n.Rd b/man/VERB_n.Rd new file mode 100644 index 0000000..4d97e91 --- /dev/null +++ b/man/VERB_n.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-httr.R +\name{VERB_n} +\alias{VERB_n} +\title{Generic implementation of HTTP methods with retries and authentication} +\usage{ +VERB_n(VERB, n = 5) +} +\description{ +Generic implementation of HTTP methods with retries and authentication +} +\note{ +This function is meant to be used internally. Only use when debugging. +} +\keyword{internal} diff --git a/man/build_metadata_xml_from_list.Rd b/man/build_metadata_xml_from_list.Rd new file mode 100644 index 0000000..56a1ff4 --- /dev/null +++ b/man/build_metadata_xml_from_list.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-xml.R +\name{build_metadata_xml_from_list} +\alias{build_metadata_xml_from_list} +\title{Metadata List to XML Converter} +\usage{ +build_metadata_xml_from_list(input_data, metatype = NULL, root_name = NULL, + ns = c(character(0)), root = NULL) +} +\arguments{ +\item{input_data}{XML document serving as the basis upon which to add the list} + +\item{metatype}{a character indicating the element name of each record in the list} + +\item{root_name}{character; the name of the root node if created} + +\item{ns}{named vector; a collection of character strings indicating the namespace +definitions of the root node if created} + +\item{root}{\code{XMLNode}; a node to be used as the root} +} +\value{ +A XML document with the sublist data added +} +\description{ +This function converts a list of metadata to XML +} +\concept{ +metadata salesforce api +} diff --git a/man/build_soap_xml_from_list.Rd b/man/build_soap_xml_from_list.Rd new file mode 100644 index 0000000..39357b6 --- /dev/null +++ b/man/build_soap_xml_from_list.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-xml.R +\name{build_soap_xml_from_list} +\alias{build_soap_xml_from_list} +\title{Build XML Request Body} +\usage{ +build_soap_xml_from_list(input_data, operation = c("create", "retrieve", + "update", "upsert", "delete", "search", "query", "queryMore", + "describeSObjects"), object_name = NULL, fields = NULL, + external_id_fieldname = NULL, root_name = NULL, ns = c(character(0)), + root = NULL) +} +\arguments{ +\item{input_data}{a \code{data.frame} of data to fill the XML body} + +\item{operation}{character; a string defining the type of operation being +performed (e.g. "insert", "update", "upsert", "delete")} + +\item{object_name}{character; the name of one Salesforce objects that the +function is operating against (e.g. "Account", "Contact", "CustomObject__c")} + +\item{fields}{character; one or more strings indicating the fields to be returned +on the records} + +\item{external_id_fieldname}{character; string identifying a custom field on the +object that has been set as an "External ID" field. This field is used to reference +objects during upserts to determine if the record already exists in Salesforce or not.} + +\item{root_name}{character; the name of the root node if created} + +\item{ns}{named vector; a collection of character strings indicating the namespace +definitions of the root node if created} + +\item{root}{\code{XMLNode}; a node to be used as the root} +} +\value{ +a XML document +} +\description{ +Parse data into XML format +} +\note{ +This function is meant to be used internally. Only use when debugging. +} +\keyword{internal} diff --git a/man/catch_errors.Rd b/man/catch_errors.Rd new file mode 100644 index 0000000..f9ad8e9 --- /dev/null +++ b/man/catch_errors.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-httr.R +\name{catch_errors} +\alias{catch_errors} +\title{Function to catch and print HTTP errors} +\usage{ +catch_errors(x) +} +\description{ +Function to catch and print HTTP errors +} +\note{ +This function is meant to be used internally. Only use when debugging. +} +\keyword{internal} diff --git a/man/figures/cloud.png b/man/figures/cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d90f711bf08a0af4e2c7802f8f3daaba966e87 GIT binary patch literal 17110 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 IM?K^J5B$4fCjbBd literal 0 HcmV?d00001 diff --git a/man/figures/logo.png b/man/figures/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf5fa7416ca838af0cf6a7e28a2d22e347d64ea GIT binary patch literal 12013 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 literal 0 HcmV?d00001 diff --git a/man/figures/old-logo.png b/man/figures/old-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2ae3be2575547e75de3543f93380993dce0d92 GIT binary patch literal 4897 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

?-z_v=WKEy zpp43cF1* z_`AU!<3qU$AS|O8hN}RT(YWK<${@;APb}mxMP}VIBiN{{F8z|t^WhaFh6&dVj7F#w z)Im11hd?ol_1BWGb5MSM9%>_`GPH{*@LU(**iOgxServ1Gn1xyC0NUCxV{9*BIq+U z_H%j`&Q9&L;PpSreg)02Ncpu1w zhAbU~j|8Z_sx?Er=nn1C10W23r>;;puH#0|TzyBwUn8oY+Re;RT#EwPC+b(@XO7RY z+U2Ix0kCG{O6KmeBcm5wiy&d?_`4>yn?;2vw0%8IA8T^_@oX=+HKC#CtnbdBk6Jl1Wfc>WB$OuIlK2qJ&zi)T|UEC=;^-P$k~$*CyQ5WgpGHSM&Tk zC%N78yehgnu}!rWDa%(#Yz|C~fAXqeo@X6ld6U5%wAq#$2iU`M#rf;~tugL<^_}>i zCX+`})F*!bY$<=!+Z=;skEuoXRe!maPxxjT7cD$>|D2|$22&{i`^BE)n2)WCPmz33 zVaotXE!b3&>hQQDF0aG_?Lv%+TeGi*UatAUVV9Xr(+Ugg_9G*v91daM{4qc`Wm}kU z^Xm!n#)O{@6p+?aK3ijWB9l+&UR1?%N5#a`Mm> zc2nq#r;ArrksVH&r5b=)2`-%0(w-AbCYw9M0bf%7q_ugj#n?SE=Cb!%pd*YtvNu&F z*TRO8F2dki#?CU1)GtPRVI3iENn4ayj~(q-8XJUqmugwgU}Rd56SxB_s}#&a3jIt|~a&yHIO zs}64DRTg1V-F{YB{wMHNvNHVrfd~^w22}=F7o;`?np@)8jlO4ByHGxluyJ{|%>B{c zwWv`!LzdzAA4QPi>SYFBS6mF;$@V*IK-l{t26EORN;>AEZ2vmjNeBdz4yQgVFQ1G3 z`I1@`>N*i;{c){9ju`J(-z0h~J57qR^v5JP+QmuyPezXF#YLHz(ufuR+9@~ONw^yw zYiLk(r{^l|5vNb4qqr{T{$AVl{thH<93-(l_-;TTKbHx<)>Ix=%K5D?Mj{k1xq+

UtqDPk8yiUKi|`XRifzPsX&?NgT3BPsSR6vE3fQ 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 + mutate(FirstName = "TestTest") + + # sf_update ------------------------------------------------------------------ + updated_records <- sf_update(queried_records, object_name="Contact", api_type="Bulk 1.0") + expect_is(updated_records, "tbl_df") + expect_named(updated_records, c("Id", "Success", "Created", "Error")) + expect_equal(nrow(updated_records), nrow(queried_records)) + expect_true(all(updated_records$Success == "true")) + expect_true(all(updated_records$Created == "false")) + + new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=paste0(prefix, letters[n+1])) + upserted_contacts <- bind_rows(queried_records %>% select(-Id), new_record) + + # sf_upsert ------------------------------------------------------------------ + upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c", + api_type = "Bulk 1.0") + expect_is(upserted_records, "tbl_df") + expect_named(upserted_records, c("Id", "Success", "Created", "Error")) + expect_equal(nrow(upserted_records), nrow(upserted_contacts)) + expect_true(all(upserted_records$Success == "true")) + expect_equal(upserted_records$Created, c("false", "false", "true")) + + # sf_delete ------------------------------------------------------------------ + ids_to_delete <- unique(c(upserted_records$Id, queried_records$Id)) + deleted_records <- sf_delete(ids_to_delete, object_name="Contact", api_type = "Bulk 1.0") + expect_is(deleted_records, "tbl_df") + expect_named(deleted_records, c("Id", "Success", "Created", "Error")) + expect_equal(nrow(deleted_records), length(ids_to_delete)) + expect_true(all(deleted_records$Success == "true")) + expect_true(all(deleted_records$Created == "false")) +}) + +context("Bulk 2.0") + +test_that("testing Bulk 2.0 Functionality", { + + n <- 2 + prefix <- paste0("Bulk-", as.integer(runif(1,1,100000)), "-") + new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=paste0(prefix, letters[1:n])) + # sf_create ------------------------------------------------------------------ + created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 2.0") + expect_is(created_records, "tbl_df") + expect_named(created_records, c("sf__Id", "sf__Created", "FirstName", "LastName", + "My_External_Id__c", "sf__Error")) + expect_equal(nrow(created_records), n) + expect_true(all(is.na(created_records$sf__Error))) + expect_true(all(created_records$sf__Created == "true")) + + # sf_retrieve ---------------------------------------------------------------- + expect_error( + retrieved_records <- sf_retrieve(ids=created_records$sf__Id, + fields=c("FirstName", "LastName"), + object_name="Contact", + api_type="Bulk 2.0") + ) + + my_sosl <- paste("FIND {(336)} in phone fields returning", + "contact(id, firstname, lastname, my_external_id__c),", + "lead(id, firstname, lastname)") + # sf_search ------------------------------------------------------------------ + expect_error( + searched_records <- sf_search(my_sosl, is_sosl=TRUE, api_type="Bulk 2.0") + ) + + ids_from_created <- created_records$sf__Id + my_soql <- sprintf("SELECT Id, + FirstName, + LastName, + My_External_Id__c + FROM Contact + WHERE Id in ('%s')", + paste0(ids_from_created, collapse="','")) + # sf_query ------------------------------------------------------------------- + expect_error( + queried_records <- sf_query(soql=my_soql, object_name="Contact", api_type="Bulk 2.0") + ) + + queried_records <- sf_query(soql=my_soql, object_name="Contact", api_type="Bulk 1.0") + queried_records <- queried_records %>% + mutate(FirstName = "TestTest") + + # sf_update ------------------------------------------------------------------ + updated_records <- sf_update(queried_records, object_name="Contact", api_type="Bulk 2.0") + expect_is(updated_records, "tbl_df") + expect_named(updated_records, c("sf__Id", "sf__Created", "FirstName", "Id", "LastName", + "My_External_Id__c", "sf__Error")) + expect_equal(nrow(updated_records), nrow(queried_records)) + expect_true(all(is.na(updated_records$sf__Error))) + expect_true(all(updated_records$sf__Created == "false")) + + new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=paste0(prefix, letters[n+1])) + upserted_contacts <- bind_rows(queried_records %>% select(-Id), new_record) + + # sf_upsert ------------------------------------------------------------------ + upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c", + api_type = "Bulk 2.0") + expect_is(upserted_records, "tbl_df") + expect_named(upserted_records, c("sf__Id", "sf__Created", "FirstName", "LastName", + "My_External_Id__c", "sf__Error")) + expect_equal(nrow(upserted_records), nrow(upserted_contacts)) + expect_true(all(is.na(upserted_records$sf__Error))) + expect_equal(upserted_records$sf__Created, c("false", "false", "true")) + + # sf_delete ------------------------------------------------------------------ + ids_to_delete <- unique(c(upserted_records$sf__Id, queried_records$Id)) + deleted_records <- sf_delete(ids_to_delete, object_name="Contact", api_type = "Bulk 2.0") + expect_is(deleted_records, "tbl_df") + expect_named(deleted_records, c("sf__Id", "sf__Created", "Id", "sf__Error")) + expect_equal(nrow(deleted_records), length(ids_to_delete)) + expect_true(all(is.na(deleted_records$sf__Error))) + expect_true(all(deleted_records$sf__Created == "false")) +}) diff --git a/tests/testthat/test-compatibility.R b/tests/testthat/test-compatibility.R new file mode 100644 index 0000000..12e9990 --- /dev/null +++ b/tests/testthat/test-compatibility.R @@ -0,0 +1,188 @@ +context("RForcecom Compatibility") + +salesforcer_test_settings <- readRDS("salesforcer_test_settings.rds") +salesforcer_token <- readRDS("salesforcer_token.rds") + +test_that("testing rforcecom.login compatibility", { + + username <- salesforcer_test_settings$username + password <- salesforcer_test_settings$password + security_token <- salesforcer_test_settings$security_token + + # must set the API Version here because new calls to session will not + # create a new sessionId and then we are stuck with version 35.0 (the default from RForcecom::rforcecom.login) + session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) + suppressWarnings( + session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) + ) + + expect_equal(session1, session2) +}) + +username <- salesforcer_test_settings$username +password <- salesforcer_test_settings$password +security_token <- salesforcer_test_settings$security_token +session <- RForcecom::rforcecom.login(username=username, + password=paste0(password, security_token), + apiVersion = getOption("salesforcer.api_version")) + +sf_auth(token = salesforcer_token) + +test_that("testing rforcecom.query compatibility", { + + soql <- "SELECT Id, Account.Name, Email FROM Contact WHERE Email != NULL LIMIT 10" + + result1 <- RForcecom::rforcecom.query(session, soqlQuery=soql) + suppressWarnings(result2 <- salesforcer::rforcecom.query(session, soqlQuery=soql)) + + expect_equal(sort(names(result1)), sort(names(result2))) + expect_equal(nrow(result1), nrow(result2)) +}) + +test_that("testing rforcecom.bulkQuery compatibility", { + + soql <- "SELECT Id, Email FROM Contact LIMIT 10" + object <- "Contact" + + result1 <- RForcecom::rforcecom.bulkQuery(session, soqlQuery=soql, object=object) + suppressWarnings(result2 <- salesforcer::rforcecom.bulkQuery(session, soqlQuery=soql, object=object)) + + expect_equal(sort(names(result1)), sort(names(result2))) + expect_equal(nrow(result1), nrow(result2)) +}) + +test_that("testing rforcecom.create compatibility", { + + object <- "Contact" + fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility") + + result1 <- RForcecom::rforcecom.create(session, objectName=object, fields) + suppressWarnings(result2 <- salesforcer::rforcecom.create(session, objectName=object, fields)) + + expect_equal(names(result1), c("id", "success")) + expect_is(result1, "data.frame") + expect_is(result2, "data.frame") + expect_equal(sort(names(result1)), sort(names(result2))) + expect_equal(nrow(result1), nrow(result2)) + + # clean up + delete_result1 <- sf_delete(ids=c(result1$id, result2$id), object) +}) + +test_that("testing rforcecom.delete compatibility", { + + object <- "Contact" + new_contact <- c(FirstName="Test", LastName="Contact-Delete-Compatibility") + + result1 <- sf_create(new_contact, "Contact") + result1 <- RForcecom::rforcecom.delete(session, objectName=object, id=result1$id) + + result2 <- sf_create(new_contact, "Contact") + suppressWarnings(result2 <- salesforcer::rforcecom.delete(session, objectName=object, id=result2$id)) + + expect_null(result1) + expect_equal(result1, result2) +}) + +test_that("testing rforcecom.update compatibility", { + + object <- "Contact" + new_contact <- c(FirstName="Test", LastName="Contact-Update-Compatibility") + fields <- c(FirstName="Test", LastName="Contact-Update-Compatibility2") + + create_result1 <- sf_create(new_contact, "Contact") + result1 <- RForcecom::rforcecom.update(session, objectName=object, id=create_result1$id, fields) + + create_result2 <- sf_create(new_contact, "Contact") + suppressWarnings(result2 <- salesforcer::rforcecom.update(session, objectName=object, id=create_result2$id, fields)) + + expect_null(result1) + expect_equal(result1, result2) + + # clean up + delete_result1 <- sf_delete(ids=c(create_result1$id, create_result2$id), object) +}) + +test_that("testing rforcecom.upsert compatibility", { + + object <- "Contact" + this_external_id <- "TestUpsert1" + new_contact <- c(FirstName="Test", + LastName="Contact-Upsert-Compatibility", + My_External_Id__c=this_external_id) + create_result1 <- sf_create(new_contact, "Contact") + fields <- c(FirstName="Test", + LastName="Contact-Upsert-Compatibility2") + result1 <- RForcecom::rforcecom.upsert(session, + objectName=object, + externalIdField="My_External_Id__c", + externalId = this_external_id, + fields) + + this_external_id <- "TestUpsert2" + new_contact <- c(FirstName="Test", + LastName="Contact-Upsert-Compatibility", + My_External_Id__c=this_external_id) + create_result2 <- sf_create(new_contact, "Contact") + fields <- c(FirstName="Test", + LastName="Contact-Upsert-Compatibility2") + suppressWarnings( + result2 <- salesforcer::rforcecom.upsert(session, + objectName=object, + externalIdField="My_External_Id__c", + externalId = this_external_id, + fields) + ) + + expect_null(result1) + expect_equal(result1, result2) + + # clean up + delete_result1 <- sf_delete(ids=c(create_result1$id, create_result2$id), object) +}) + +test_that("testing rforcecom.getServerTimestamp compatibility", { + result1 <- RForcecom::rforcecom.getServerTimestamp(session) + suppressWarnings(result2 <- salesforcer::rforcecom.getServerTimestamp(session)) + expect_equal(round(result1, units = "mins"), + round(result2, units = "mins")) +}) + +test_that("testing rforcecom.retrieve compatibility", { + + objectName <- "Account" + fields <- c("name", "Industry", "AnnualRevenue") + + result1 <- RForcecom::rforcecom.retrieve(session, objectName, fields, limit = 5) + suppressWarnings(result2 <- salesforcer::rforcecom.retrieve(session, objectName, fields, limit = 5)) + + expect_equal(sort(names(result1)), sort(names(result2))) + expect_equal(nrow(result1), nrow(result2)) +}) + +test_that("testing rforcecom.search compatibility", { + + search_string <- "(336)" + result1 <- RForcecom::rforcecom.search(session, search_string) + suppressWarnings(result2 <- salesforcer::rforcecom.search(session, search_string)) + + expect_null(result1) + # rforcecom.search has a bug that wont return right data + expect_is(result2, "data.frame") +}) + +# not exported? +# test_that("testing rforcecom.bulkAction compatibility", { +# n <- 2 +# prefix <- paste0("Bulk-", as.integer(runif(1,1,100000)), "-") +# new_contacts <- tibble(FirstName = rep("Test", n), +# LastName = paste0("Contact-Create-", 1:n), +# My_External_Id__c=paste0(prefix, letters[1:n])) +# +# result1 <- RForcecom:::rforcecom.bulkAction(session, operation='insert', +# data=new_contacts, object='Contact') +# result2 <- salesforcer::rforcecom.bulkAction(session, operation='insert', +# data=new_contacts, object='Contact') +# }) \ No newline at end of file diff --git a/tests/testthat/test-describe.R b/tests/testthat/test-describe.R new file mode 100644 index 0000000..d877e94 --- /dev/null +++ b/tests/testthat/test-describe.R @@ -0,0 +1,22 @@ +context("Describe") + +salesforcer_token <- readRDS("salesforcer_token.rds") +sf_auth(token = salesforcer_token) + +test_that("testing sf_describe_objects", { + account_metadata <- sf_describe_objects("Account") + expect_is(account_metadata, "list") + expect_equal(length(account_metadata), 1) + expect_equal(unlist(account_metadata[[1]]$name), "Account") + + account_metadata_REST <- sf_describe_objects("Account", api_type="REST") + expect_is(account_metadata_REST, "list") + expect_equal(length(account_metadata_REST), 1) + expect_equal(unlist(account_metadata_REST[[1]]$name), "Account") + + multiple_objs_metadata <- sf_describe_objects(c("Contact", "Lead")) + expect_is(multiple_objs_metadata, "list") + expect_equal(length(multiple_objs_metadata), 2) + expect_equal(sort(c(unlist(multiple_objs_metadata[[1]]$name), + unlist(multiple_objs_metadata[[2]]$name))), c("Contact", "Lead")) +}) diff --git a/tests/testthat/test-metadata.R b/tests/testthat/test-metadata.R new file mode 100644 index 0000000..3f070a5 --- /dev/null +++ b/tests/testthat/test-metadata.R @@ -0,0 +1,151 @@ +context("Metadata API") + +salesforcer_token <- readRDS("salesforcer_token.rds") +sf_auth(token = salesforcer_token) + +# provide the details for creating an object +rand_int <- as.integer(runif(1,1,100000)) +base_obj_name <- paste0("Custom_Account_", rand_int) +custom_object <- list() +custom_object$fullName <- paste0(base_obj_name, "__c") +custom_object$label <- paste0(gsub("_", " ", base_obj_name)) +custom_object$pluralLabel <- paste0(base_obj_name, "s") +custom_object$nameField <- list(displayFormat = 'AN-{0000}', + label = paste0(base_obj_name, ' Number'), + type = 'AutoNumber') +custom_object$deploymentStatus <- 'Deployed' +custom_object$sharingModel <- 'ReadWrite' +custom_object$enableActivities <- 'true' +custom_object$description <- paste0(base_obj_name, " created by the Metadata API") +custom_object_result <- sf_create_metadata(metadata_type = 'CustomObject', + metadata = custom_object) + +# adding custom fields +# input formatted as a list +custom_fields1 <- list(list(fullName=paste0(base_obj_name, '__c.CustomField1__c'), + label='Test Field1', + length=100, + type='Text'), + list(fullName=paste0(base_obj_name, '__c.CustomField2__c'), + label='Test Field2', + length=100, + type='Text')) +create_fields_result1 <- sf_create_metadata(metadata_type = 'CustomField', + metadata = custom_fields1) + +# input formatted as a data.frame +custom_fields2 <- data.frame(fullName=c(paste0(base_obj_name, '__c.CustomField3__c'), + paste0(base_obj_name, '__c.CustomField4__c')), + label=c('Test Field3', 'Test Field4'), + length=c(44,45), + type=c('Text', 'Text')) +create_fields_result2 <- sf_create_metadata(metadata_type = 'CustomField', + metadata = custom_fields2) + +# specify a new labels +update_metadata <- custom_object +update_metadata$fullName <- paste0(base_obj_name, "__c") +update_metadata$label <- paste0(gsub("_", " ", base_obj_name), " - Updated") +update_metadata$pluralLabel <- paste0(base_obj_name, "_Updated", "s") +updated_custom_object_result <- sf_update_metadata(metadata_type = 'CustomObject', + metadata = update_metadata) + +renamed_custom_object_result <- sf_rename_metadata(metadata_type = 'CustomObject', + old_fullname = paste0("Custom_Account_", rand_int, "__c"), + new_fullname = paste0("Custom_Account_", rand_int+1, "__c")) + +upsert_metadata <- list(custom_object, custom_object) +upsert_metadata[[1]]$fullName <- paste0("Custom_Account_", rand_int+1, "__c") +upsert_metadata[[1]]$label <- 'New Label Custom_Account2' +upsert_metadata[[1]]$pluralLabel <- 'Custom_Account2s_new' +upsert_metadata[[2]]$fullName <- paste0("Custom_Account_", rand_int+2, "__c") +upsert_metadata[[2]]$label <- 'New Label Custom_Account3' +upsert_metadata[[2]]$pluralLabel <- 'Custom_Account3s_new' +upserted_custom_object_result <- sf_upsert_metadata(metadata_type = 'CustomObject', + metadata = upsert_metadata) + +# read operations +describe_obj_result <- sf_describe_metadata() +list_obj_result <- sf_list_metadata(queries=list(list(type='CustomObject'))) +read_obj_result <- sf_read_metadata(metadata_type='CustomObject', + object_names=paste0("Custom_Account_", rand_int+1, "__c")) +retrieve_request <- list(unpackaged=list(types=list(members='*', name='CustomObject'))) +retrieve_info <- sf_retrieve_metadata(retrieve_request) + +# cleanup everything we created by deleting it +deleted_custom_object_result <- sf_delete_metadata(metadata_type = 'CustomObject', + object_names = c(paste0("Custom_Account_", rand_int+1, "__c"), + paste0("Custom_Account_", rand_int+2, "__c"))) + +test_that("sf_create_metadata", { + expect_is(custom_object_result, "tbl_df") + expect_named(custom_object_result, c('fullName', 'success')) + expect_equal(nrow(custom_object_result), 1) + expect_equal(custom_object_result$success, 'true') + + expect_is(create_fields_result1, "tbl_df") + expect_named(create_fields_result1, c('fullName', 'success')) + expect_equal(nrow(create_fields_result1), 2) + expect_true(all(create_fields_result1$success == 'true')) + + expect_is(create_fields_result2, "tbl_df") + expect_named(create_fields_result2, c('fullName', 'success')) + expect_equal(nrow(create_fields_result2), 2) + expect_true(all(create_fields_result2$success == 'true')) +}) + +test_that("sf_update_metadata", { + expect_is(updated_custom_object_result, "tbl_df") + expect_named(updated_custom_object_result, c('fullName', 'success')) + expect_equal(nrow(updated_custom_object_result), 1) + expect_equal(updated_custom_object_result$success, 'true') +}) + +test_that("sf_rename_metadata", { + expect_is(renamed_custom_object_result, "tbl_df") + expect_named(renamed_custom_object_result, c('fullName', 'success')) + expect_equal(nrow(renamed_custom_object_result), 1) + expect_equal(renamed_custom_object_result$success, 'true') +}) + +test_that("sf_upsert_metadata", { + expect_is(upserted_custom_object_result, "tbl_df") + expect_named(upserted_custom_object_result, c('created', 'fullName', 'success')) + expect_equal(nrow(upserted_custom_object_result), 2) + expect_true(all(upserted_custom_object_result$success == 'true')) + expect_equal(upserted_custom_object_result$created, c('false', 'true')) +}) + +test_that("sf_describe_metadata", { + expect_is(describe_obj_result, "tbl_df") + expect_true(all(c("partialSaveAllowed", "testRequired", + "organizationNamespace", "metadataObjects") %in% + names(describe_obj_result))) +}) + +test_that("sf_list_metadata", { + expect_is(list_obj_result, "tbl_df") + expect_true(all(c('createdById', 'createdByName', 'createdDate', 'fileName', 'fullName', + 'id', 'lastModifiedById', 'lastModifiedByName', 'lastModifiedDate', + 'manageableState', 'namespacePrefix', 'type') %in% + names(list_obj_result))) +}) + +test_that("sf_read_metadata", { + expect_is(read_obj_result, "list") + expect_true(all(c('fullName', 'actionOverrides', 'fields', 'searchLayouts', 'sharingModel') %in% + names(read_obj_result[[1]]))) +}) + +test_that("sf_retrieve_metadata", { + expect_is(retrieve_info, "tbl_df") + expect_true(all(c('done', 'id', 'status', 'success', 'fileProperties') %in% + names(retrieve_info))) +}) + +test_that("sf_delete_metadata", { + expect_is(deleted_custom_object_result, "tbl_df") + expect_named(deleted_custom_object_result, c('fullName', 'success')) + expect_equal(nrow(deleted_custom_object_result), 2) + expect_true(all(deleted_custom_object_result$success == 'true')) +}) diff --git a/tests/testthat/test-org-utils.R b/tests/testthat/test-org-utils.R new file mode 100644 index 0000000..1b38d41 --- /dev/null +++ b/tests/testthat/test-org-utils.R @@ -0,0 +1,42 @@ +context("Org Utils") + +test_that("testing sf_user_info()", { + res <- sf_user_info() + expect_is(res, "list") + expect_true(all(c("id", "isActive", "firstName", "lastName", "email") %in% names(res))) +}) + +test_that("testing sf_server_timestamp()", { + res <- sf_server_timestamp() + expect_is(res, "POSIXct") +}) + +test_that("testing sf_list_rest_api_versions()", { + res <- sf_list_rest_api_versions() + versions <- sapply(res, function(x){as.integer(x$version)}) + expect_is(res, "list") + expect_true(all(20:42 %in% versions)) +}) + +test_that("testing sf_list_resources()", { + res <- sf_list_resources() + expect_is(res, "list") + expect_true(all(c("metadata", "chatter", "analytics", + "search", "parameterizedSearch", + "limits", "query", "sobjects", "actions") %in% names(res))) +}) + +test_that("testing sf_list_api_limits()", { + res <- sf_list_api_limits() + expect_is(res, "list") + expect_true(all(c("DailyApiRequests", "DailyBulkApiRequests", "PermissionSets", + "DataStorageMB", "FileStorageMB") %in% names(res))) +}) + +test_that("testing sf_list_objects()", { + res <- sf_list_objects() + valid_object_names <- sapply(res$sobjects, FUN=function(x){x$name}) + expect_is(res, "list") + expect_true(all(c("Account", "Contact", "Lead", + "Opportunity", "Task") %in% valid_object_names)) +}) diff --git a/tests/testthat/test-rest.R b/tests/testthat/test-rest.R new file mode 100644 index 0000000..f153358 --- /dev/null +++ b/tests/testthat/test-rest.R @@ -0,0 +1,81 @@ +context("REST API") + +salesforcer_token <- readRDS("salesforcer_token.rds") +sf_auth(token = salesforcer_token) + +test_that("testing REST API Functionality", { + + n <- 2 + prefix <- paste0("REST-", as.integer(runif(1,1,100000)), "-") + new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=paste0(prefix, letters[1:n])) + # sf_create ------------------------------------------------------------------ + created_records <- sf_create(new_contacts, "Contact", api_type="REST") + expect_is(created_records, "tbl_df") + expect_equal(names(created_records), c("id", "success", "errors")) + expect_equal(nrow(created_records), n) + + # sf_retrieve ---------------------------------------------------------------- + retrieved_records <- sf_retrieve(ids=created_records$id, + fields=c("FirstName", "LastName"), + object_name="Contact", + api_type="REST") + expect_is(retrieved_records, "tbl_df") + expect_equal(names(retrieved_records), c("Id", "FirstName", "LastName")) + expect_equal(nrow(retrieved_records), n) + + # FYI: Will not find newly created records because records need to be indexed + # Just search for some default records + my_sosl <- paste("FIND {(336)} in phone fields returning", + "contact(id, firstname, lastname, my_external_id__c),", + "lead(id, firstname, lastname)") + # sf_search ------------------------------------------------------------------ + searched_records <- sf_search(my_sosl, is_sosl=TRUE, api_type="REST") + expect_is(searched_records, "tbl_df") + expect_equal(names(searched_records), c("sobject", "Id", "FirstName", "LastName", "My_External_Id__c")) + expect_equal(nrow(searched_records), 3) + + my_soql <- sprintf("SELECT Id, + FirstName, + LastName, + My_External_Id__c + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + # sf_query ------------------------------------------------------------------- + queried_records <- sf_query(my_soql, api_type="REST") + expect_is(queried_records, "tbl_df") + expect_equal(names(queried_records), c("Id", "FirstName", "LastName", "My_External_Id__c")) + expect_equal(nrow(queried_records), n) + + queried_records <- queried_records %>% + mutate(FirstName = "TestTest") + + # sf_update ------------------------------------------------------------------ + updated_records <- sf_update(queried_records, object_name="Contact", api_type="REST") + expect_is(updated_records, "tbl_df") + expect_equal(names(updated_records), c("id", "success", "errors")) + expect_equal(nrow(updated_records), n) + + new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=paste0(prefix, letters[n+1])) + upserted_contacts <- bind_rows(queried_records %>% select(-Id), new_record) + + # sf_upsert ------------------------------------------------------------------ + upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c", + api_type = "REST") + expect_is(upserted_records, "tbl_df") + expect_equal(names(upserted_records), c("id", "success", "errors")) + expect_equal(nrow(upserted_records), nrow(upserted_records)) + + # sf_delete ------------------------------------------------------------------ + ids_to_delete <- unique(c(upserted_records$id[!is.na(upserted_records$id)], queried_records$Id)) + deleted_records <- sf_delete(ids_to_delete, api_type = "REST") + expect_is(deleted_records, "tbl_df") + expect_equal(names(deleted_records), c("id", "success", "errors")) + expect_equal(nrow(deleted_records), length(ids_to_delete)) +}) diff --git a/tests/testthat/test-search.R b/tests/testthat/test-search.R new file mode 100644 index 0000000..545c8b4 --- /dev/null +++ b/tests/testthat/test-search.R @@ -0,0 +1,38 @@ +context("Search") + +salesforcer_token <- readRDS("salesforcer_token.rds") +sf_auth(token = salesforcer_token) + +test_that("testing SOSL", { + my_sosl <- paste("FIND {(336)} in phone fields returning", + "contact(id, firstname, lastname, my_external_id__c),", + "lead(id, firstname, lastname)") + # sf_search ------------------------------------------------------------------ + searched_records1 <- sf_search(my_sosl, is_sosl=TRUE, api_type="SOAP") + searched_records2 <- sf_search(my_sosl, is_sosl=TRUE, api_type="REST") + expect_is(searched_records1, "tbl_df") + expect_named(searched_records1, c("sobject", "Id", "FirstName", + "LastName", "My_External_Id__c")) + expect_equal(names(searched_records1), names(searched_records2)) + expect_equal(nrow(searched_records1), nrow(searched_records2)) +}) + +test_that("testing parameterized search", { + my_free_text_search <- "(336)" + searched_records1 <- sf_search(my_free_text_search, api_type="REST") + searched_records2 <- sf_search(my_free_text_search, api_type="REST", + objects = c("Account", "Contact", "Lead"), + fields_scope = "PHONE", + fields = c("Id", "Name"), + overall_limit = 1000, + spell_correction = FALSE) + expect_is(searched_records1, "tbl_df") + expect_named(searched_records1, c("sobject", "Id")) + expect_is(searched_records2, "tbl_df") + expect_named(searched_records2, c("sobject", "Id", "Name")) + expect_equal(nrow(searched_records1), nrow(searched_records2)) + + expect_error( + searched_records <- sf_search(my_free_text_search, is_sosl=FALSE, api_type="SOAP") + ) +}) diff --git a/tests/testthat/test-soap.R b/tests/testthat/test-soap.R new file mode 100644 index 0000000..da8d496 --- /dev/null +++ b/tests/testthat/test-soap.R @@ -0,0 +1,81 @@ +context("SOAP API") + +salesforcer_token <- readRDS("salesforcer_token.rds") +sf_auth(token = salesforcer_token) + +test_that("testing SOAP API Functionality", { + + n <- 2 + prefix <- paste0("SOAP-", as.integer(runif(1,1,100000)), "-") + new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=paste0(prefix, letters[1:n])) + # sf_create ------------------------------------------------------------------ + created_records <- sf_create(new_contacts, "Contact", api_type="SOAP") + expect_is(created_records, "tbl_df") + expect_equal(names(created_records), c("id", "success")) + expect_equal(nrow(created_records), n) + + # sf_retrieve ---------------------------------------------------------------- + retrieved_records <- sf_retrieve(ids=created_records$id, + fields=c("FirstName", "LastName"), + object_name="Contact", + api_type="SOAP") + expect_is(retrieved_records, "tbl_df") + expect_equal(names(retrieved_records), c("Id", "FirstName", "LastName")) + expect_equal(nrow(retrieved_records), n) + + # FYI: Will not find newly created records because records need to be indexed + # Just search for some default records + my_sosl <- paste("FIND {(336)} in phone fields returning", + "contact(id, firstname, lastname, my_external_id__c),", + "lead(id, firstname, lastname)") + # sf_search ------------------------------------------------------------------ + searched_records <- sf_search(my_sosl, is_sosl=TRUE, api_type="SOAP") + expect_is(searched_records, "tbl_df") + expect_equal(names(searched_records), c("sobject", "Id", "FirstName", "LastName", "My_External_Id__c")) + expect_equal(nrow(searched_records), 3) + + my_soql <- sprintf("SELECT Id, + FirstName, + LastName, + My_External_Id__c + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + # sf_query ------------------------------------------------------------------- + queried_records <- sf_query(my_soql, api_type="SOAP") + expect_is(queried_records, "tbl_df") + expect_equal(names(queried_records), c("Id", "FirstName", "LastName", "My_External_Id__c")) + expect_equal(nrow(queried_records), n) + + queried_records <- queried_records %>% + mutate(FirstName = "TestTest") + + # sf_update ------------------------------------------------------------------ + updated_records <- sf_update(queried_records, object_name="Contact", api_type="SOAP") + expect_is(updated_records, "tbl_df") + expect_equal(names(updated_records), c("id", "success")) + expect_equal(nrow(updated_records), n) + + new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=paste0(prefix, letters[n+1])) + upserted_contacts <- bind_rows(queried_records %>% select(-Id), new_record) + + # sf_upsert ------------------------------------------------------------------ + upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c", + api_type = "SOAP") + expect_is(upserted_records, "tbl_df") + expect_equal(names(upserted_records), c("created", "id", "success")) + expect_equal(nrow(upserted_records), nrow(upserted_records)) + + # sf_delete ------------------------------------------------------------------ + ids_to_delete <- unique(c(upserted_records$id[!is.na(upserted_records$id)], queried_records$Id)) + deleted_records <- sf_delete(ids_to_delete, api_type = "SOAP") + expect_is(deleted_records, "tbl_df") + expect_equal(names(deleted_records), c("id", "success")) + expect_equal(nrow(deleted_records), length(ids_to_delete)) +}) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R new file mode 100644 index 0000000..53d0fc4 --- /dev/null +++ b/tests/testthat/test-utils.R @@ -0,0 +1,39 @@ +context("Utils") + +test_that("testing input_data validation", { + input_data <- 1:3 + res1a <- sf_input_data_validation(input_data) + expect_equal(res1a, data.frame(`X1.3`=1:3, check.names = FALSE)) + res1b <- sf_input_data_validation(input_data, operation='delete') + expect_equal(res1b, data.frame(Id=1:3)) + + input_data <- list(1,2,3) + res2a <- sf_input_data_validation(input_data) + expect_equal(res2a, data.frame(`unlist(input_data)`=1:3, check.names = FALSE)) + res2b <- sf_input_data_validation(input_data, operation='delete') + expect_equal(res2b, data.frame(Id=1:3)) + + input_data <- c(Id=1,b=2,c=3) + res3a <- sf_input_data_validation(input_data) + expect_equal(res3a, data.frame(Id=1,b=2,c=3)) + res3b <- sf_input_data_validation(input_data, operation='delete') + expect_equal(res3b, data.frame(Id=1,b=2,c=3)) + input_data <- input_data[-which(names(input_data)=="Id")] + expect_error(sf_input_data_validation(input_data, operation='update')) + + input_data <- list(Id=1,b=2,c=3) + res4a <- sf_input_data_validation(input_data) + expect_equal(res4a, data.frame(Id=1,b=2,c=3)) + res4b <- sf_input_data_validation(input_data, operation='delete') + expect_equal(res4b, data.frame(Id=1,b=2,c=3)) + input_data$Id <- NULL + expect_error(sf_input_data_validation(input_data, operation='update')) + + input_data <- data.frame(Id=1,b=2,c=3) + res5a <- sf_input_data_validation(input_data) + expect_equal(res5a, input_data) + res5b <- sf_input_data_validation(input_data, operation='delete') + expect_equal(res5b, input_data) + input_data <- input_data[,c('b','c')] + expect_error(sf_input_data_validation(input_data, operation='update')) +}) diff --git a/vignettes/getting-started.Rmd b/vignettes/getting-started.Rmd new file mode 100644 index 0000000..3826de6 --- /dev/null +++ b/vignettes/getting-started.Rmd @@ -0,0 +1,189 @@ +--- +title: "Getting Started" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Getting Started} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +First, load the `salesforcer` package and login. There are two ways to authenticate: +1) OAuth 2.0 and 2) Basic Username-Password. It is recommended to use OAuth 2.0 so that +passwords do not have to be shared/embedded within scripts. User credentials will +be stored in locally cached file entitled ".httr-oauth-salesforcer" in the current working +directory. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) +``` + +```{r load-package, eval=FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +library(salesforcer) +sf_auth() +``` + +Just a note, that it's not necessary to setup your own Connected App in Salesforce +to use OAuth 2.0 authentication. The only difference is that the authentication +will be run through the client created and associated with the `salesforcer` +package. By using the package client, you will *NOT* be giving access to Salesforce +to anyone, the package is just the medium for you to connect to your own data. +If you wanted more control you would specify those options like so: + +```{r other-params, eval=FALSE} +options(salesforcer.consumer_key = "012345678901-99thisisatest99connected33app22key") +options(salesforcer.consumer_secret = "Th1s1sMyConsumerS3cr3t") + +sf_auth() +``` + +After logging in with `sf_auth()`, you can check your connectivity by looking at +the information returned about the current user. It should be information about you! + +```{r} +# pull down information of person logged in +# it's a simple easy call to get started +# and confirm a connection to the APIs +user_info <- sf_user_info() +sprintf("User Id: %s", user_info$id) +sprintf("User Active?: %s", user_info$isActive) +``` + +### Create +Salesforce has objects and those objects contain records. One default object is the +"Contact" object. This example shows how to create two records in the Contact object. + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, "Contact") +created_records +``` + +### Retrieve +Retrieve pulls down a specific set of records and fields. It's very similar to +running a query, but doesn't use SOQL. Here is an example where we retrieve the +data we just created. + +```{r} +retrieved_records <- sf_retrieve(ids=created_records$id, + fields=c("FirstName", "LastName"), + object_name="Contact") +retrieved_records +``` + + +### Query + +Salesforce has proprietary form of SQL called SOQL (Salesforce Object Query +Language). SOQL is a powerful tool that allows you to return the attributes of records +on almost any object in Salesforce including Accounts, Contacts, Tasks, Opportunities, +even Attachments! Below is an example where we grab the data we just created +including Account object information for which the Contact record is associated +with. The Account column is all `NA` since we have yet to provide information to +link these Contacts with Accounts. + +```{r query-records} +my_soql <- sprintf("SELECT Id, + Account.Name, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$id , collapse="','")) + +queried_records <- sf_query(my_soql) +queried_records +``` + +### Update + +After creating records you can update them using `sf_update()`. Updating a record +requires you to pass the Salesforce `Id` of the record. Salesforce creates a unique +18-character identifier on each record and uses that to know which record to +attach the update information you provide. Simply include a field or column in your +update dataset called "Id" and the information will be matched. Here is an example +where we update each of the records we created earlier with a new first name +called "TestTest". + +```{r update-records} +# Update some of those records +queried_records <- queried_records %>% + mutate(FirstName = "TestTest") %>% + select(-Account) + +updated_records <- sf_update(queried_records, object_name="Contact") +updated_records +``` + +### Delete +You can also delete records in Salesforce. The method implements a "soft" delete +meaning that the deleted records go to the Recycle Bin which can be emptied or +queried against later in the event that the record needed. + +```{r} +deleted_records <- sf_delete(updated_records$id) +deleted_records +``` + +### Upsert +Finally, Salesforce has a unique method called "upsert" that allows you to +create and/or update records at the same time. More specifically, if the record +is not found based an an "External Id" field, then Salesforce will create the +record instead of updating one. Below is an example where we create 2 records, +then upsert 3, where 2 are matched and updated and one is created. **NOTE**: You +will need to create a custom field on the target object and ensure it is labeled as +an "External Id" field. Read more at http://blog.jeffdouglas.com/2010/05/07/using-exernal-id-fields-in-salesforce/. + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n), + My_External_Id__c=letters[1:n]) +created_records <- sf_create(new_contacts, "Contact") + +upserted_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Upsert-", 1:n), + My_External_Id__c=letters[1:n]) +new_record <- tibble(FirstName = "Test", + LastName = paste0("Contact-Upsert-", n+1), + My_External_Id__c=letters[n+1]) +upserted_contacts <- bind_rows(upserted_contacts, new_record) + +upserted_records <- sf_upsert(input_data=upserted_contacts, + object_name="Contact", + external_id_fieldname="My_External_Id__c") +upserted_records +``` + +```{r, include = FALSE} +deleted_records <- sf_delete(upserted_records$id) +``` + +### Check out the Tests + +The **salesforcer** package has quite a bit of unit test coverage to track any +changes made between newly released versions of the Salesforce API (typically 4 each year). +These tests are an excellent source of examples because they cover most all cases of +utilizing the package functions. diff --git a/vignettes/transitioning-from-RForcecom.Rmd b/vignettes/transitioning-from-RForcecom.Rmd new file mode 100644 index 0000000..59cbc4e --- /dev/null +++ b/vignettes/transitioning-from-RForcecom.Rmd @@ -0,0 +1,142 @@ +--- +title: "Transitioning from RForcecom" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Transitioning from RForcecom} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +While writing the **salesforcer** package we were keenly aware that many folks +are already using the **RForcecom** package to connect to Salesforce. In order +to foster adoption and switching between the packages **salesforcer** replicates +the functionality of many **RForcecom** functions so that you will only need to swap +out `library(RForcecom)` for `library(salesforcer)` and still have your production +tested scripts perform as usual. + +### Authentication + +**salesforcer** supports OAuth 2.0 authentication which is preferred, but for +backward compatibility provides the username-password authentication routine +implemented by **RForcecom**. Here is an example running the function from +each of the packages side-by-side and producing the same result. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +options_path <- here::here("tests", "testthat", "salesforcer_test_settings.rds") +salesforcer_test_settings <- readRDS(options_path) +username <- salesforcer_test_settings$username +password <- salesforcer_test_settings$password +security_token <- salesforcer_test_settings$security_token +``` + +```{r, warning=FALSE} +# the RForcecom way +session1 <- RForcecom::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session1['sessionID'] <- "{MASKED}" +session1 + +# replicated in salesforcer package +session2 <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +session2['sessionID'] <- "{MASKED}" +session2 +``` + +```{r, include=FALSE} +# keep using the session, just rename it to "session" +session <- salesforcer::rforcecom.login(username, paste0(password, security_token), + apiVersion=getOption("salesforcer.api_version")) +``` + +Note that we must set the API version here because calls to session will not create +a new sessionId and then we are stuck with version 35.0 (the default from +RForcecom::rforcecom.login). Some functions in **salesforcer** implement API calls +that are only available after version 35.0. + +### CRUD Operations + +"CRUD" operations (Create, Retrieve, Update, Delete) in the **RForcecom** package +only operate on one record at a time. One benefit to using the **salesforcer** package +is that these operations will accept a named vector (one record) or an entire `data.frame` +or `tbl_df` of records to churn through. However, rest assured that the replicated +functions behave exactly the same way if you are hesitant to making the switch. + +```{r, warning=FALSE} +object <- "Contact" +fields <- c(FirstName="Test", LastName="Contact-Create-Compatibility") + +# the RForcecom way +result1 <- RForcecom::rforcecom.create(session, objectName=object, fields) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.create(session, objectName=object, fields) +result2 +``` + +Here is an example showing the reduction in code of using **salesforcer** if you +would like to create multiple records. + +```{r, warning=FALSE} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) + +# the RForcecom way +rforcecom_results <- NULL +for(i in 1:nrow(new_contacts)){ + temp <- RForcecom::rforcecom.create(session, + objectName = "Contact", + fields = unlist(slice(new_contacts,i))) + rforcecom_results <- bind_rows(rforcecom_results, temp) +} +rforcecom_results + +# the better way in salesforcer to do multiple records +salesforcer_results <- sf_create(new_contacts, object_name="Contact") +salesforcer_results +``` + +### Query + +**salesforcer** also has better printing and type-casting when returning query result +thanks to features of the readr package. + +```{r, warning=FALSE} +this_soql <- "SELECT Id, Email FROM Contact LIMIT 5" + +# the RForcecom way +result1 <- RForcecom::rforcecom.query(session, soqlQuery = this_soql) +result1 + +# replicated in salesforcer package +result2 <- salesforcer::rforcecom.query(session, soqlQuery = this_soql) +result2 + +# the better way in salesforcer to query +salesforcer_results <- sf_query(this_soql) +salesforcer_results +``` + +In the future more features will be migrated from **RForcecom** to make the +transition as seamless as possible. diff --git a/vignettes/working-with-bulk-api.Rmd b/vignettes/working-with-bulk-api.Rmd new file mode 100644 index 0000000..161b212 --- /dev/null +++ b/vignettes/working-with-bulk-api.Rmd @@ -0,0 +1,92 @@ +--- +title: "Working with Bulk API" +author: "Steven M. Mortimer" +date: "2018-03-12" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 4 + keep_md: true +vignette: > + %\VignetteIndexEntry{Working with Bulk API} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, echo = FALSE} +NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + purl = NOT_CRAN, + eval = NOT_CRAN +) +``` + +### Using the Bulk API + +First, load the `salesforcer` package and login. + +```{r auth, include = FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +suppressWarnings(suppressMessages(library(here))) +library(salesforcer) +token_path <- here::here("tests", "testthat", "salesforcer_token.rds") +suppressMessages(sf_auth(token = token_path, verbose = FALSE)) +``` + +```{r load-package, eval=FALSE} +suppressWarnings(suppressMessages(library(dplyr))) +library(salesforcer) +sf_auth() +``` + +For really large inserts, updates, deletes, upserts, queries you can just add +"api_type" = "Bulk" to most functions to get the benefits of using the Bulk API +instead of the SOAP or REST APIs. Here is the difference in using the REST API vs. +the Bulk API to do an insert: + +```{r} +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +# REST +rest_created_records <- sf_create(new_contacts, object_name="Contact", api_type="REST") +rest_created_records +# Bulk +bulk_created_records <- sf_create(new_contacts, object_name="Contact", api_type="Bulk 1.0") +bulk_created_records +``` + +There are some differences in the way each API returns response information; however, +the end result is exactly the same for these two calls. Also, note that this +package utilizes the Bulk 2.0 API for most bulk calls except for bulk queries +since Salesforce has not yet implemented it in 2.0. + +Here is a simple workflow of adding, querying, and deleting records using the Bulk API. + +```{r} +# just add api_type="Bulk" to most calls! +# create bulk +object <- "Contact" +n <- 2 +new_contacts <- tibble(FirstName = rep("Test", n), + LastName = paste0("Contact-Create-", 1:n)) +created_records <- sf_create(new_contacts, object_name=object, api_type="Bulk 1.0") +created_records + +# query bulk +my_soql <- sprintf("SELECT Id, + FirstName, + LastName + FROM Contact + WHERE Id in ('%s')", + paste0(created_records$Id , collapse="','")) + +queried_records <- sf_query(my_soql, object_name=object, api_type="Bulk 1.0") +queried_records + +# delete bulk +deleted_records <- sf_delete(queried_records$Id, object_name=object, api_type="Bulk 1.0") +deleted_records +```

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 Ypn&KQAF=BB9QbFu-f>;7CG+tA0F3pvA^-pY literal 0 HcmV?d00001 diff --git a/man/figures/old-salesforcer.png b/man/figures/old-salesforcer.png new file mode 100644 index 0000000000000000000000000000000000000000..90772457326c3f9f0c08d9f12be6de0bcef9ee36 GIT binary patch literal 30993 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 z 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