diff --git a/.Rbuildignore b/.Rbuildignore
index 49c3089..9084026 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -1,9 +1,10 @@
-^Meta$
+^data$
^doc$
+^man-roxygen$
+^Meta$
+
^.*\.Rproj$
^\.Rproj\.user$
-
-Dockerfile
-cloudbuild.yaml
-man-roxygen
-inst/application/data/taxdata
+^Dockerfile$
+^cloudbuild\.yaml$
+^inst/application/data/taxdata$
diff --git a/DESCRIPTION b/DESCRIPTION
index 17b3fab..4a1f220 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: SmaRP
Title: SmaRP: Smart Retirement Planning
-Version: 1.1.1
+Version: 1.2.0
Authors@R: c(person("Gabriel", "Foix", role = c("aut", "cre"),
email = "gabriel.foix@mirai-solutions.com"),
person("Francesca", "Vitalini", role = c("aut"),
@@ -14,6 +14,9 @@ Authors@R: c(person("Gabriel", "Foix", role = c("aut", "cre"),
Description: Shiny App to calculate total pension fund.
Depends: R (>= 3.5.0)
License: GPL-3
+URL: https://mirai-solutions.ch,
+ https://github.com/miraisolutions/SmaRP#readme
+BugReports: https://github.com/miraisolutions/SmaRP/issues
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
diff --git a/NAMESPACE b/NAMESPACE
index 2d43edf..f7fc66e 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -22,6 +22,7 @@ export(makeTable)
export(need_not_zero)
export(printCurrency)
export(returnPLZKanton)
+export(update_neg)
export(withModalSpinner)
import(dplyr)
importFrom(dplyr,'%>%')
diff --git a/NEWS.md b/NEWS.md
index b9ba1c1..b19a01f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,24 @@
+# SmaRP 1.2.0
+
+### Changes
+
+* The naming of pension funds was reviewed and aligned, and now reflects the official terminology (#103).
+* The 3rd Pillar annual contribution in the app is now initialized with a non-zero value (#129).
+* Negative input values are now re-set to zero, and maximum allowed values were consolidated (#129).
+* `launch_application()` exposes the `launch.browser` argument of `shiny::runApp()` (#108).
+* Minor updates to package vignettes (#101).
+
+### Fixes
+
+* Missing page title in the app (#118).
+* Missing automatic cleanup of data created via configure (#119).
+* App header background image re-centering upon page resize (#123).
+
+### Maintenance
+
+* Included `URL` and `BugReports` in DESCRIPTION file (#125).
+* Updated `install_github()` README instructions due to un-supported `build_vignettes` argument (#120).
+
# SmaRP 1.1.1
### Fixes
diff --git a/R/TaxBenefit.R b/R/TaxBenefit.R
index 63ccdd2..c359a75 100644
--- a/R/TaxBenefit.R
+++ b/R/TaxBenefit.R
@@ -178,7 +178,7 @@ lookupTaxAmount <- function(Income, Tabelle, CivilStatus) {
#'
#' @import dplyr
#'
-#' @return data.frame tax benefit path.
+#' @return data.frame tax benefits path.
#' @examples
#' \dontrun{buildTaxBenefits(
#' birthday,
@@ -236,7 +236,7 @@ buildTaxBenefits <- function(birthday,
#'
#' @rdname calcTaxBenefitSwiss
#'
-#' @description Calculates the tax benefit as a difference of the taxes paid with and without retirement contributions.
+#' @description Calculates the tax benefits as a difference of the taxes paid with and without retirement contributions.
#' Calls 'getTaxAmount()', therefore, it assumes objects in the global environment.
#' @seealso [getTaxAmount()]
#' @seealso swisstax
@@ -245,7 +245,7 @@ buildTaxBenefits <- function(birthday,
#' @param TaxableIncome Vector of annual taxable income until retirement.
#' @inheritParams getTaxAmount
#'
-#' @return Single tax benefit (tax relief) of one contribution.
+#' @return Single tax benefits (tax relief) of one contribution.
#' @examples
#' \dontrun{
#' calcTaxBenefitSwiss(ExpectedSalaryPath = seq(90000, 100000, 1000),
diff --git a/R/core.R b/R/core.R
index bdf5fcd..1e0950b 100644
--- a/R/core.R
+++ b/R/core.R
@@ -108,15 +108,15 @@ getRetirementCalendar <- function(birthday, givenday = today("UTC"), RetirementA
#'
#' @rdname buildContributionP2Path
#'
-#' @description Gather all the required information to project the annual contributions to the occupational pension fund.
+#' @description Gather all the required information to project the annual contributions to the occupational fund.
#'
#' @inheritParams buildt
#' @template salary
#' @template P2
-#' @param CurrentP2 Value of the current assets in the Occupational Pension Fund.
+#' @param CurrentP2 Value of the current assets in the Occupational Fund.
#' @param rate Interests rate on annual basis. Constant interest rates are assumed.
#'
-#' @return All contributions to the Pillar II in annual basis.
+#' @return All contributions to the 2nd Pillar on an annual basis.
#'
#' @examples
#' \dontrun{
@@ -197,7 +197,7 @@ calcExpectedSalaryPath <- function(Salary, SalaryGrowthRate, ncp) {
#'
#' @rdname calcBVGpurchase
#'
-#' @description Calculate the path of purchases to the Pilar II (Occupational pension fund, BVG).
+#' @description Calculate the path of purchases to the 2nd Pillar (Occupational fund, BVG).
#'
#' @inheritParams calcExpectedSalaryPath
#' @inheritParams buildContributionP2Path
@@ -220,15 +220,15 @@ calcBVGpurchase <- function(TypePurchase, P2purchase, ncp) {
#'
#' @rdname buildContributionP3path
#'
-#' @description Build the contribution path for a standard pension fund, called Pillar III in Switzerland.
+#' @description Build the contribution path for a standard pension fund, called 3rd Pillar in Switzerland.
#' Based on 'calcAnnuityAcumPath()'.
#'
#' @inheritParams buildt
#' @inheritParams calcExpectedSalaryPath
#' @template P3
-#' @param CurrentP3 Value of the current assets in the Private Pension Fund (Pillar 3).
+#' @param CurrentP3 Value of the current assets in the Private Fund (3rd Pillar).
#'
-#' @return All contributions to the Pillar III in annual basis.
+#' @return All contributions to the 3rd Pillar on an annual basis.
#' @examples
#' \dontrun{
#' buildContributionP3path(
@@ -434,6 +434,25 @@ need_not_zero <- function(input, inputname) {
}
}
+#' @title update_neg
+#'
+#' @rdname update_neg
+#'
+#' @description Automatically updates numericInput to zero if input is negative.
+#'
+#' @param inputId Field name.
+#' @param session Current session.
+#'
+#' @return Zero value.
+#' @export
+update_neg <- function(inputId, session) {
+ val <- 0
+ input <- session$input[[inputId]]
+ if (!is.na(input) && input < val) {
+ shiny::updateNumericInput(session, toString(inputId), value = val)
+ }
+}
+
# Format Percentage ----
diff --git a/R/launch_application.R b/R/launch_application.R
index 60d2cbf..403e21f 100644
--- a/R/launch_application.R
+++ b/R/launch_application.R
@@ -1,11 +1,11 @@
#' @title launch_application
-#'
+#'
#' @rdname launch_application
#'
#' @description Launch the SmaRP Shiny wep app.
#'
-#' @param ... Additional arguments passed on to [runApp()]. Note that
-#' argument `launch.browser` is always passed as `TRUE`.
+#' @inheritParams shiny::runApp
+#' @param ... Additional arguments passed on to [runApp()].
#'
#' @return Side-effecting function. Launches the SmaRP app.
#'
@@ -15,10 +15,10 @@
#' }
#' @importFrom shiny runApp
#' @export
-launch_application <- function(...) {
+launch_application <- function(launch.browser = interactive(), ...) {
runApp(
appDir = system.file("application", package = "SmaRP"),
- launch.browser = TRUE,
+ launch.browser = launch.browser,
...
)
}
diff --git a/README.md b/README.md
index d3616c4..78245a8 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
``` r
-devtools::install_github("miraisolutions/SmaRP", build_vignettes = TRUE)
+devtools::install_github("miraisolutions/SmaRP", build_opts = "")
```
and running
``` r
@@ -43,11 +44,11 @@ SmaRP::launch_application()
## Details and key features
-The evolution of the total retirement fund over time is computed by projecting the value of the occupational pension fund (Pillar II), the private pension fund (Pillar III) and the tax relief, thus deriving their contributions at the desired retirement age.
+The evolution of the total retirement fund over time is computed by projecting the value of the occupational fund (2nd Pillar), the private fund (3rd Pillar) and the tax relief, thus deriving their contributions at the desired retirement age.
-*Contributions to Pillar II* are calculated from the salary and any additional voluntary purchases.
+*Contributions to the second Pillar* are calculated from the salary and any additional voluntary purchases.
-*Contributions to Pillar III* are fully voluntary and repeated every year until retirement.
+*Contributions to the third Pillar* are fully voluntary and repeated every year until retirement.
*Tax savings* are built as an additional fund where tax relieves from a certain year are used as contributions for the next. Tax relieves are calculated using an approximation of the given gross salary and other factors including: residence, civil status, number on kids, etc.
@@ -64,8 +65,8 @@ The evolution of the total retirement fund over time is computed by projecting t
- Constant interest rates are assumed throughout the working life.
- Inflation is not taken into account, although it can be proxied using the salary growth rate input.
- The retirement plan is valid for employees only, i.e. persons whose main income is a salary. Self-employed people do not belong to this category.
-- The publicly managed pay-as-you-go system (Pillar I) is not considered.
-- All generated tax benefits are 100% reinvested as an additional fund, interpreting the same return as the private pension fund.
+- The publicly managed pay-as-you-go system (1st Pillar) is not considered.
+- All generated tax benefits are 100% reinvested as an additional fund, interpreting the same return as the private fund.
- In case of married couples with double income, the combined amount of all variables should be entered and a 50% income distribution is assumed.
@@ -97,6 +98,6 @@ Legal parameters in **SmaRP** are defined in [SmaRP/inst/application/global.R](h
While **SmaRP** was developed under the utmost care and diligence, Mirai Solutions does not guarantee for its accuracy and correctness. In addition, **SmaRP** is based on assumptions and projections (explained in a section above and in the PDF report) and as such computed figures should be understood as general references and do not hold any legal value.
-Besides standard unit tests at the functional level, results from the **SmaRP** web app have been checked against other online free sources for Pillar II and III and tax calculators.
+Besides standard unit tests at the functional level, results from the **SmaRP** web app have been checked against other online free sources for second, third Pillars and tax calculators.
To keep testing and improving **SmaRP**, we encourage users to get back to us! Your feedback is always highly appreciated. You can use the issue tracker on GitHub to suggest enhancements or report problems, and reach out via email at info@mirai-solutions.com for any questions and comments.
diff --git a/inst/application/global.R b/inst/application/global.R
index ed9cbc7..9a4d68c 100644
--- a/inst/application/global.R
+++ b/inst/application/global.R
@@ -2,9 +2,6 @@ library(SmaRP)
`%>%` <- magrittr::`%>%`
# Global variables
-# Gender-based retirement age
-MRetirementAge <- 65
-FRetirementAge <- 64
# https://www.admin.ch/opc/de/classified-compilation/19820152/index.html#a8
MinBVG <- 24885 # Min Koordinierter Lohn (MinBVG = MaxAHV * (7 / 8))
@@ -105,3 +102,27 @@ BerufsauslagenMax <- 4000
BerufsauslagenMin <- 2000
NBU <- 0.0084
maxNBU <- 1065
+
+# List of initial, max and min values
+value <- list (
+ birthday = "1980-12-30",
+ gender = "M",
+ min_retirement = 55,
+ max_retirement = 70,
+ retirement_female = 64,
+ retirement_male = 65,
+ plz = with(PLZGemeinden, PLZGDENAME[match(8001, PLZ)]),
+ rate = "A",
+ min_children = 0,
+ max_children = 9,
+ church = "A",
+ salary = 100000,
+ max_salary = 1e+08,
+ growth_rate = 0.5,
+ p2 = 100000,
+ min_p2_interest = 100 * BVGMindestzinssatz,
+ p2_voluntary = 0,
+ p3 = 50000,
+ p3_annual = 5000,
+ p3_return = 100 * BVGMindestzinssatz
+)
diff --git a/inst/application/report.Rmd b/inst/application/report.Rmd
index 1bafe5c..10f4369 100644
--- a/inst/application/report.Rmd
+++ b/inst/application/report.Rmd
@@ -108,11 +108,11 @@ Smart Retirement Planning (**SmaRP**) is a [Mirai Solutions](https://mirai-solut
It is implemented as an [R Shiny](https://shiny.rstudio.com/) pension calculator web app, in the form of an R package. The source code is available on [GitHub](https://github.com/miraisolutions/SmaRP.git) and the app itself online at http://mirai-solutions.ch/apps/smarp/.
-**SmaRP** is based on the [three pillars pension system](https://en.wikipedia.org/wiki/Pension_system_in_Switzerland) and reflects the complexity of its legal framework. The bulk of the retirement income are the second and third pillar, which employees can actively manage and make decisions impacting their total pension fund at retirement. The first pillar is not considered as it is a pay-as-you-go universal system whose benefits depend on the income earned during the working life and the number of years contributed. In addition, since non-mandatory contributions are tax favored, SmaRP incorporates an additional fund -the Tax benefits fund- to outline the effects of those tax reliefs on the long run.
+**SmaRP** is based on the [three pillars pension system](https://en.wikipedia.org/wiki/Pension_system_in_Switzerland) and reflects the complexity of its legal framework. The bulk of the retirement income are the second and third pillar, which employees can actively manage and make decisions impacting their total pension fund at retirement. The first pillar is not considered as it is a pay-as-you-go universal system whose benefits depend on the income earned during the working life and the number of years contributed. In addition, since non-mandatory contributions are tax favored, SmaRP incorporates an additional fund -the Tax benefits- to outline the effects of those tax reliefs on the long run.
SmaRP is based on assumptions and includes some simplifications. Thus, it is advisable to use the app to perform different "what-if" scenarios and assess their feasibility. Any outcome should consider some degree of uncertainty.
-The main drivers of the retirement pension fund are:
+The main drivers of the retirement fund are:
- **Salary** - the higher the stipend, the higher the future pension. The salary growth rate can be used as a proxy of the inflation or a general economic growth.
@@ -124,9 +124,9 @@ The main drivers of the retirement pension fund are:
- **Time** - the sooner the employee will start investing, the higher the final return will be.
-Note that SmaRP does not make any consideration about the usage of the retirement pension funds.
+Note that SmaRP does not make any consideration about the usage of the retirement funds.
-The main outcome is displayed in the "Results" section with a more detailed drill down in Appendix 2; formulas used to obtain these results are explained in Appendix 1. In addition, a list of assumptiuons and limitations is provided in a separate section as well as a brief explantation of the Swiss retirement system.
+The main outcome is displayed in the "Results" section with a more detailed drill down in Appendix 2; formulas used to obtain these results are explained in Appendix 1. In addition, a list of assumptions and limitations is provided in a separate section as well as a brief explanation of the Swiss retirement system.
\newpage
@@ -149,8 +149,6 @@ Based on the information inserted in the three pillars, the total retirement fun
The two plots below represent the time evolution of the different funds and their contribution to the total retirement fund at retirement, respectively.
-
-
```{r timeSeriesPlot, echo = FALSE}
tserieGraphData.columns <- setdiff(names(params$TserieGraphData), "Calendar")
@@ -162,7 +160,7 @@ tserieGraphData.long$variable <- factor(tserieGraphData.long$variable,
decreasing = TRUE))
ggplot(tserieGraphData.long, aes(x = Calendar, y = value, fill = variable)) +
- scale_fill_manual(NULL, values = c("Occupational Fund" = "#008cc3", "Private Fund" = "#FF9966", "Tax Benefits" = "#13991c")) +
+ scale_fill_manual(NULL, values = c("2nd Pillar" = "#008cc3", "3rd Pillar" = "#FF9966", "Tax Benefits" = "#13991c")) +
scale_y_continuous(labels = scales::comma) +
labs(x = "Year", y = "Return [CHF]") +
geom_area(alpha = 0.6) +
@@ -196,7 +194,7 @@ ggplot(data = barGraphData.long, aes(x = contribution, y = value, fill = variabl
scale_x_discrete(breaks = NULL) +
scale_y_continuous(labels = scales::percent) +
coord_flip() +
- scale_fill_manual(NULL, values = c("Occupational Fund" = "#008cc3", "Private Fund" = "#FF9966", "Tax Benefits" = "#13991c")) +
+ scale_fill_manual(NULL, values = c("2nd Pillar" = "#008cc3", "3rd Pillar" = "#FF9966", "Tax Benefits" = "#13991c")) +
labs(x = NULL, y = "% Contribution of each fund at retirement") +
theme(
axis.text = element_text(size = 10),
@@ -211,7 +209,7 @@ ggplot(data = barGraphData.long, aes(x = contribution, y = value, fill = variabl
-The graphs above display the amounts at the end of each year for the Pillar II, Pillar III and Tax Benefit fund. The corresponding formulas are in Appendix 1 of this document and a more detailed break down of the amounts can be found in Appendix 2. A comprehensive set of values calculated can de downloaded as well from the Table tab.
+Corresponding formulas are in Appendix 1 of this document and a more detailed break down of the amounts can be found in Appendix 2. A comprehensive set of values calculated can de downloaded as well from the Table tab.
@@ -230,18 +228,18 @@ The results shown above are based on the following inputs set by the user on the
SalaryGrowthRate <- params$SalaryGrowthRate * 100
```
* The current salary is **`r printCurrency(params$Salary)` CHF**, with a growth rate of `r SalaryGrowthRate`%, which is assumed constant until retirement.
-* The occupational pension fund (Pillar II) is of **`r printCurrency(params$CurrentP2)` CHF**.
+* The occupational fund (2nd Pillar) is of **`r printCurrency(params$CurrentP2)` CHF**.
```{r msgP2, echo = FALSE}
if(is.null(params$P2purchase) || params$P2purchase == 0){
- msgP2 <- "No voluntary contribution to Pillar II is made."
+ msgP2 <- "No voluntary contribution to the second Pillar is made."
} else {
- msgP2 <- paste0("The voluntary contribution to Pillar II is of ", params$P2purchase, " CHF and is made as a ", TypePurchase, ".")
+ msgP2 <- paste0("The voluntary contribution to the second Pillar is of ", params$P2purchase, " CHF and is made as a ", TypePurchase, ".")
}
```
* `r msgP2`
-* Pillar II has an interest rate of `r params$rate*100`%. We ensure that the amount considered in the analysis is always higher than the minimum required by law.
-* The private pension fund (Pillar III) is of `r printCurrency(params$CurrentP3)` CHF.
-* The annual contribution to Pillar III is of `r printCurrency(params$P3purchase)` CHF, with an expected return of `r params$returnP3*100`%.
+* Second Pillar has an interest rate of `r params$rate*100`%. We ensure that the amount considered in the analysis is always higher than the minimum required by law.
+* The private fund (3rd Pillar) is of `r printCurrency(params$CurrentP3)` CHF.
+* The annual contribution to the third Pillar is of `r printCurrency(params$P3purchase)` CHF, with an expected return of `r params$returnP3*100`%.
```{r maritallabel, echo = FALSE}
if(params$rate_group == "A"){
maritallabel <- "Single"
@@ -271,11 +269,11 @@ if (params$churchtax == "N"){
SmaRP is valid for employees only, i.e. persons whose main income is a salary. Self-employed people do not belong to this category.
-SmaRP takes into account only the occupational (Pillar II) and the private (Pillar III) pension funds. The state-run pay-as-you-earn system (Pillar I) is law and salary dependent only, meaning there is no active decision-making from the employee's side. Therefore, it is not explicitly considered.
+SmaRP takes into account only the occupational (2nd Pillar) and the private (3rd Pillar) funds. The state-run pay-as-you-earn system (1st Pillar) is law and salary dependent only, meaning there is no active decision-making from the employee's side. Therefore, it is not explicitly considered.
-When calculating contributions to the Occupational Pension Fund (Pillar II) any salary above minimum threshold is taken into account to generate the retirement benefits.
+When calculating contributions to the Occupational Fund (2nd Pillar) any salary above minimum threshold is taken into account to generate the retirement benefits.
-SmaRP considers the tax saving generated by the voluntary retirement contributions, assuming that all generated tax benefits are 100% reinvested as an additional fund. The return from these tax benefits is set to be the same as those of the private pension fund.
+SmaRP considers the tax saving generated by the voluntary retirement contributions, assuming that all generated tax benefits are 100% reinvested as an additional fund. The return from these tax benefits is set to be the same as those of the private fund.
In case of married couples with double-income, SmaRP assumes that all monetary amounts are split 50% and both members have the same age. For more information, please refer to Appendix 3.
@@ -289,7 +287,7 @@ A proxy of the taxable income is used to calculate tax savings.[^3] The taxable
* Any additional voluntary contributions.
-[^1]: SmaRP does not make any consideration about the usage of the retirement pension funds. For the Occupational pension fund, the Swiss pension law allows retirees to take the full amount as a lump sum or receive their pension in the form of a life annuity, or a mix of both. In that case, the minimum conversion rate is 6.8% (since 2017) and can vary depending on the retirement age. The Private fund, however, gets always paid as a lump sum.
+[^1]: SmaRP does not make any consideration about the usage of the retirement funds. For the Occupational fund, the Swiss pension law allows retirees to take the full amount as a lump sum or receive their pension in the form of a life annuity, or a mix of both. In that case, the minimum conversion rate is 6.8% (since 2017) and can vary depending on the retirement age. The Private fund, however, gets always paid as a lump sum.
[^2]: Church taxes differ based on the type (Evangelische or Roeman-katolische Kirche) and canton of residence. SmaRP does not make such distinction and always assumes the highest of the values. Moreover, when the church-tax depends on the cantonal tax rate (instead of being a fixed factor), an approximation is made and treated as the maximum possible factor (relevant for cantons: VS, BS, BL).
[^3]: Taxes on assets are not considered.
[^4]: Although most of those parameters can vary a bit depending on the canton, we use the federal values as proxy.
@@ -315,11 +313,11 @@ The Swiss social retirement system is based on a three-pillar regime.
\vspace{12pt}
-Pillar I is a state-run pay-as-you-earn system with minimum benefits[^5]. It aims at providing a subsistence level of income to all retirees. The annuity at retirement depends on the amount of income earned and the number of years contributed. Since all parameters are law dependent, it is not explicitly considered in SmaRP.
+First Pillar is a state-run pay-as-you-earn system with minimum benefits[^5]. It aims at providing a subsistence level of income to all retirees. The annuity at retirement depends on the amount of income earned and the number of years contributed. Since all parameters are law dependent, it is not explicitly considered in SmaRP.
-Pillar II is a compulsory, tax-deductible company occupational pension insurance fund[^6]. Its goal is to maintain pre-retirement living standards. Voluntary additional buy-ins are regulated, but allow for benefits enhancements at retirement age while reducing the tax burden during the working career. The pensionable salary is defined as part of the AHV with a range between 7/8 and 3 times the AHV salary (between 24.675 and 84.600 as of 01-01-2018). The amount within this range is called the "Mandatory Component" and all employers are required by law to insure at least this compulsory share. However, they are free to offer coverage for the salary above the upper threshold, which the vast majority provides as this extra coverage has become a de facto "must have" to attract employees.
+Second Pillar is a compulsory, tax-deductible company occupational pension insurance fund[^6]. Its goal is to maintain pre-retirement living standards. Voluntary additional buy-ins are regulated, but allow for benefits enhancements at retirement age while reducing the tax burden during the working career. The pensionable salary is defined as part of the AHV with a range between 7/8 and 3 times the AHV salary (between 24.675 and 84.600 as of 01-01-2018). The amount within this range is called the "Mandatory Component" and all employers are required by law to insure at least this compulsory share. However, they are free to offer coverage for the salary above the upper threshold, which the vast majority provides as this extra coverage has become a de facto "must have" to attract employees.
-Pillar III is a voluntary contribution; it is a privately-run, tax-deductible insurance fund. The private pension fund is modeled as an asset of a given amount ("Current assets"), to which contributions can be added annually ("Annual contribution"). The annual expected return of this asset is given as an input and assumed constant until the retirement date.
+Third Pillar is a voluntary contribution; it is a privately-run, tax-deductible insurance fund. The private fund is modeled as an asset of a given amount ("Current assets"), to which contributions can be added annually ("Annual contribution"). The annual expected return of this asset is given as an input and assumed constant until the retirement date.
Tax benefits are always a key factor towards a smart retirement project. SmaRP takes them into consideration and implements them as an additional fund.
@@ -348,7 +346,7 @@ Retirement age can be either explicitly provided as an input or inferred from th
While **SmaRP** was developed under the utmost care and diligence, Mirai Solutions does not guarantee for its accuracy and correctness. In addition, **SmaRP** is based on assumptions and projections and as such computed figures should be understood as general references and do not hold any legal value.
[^5]: For more information regarding the first pillar, check the official site [here](https://www.ahv-iv.ch/en)
-[^6]: All details of current legislation on Pillar II can be found in German, French or Italian [here](https://www.axa.ch/en/corporate-customers/offers/knowledge/current%20legislation-pillar-2.html)
+[^6]: All details of current legislation on the second Pillar can be found in German, French or Italian [here](https://www.axa.ch/en/corporate-customers/offers/knowledge/current%20legislation-pillar-2.html)
\newpage
@@ -356,7 +354,7 @@ While **SmaRP** was developed under the utmost care and diligence, Mirai Solutio
# Appendix 1: Methodology
-## Pillar II
+## 2nd Pillar
The savings process for retirement benefits starts on January 1st following the year in which the person turns 24.
@@ -367,7 +365,7 @@ where
- $S(t)$ is the current Salary at year $t$,
- $S_{AHV}$ is the AHV salary[^7].
-Contribution rates under Pillar II are defined by law.[^8]
+Contribution rates under the second Pillar are defined by law.[^8]
\begin{center}
\begin{tabular}{c | c | c | c | c }
\hline
@@ -388,26 +386,26 @@ where
$$ r = 1\% $$
-$$ Pillar II = \sum_{t=t_0}^T(MCon + VCon) * \exp^{r*(T - t)} $$
+$$ P_2 = \sum_{t=t_0}^T(MCon + VCon) * \exp^{r*(T - t)} $$
where
- $VCon$ is the Voluntary Contribution
-## Pillar III
+## 3rd Pillar
-The private pension fund ($PillarIII$) at year $t$ is calculated as:
+The private fund ($P_3$) at year $t$ is calculated as:
-$$ PillarIII (t)= \sum_{t=t_0}^TVCon * e^{r(T - t)} $$
+$$ P_3 (t)= \sum_{t=t_0}^TVCon * e^{r(T - t)} $$
where
-- $r$ is the interest rate applied to the private pension fund[^9],
+- $r$ is the interest rate applied to the private fund[^9],
- $t_0$ is today's date,
- $T$ is the retirement age.
## Tax Benefit
-Granted that the marginal tax rate is provided as an input, the tax benefit ($TBe$) at year $t$ is calculated as:
+Granted that the marginal tax rate is provided as an input, the tax benefits ($TBe$) at year $t$ is calculated as:
$$ TBe(t) = \sum_{t=t_0}^TVCon(t) * TR(t) * e^{r(T - t)} $$
@@ -425,7 +423,7 @@ where
- $Tax_{S}(t)$ is the tax bill based on the gross salary at each $t$,
- $Tax_{inc}(t)$ is the tax bill based on the Taxable income at each $t$,
-- $TBe(t)$ is the Tax Benefit generated by the difference of the tow.
+- $TBe(t)$ is the Tax Benefits generated by the difference of the tow.
Taxable income ($I$) at time $t$ is computed as:
@@ -433,7 +431,7 @@ $$ I(t) = \max(S(t) - \min(TotalCon, MaxConTax), 0) $$
where
-- $TotalCon$ is the sum of the Pillar II and Pillar III purchases,
+- $TotalCon$ is the sum of the second and third Pillars purchases,
- $MaxConTax$ is the maximum deductible amount allowed by law.[^11]
@@ -508,7 +506,7 @@ pander(Road2Retirement_to_print_Summarized)
```{r Road2Retirement_to_print_Pillar2, echo = FALSE, eval = show_text, include = show_text}
if (show_text){
moncols <- c("Direct Contribution", "Total Contribution", "Return", "Occupational Fund")
- set.caption('Occupational Pension Fund - Pillar 2')
+ set.caption('Occupational Fund - 2nd Pillar')
Road2Retirement_to_print_Pillar2 <- Road2Retirement_to_print %>%
mutate(`Direct Contribution` = P2ContributionPath + P2purchase) %>%
rename(`Total Contribution` = DirectP2) %>%
@@ -522,7 +520,7 @@ if (show_text){
```{r Road2Retirement_to_print_Pillar3, echo = FALSE, eval=show_text, include=show_text}
moncols <- c("Direct Contribution", "Total Contribution", "Return", "Private Fund")
-set.caption('Private Pension Fund - Pillar 3')
+set.caption('Private Fund - 3rd Pillar')
Road2Retirement_to_print_Pillar3 <- Road2Retirement_to_print %>%
mutate(`Direct Contribution` = P3ContributionPath + P3purchase) %>%
rename(`Total Contribution` = DirectP3) %>%
@@ -535,7 +533,7 @@ pander(Road2Retirement_to_print_Pillar3)
```{r Road2Retirement_to_print_TaxBenefit, echo = FALSE, eval=show_tax, include=show_tax}
moncols <- c("Direct Tax", "Return Tax", "Total Tax")
-set.caption('Tax Benefit Fund')
+set.caption('Tax Benefits')
Road2Retirement_to_print_TaxBenefit <- Road2Retirement_to_print %>%
rename(`Direct Tax` = DirectTax) %>%
rename(`Return Tax` = ReturnTax) %>%
@@ -552,7 +550,7 @@ pander(Road2Retirement_to_print_TaxBenefit)
In case of married couples with double income, the following considerations should be taken into account.
Pension funds are individual (not familiar). However, the tax rates are familiar, i.e. number of children and marital status are considered. That implies that the user can perform two calculations, both with some level of inaccuracy.
-1. The user can simply enter all the information individually, without taking into account his partner. It that case, most likely, the tax rate will be underestimated and as a consequence the tax benefit generated.
+1. The user can simply enter all the information individually, without taking into account his partner. It that case, most likely, the tax rate will be underestimated and as a consequence the tax benefits generated.
2. The user can enter the combined amount of all variables (salary, current assets and purchases). In this case, however, note that two simplifications have been taken into account.
diff --git a/inst/application/server.R b/inst/application/server.R
index 62e4f69..8463749 100644
--- a/inst/application/server.R
+++ b/inst/application/server.R
@@ -26,39 +26,41 @@ function(input, output, session) {
# Retirement Age
RetirementAge <- reactive({
+
+ val <- max(min(isnotAvailableReturnZero(input$RetirementAge), value$max_retirement), value$min_retirement)
+ if (!is.na(input$RetirementAge) && input$RetirementAge != val) {
+ updateNumericInput(session, "RetirementAge", value = val)
+ }
+
if (input$provideRetirementAge) {
validate(need(input$RetirementAge, VM$RetirementAge))
- min(70, input$RetirementAge)
+ min(value$max_retirement, input$RetirementAge)
} else {
if (gender() == "M") {
- MRetirementAge
+ value$retirement_male
} else {
- FRetirementAge
+ value$retirement_female
}
}
}) %>% debounce(millis = 100)
- observeEvent(input$RetirementAge, ignoreNULL = TRUE, {
- if (!is.na(input$RetirementAge) && input$RetirementAge > 70) {
- updateNumericInput(session, "RetirementAge", value = 70)
- }
- })
-
observeEvent(input$gender, {
if (gender() == "F") {
- updateNumericInput(session, "RetirementAge", value = 64)
+ updateNumericInput(session, "RetirementAge", value = value$retirement_female)
} else {
- updateNumericInput(session, "RetirementAge", value = 65)
+ updateNumericInput(session, "RetirementAge", value = value$retirement_male)
}
})
- # Pillar III ----
+ # 3rd Pillar ----
# default option 0
CurrentP3_notZero <- reactive({
isnotAvailableReturnZero(input$CurrentP3)
})
CurrentP3 <- reactive({
+ update_neg("CurrentP3", session)
+
if (P3purchase() == 0 &
Salary() == 0 & CurrentP2() == 0 & P2purchase() == 0) {
validate(
@@ -74,6 +76,7 @@ function(input, output, session) {
})
P3purchase <- reactive({
+ update_neg("P3purchase", session)
isnotAvailableReturnZero(input$P3purchase)
})
@@ -82,6 +85,8 @@ function(input, output, session) {
})
returnP3 <- reactive({
+ update_neg("returnP3", session)
+
if (CurrentP3() == 0 &
P3purchase() == 0 &
Salary() == 0 & CurrentP2() == 0 & P2purchase() == 0) {
@@ -121,7 +126,7 @@ function(input, output, session) {
# Number of kids (max = 9)
NChildren <- reactive({
- val <- max(min(isnotAvailableReturnZero(input$NChildren), 9), 0)
+ val <- max(min(isnotAvailableReturnZero(input$NChildren), value$max_children), 0)
if (!is.na(input$NChildren) && input$NChildren != val) {
updateNumericInput(session, "NChildren", value = val)
}
@@ -145,7 +150,7 @@ function(input, output, session) {
# Salary
Salary <- reactive({
- val <- max(min(isnotAvailableReturnZero(input$Salary), 1e+08), 0)
+ val <- max(min(isnotAvailableReturnZero(input$Salary), value$max_salary), 0)
if (!is.na(input$Salary) && input$Salary != val) {
updateNumericInput(session, "Salary", value = val)
}
@@ -153,23 +158,26 @@ function(input, output, session) {
}) %>% debounce(millis = 100)
SalaryGrowthRate <- reactive({
+ update_neg("SalaryGrowthRate", session)
isnotAvailableReturnZero(input$SalaryGrowthRate / 100)
})
- # Pillar II
+ # 2nd Pillar
CurrentP2 <- reactive({
+ update_neg("CurrentP2", session)
isnotAvailableReturnZero(input$CurrentP2)
})
P2interestRate <- reactive({
- if (isnotAvailable(input$P2interestRate)) {
- BVGMindestzinssatz
- } else {
- input$P2interestRate / 100
+ val <- value$min_p2_interest
+ if (!is.na(input$P2interestRate) && input$P2interestRate < val) {
+ updateNumericInput(session, "P2interestRate", value = val)
}
+ isnotAvailableReturnZero(input$P2interestRate / 100)
})
P2purchase <- reactive({
+ update_neg("P2purchase", session)
isnotAvailableReturnZero(input$P2purchase)
})
@@ -241,11 +249,11 @@ function(input, output, session) {
TserieGraphData <- reactive({
Road2Retirement() %>%
mutate(`Tax Benefits` = TotalTax) %>%
- mutate(`Occupational Fund` = DirectP2 + ReturnP2) %>%
- mutate(`Private Fund` = DirectP3 + ReturnP3) %>%
+ mutate(`2nd Pillar` = DirectP2 + ReturnP2) %>%
+ mutate(`3rd Pillar` = DirectP3 + ReturnP3) %>%
select(Calendar,
- `Occupational Fund`,
- `Private Fund`,
+ `2nd Pillar`,
+ `3rd Pillar`,
`Tax Benefits`) %>%
.[, colSums(. != 0, na.rm = TRUE) > 0]
})
@@ -269,9 +277,9 @@ function(input, output, session) {
FotoFinish <- reactive({
Road2Retirement() %>%
mutate(`Tax Benefits` = TotalTax) %>%
- mutate(`Occupational Fund` = DirectP2 + ReturnP2) %>%
- mutate(`Private Fund` = DirectP3 + ReturnP3) %>%
- select(`Occupational Fund`, `Private Fund`, `Tax Benefits`) %>%
+ mutate(`2nd Pillar` = DirectP2 + ReturnP2) %>%
+ mutate(`3rd Pillar` = DirectP3 + ReturnP3) %>%
+ select(`2nd Pillar`, `3rd Pillar`, `Tax Benefits`) %>%
tail(1) %>%
prop.table() %>%
select_if(function(x)
diff --git a/inst/application/ui.R b/inst/application/ui.R
index 3f01f51..31ad80d 100644
--- a/inst/application/ui.R
+++ b/inst/application/ui.R
@@ -10,7 +10,7 @@ boxPlus <- shinydashboardPlus::boxPlus
# fluidPage UI
fluidPage(
-
+ title = "SmaRP: Smart Retirement Planning",
tags$head(
tags$script(
type = "text/javascript",
@@ -75,7 +75,7 @@ fluidPage(
6,
dateInput("Birthdate",
label = "Birthdate",
- value = "1980-12-30",
+ value = value$birthday,
format = "dd-mm-yyyy"
) %>%
bs_embed_tooltip(title = IB$Birthdate, placement = "right")
@@ -86,7 +86,7 @@ fluidPage(
label = "Gender Affiliation",
inline = TRUE,
choices = list("Male" = "M", "Female" = "F"),
- selected = "M"
+ selected = value$gender
)
)
),
@@ -110,11 +110,10 @@ fluidPage(
numericInput(
"RetirementAge",
label = NULL, # "Desired Retirement Age",
- value = 64,
+ value = value$max_retirement,
step = 1,
- min = 55,
- max = 70 # note this doesn't prevent or warn users entering
- # larger numbers manually (see e.g. https://github.com/rstudio/shiny/issues/1022#issuecomment-282305308)
+ min = value$min_retirement,
+ max = value$max_retirement
) %>%
bs_embed_tooltip(title = IB$RetirementAge, placement = "right")
)
@@ -128,7 +127,7 @@ fluidPage(
selectInput("plzgemeinden",
label = h5("Postal Code / Municipality"),
choices = PLZGemeinden$PLZGDENAME,
- selected = with(PLZGemeinden, PLZGDENAME[match(8001, PLZ)])
+ selected = value$plz
)
)
),
@@ -142,16 +141,16 @@ fluidPage(
bs_embed_tooltip(title = IB$rate_group, placement = "right"),
inline = TRUE,
choices = Rate_group.list,
- selected = "A"
+ selected = value$rate
)
),
column(
6,
numericInput("NChildren",
label = "# Children",
- value = 0,
+ value = value$min_children,
min = 0,
- max = 9
+ max = value$max_children
) %>%
bs_embed_tooltip(title = IB$NChildren, placement = "right")
)
@@ -165,7 +164,7 @@ fluidPage(
label = "Church Affiliation",
inline = TRUE,
choices = church_tax.list,
- selected = "A"
+ selected = value$church
)
)
),
@@ -176,10 +175,10 @@ fluidPage(
), # end Personal Info fluidRow
- # Pillar II -------
+ # 2nd Pillar -------
fluidRow(
boxPlus(
- title = "Occupational Pension Fund - Pillar II",
+ title = "Occupational Fund - Second Pillar",
status = "primary",
collapsible = TRUE,
collapsed = TRUE,
@@ -192,17 +191,16 @@ fluidPage(
6,
numericInput("Salary",
label = "Current Annual Salary",
- value = 100000,
+ value = value$salary,
step = 1000,
min = 0
) %>%
bs_embed_tooltip(title = IB$Salary, placement = "right"),
numericInput("SalaryGrowthRate",
label = "Expected Salary Growth Rate %",
- value = 0.5,
+ value = value$growth_rate,
step = 0.1,
- min = 0,
- max = 100
+ min = 0
) %>%
bs_embed_tooltip(title = IB$SalaryGrowthRate, placement = "right")
),
@@ -210,17 +208,16 @@ fluidPage(
6,
numericInput("CurrentP2",
label = "Current BVG Assets",
- value = 100000,
+ value = value$p2,
step = 1000,
min = 0
) %>%
bs_embed_tooltip(title = IB$CurrentP2, placement = "right"),
numericInput("P2interestRate",
label = "Interest Rate % (optional)",
- value = 100 * BVGMindestzinssatz,
+ value = value$min_p2_interest,
step = 1,
- min = 100 * BVGMindestzinssatz,
- max = 100
+ min = value$min_p2_interest
) %>%
bs_embed_tooltip(title = IB$P2interestRate, placement = "right")
)
@@ -230,7 +227,7 @@ fluidPage(
6,
numericInput("P2purchase",
label = "Voluntary Purchases",
- value = 0,
+ value = value$p2_voluntary,
step = 500,
min = 0
) %>%
@@ -249,10 +246,10 @@ fluidPage(
) # end boxPlus
), # end fluidRow
- # Pillar III -------
+ # 3rd Pillar -------
fluidRow(
boxPlus(
- title = "Private Pension Fund - Pillar III",
+ title = "Private Fund - Third Pillar",
status = "primary",
collapsible = TRUE,
collapsed = TRUE,
@@ -265,7 +262,7 @@ fluidPage(
12,
numericInput("CurrentP3",
label = "Current Assets",
- value = 50000,
+ value = value$p3,
step = 1000,
min = 0
) %>%
@@ -277,23 +274,22 @@ fluidPage(
12,
numericInput("P3purchase",
label = "Annual Contribution",
- value = 0,
+ value = value$p3_annual,
step = 500,
min = 0
) %>%
bs_embed_tooltip(title = IB$P3purchase, placement = "right"),
numericInput("returnP3",
label = "Expected Return %",
- value = BVGMindestzinssatz * 100,
+ value = value$p3_return,
step = 0.1,
- min = 0,
- max = 100
+ min = 0
) %>%
bs_embed_tooltip(title = IB$returnP3, placement = "right")
)
)
- ) # end Pillar III boxPlus
- ), # end Pillar III fluidRow
+ ) # end of 3rd Pillar boxPlus
+ ), # end of 3rd Pillar fluidRow
NULL
diff --git a/inst/application/www/style.css b/inst/application/www/style.css
index d0ecbb9..b2bbb7b 100644
--- a/inst/application/www/style.css
+++ b/inst/application/www/style.css
@@ -22,8 +22,8 @@ html {
margin-bottom: 10px;
background-color: #009edb;
background-image: url("illu-header-data.png");
- background-repeat: repeat-x;
- background-position: center center;
+ background-repeat: repeat;
+ background-position: 0 200px;
background-size: auto 400px;
}
diff --git a/man-roxygen/P2.R b/man-roxygen/P2.R
index cd52c28..50a17c2 100644
--- a/man-roxygen/P2.R
+++ b/man-roxygen/P2.R
@@ -1,2 +1,2 @@
-#' @param P2purchase Annual voluntary contribution to the Occupational Pension Fund.
-#' @param TypePurchase AnnualP2 if the purchase on the pillar II gets repeated every year until retirement.
+#' @param P2purchase Annual voluntary contribution to the Occupational Fund.
+#' @param TypePurchase AnnualP2 if the purchase on the second pillar gets repeated every year until retirement.
diff --git a/man-roxygen/P3.R b/man-roxygen/P3.R
index d6074a8..5a9c670 100644
--- a/man-roxygen/P3.R
+++ b/man-roxygen/P3.R
@@ -1,2 +1,2 @@
-#' @param P3purchase Annual voluntary contribution to the Private Pension Fund (Pillar 3).
-#' @param returnP3 Annual expected return on the Private Pension Fund.
+#' @param P3purchase Annual voluntary contribution to the Private Fund (3rd Pillar).
+#' @param returnP3 Annual expected return on the Private Fund.
diff --git a/man/buildContributionP2Path.Rd b/man/buildContributionP2Path.Rd
index f148343..473a649 100644
--- a/man/buildContributionP2Path.Rd
+++ b/man/buildContributionP2Path.Rd
@@ -15,11 +15,11 @@ buildContributionP2Path(birthday, Salary, SalaryGrowthRate, CurrentP2,
\item{SalaryGrowthRate}{Rate at which the salary increases/decreases.}
-\item{CurrentP2}{Value of the current assets in the Occupational Pension Fund.}
+\item{CurrentP2}{Value of the current assets in the Occupational Fund.}
-\item{P2purchase}{Annual voluntary contribution to the Occupational Pension Fund.}
+\item{P2purchase}{Annual voluntary contribution to the Occupational Fund.}
-\item{TypePurchase}{AnnualP2 if the purchase on the pillar II gets repeated every year until retirement.}
+\item{TypePurchase}{AnnualP2 if the purchase on the second pillar gets repeated every year until retirement.}
\item{rate}{Interests rate on annual basis. Constant interest rates are assumed.}
@@ -28,10 +28,10 @@ buildContributionP2Path(birthday, Salary, SalaryGrowthRate, CurrentP2,
\item{RetirementAge}{Age of retirement.}
}
\value{
-All contributions to the Pillar II in annual basis.
+All contributions to the 2nd Pillar on an annual basis.
}
\description{
-Gather all the required information to project the annual contributions to the occupational pension fund.
+Gather all the required information to project the annual contributions to the occupational fund.
}
\examples{
\dontrun{
diff --git a/man/buildContributionP3path.Rd b/man/buildContributionP3path.Rd
index 91c8dfe..370f9c0 100644
--- a/man/buildContributionP3path.Rd
+++ b/man/buildContributionP3path.Rd
@@ -10,21 +10,21 @@ buildContributionP3path(birthday, P3purchase, CurrentP3, returnP3,
\arguments{
\item{birthday}{Date of birth ("YYYY-MM-DD").}
-\item{P3purchase}{Annual voluntary contribution to the Private Pension Fund (Pillar 3).}
+\item{P3purchase}{Annual voluntary contribution to the Private Fund (3rd Pillar).}
-\item{CurrentP3}{Value of the current assets in the Private Pension Fund (Pillar 3).}
+\item{CurrentP3}{Value of the current assets in the Private Fund (3rd Pillar).}
-\item{returnP3}{Annual expected return on the Private Pension Fund.}
+\item{returnP3}{Annual expected return on the Private Fund.}
\item{givenday}{Date at which the age is computed ("YYYY-MM-DD").}
\item{RetirementAge}{Age of retirement.}
}
\value{
-All contributions to the Pillar III in annual basis.
+All contributions to the 3rd Pillar on an annual basis.
}
\description{
-Build the contribution path for a standard pension fund, called Pillar III in Switzerland.
+Build the contribution path for a standard pension fund, called 3rd Pillar in Switzerland.
Based on 'calcAnnuityAcumPath()'.
}
\examples{
diff --git a/man/buildTaxBenefits.Rd b/man/buildTaxBenefits.Rd
index 5710dd0..d6580dd 100644
--- a/man/buildTaxBenefits.Rd
+++ b/man/buildTaxBenefits.Rd
@@ -11,13 +11,13 @@ buildTaxBenefits(birthday, TypePurchase, P2purchase, P3purchase, returnP3,
\arguments{
\item{birthday}{Date of birth ("YYYY-MM-DD").}
-\item{TypePurchase}{AnnualP2 if the purchase on the pillar II gets repeated every year until retirement.}
+\item{TypePurchase}{AnnualP2 if the purchase on the second pillar gets repeated every year until retirement.}
-\item{P2purchase}{Annual voluntary contribution to the Occupational Pension Fund.}
+\item{P2purchase}{Annual voluntary contribution to the Occupational Fund.}
-\item{P3purchase}{Annual voluntary contribution to the Private Pension Fund (Pillar 3).}
+\item{P3purchase}{Annual voluntary contribution to the Private Fund (3rd Pillar).}
-\item{returnP3}{Annual expected return on the Private Pension Fund.}
+\item{returnP3}{Annual expected return on the Private Fund.}
\item{Salary}{Stipend.}
@@ -36,7 +36,7 @@ buildTaxBenefits(birthday, TypePurchase, P2purchase, P3purchase, returnP3,
\item{RetirementAge}{Age of retirement.}
}
\value{
-data.frame tax benefit path.
+data.frame tax benefits path.
}
\description{
All inputs are scalars. Builds a data frame as long as the years to retirement.
diff --git a/man/calcBVGpurchase.Rd b/man/calcBVGpurchase.Rd
index 5e8d69d..90a51f1 100644
--- a/man/calcBVGpurchase.Rd
+++ b/man/calcBVGpurchase.Rd
@@ -7,9 +7,9 @@
calcBVGpurchase(TypePurchase, P2purchase, ncp)
}
\arguments{
-\item{TypePurchase}{AnnualP2 if the purchase on the pillar II gets repeated every year until retirement.}
+\item{TypePurchase}{AnnualP2 if the purchase on the second pillar gets repeated every year until retirement.}
-\item{P2purchase}{Annual voluntary contribution to the Occupational Pension Fund.}
+\item{P2purchase}{Annual voluntary contribution to the Occupational Fund.}
\item{ncp}{Length contribution path to retirement.}
}
@@ -17,7 +17,7 @@ calcBVGpurchase(TypePurchase, P2purchase, ncp)
BVG purchase.
}
\description{
-Calculate the path of purchases to the Pilar II (Occupational pension fund, BVG).
+Calculate the path of purchases to the 2nd Pillar (Occupational fund, BVG).
}
\examples{
\dontrun{
diff --git a/man/calcTaxBenefitSwiss.Rd b/man/calcTaxBenefitSwiss.Rd
index c5956a8..928460a 100644
--- a/man/calcTaxBenefitSwiss.Rd
+++ b/man/calcTaxBenefitSwiss.Rd
@@ -23,10 +23,10 @@ calcTaxBenefitSwiss(ExpectedSalaryPath, TaxableIncome, rate_group, Age,
\item{churchtax}{Y/N \code{Character} Y/N}
}
\value{
-Single tax benefit (tax relief) of one contribution.
+Single tax benefits (tax relief) of one contribution.
}
\description{
-Calculates the tax benefit as a difference of the taxes paid with and without retirement contributions.
+Calculates the tax benefits as a difference of the taxes paid with and without retirement contributions.
Calls 'getTaxAmount()', therefore, it assumes objects in the global environment.
}
\examples{
diff --git a/man/launch_application.Rd b/man/launch_application.Rd
index 7789012..234621c 100644
--- a/man/launch_application.Rd
+++ b/man/launch_application.Rd
@@ -4,11 +4,15 @@
\alias{launch_application}
\title{launch_application}
\usage{
-launch_application(...)
+launch_application(launch.browser = interactive(), ...)
}
\arguments{
-\item{...}{Additional arguments passed on to \code{\link[=runApp]{runApp()}}. Note that
-argument \code{launch.browser} is always passed as \code{TRUE}.}
+\item{launch.browser}{If true, the system's default web browser will be
+launched automatically after the app is started. Defaults to true in
+interactive sessions only. This value of this parameter can also be a
+function to call with the application's URL.}
+
+\item{...}{Additional arguments passed on to \code{\link[=runApp]{runApp()}}.}
}
\value{
Side-effecting function. Launches the SmaRP app.
diff --git a/man/update_neg.Rd b/man/update_neg.Rd
new file mode 100644
index 0000000..deabeba
--- /dev/null
+++ b/man/update_neg.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/core.R
+\name{update_neg}
+\alias{update_neg}
+\title{update_neg}
+\usage{
+update_neg(inputId, session)
+}
+\arguments{
+\item{inputId}{Field name.}
+
+\item{session}{Current session.}
+}
+\value{
+Zero value.
+}
+\description{
+Automatically updates numericInput to zero if input is negative.
+}
diff --git a/tools/config.R b/tools/config.R
index 1dcb892..c3c62b8 100644
--- a/tools/config.R
+++ b/tools/config.R
@@ -177,18 +177,11 @@ configure_common <- function(type) {
configure_platform <- function(type) {
- sysname <- Sys.info()[["sysname"]]
- switch(
- sysname,
- "Windows" = configure_platform_windows(type),
- "Darwin" = configure_platform_darwin(type),
- "Linux" = configure_platform_linux(type),
- "SunOS" = configure_platform_solaris(type),
- stop("unrecognized platform '", sysname, "'")
- )
-}
+ sysname <- tolower(Sys.info()[["sysname"]])
-configure_platform_common <- function(subdirs, type) {
+ subdirs <- sysname
+ if (sysname != "windows")
+ subdirs <- c("unix", subdirs)
dirs <- c("R", "src")
for (dir in dirs) {
@@ -209,26 +202,6 @@ configure_platform_common <- function(subdirs, type) {
}
}
-configure_platform_windows <- function(type) {
- subdirs <- c("windows", bitness("windows/win"))
- configure_platform_common(subdirs, type)
-}
-
-configure_platform_darwin <- function(type) {
- subdirs <- c("unix", "darwin", bitness("darwin/darwin"))
- configure_platform_common(subdirs, type)
-}
-
-configure_platform_linux <- function(type) {
- subdirs <- c("unix", "linux", bitness("linux/linux"))
- configure_platform_common(subdirs, type)
-}
-
-configure_platform_solaris <- function(type) {
- subdirs <- c("unix", "sunos", bitness("sunos/sunos"))
- configure_platform_common(subdirs, type)
-}
-
#' Execute R CMD config
#'
#' Read information about how \R is configured as through `R CMD config`.
@@ -578,10 +551,6 @@ parse_key_value <- function(
named(as.list(vals), keys)
}
-bitness <- function(prefix = "") {
- paste(prefix, .Machine$sizeof.pointer * 8, sep = "")
-}
-
move_directory <- function(source, target) {
# ensure we're trying to move a directory
diff --git a/tools/config/cleanup.R b/tools/config/cleanup.R
index 88c6584..5b6ba83 100644
--- a/tools/config/cleanup.R
+++ b/tools/config/cleanup.R
@@ -1,4 +1,4 @@
# Clean up files generated during configuration here.
# Use 'remove_file()' to remove files generated during configuration.
-
+unlink("data", recursive = TRUE)
diff --git a/tools/config/configure.R b/tools/config/configure.R
index 28acd82..ea92479 100644
--- a/tools/config/configure.R
+++ b/tools/config/configure.R
@@ -5,13 +5,12 @@
# Tooltip and validation message lists containing texts
# Stored as data. To load, run e.g. `load("data/VM.rda")`
-
# Info Box
IB <- list(
Birthdate = "Date of birth",
- CurrentP3 = "Current retirement assets in your Private Pension Fund",
- CurrentP2 = "Current retirement assets in your Occupational Pension Fund",
- P3purchase = "Annual contributions into your Private Pension Fund. Note that SmaRP assumes that the same contributions repeats every year until the retirement",
+ CurrentP3 = "Current retirement assets in your Private Fund",
+ CurrentP2 = "Current retirement assets in your Occupational Fund",
+ P3purchase = "Annual contributions into your Private Fund. Note that SmaRP assumes that the same contributions repeats every year until the retirement",
P2purchase = "Voluntary purchases in annual basis",
returnP3 = "Annual expected return. Note that SmaRP keeps the return constant",
TaxRelief = "Maximum amount you can deduct from your taxable income via voluntary contributions to retirement funds",
@@ -22,7 +21,7 @@ IB <- list(
SalaryGrowthRate = "Annual expected salary growth rate. Note that this growth rate keeps constant during the full career",
TypePurchase = "Single: one-off purchase; Annual: constant annual purchase",
rate_group = "If Married with Double Income, please enter all inputs as aggregated values",
- P2interestRate = "Interest Rate on the Occupational Pension Fund return. If not provided, the minimum by low is used",
+ P2interestRate = "Interest Rate on the Occupational Fund return. If not provided, the minimum by low is used",
git = "Redirect to git repository",
RetirementAge = "Enter desired retirement age",
RetirementAgeOptional = "Possibility to enter desired retirement age manually",
@@ -36,18 +35,16 @@ VM <- list(
Birthdate2 = "You should be retired already",
RetirementAge = "Provide the desired retirement age",
need_not_zero_base = "Provide a non zero value for ",
- CurrentP3_notZero = "Private Pension Fund",
- CurrentP3_CurrentP2_Salary_Purchases_notZero = "either Salary, Private Pension Fund, Occupational Pension Fund or funds purchases",
- returnP3_notzero = "Private Pension Fund return",
+ CurrentP3_notZero = "Private Fund",
+ CurrentP3_CurrentP2_Salary_Purchases_notZero = "either Salary, Private Fund, Occupational Fund or funds purchases",
+ returnP3_notzero = "Private Fund return",
plzgemeinden = "Provide a valid postal code / municipality",
rate_group = "Provide a valid civil status",
Salary = "Provide a non-zero Income",
- TypePurchase = "Provide a valid Occupational Pension Fund purchase type",
+ TypePurchase = "Provide a valid Occupational Fund purchase type",
TaxRateSwiss = "Provide a valid Tax Rate"
)
dir.create("data")
save(IB, file = "data/IB.rda")
save(VM, file = "data/VM.rda")
-
-# source_file("MessageData.R")
diff --git a/vignettes/figures/mirai.png b/vignettes/figures/mirai.png
new file mode 100644
index 0000000..5c3096c
Binary files /dev/null and b/vignettes/figures/mirai.png differ
diff --git a/vignettes/smarp_server.Rmd b/vignettes/smarp_server.Rmd
index 2361fcb..abd3bca 100644
--- a/vignettes/smarp_server.Rmd
+++ b/vignettes/smarp_server.Rmd
@@ -20,6 +20,13 @@ suppressPackageStartupMessages(library(googleVis))
library(dplyr, warn.conflicts = FALSE)
library(magrittr)
```
+
+```{r, echo=FALSE}
+htmltools::img(src = knitr::image_uri("figures/mirai.png"),
+ alt = 'logo',
+ style = 'position:absolute; top:0; right:0; padding:10px; margin-right:200px; max-height: 40px;border-style: none;')
+```
+
## Introduction
```{r child = 'children/short-intro.Rmd'}
@@ -33,7 +40,7 @@ The server includes: reactive variables, Mirai Solutions colors definition, plot
## Reactive variables
-All inputs from the ui are then used to perform calculations, draw plots and write statements. Because these values are different for each user, the app will have to be constantly updated, thus the need for reactive statements. A simple example of a reactive statement used in the server can be found below:
+All inputs from the ui are then used to perform calculations, draw plots and write statements. Because these values are different for each user, the app will have to be constantly updated, thus the need for reactive statements. A simple example of a reactive statement is the one for the gender, which can be found in the server:
```{r, eval = FALSE}
gender <- reactive({
@@ -61,11 +68,11 @@ All functions used in this script can be found in the R directory.
## Plots
-The ui displays two plots, one in the form of a graph and the other of a bar, shown below:
+The ui displays two plots, one in the form of a line plot and the other in the form of of a bar plot.
![](figures/plots.png "Plots")
-They are both rendered using the `renderGvis` function from the googleVis package, where all specifications are made. Plot 1 is shown below:
+They are both rendered using the `renderGvis` function from the googleVis package, where all specifications are made. The code to render `out$plot1` is an example to render a googleVis plot:
```{r, eval = FALSE}
output$plot1 <- renderGvis({
@@ -89,7 +96,7 @@ where,
TserieGraphData is the specific plot type
xvar and yvar are the x and y axis
-options include all of the aesthetically features including the Mirai blue, which is defined as a particular shade as following:
+options include all of the aesthetic features including the Mirai color palette, which is defined via as hex codes:
```{r}
miraiColors <- "['#008cc3', '#FF9966', '#13991c']"
@@ -97,7 +104,7 @@ miraiColors <- "['#008cc3', '#FF9966', '#13991c']"
## Statements and report name
-The total retirement value text as well as the disclaimer are created using the shiny function renderText. Within the function, the paste command is used to combine set sentences with changing values as shown below:
+The total retirement value text as well as the disclaimer are created using the shiny function renderText. Within the function, the paste command can be used to combine fixed sentences with changing values:
```{r, eval = FALSE}
reportname <- reactive(
@@ -111,7 +118,7 @@ Sys.Date is the date the report was created
## Download button
-The download button is rendered using the shiny downloadHandler function. Within this function, all of the specifics of the report are specified (i.e. which Rmd file to compile, the name of the file and the format) as shown below:
+The download button is rendered using the shiny downloadHandler function. Within this function, all of the specifications of the report are listed (i.e. which Rmd file to compile, the name of the file and the format):
```{r, eval = FALSE}
output$report <- downloadHandler(
diff --git a/vignettes/smarp_ui.Rmd b/vignettes/smarp_ui.Rmd
index 28baf59..a56f940 100644
--- a/vignettes/smarp_ui.Rmd
+++ b/vignettes/smarp_ui.Rmd
@@ -18,6 +18,13 @@ knitr::opts_chunk$set(
library(shiny)
```
+```{r, echo=FALSE}
+htmltools::img(src = knitr::image_uri("figures/mirai.png"),
+ alt = 'logo',
+ style = 'position:absolute; top:0; right:0; padding:10px; margin-right:200px; max-height: 40px;border-style: none;')
+```
+
+
## Introduction
```{r child = 'children/short-intro.Rmd'}
@@ -27,7 +34,7 @@ This vignette describes the UI components and their inner-workings. It is progra
## Outline
-The ui script is wrapped inside a `fluiPage` divided into different `fluidRow`s, one for each component: header, Personal Info, Pillar II - III and plots and table. Every component is then organized into a combination of other `fluidRow`s and `column`s.
+The ui script is wrapped inside a `fluiPage` divided into different `fluidRow`s, one for each component: header, Personal Info, second, third Pillars and plots and table. Every component is then organized into a combination of other `fluidRow`s and `column`s.
@@ -38,7 +45,7 @@ The header is the first object starting from the top of the page and it includes
![](figures/SmaRP_logo.png "SmaRP_logo")
-These three objects are placed inside a `fluidRow` and divided into two columns: one containing the logo and the blue bar and the other the title. The blue bar and the logo is dragged from the Mirai Solutions website in the form of a URL and the logo as a .png image. A sample of the code is shown below:
+These three objects are placed inside a `fluidRow` and divided into two columns: one containing the logo and the blue bar and the other the title. The blue bar and the logo is dragged from the Mirai Solutions website in the form of a URL and the logo as a .png image:
```{r, eval = FALSE}
fluidRow(
@@ -62,11 +69,11 @@ style determines where objects should be located.
## Personal Info
-The personal Info panel gathers the user's personal data, later used to perform calculations. A snippet of the panel's outline can be found below
+The personal Info panel gathers the user's personal data, later used to perform calculations. Fields are aligned both vertically and horizontally as shown in the snippet.
![](figures/SmaRP_personal_info.png "SmaRP_personal_info")
-Each component is created using a specific shiny function, explained below:
+Each component is created using a specific shiny function:
* Personal Info: text object with `h4` dimensions
* Birthday: `dateInput` object with date-month-year format. The user can either select a date form the calendar or manually type it in
@@ -77,7 +84,7 @@ Each component is created using a specific shiny function, explained below:
* Kids: `numericInput` object. The user can increase/decrease the number with the arrows or enter it manually; the default is zero
* Church affiliation: optional `checkbox` object.
-Even though most components are self explanatory, `bsTooltip`s were added to provide short explanations. They appear in the form of a black box when the user places the cursor on a specific object. A sample of the code is shown below:
+Even though most components are self explanatory, `bsTooltip`s were added to provide short explanations. They appear in the form of a box when the user places the cursor on a specific object:
```{r, eval = FALSE}
fluidRow(
@@ -95,15 +102,15 @@ fluidRow(
```
-## Pillar II and III
+## 2nd and 3rd Pillar
-Below the personal info part lies the pillars section. Pillar II is intended for the case of an occupational pension fund and Pillar III for a private one.
+Below the personal info part lies the pillars section. Second Pillar is intended for the case of an occupational fund and the third Pillar for a private one.
-![](figures/SmaRP_Pillar_II.png "SamRP_Pillar_II")
+![](figures/SmaRP_Pillar_II.png "SmaRP_Pillar_2")
-![](figures/SmaRP_Pillar_III.png "SamRP_Pillar_III")
+![](figures/SmaRP_Pillar_III.png "SmaRP_Pillar_3")
-They both contain `numericInput`s inside `fluidRow`s and a `radioButtons` in the case of Pillar II.
+They both contain `numericInput`s inside `fluidRow`s and a `radioButtons` in the case of the second Pillar.
## Plots and table
@@ -117,7 +124,7 @@ The table reports many output values including: Calendar, DirectP2, ReturnP2, To
GitHub and Mirai Solutions logos were imported using urls.
-The disclaimer message was created using the `verbatimTextOutput` function as shown below:
+The disclaimer message was created using the `verbatimTextOutput` function:
```{r, eval = FALSE}
fluidRow(
diff --git a/vignettes/smarp_user_manual.Rmd b/vignettes/smarp_user_manual.Rmd
index da93826..94d21d5 100644
--- a/vignettes/smarp_user_manual.Rmd
+++ b/vignettes/smarp_user_manual.Rmd
@@ -9,6 +9,12 @@ vignette: >
%\VignetteEncoding{UTF-8}
---
+```{r, echo=FALSE}
+htmltools::img(src = knitr::image_uri("figures/mirai.png"),
+ alt = 'logo',
+ style = 'position:absolute; top:0; right:0; padding:10px; margin-right:200px; max-height: 40px;border-style: none;')
+```
+
## Introduction
```{r child = 'children/short-intro.Rmd'}
@@ -35,13 +41,13 @@ The following is a list describing components in the first panel. Unless otherwi
- **Church Affiliation** only requires a yes or no answer. No specification regarding which type is requested.
-## Occupational Pension Fund - Pillar II
+## Occupational Fund - 2nd Pillar
-The second panel contains all fields related to the occupational pension fund.
+The second panel contains all fields related to the occupational fund.
-- **Current Annual Salary** is the base to calculate contributions to the Occupational Pension Fund and the tax relief generated with the non-mandatory contributions. It is inserted in gross terms (before tax) with the maximum value set at 100M CHF.
+- **Current Annual Salary** is the base to calculate contributions to the Occupational Fund and the tax relief generated with the non-mandatory contributions. It is inserted in gross terms (before tax) with the maximum value set at 100M CHF.
-- **Current BVG Assets** is the amount already invested in the Occupational pension fund and can be found on the annual report of the Pension Fund.[^1]
+- **Current BVG Assets** is the amount already invested in the Occupational fund and can be found on the annual report of the Pension Fund.[^1]
- **Expected Salary Growth Rate %** should be entered in percentage and is constant during the full working life. Note that since all values are in nominal terms, the salary growth rate can be used as a proxy of the inflation or a general economic growth. References regarding historical values can be found [here](https://tradingeconomics.com/switzerland/wage-growth).
@@ -52,41 +58,41 @@ The second panel contains all fields related to the occupational pension fund.
- **Purchase Type** refers to previous voluntary purchases and can be made as a single or a constant, multi-year, working-life long contribution.
-## Private Pension Fund - Pillar III
+## Private Fund - Third Pillar
-The third panel is the private pension fund. It is non-compulsory and only includes annual contributions.
+The third panel is the private fund. It is non-compulsory and only includes annual contributions.
-- **Current Assets** is the amount already invested in the private pension fund.[^3]
+- **Current Assets** is the amount already invested in the private fund.[^3]
- **Annual Contribution** to the private fund on an annual basis is assumed to be constant throughout the entire working life.
-- **Expected Return %** is the average expected return from the private pension fund. It should be entered in percentage and is constant throughout the entire working life.[^4]
+- **Expected Return %** is the average expected return from the private fund. It should be entered in percentage and is constant throughout the entire working life.[^4]
## Results
The text box above the plots summarizes the total pension fund the user will get at the end of his working life.[^5]
-The total pension fund can be divided in three components: Occupational pension fund, Private pension fund and tax benefits fund.
+The total pension fund can be divided in three components: Occupational fund, Private fund and tax benefits.
-**The tax benefits fund** cannot be directly capitalized as the other two, but is generated indirectly through tax relieves coming from contributions to the other funds.
+**The tax benefits** cannot be directly capitalized as the other two, but is generated indirectly through tax relieves coming from contributions to the other funds.
-There are some important notes to consider about the tax benefits fund.
+There are some important notes to consider about the tax benefits.
-- Contributions are calculated as the tax relief is generated and therefore are related to the marginal tax rate of each individual. The higher the tax rate, the higher the tax relief and thus the tax benefits fund.
+- Contributions are calculated as the tax relief is generated and therefore are related to the marginal tax rate of each individual. The higher the tax rate, the higher the tax relief and thus the tax benefits.
- The cap on the tax relief is defined by the Swiss federal government.
- SmaRP assumes that all tax benefits are reinvested and somehow saved until retirement.
-- The average expected return is the same as the private pension fund.
+- The average expected return is the same as the private fund.
### Plot tab
**The evolution of the different funds is shown on the first plot.** Mouseovering the graph lines, date and amount are displayed on an informative box.
-**The bar plot below shows the distribution among funds at retirement age.**
+**The bar plot shows the distribution among funds at retirement age.**
- In case that no voluntary contributions to the occupational fund or private fund are available, only the occupational fund will be displayed.
@@ -119,7 +125,7 @@ Given that those assumptions are specific to a very distinct scenario, married u
[^1]: SmaRP assumes that the current BVG assets did not generate any tax benefits in the past, meaning that all funds come from mandatory contributions.
-[^2]: Voluntary contributions to the Occupational Pension Fund represent an ad-hoc "purchase" of pension benefits made by the retiree. These purchases are usually made to fill gaps in the working life or to cover up previous lower salaries after a wage raise.
-[^3]: SmaRP assumes that current assets on the private pension funds did not generate any tax benefits in the past.
-[^4]: SmaRP assumes that the average expected return is the same for private pension funds as for the tax return.
-[^5]: SmaRP does not make any consideration about the usage of the retirement pension funds. For the Occupational pension fund, the Swiss pension law allows retirees to take the full amount as a lump sum, receive their pension in the form of a life annuity, or a mix of both. In the last case, the minimum conversion rate as of 2018 is 6.8% and can vary depending on the retirement age. The Private fund, however, is always paid as a lump sum.
+[^2]: Voluntary contributions to the Occupational Fund represent an ad-hoc "purchase" of pension benefits made by the retiree. These purchases are usually made to fill gaps in the working life or to cover up previous lower salaries after a wage raise.
+[^3]: SmaRP assumes that current assets on the private funds did not generate any tax benefits in the past.
+[^4]: SmaRP assumes that the average expected return is the same for private funds as for the tax return.
+[^5]: SmaRP does not make any consideration about the usage of the retirement funds. For the Occupational fund, the Swiss pension law allows retirees to take the full amount as a lump sum, receive their pension in the form of a life annuity, or a mix of both. In the last case, the minimum conversion rate as of 2018 is 6.8% and can vary depending on the retirement age. The Private fund, however, is always paid as a lump sum.