--- title: "French investment illustration: stylized SPV tax impact" author: "Package cre.dcf" output: rmarkdown::html_vignette: toc: true toc_depth: 3 number_sections: true vignette: > %\VignetteIndexEntry{French investment illustration: stylized SPV tax impact} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE) library(cre.dcf) library(dplyr) library(tibble) library(scales) library(yaml) ``` ## Purpose This vignette illustrates how `tax_run_spv()` can be used on a French office investment case. It is intentionally a **stylized French-like SPV illustration**, not a legal or tax opinion. As of **April 1, 2026**, the normal French corporate income-tax rate is **25%**, following the official French tax administration's published corporate-tax guidance consulted for this vignette. The rest of the tax assumptions below are simulated package inputs chosen to remain within the current scope of `tax_run_spv()`: - straight-line depreciation only, - simple interest deductibility, - simple loss carryforwards, - no investor-level taxes, - no withholding taxes, - no treaty logic, - no attempt to encode the full French interest-limitation regime. The point of the vignette is therefore methodological: show how a French case can be parameterized in the current generic engine without pretending to replicate the full French tax code. ## Start from a French operating case We use the package's `preset_core.yml`, which already describes a stylized Paris 8e office investment. ```{r} cfg_path <- system.file("extdata", "preset_core.yml", package = "cre.dcf") cfg <- yaml::read_yaml(cfg_path) case <- run_case(cfg) bullet_summary <- case$comparison$summary |> filter(scenario == "debt_bullet") |> transmute( scenario, irr_project, irr_equity, min_dscr, max_ltv_forward, ops_share, tv_share ) knitr::kable( bullet_summary, digits = 3, caption = "Before-tax baseline for the stylized French core-office case" ) ``` At this stage, the core DCF is still entirely before tax. The tax layer comes next and consumes the consolidated cash-flow table. ## Translate the French-like SPV into tax inputs The current tax engine needs two objects: - a tax basis extracted from the pre-tax case, - a tax specification describing the stylized SPV rules. ```{r} tax_basis <- tax_basis_spv(case) tax_assumptions <- tibble::tribble( ~item, ~value, ~comment, "Corporate income tax", "25%", "Official French normal CIT rate as of April 1, 2026", "Land share", "20%", "Stylized non-depreciable portion", "Building share", "65%", "Stylized depreciable structure", "Fit-out share", "15%", "Stylized depreciable tenant-improvement bucket", "Building life", "30 years", "Stylized straight-line life", "Fit-out life", "10 years", "Stylized straight-line life", "Interest deductibility", "full", "Current engine scope, not full French law", "Loss carryforward", "on", "Stylized carryforward allowed", "Offset cap", "50%", "Stylized cap used to keep the rule conservative" ) knitr::kable( tax_assumptions, caption = "French-like tax assumptions used in this vignette" ) ``` ```{r} tax_spec <- tax_spec_spv( corp_tax_rate = 0.25, depreciation_spec = depreciation_spec( acquisition_split = tibble::tribble( ~bucket, ~share, ~life_years, ~method, ~depreciable, "land", 0.20, NA, "none", FALSE, "building", 0.65, 30, "straight_line", TRUE, "fitout", 0.15, 10, "straight_line", TRUE ), capex_bucket = "fitout", start_rule = "full_year" ), interest_rule = interest_rule(mode = "full"), loss_rule = loss_rule( carryforward = TRUE, carryforward_years = Inf, offset_cap_pct = 0.50 ) ) tax_res <- tax_run_spv(tax_basis, tax_spec) ``` ## Read the yearly tax table The yearly table below is the main output of `tax_run_spv()`. ```{r} tax_view <- tax_res$tax_table |> select( year, noi, tax_depreciation, deductible_interest, taxable_income_pre_losses, loss_cf_open, loss_cf_used, cash_is, after_tax_equity_cf ) knitr::kable( tax_view, digits = 0, caption = "Stylized French SPV tax table" ) ``` This is the main reading grid: - `tax_depreciation` transforms acquisition basis and capex into fiscal charges, - `deductible_interest` removes the debt cost that is deductible under the simplified rule, - `taxable_income_pre_losses` is the taxable base before using prior losses, - `loss_cf_open` and `loss_cf_used` show how prior tax losses are mobilized, - `cash_is` is the annual corporate income tax paid by the SPV, - `after_tax_equity_cf` is the equity cash flow net of that annual tax. ## Compare pre-tax and after-tax equity cash flows The generic engine does not yet build a complete French investor-level valuation. It does, however, let us measure the tax drag at the SPV level. ```{r} equity_bridge <- tax_res$tax_table |> select(year, pre_tax_equity_cf, cash_is, after_tax_equity_cf) knitr::kable( equity_bridge, digits = 0, caption = "Bridge from pre-tax to after-tax equity cash flows" ) ``` We can also compare the before-tax leveraged IRR with a stylized after-tax SPV equity IRR computed on `after_tax_equity_cf`. ```{r} pre_tax_equity_irr <- case$leveraged$irr_equity after_tax_equity_irr <- irr_safe(tax_res$tax_table$after_tax_equity_cf) tax_highlights <- tibble( pre_tax_equity_irr = pre_tax_equity_irr, after_tax_spv_equity_irr = after_tax_equity_irr, total_cash_is = tax_res$summary$total_cash_is, total_tax_depreciation = tax_res$summary$total_tax_depreciation, exit_year_cash_is = tax_res$tax_table$cash_is[ tax_res$tax_table$year == max(tax_res$tax_table$year) ] ) knitr::kable( tax_highlights, digits = 3, caption = "Stylized before-tax versus after-tax SPV reading" ) ``` In this example: - the pre-tax DCF remains the economic backbone of the case, - the stylized French tax layer reduces equity cash flows through annual `cash_is`, - depreciation materially shapes the taxable base, - and the exit year remains a critical point because the final tax charge can be large. ## What this vignette captures and what it does not This French illustration is useful because it shows a coherent workflow: 1. build the investment case, 2. extract a tax basis, 3. define a country-like SPV parameterization, 4. read the yearly tax consequences. But it still has clear limits. Captured: - a French office investment setting, - a normal-CIT-rate scenario, - non-depreciable land, - depreciable building and fit-out buckets, - simple loss carryforwards, - a visible bridge from pre-tax to after-tax equity cash flows. Not captured: - the full French interest-limitation regime, - the exact French loss-carryforward formula, - shareholder taxation, - transfer-tax mechanics beyond the acquisition-cost block already embedded in the DCF, - exit-structuring choices, - treaty and cross-border effects. ## Summary This vignette shows how `cre.dcf` can already support a realistic French-style teaching case without hard-coding French tax law into the package core. - The before-tax DCF remains the common economic layer. - `tax_run_spv()` adds a stylized SPV tax reading on top of it. - The result is useful for scenario analysis and methodology, but should not be read as legal advice or as a complete French tax model.