# ETL
library(tidyverse)
# Supply Chain
library(planr)36 Convert inventories to coverage
37 Upload libraries
38 Objective
We’re going to explain here how to use the function inv_to_cov() from the R package planr.
This function aims to convert projected inventories into their related coverages based on the :
the demand forecasts.
the projected inventories
It’s the opposite of the function proj_cov(), which converts a projected coverage into inventories.
39 Create a demo dataset
Let’s create a dataframe with the 4 variables we need for our calculation:
a DFU : 3 Products, A, B and C.
a Period of time : in monthly bucket.
some Projected Inventories : the monthy ending inventories of each product.
some Demand forecasts : some (monthly) sales forecasts for each product.
# create the variables
DFU <- c("Product_A", "Product_B", "Product_C")
Period <- format(seq(as.Date("2026-09-01"), by = "month", length.out = 24))
# merge and create a dataframe
set.seed(42)
df1 <- crossing(DFU, Period) |>
mutate(
Inventories = sample(100:300, n(), replace = TRUE),
Demand = sample(50:200, n(), replace = TRUE)
)
# format the Period as a Date
df1$Period <- as.Date(df1$Period, format = "%Y-%m-%d")
# keep results
inventories_data <- df1
glimpse(df1) Rows: 72
Columns: 4
$ DFU <chr> "Product_A", "Product_A", "Product_A", "Product_A", "Produ…
$ Period <date> 2026-09-01, 2026-10-01, 2026-11-01, 2026-12-01, 2027-01-0…
$ Inventories <int> 148, 164, 252, 173, 245, 221, 148, 227, 146, 123, 170, 199…
$ Demand <int> 84, 65, 150, 118, 167, 179, 131, 162, 195, 118, 159, 153, …
40 Apply function
Now we apply the function inv_to_cov() to this dataframe.
The output is a dataframe with 6 variables. We get 2 additional ones:
Projected.Inventories.Qty : which is actually equal to the initial input [Inventories].
Calculated.Coverage.in.Periods : the conversion of those projected inventories into coverages, considering the Demand Forecasts.
# apply function
df1 <- planr::inv_to_cov(inventories_data)
# keep results
calculated_data <- df1
glimpse(df1)Rows: 72
Columns: 6
$ DFU <chr> "Product_A", "Product_A", "Product_A", …
$ Period <date> 2026-09-01, 2026-10-01, 2026-11-01, 20…
$ Demand <dbl> 84, 65, 150, 118, 167, 179, 131, 162, 1…
$ Opening <dbl> 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ Projected.Inventories.Qty <dbl> 148, 164, 252, 173, 245, 221, 148, 227,…
$ Calculated.Coverage.in.Periods <dbl> 1.6, 1.1, 1.8, 1.0, 1.5, 1.6, 0.9, 1.3,…
Let’s analyze the results
We select the “Product_A” and look at the results:
- at the end of the 1st Period “2026-09-01”, we have 1.6 months of coverage. 148 units indeed cover the Demand of “2026-10-01” and part of the next one of “2026-11-01”.
- the same mechanism applies to the following Periods of time.
# filter on DFU
df1 <- calculated_data |> filter(DFU == "Product_A")
print(df1) DFU Period Demand Opening Projected.Inventories.Qty
1 Product_A 2026-09-01 84 64 148
2 Product_A 2026-10-01 65 0 164
3 Product_A 2026-11-01 150 0 252
4 Product_A 2026-12-01 118 0 173
5 Product_A 2027-01-01 167 0 245
6 Product_A 2027-02-01 179 0 221
7 Product_A 2027-03-01 131 0 148
8 Product_A 2027-04-01 162 0 227
9 Product_A 2027-05-01 195 0 146
10 Product_A 2027-06-01 118 0 123
11 Product_A 2027-07-01 159 0 170
12 Product_A 2027-08-01 153 0 199
13 Product_A 2027-09-01 89 0 188
14 Product_A 2027-10-01 198 0 264
15 Product_A 2027-11-01 106 0 209
16 Product_A 2027-12-01 149 0 119
17 Product_A 2028-01-01 91 0 253
18 Product_A 2028-02-01 195 0 213
19 Product_A 2028-03-01 140 0 210
20 Product_A 2028-04-01 62 0 230
21 Product_A 2028-05-01 103 0 140
22 Product_A 2028-06-01 132 0 188
23 Product_A 2028-07-01 81 0 126
24 Product_A 2028-08-01 109 0 263
Calculated.Coverage.in.Periods
1 1.6
2 1.1
3 1.8
4 1.0
5 1.5
6 1.6
7 0.9
8 1.3
9 1.2
10 0.8
11 1.2
12 1.6
13 0.9
14 2.1
15 1.7
16 1.1
17 1.4
18 2.1
19 2.3
20 2.0
21 1.1
22 2.0
23 99.0
24 99.0
