load("data/default_constants_list.Rda")
load("data/default_constants_table.Rda")
load("data/default_employees.Rda")
load("data/default_end_month.Rda")
load("data/default_growth_rates.Rda")
load("data/default_int_lev.Rda")
load("data/default_lease_att.Rda")
load("data/default_past_leases.Rda")
load("data/default_start_month.Rda")
load("data/norm_default.Rda")
load("data/norm_early_default.Rda")
library(dplyr)
library(ggplot2)
library(xlsx)
#
#' The reverse.irr function
#'
#' This function calculates the irr of a lease (as if it was a loan) given an
#' initial value and a payment schedule, used here as a helper for asset.val
#' @param init.val is the starting value of the lease, or the amount of money lent
#' @param pay schedule is a vector of payments in the lease, make sure it has no gaps in the schedule
#' @return a number representing the IRR of the inputs
#' @export
#' @examples
#' reverse.irr(init.val = 1200, pay.schedule = rep(200,10))
reverse.irr <- function(init.val,
pay.schedule){
f <- function (y){
sum(pay.schedule / (1 + y)^(1: length(pay.schedule))) - init.val
}
uniroot(f, c(-1,1))$root
}
#' The asset.val function
#'
#' This function calculates the asset value of a lease given an initial value and a payment schedule
#' @param init.val is the starting value of the lease, or the amount of money lent
#' @param pay schedule is a vector of payments in the lease
#' @return a vector representing the value of the asset over the pay.schedule
#' @export
#' @examples
#' asset.val(init.val = 1200, pay.schedule = c(200,0,0,200,0,200,0,200,0,200,200,0,0,200,200,0,200,0,200))
asset.val <- function(init.val,
pay.schedule){
relevant.pay.indexes <- c(which(pay.schedule != 0))
relevant.pay <- pay.schedule[relevant.pay.indexes]
temp = rep(init.val, length(relevant.pay))
toReturn <- rep(0,length(pay.schedule))
temp[1] = init.val - (relevant.pay[1] - reverse.irr(init.val = init.val, pay.schedule = relevant.pay) * init.val)
for (x in 2:length(relevant.pay)){
temp[x] = temp[x-1] -
(relevant.pay[x] - reverse.irr(init.val = init.val, pay.schedule = relevant.pay) * temp[x-1])
toReturn[relevant.pay.indexes[x-1] : (relevant.pay.indexes[x] - 1)] <- temp[x-1]
}
toReturn[1: relevant.pay.indexes[1] - 1] <- init.val
toReturn[which(toReturn < 0)] <- 0
toReturn
}
#' The lease.combinations function
#'
#' This function calculates the all possible combinations of leases given a set of attributes
#' @param lease.att, a list of lists that represent different distributions of lease traits
#' @return a data frame where each row represents a lease
#' @export
lease.combinations <- function(lease.att = default.lease.att) {
combs <- expand.grid(lease.length = lease.att$lease.length$param.types,
markup = lease.att$markup$param.types,
sales.price = lease.att$sales.price$param.types,
init.pay.pct = lease.att$init.pay.pct$param.types,
pay.freq = lease.att$pay.freq$param.types,
pay.manner = lease.att$pay.manner$param.types)
calc.weights <- function(a.row){
lease.att$lease.length$param.dist[which(lease.att$lease.length$param.types == as.numeric(a.row['lease.length']))] *
lease.att$markup$param.dist[which(lease.att$markup$param.types == as.numeric(a.row['markup']))]*
lease.att$sales.price$param.dist[which(lease.att$sales.price$param.types == as.numeric(a.row['sales.price']))] *
lease.att$init.pay.pct$param.dist[which(lease.att$init.pay.pct$param.types == as.numeric(a.row['init.pay.pct']))] *
lease.att$pay.freq$param.dist[which(lease.att$pay.freq$param.types == a.row['pay.freq'])] *
lease.att$pay.manner$param.dist[which(lease.att$pay.manner$param.types == a.row['pay.manner'])]
}
combs$weights = apply(combs, 1, calc.weights)
combs
}
test.lease.combinations <- lease.combinations()
#' The prd function
#'
#' This function calculates a predicted payments vector given data about previous payments and installments
#' @param co.indicator, a boolean indicating whether the lease is charged off.
#' If charged off, predicted payments vector is just 0s.
#' @param past.payments, A vector containing past payments.
#' @param past.pay.dates, A vector containing the dates of past payments (corresponds 1:1 with past.payments)
#' @param installments, A vector with all the installments of the lease
#' @param installment.states, A vector containing the states of all installments (corresponds 1:1 with installments)
#' @param installments.balance, A vector with the balance remaining of all installments. Is 0 if the installment is
#' paid. (corresponds 1:1 with installments)
#' @param installment.dates, A vector containing the dates each installment is due (corresponds 1:1 with installments)
#' @param installment.pay.dates, A vector containing the dates paid installments were paid. Corresponds 1:1 with installments,
#' but is NA for installments that have not been paid.
#' @param installment.indexes, A vector containing the indexes of each installment in the larger data frame. (corresponds
#' 1:1 with installments)
#' @param pay.gap, An integer representing the number of days between scheduled payments
#' @param start.index, An integer representing the index matching this lease's start date in the larger data frame
#' @param start.date, The start date of the lease
#' @param paid.buckets, Vector of integers representing different "buckets" of ranges for leases that have already been partially
#' paid. Should be same lenghth as paid.bucket.vals
#' @param paid.bucket.vals, Vector of values that correspond to each bucket in paid.buckets. Index 1 in paid.bucket.vals
#' corresponds with values under index 1 in paid.buckets, Index 2 in paid.bucket.vals corresponds with values between
#' indexes 1 and 2 in paid.buckets, and so on.
#' @param new.buckets, Vector of integers representing different "buckets" of ranges for brand new lesases. Should be same length as
#' new.bucket.vals
#' @param new.bucket.vals: Vector of values that correspond to each bucket in new.buckets.Indexes correspond the same way as paid.bucket.vals
#' and paid.buckets.
#' @param assumptions: constant values, represented as a list
#' @param default.rate: default rate represented as a vector 1000 long with values between 0 and 1
#' @return A vector representing the predicted payments for the future.
#' @export
prd <- function(co.indicator = FALSE, past.payments, past.pay.dates, installments, installment.states,
installments.balance, installment.dates, installment.pay.dates, installment.indexes,
pay.gap, start.index, start.date, paid.buckets = c(0,5,20,40,1000),
paid.bucket.vals = c(.1,.5,1,2,4), new.buckets = c(0,30,60,1000), new.bucket.vals = c(.5,.5,.75,1),
assumptions = default.constants.list, default.rate = norm.default.rate){
if (!co.indicator){
# Leases only have predicted future payments if they aren't charged off.
paid.indexes = which(installment.states == "paid")
unpaid.indexes = which(installment.states == "unpaid")
if (length(past.payments) != 0){
# If there have been past payments that data is taken into account when predicting future payments
if (length(paid.indexes) == 0){
# If no installments have been fully paid yet
future.payments <- installments.balance[unpaid.indexes]
average.days.late = sum(past.pay.dates - installment.dates[1])
} else {
# If installments have already been paid in the past
last.paid = (which(installment.states == "unpaid")[1] - 1)
average.prop.paid = sum(past.payments[which(past.pay.dates <= installment.pay.dates[last.paid])]) /
sum(installments[1:last.paid])
average.days.late = round(mean(installment.pay.dates[paid.indexes] - installment.dates[paid.indexes]))
if (average.prop.paid > 1){
# If people "overpay" on installments, they get a discount and potentially less payments total
future.payments = sum(installments.balance[unpaid.indexes]) - cumsum(installments.balance[unpaid.indexes])
+ ((average.prop.paid-1) * installments.balance[unpaid.indexes] / (1 - assumptions$early.pay.discount))
future.payments[which(future.payments < 0)] <- 0
future.payments <- pmin(future.payments,average.prop.paid * installments.balance[unpaid.indexes])
} else {
future.payments <- installments.balance[unpaid.indexes]
}
}
# Depending on how many days late payments are, the default rate will be amplified to a certain extent
default.amp = paid.bucket.vals[min(which(paid.buckets > average.days.late))]
# if for some reason a lease is longer than 1000 days
temp = installment.indexes[unpaid.indexes] - start.index
temp[which(temp > 999)] = 999
future.payments <- future.payments *
cumprod(default.rate[1 + temp]^(pay.gap * 12 / 365 * default.amp))
return(future.payments)
} else if (length(past.payments) == 0){
# If there have been no past payments
average.days.late = (Sys.Date() - start.date)
# Depending on how late the first payment has been outstanding, default rate will be amplified
default.amp = new.bucket.vals[min(which(new.buckets > average.days.late))]
# If it's over 1000 days for some reason
temp = installment.indexes - start.index
temp[which(temp > 999)] = 999
future.payments <- installments.balance[unpaid.indexes] *
cumprod(default.rate[1 +temp]^(pay.gap * 12 / 365 * default.amp))
return(future.payments)
}
} else {
# If lease is charged off, predicted payments are just 0s
return(rep(0, length(which(installment.states == "unpaid"))))
}
}
#' The collect.past function
#'
#' This function takes in a dataframe (default.past.leases) containing data about leases,
#' and returns a dataframe with financial parameters
#'
#' @param dataframe with data about leases. Needs to have fields for lease status, pay frequency, price,
#' down payment, start date,installments, installment dates, installment balances, installment pay dates,
#' installment states, payments, and payment dates.
#' @param assumptions, list of constant values
#' @return A by-day dataframe with financial parameters payment.due, payment.expected, payment.process.cost,
#' asset.acq.outflow, total.assets.linear, total.assets.loan, lease.depreciation, bad.debt
#' @export
collect.past <- function(leases = default.past.leases,
assumptions = default.constants.list){
toReturn <- data.frame(dates = seq(min(leases$start.date) - 10, by = "day",
length.out = (max(leases$start.date) - min(leases$start.date) + 1012)),
payment.due = 0,
payment.expected = 0,
payment.process.cost = 0,
asset.acq.outflow = 0,
total.assets.linear = 0,
total.assets.loan = 0,
lease.depreciation = 0,
bad.debt = 0,
leases.booked = 0,
no.stores = 0,
ongoing.leases = 0,
payments.sum = 0)
# Iterate through each lease
for (x in 1: nrow(leases)) {
payments.vector = rep(0,length(toReturn$payment.expected))
pdue.vector = rep(0,length(toReturn$payment.due))
if (leases$status[x] == "returned"){
# If leases are "returned" they basically don't exist except for payments arleady made
past.payment.indexes <- unlist(sapply(leases$payment.dates[[x]], function(date){which(date == toReturn$dates)}))
# Group the past payments so that payments on same days are combined
unique.pay.indexes = unique(past.payment.indexes)
unique.payments = rep(0, length(unique.pay.indexes))
for (i in 1:length(past.payment.indexes)){
unique.payments[which(unique.pay.indexes == past.payment.indexes[i])] =
unique.payments[which(unique.pay.indexes == past.payment.indexes[i])] +
leases$lease.payments[[x]][i]
}
# Past payments
toReturn$payment.expected[unique.pay.indexes] = toReturn$payment.expected[unique.pay.indexes] + unique.payments
} else {
start.index <- which(toReturn$dates == leases$start.date[x])
toReturn$leases.booked[start.index] <- toReturn$leases.booked[start.index] + 1
toReturn$no.stores[start.index] <- max(toReturn$no.stores[start.index], toReturn$leases.booked[start.index] / assumptions$leases.per.store)
toReturn$no.stores[(start.index+1):nrow(toReturn)] <- pmax(toReturn$no.stores[(start.index+1):nrow(toReturn)], toReturn$no.stores[start.index])
# Payment gap
pay.gap = if (leases$freq[[x]] == "weekly") 7
else if (leases$freq[[x]] == "biweekly") 14
else if (leases$freq[[x]] == "monthly") 365/12
else if (substr(leases$freq[[x]],1,11) == "semimonthly") 15
# Add down payment in payment vectors
toReturn$payment.due[start.index] <- toReturn$payment.due[start.index] + leases$down.payments[x]
toReturn$payment.expected[start.index] <- toReturn$payment.expected[start.index] + leases$down.payments[x]
pdue.vector[start.index] <- pdue.vector[start.index] + leases$down.payments[x]
payments.vector[start.index] <- payments.vector[start.index] +leases$down.payments[x]
# Indexes of installments in toReturn
installment.indexes <- unlist(sapply(leases$installment.dates[[x]], function(date){which(date == toReturn$dates)}))
# Payments Due
toReturn$payment.due[installment.indexes] = toReturn$payment.due[installment.indexes] + leases$installments[[x]]
pdue.vector[installment.indexes] = pdue.vector[installment.indexes] + leases$installments[[x]]
# Indexes of payments in toReturn
past.payment.indexes <- unlist(sapply(leases$payment.dates[[x]], function(date){which(date == toReturn$dates)}))
# Group the past payments so that payments on same days are combined
unique.pay.indexes = unique(past.payment.indexes)
unique.payments = rep(0, length(unique.pay.indexes))
for (i in 1:length(past.payment.indexes)){
unique.payments[which(unique.pay.indexes == past.payment.indexes[i])] =
unique.payments[which(unique.pay.indexes == past.payment.indexes[i])] +
leases$lease.payments[[x]][i]
}
# Past payments
toReturn$payment.expected[unique.pay.indexes] = toReturn$payment.expected[unique.pay.indexes] + unique.payments
payments.vector[unique.pay.indexes] = payments.vector[unique.pay.indexes] + unique.payments
# Asset.Acq.Outflow
toReturn$asset.acq.outflow[start.index] <- toReturn$asset.acq.outflow[start.index] + leases$price[x] + leases$down.payments[x]
# Linear Asset Valuation
# How long a lease lasts
lease.length.days <- if (leases$status[[x]] == "paid") (as.numeric(max(leases$payment.dates[[x]]) - leases$start.date[x]) + 1)
else (as.numeric(max(leases$installment.dates[[x]]) - leases$start.date[x]) + 1)
# How long after the start.date until first payment
first.pay.gap <- leases$installment.dates[[x]][1] - leases$start.date[x]
if (first.pay.gap < 0) first.pay.gap = 0
if (lease.length.days < 0){
# If lease is paid off before its start.date it has no value as an asset
temp.linear = 0
} else if (lease.length.days < first.pay.gap) {
# If the lease is paid off before its first installment is due value goes to 0 from that point on
coeff <- (leases$price[x] + leases$down.payments[x]) / lease.length.days
temp.linear = rep(0, length(toReturn$total.assets.linear))
temp.linear[(start.index + 1): (start.index + lease.length.days + 1)] = leases$price[x] + leases$down.payments[x]
toReturn$ongoing.leases[start.index : (start.index + lease.length.days)] =
toReturn$ongoing.leases[start.index : (start.index + lease.length.days)] + 1
} else {
# Else, the lease value is a flat line until the first installment is due, when it depreciates linearly
coeff <- (leases$price[x] + leases$down.payments[x]) / lease.length.days
temp.linear = rep(0, length(toReturn$total.assets.linear))
temp.linear[(start.index + 1): (start.index + first.pay.gap + 1)] = leases$price[x] + leases$down.payments[x]
temp.linear[(start.index + first.pay.gap + 2): (start.index + lease.length.days)] =
leases$price[x] + leases$down.payments[x] - coeff*c(1:(lease.length.days - first.pay.gap - 1))
toReturn$ongoing.leases[start.index : (start.index + lease.length.days)] =
toReturn$ongoing.leases[start.index : (start.index + lease.length.days)] + 1
}
# Loan assets valuation
if (lease.length.days < 30){
# If lease length is small, just make it the same as the linear valuation
temp.loan = temp.linear
} else {
# If lease length is large, use asset.val to generate an asset curve
temp.loan <- if (leases$status[[x]] == "paid") (asset.val(init.val = leases$price[x] + leases$down.payments[x], pay.schedule = payments.vector))
else (asset.val(init.val = leases$price[x] + leases$down.payments[x], pay.schedule = pdue.vector))
temp.loan[1:start.index] <- 0
}
# Predicting payments
unpaid.indexes = which(leases$installment.states[[x]] == "unpaid")
if (leases$status[[x]] == "active" && length(unpaid.indexes) != 0){
# Only active payments will have future payments
if ((Sys.Date() - leases$installment.dates[[x]][unpaid.indexes[1]]) > assumptions$charge.off.time && length(leases$lease.payments[[x]]) != 0){
# If the lease hasn't had any new payments for a certain time, it's charged off and the asset value/bad debt is changed to reflect that
temp.linear[which(toReturn$dates == leases$installment.dates[[x]][unpaid.indexes[1]] + assumptions$charge.off.time) : length(temp.linear)] <- 0
temp.loan[which(toReturn$dates == leases$installment.dates[[x]][unpaid.indexes[1]] + assumptions$charge.off.time) : length(temp.loan)] <- 0
bad.debt.temp = leases$installments.balance[[x]][unpaid.indexes]
toReturn$bad.debt[installment.indexes[unpaid.indexes]] = toReturn$bad.debt[installment.indexes[unpaid.indexes]] + bad.debt.temp
} else if ((Sys.Date() - leases$start.date[x]) > assumptions$charge.off.time && length(leases$lease.payments[[x]]) == 0) {
# If the lease hasn't had any payments at all for a certain time, it's charged off and the asset value/bad debt is changed
temp.linear <- rep(0, length(temp.linear))
temp.loan <- rep(0,length(temp.loan))
bad.debt.temp = leases$installments.balance[[x]]
toReturn$bad.debt[installment.indexes] = toReturn$bad.debt[installment.indexes] + bad.debt.temp
} else {
# Else, use prd to predict payments and add those payments to the appropriate vectors
toAdd <- prd(past.payments = leases$lease.payments[[x]], past.pay.dates = leases$payment.dates[[x]],
installments = leases$installments[[x]], installment.states = leases$installment.states[[x]],
installments.balance = leases$installments.balance[[x]], installment.dates = leases$installment.dates[[x]],
installment.pay.dates = leases$installment.pay.dates[[x]], installment.indexes = installment.indexes,
pay.gap = pay.gap, start.index = start.index, start.date = leases$start.date[x])
toReturn$payment.expected[installment.indexes[unpaid.indexes]] =
toReturn$payment.expected[installment.indexes[unpaid.indexes]] + toAdd
payments.vector[installment.indexes[unpaid.indexes]] =
payments.vector[installment.indexes[unpaid.indexes]] + toAdd
bad.debt.toAdd = leases$installments.balance[[x]][unpaid.indexes] - toAdd
bad.debt.toAdd[which(bad.debt.toAdd < 0)] = 0
toReturn$bad.debt[installment.indexes[unpaid.indexes]] = toReturn$bad.debt[installment.indexes[unpaid.indexes]] + bad.debt.toAdd
}
}
# Now, update the toReturn linear and loan assets
toReturn$total.assets.linear <- toReturn$total.assets.linear + temp.linear
toReturn$total.assets.loan <- toReturn$total.assets.loan + temp.loan
# Deal with payments sum
toReturn$payments.sum[start.index: length(payments.vector)] <- toReturn$payments.sum[start.index: length(payments.vector)] +
(sum(payments.vector[start.index : length(payments.vector)]) -cumsum(payments.vector[start.index : length(payments.vector)])) *
sum(pdue.vector)/sum(payments.vector)
# Lease Depreciation
pay.indexes <- which(payments.vector != 0)
pay.indexes <- pay.indexes[which(pay.indexes > start.index)]
if (length(pay.indexes) == 0){
# If there are no payments after the start date, the lease just completely depreciates at that date
pay.indexes = start.index + 1
deprec.values = temp.linear[start.index + 1]
} else if (length(pay.indexes) == 1) {
# If there is only 1 payment after the start date, the lease completely depreciates at that payment
deprec.values = temp.linear[start.index + 1]
} else{
# If there are multiple payments, use an algorithm to calculate depreciation values between payments
deprec.values <- 1:length(pay.indexes)
deprec.values[1] = temp.linear[start.index + 1] - temp.linear[pay.indexes[1]]
for (i in 2: length(pay.indexes)){
deprec.values[i] = temp.linear[pay.indexes[i - 1]] - temp.linear[pay.indexes[i]]
}
if (temp.linear[pay.indexes[length(pay.indexes)]] != 0){
deprec.values[length(pay.indexes)] = deprec.values[length(pay.indexes)] + temp.linear[pay.indexes[length(pay.indexes)]]
}
}
# Check if any payments are NA, if so just set to 0.
if (any(is.na(deprec.values))){
deprec.values = 0
}
toReturn$lease.depreciation[pay.indexes] = toReturn$lease.depreciation[pay.indexes] + deprec.values
}
}
# Payment.process.cost is just a percentage of the payment.expected
toReturn$payment.process.cost = toReturn$payment.expected * assumptions$pay.process.pct
toReturn
}
test.collect.past <- collect.past()
#' The calc.average function
#'
#' Calculates an average lease given a large distribution of leases
#'
#' @param leases, a data.frame where each row is a lease
#' @param assumptions, list of constant values
#' @param default.rate, a vector representing the default rate, must be 1000 length with values between 0 and 1
#' @param early.default.rate, a vector representing the early default rate, must be 1000 length with values between 0 and 1
#' @return a data frame representing cash flow metrics of the average of input leases
#' @export
calc.average <- function(leases = test.lease.combinations,
assumptions = default.constants.list,
default.rate = norm.default.rate,
early.default.rate = norm.early.default.rate){
# Initialize the data.frame, set days to 2 years
toReturn <- data.frame(days = c(1:1000),
payment.due = 0,
payment.expected = 0,
payment.process.cost = 0,
asset.acq.outflow = 0,
total.assets.linear = 0,
total.assets.loan = 0,
lease.depreciation = 0,
bad.debt = 0,
payments.sum = 0)
for (x in 1: nrow(leases)) {
# multiply sales price by weight
this.sales.price <- leases[x, 'sales.price']*leases[x, 'weights']
# time between each payment depends on lease type
payment.gap <- if (leases[x, 'pay.freq'] == "w") 7
else if (leases[x, 'pay.freq'] == "b") 14
else if (leases[x, 'pay.freq'] == "s") floor(365/24)
else if (leases[x, 'pay.freq'] == "m") floor(365/12)
# the number of payments if this was a normal lease
no.payments.norm <- if (leases[x, 'pay.freq'] == "w") c(1:floor(leases[x, 'lease.length'] * 365 / 84))
else if (leases[x, 'pay.freq'] == "b") c(1:floor(leases[x, 'lease.length'] * 365 / 168))
else if (leases[x, 'pay.freq'] == "s") c(1: (leases[x, 'lease.length'] * 2))
else if (leases[x, 'pay.freq'] == "m") c(1: leases[x, 'lease.length'])
# First values representing the initial payment,same for pay due, pay expected, and asset acquisition cost
initial.pay <- this.sales.price * leases[x, 'init.pay.pct']
toReturn$payment.due[1] = toReturn$payment.due[1] + initial.pay
toReturn$payment.expected[1] = toReturn$payment.expected[1] + initial.pay
toReturn$asset.acq.outflow[1] = toReturn$asset.acq.outflow[1] + initial.pay
# payment due is calculated as if lease was normal
payment.amt <- (this.sales.price - initial.pay) * leases[x, 'markup'] / length(no.payments.norm)
toReturn$payment.due[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] <-
toReturn$payment.due[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] + payment.amt
# Asset acquisition outflow is also always the same
toReturn$asset.acq.outflow[assumptions$delivery.time] <-
toReturn$asset.acq.outflow[assumptions$delivery.time] + assumptions$discount*(this.sales.price - initial.pay)
# payment expected (and processing cost) depends on type of lease
if (leases[x, 'pay.manner'] == "90D"){
no.payments.actual <-
if (leases[x, 'pay.freq'] == "w") c(1: floor((90 + assumptions$delivery.time - assumptions$first.pay.gap)/7))
else if (leases[x, 'pay.freq'] == "b") c(1:floor((90 + assumptions$delivery.time - assumptions$first.pay.gap)/14))
else if (leases[x, 'pay.freq'] == "s") c(1: floor((90 + assumptions$delivery.time - assumptions$first.pay.gap) / 365 * 24))
else if (leases[x, 'pay.freq'] == "m") c(1: floor((90 + assumptions$delivery.time - assumptions$first.pay.gap) / 365 * 12))
payment.amt.actual <- (this.sales.price - initial.pay) * assumptions$ninetyD.markup
toReturn$payment.expected[assumptions$delivery.time + assumptions$ninetyD.gap] <-
toReturn$payment.expected[assumptions$delivery.time + assumptions$ninetyD.gap] + payment.amt.actual
toReturn$payment.process.cost[assumptions$delivery.time + assumptions$ninetyD.gap] <-
toReturn$payment.process.cost[assumptions$delivery.time + assumptions$ninetyD.gap] + payment.amt.actual * assumptions$pay.process.pct
coeff <- ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) / (length(no.payments.norm) * (payment.gap - 1) + 1 - assumptions$first.pay.gap)
temp.depr <- rep(0,1000)
temp.depr[1:(assumptions$first.pay.gap - 1)] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay)
temp.depr[assumptions$first.pay.gap : 1000] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) - coeff*c(1:(1000 - assumptions$first.pay.gap + 1))
temp.depr[(assumptions$first.pay.gap + assumptions$ninetyD.gap) : 1000] <- 0
toReturn$total.assets.linear <- toReturn$total.assets.linear + temp.depr
toReturn$total.assets.loan <- toReturn$total.assets.loan + temp.depr
# toReturn$lease.depreciation[assumptions$delivery.time + assumptions$ninetyD.gap] =
# toReturn$lease.depreciation[assumptions$delivery.time + assumptions$ninetyD.gap] + temp.depr[1]
}
else if (leases[x, 'pay.manner'] == "early"){
# the amount they actually pay, should be more than the supposed amount
actual.pay <- payment.amt * (1 + assumptions$early.pay.amt)
# the amount their payment actually counts towards their balance
effective.pay <- payment.amt+ payment.amt*assumptions$early.pay.amt/(1 - assumptions$early.pay.discount)
# the last payment is different because it's whatever's left of their balance they owe
no.payments.actual <- c(1:(1+((length(no.payments.norm) * payment.amt) %/% effective.pay)))
last.payment <- ((this.sales.price - initial.pay) * leases[x, 'markup'] )%%effective.pay
# temporary vector to hold expected payments
temp <- rep(0,length(toReturn$payment.expected))
temp[((no.payments.actual-1) * payment.gap) + assumptions$first.pay.gap] <- actual.pay
temp[max(which(temp != 0))] <- last.payment
amt.financed <- (this.sales.price - initial.pay) * assumptions$discount + initial.pay
tempdue <- rep(0,1000)
tempdue[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] <- payment.amt
temp2 <- asset.val(init.val = amt.financed, pay.schedule = tempdue)
temp2[(assumptions$first.pay.gap + (length(no.payments.actual) * payment.gap)) : 1000] <- 0
temp2[assumptions$charge.off.time:1000] = temp2[assumptions$charge.off.time:1000] * early.default.rate[1:(1000 - assumptions$charge.off.time + 1)]
toReturn$total.assets.loan = toReturn$total.assets.loan + temp2
# account for default rate
temp[((no.payments.actual-1) * payment.gap) + assumptions$first.pay.gap] <-
temp[((no.payments.actual-1) * payment.gap) + assumptions$first.pay.gap] *
cumprod(early.default.rate[(no.payments.actual -1) * payment.gap + 1]^(payment.gap/(365/12)))
bad.debt <- rep(0, length(toReturn$payment.expected))
bad.debt[which(temp != 0)] <- actual.pay - temp[which(temp!= 0)]
bad.debt[max(which(temp != 0))] <- last.payment - temp[max(which(temp != 0))]
toReturn$bad.debt <- toReturn$bad.debt + bad.debt
toReturn$payment.expected <- toReturn$payment.expected + temp
toReturn$payment.process.cost <- toReturn$payment.process.cost + temp*assumptions$pay.process.pct
coeff <- ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) / ((length(no.payments.norm)-1) * (payment.gap))
temp.depr <- rep(0,1000)
temp.depr[1:(assumptions$first.pay.gap - 1)] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay)
temp.depr[assumptions$first.pay.gap : 1000] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) - coeff*c(1:(1000 - assumptions$first.pay.gap + 1))
temp.depr[(assumptions$first.pay.gap + (length(no.payments.actual) * payment.gap)) : 1000] <- 0
temp.depr[assumptions$charge.off.time:1000] = temp.depr[assumptions$charge.off.time:1000] * early.default.rate[1:(1000 - assumptions$charge.off.time + 1)]
toReturn$total.assets.linear <- toReturn$total.assets.linear + temp.depr
pay.indexes <- which(temp != 0)
deprec.values <- 1:length(pay.indexes)
deprec.values[1] = temp.depr[1] - temp.depr[pay.indexes[1]]
for (i in 2: length(pay.indexes)){
deprec.values[i] = temp.depr[pay.indexes[i - 1]] - temp.depr[pay.indexes[i]]
}
if ((sum(deprec.values)+ temp.depr[pay.indexes[length(pay.indexes)]]) != temp.depr[1]){
print("420 blaze it")
}
# toReturn$lease.depreciation[which(temp != 0)] = toReturn$lease.depreciation[which(temp != 0)] + deprec.values
#
# # Chargeoff any leftover residue
# toReturn$lease.depreciation[max(which(temp != 0)) + assumptions$charge.off.time] = toReturn$lease.depreciation[max(which(temp != 0)) + assumptions$charge.off.time]
# + temp.depr[pay.indexes[length(pay.indexes)]]
}
else {
# temporary vector to hold expected payments
temp <- rep(0,length(toReturn$payment.expected))
temp[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] <- payment.amt
amt.financed <- (this.sales.price - initial.pay) * assumptions$discount + initial.pay
tempdue <- rep(0,1000)
tempdue[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] <- payment.amt
temp2 <- asset.val(init.val = amt.financed, pay.schedule = tempdue)
temp2[assumptions$charge.off.time:1000] = temp2[assumptions$charge.off.time:1000] * early.default.rate[1:(1000 - assumptions$charge.off.time + 1)]
toReturn$total.assets.loan = toReturn$total.assets.loan + temp2
# account for default rate
temp[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] <-
temp[((no.payments.norm-1) * payment.gap) + assumptions$first.pay.gap] *
cumprod(default.rate[(no.payments.norm-1) * payment.gap + 1]^(payment.gap/(365/12)))
bad.debt <- rep(0, length(toReturn$payment.expected))
bad.debt[which(temp != 0)] <- payment.amt - temp[which(temp!= 0)]
toReturn$bad.debt <- toReturn$bad.debt + bad.debt
toReturn$payment.expected <- toReturn$payment.expected + temp
toReturn$payment.process.cost <- toReturn$payment.process.cost + temp*assumptions$pay.process.pct
coeff <- ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) / ((length(no.payments.norm)-1) * (payment.gap))
temp.depr <- rep(0,1000)
temp.depr[1:(assumptions$first.pay.gap - 1)] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay)
temp.depr[assumptions$first.pay.gap : 1000] = ((this.sales.price - initial.pay) * assumptions$discount + initial.pay) - coeff*c(1:(1000 - assumptions$first.pay.gap + 1))
temp.depr[which(temp.depr < 0)] <- 0
temp.depr[assumptions$charge.off.time:1000] = temp.depr[assumptions$charge.off.time:1000] * default.rate[1:(1000 - assumptions$charge.off.time + 1)]
toReturn$total.assets.linear <- toReturn$total.assets.linear + temp.depr
pay.indexes <- which(temp != 0)
deprec.values <- 1:length(pay.indexes)
deprec.values[1] = temp.depr[1] - temp.depr[pay.indexes[1]]
for (i in 2: length(pay.indexes)){
deprec.values[i] = temp.depr[pay.indexes[i - 1]] - temp.depr[pay.indexes[i]]
}
# toReturn$lease.depreciation[which(temp != 0)] = toReturn$lease.depreciation[which(temp != 0)] + deprec.values
# if (sum(deprec.values) != temp.depr[1]){
# print("420 blaze it")
# }
# toReturn$lease.depreciation[max(which(temp != 0)) + assumptions$charge.off.time] = toReturn$lease.depreciation[max(which(temp != 0)) + assumptions$charge.off.time] +
# temp.depr[pay.indexes[length(pay.indexes)-1]] - temp.depr[pay.indexes[length(pay.indexes)]]
}
}
all.payment.indexes <- which(toReturn$payment.expected != 0)
total.deprec <- 1:length(all.payment.indexes)
total.deprec[1:length(all.payment.indexes)] = 0
total.deprec[1] <- toReturn$total.assets.linear[1] - toReturn$total.assets.linear[all.payment.indexes[1]]
for (i in 2: length(total.deprec)){
total.deprec[i] <- toReturn$total.assets.linear[all.payment.indexes[i-1]] - toReturn$total.assets.linear[all.payment.indexes[i]]
}
toReturn$lease.depreciation[which(toReturn$payment.expected != 0)] = toReturn$lease.depreciation[which(toReturn$payment.expected != 0)] + total.deprec
toReturn$payments.sum <- (sum(toReturn$payment.expected) - cumsum(toReturn$payment.expected)) *
sum(toReturn$payment.due) / sum(toReturn$payment.expected)
toReturn
}
test.average.lease <- calc.average()
#' The projections.by.day function
#'
#' This function projects future lease volume given a start date, end date, and projections
#'
#' @param start.date, the first date for projections to be shown
#' @param end date, the last date for projections to be shown
#' @param growth.projections, a dataframe with dates, rates, and a "per what"
#' @return a projections for each day
#' @export
projections.by.day <- function(start.date = head(as.Date(default.growth.rates$Dates, "%m/%d/%Y"), 1),
end.date= tail(as.Date(default.growth.rates$Dates, "%m/%d/%Y"), 1),
growth.projections = data.frame(date = as.Date(as.vector(default.growth.rates$Dates), "%m/%d/%Y"),
rate = as.vector(default.growth.rates$Leases),
per.what = 28)) {
# check start.date and end.date attributes
if((class(start.date) %in% "Date") == FALSE) stop ("start.date must be an object of class Date")
if((class(end.date) %in% "Date") == FALSE) stop ("end.date must be an object of class Date")
if((length(start.date) == 1) == FALSE) stop ("start.date must contain 1 date")
if((length(end.date) == 1) == FALSE) stop ("end.date must contain 1 date")
start.date.out <- min(c(start.date,growth.projections$date))
end.date.out <- max(c(end.date,growth.projections$date))
# create a data frame to hold the daily volume projections
len <- as.numeric(end.date.out - start.date.out + 1)
out <- data.frame(date=seq(start.date.out, by=1, len=len),
booked.unrounded=0,
booked=0)
# order the growth projections in case not ordered
growth.projections <- growth.projections[order(growth.projections$date),]
# check there are enough growth projections for algorithm to run
ngp <- nrow(growth.projections)
if(ngp < 1) stop("At least 1 date needs to be provided in growth.projections")
# before the earliest and after the last growth projections, the rate of growth is constant
out$booked.unrounded[which(out$date <= growth.projections$date[1])] <- growth.projections$rate[1]/growth.projections$per.what[1]
out$booked.unrounded[which(out$date >= growth.projections$date[ngp])] <- growth.projections$rate[ngp]/growth.projections$per.what[1]
if(ngp > 1) {
for(j in 2:ngp) {
len <- as.numeric(growth.projections$date[j] - growth.projections$date[(j-1)])
weights <- c(0:len) / len
out$booked.unrounded[which(out$date >= growth.projections$date[(j-1)] &
out$date <= growth.projections$date[j])] <- 1/growth.projections$per.what[1] *
((1-weights)*growth.projections$rate[(j-1)] + (weights)*growth.projections$rate[j])
}
}
# calculate the estimated booked deals on each day
rcm <- round(cumsum(out$booked.unrounded))
out$booked <- rcm - c(0,rcm[1:(length(rcm)-1)])
# only allow outputted dates within the start and end dates
out <- out[which(out$date >= start.date & out$date <= end.date),c("date","booked")]
return(out)
}
test.projections.by.day = projections.by.day()
#' The cash.flow function
#'
#' This function calculates cash flow metrics over a period of time given growth projections,
#' average lease data, and historical lease data.
#'
#' @param hist.leases, data frame with information of historical leases
#' @param average.lease, data on cash metrics of the average lease
#' @param lease.growth, growth projections for future leases
#' @param assumptions, a list of constant values
#' @param emp.sheet, information about employees
#' @return a data frame with aggregate cash flow metrics over a period of time
#' @export
cash.flow <- function(hist.leases = test.collect.past,
average.lease = test.average.lease,
lease.growth = test.projections.by.day,
assumptions = default.constants.list,
emp.sheet = default.employees){
library(dplyr)
# Initialize the data.frame, set f
toReturn <- data.frame()
# Find the first day of the month of the earliest lease, this is the date where data.frame will start
first.of.month <- as.Date(paste(substr(hist.leases$dates[1],1,8),"01",sep=""))
toReturn <- data.frame(dates = seq(first.of.month, by="day",length.out = (max(lease.growth$date) -
hist.leases$dates[1] + 1000)))
# Initialize all the parameters of the data frame, most are 0 except costs that are constant across days
toReturn$apps.per.month <- 0
toReturn$average.app.per.day <- 0
toReturn$average.app.per.day.diff <- 0
toReturn$leases.booked <- 0
toReturn$no.stores <- 0
toReturn$new.stores <- 0
toReturn$ongoing.leases <- 0
toReturn$payment.due <- 0
toReturn$payment.expected <- 0
toReturn$asset.acq.outflow <- 0
toReturn$total.assets.linear <- 0
toReturn$total.assets.loan <- 0
toReturn$lease.depreciation <- 0
toReturn$payment.process.cost <- 0
toReturn$no.employees <- 0
toReturn$no.csm <- 0
toReturn$no.salesperson <- 0
toReturn$total.salaries <- 0
toReturn$other.salaries <- 0
toReturn$sales.salaries <- 0
toReturn$csm.salaries <- 0
toReturn$employee.tax <- 0
toReturn$employee.benefit <- 0
toReturn$rent.cost <- 0
toReturn$utilities.cost <- 0
toReturn$travel.cost <- 0
toReturn$marketing.cost <- 0
toReturn$misc.cost <- 0
toReturn$third.pt.data.cost <- 0
toReturn$it.cost <- floor(assumptions$it.base * 12 / 365 * 100)/100
toReturn$legal.cost <- floor(assumptions$legal.base.month * 12 / 365 * 100) / 100
toReturn$ops.cost <- 0
toReturn$payments.sum <- 0
past.indexes <- (1 + hist.leases$dates[1] - toReturn$dates[1]) : (nrow(hist.leases) + hist.leases$dates[1] - toReturn$dates[1])
toReturn$payment.due[past.indexes] = toReturn$payment.due[past.indexes] + hist.leases$payment.due
toReturn$payment.expected[past.indexes] = toReturn$payment.expected[past.indexes] + hist.leases$payment.expected
toReturn$payment.process.cost[past.indexes] = toReturn$payment.process.cost[past.indexes] + hist.leases$payment.process.cost
toReturn$asset.acq.outflow[past.indexes] = toReturn$asset.acq.outflow[past.indexes] + hist.leases$asset.acq.outflow
toReturn$total.assets.linear[past.indexes] = toReturn$total.assets.linear[past.indexes] + hist.leases$total.assets.linear
toReturn$total.assets.loan[past.indexes] = toReturn$total.assets.loan[past.indexes] + hist.leases$total.assets.loan
toReturn$lease.depreciation[past.indexes] = toReturn$lease.depreciation[past.indexes] + hist.leases$lease.depreciation
toReturn$bad.debt[past.indexes] = toReturn$bad.debt[past.indexes] + hist.leases$bad.debt
toReturn$leases.booked[past.indexes] = toReturn$leases.booked[past.indexes] + hist.leases$leases.booked
toReturn$no.stores[past.indexes] = toReturn$leases.booked[past.indexes] + hist.leases$no.stores
toReturn$ongoing.leases[past.indexes] = toReturn$ongoing.leases[past.indexes] + hist.leases$ongoing.leases
toReturn$payments.sum[past.indexes] = toReturn$payments.sum[past.indexes] + hist.leases$payments.sum
# Third party data costs increase with number of apps, so they increase whenever a new lease happens
toReturn$third.pt.data.cost[past.indexes] <- toReturn$third.pt.data.cost[past.indexes] +
toReturn$leases.booked[past.indexes]*assumptions$third.pt.data/assumptions$app.conversion.rt
# Legal costs generally increases with growth of business, small constant ties it to each lease
toReturn$legal.cost[past.indexes] <- toReturn$legal.cost[past.indexes] + toReturn$leases.booked[past.indexes]*assumptions$add.legal.cost
# Marketing and misc costs tied to leases
toReturn$marketing.cost[past.indexes] <- toReturn$marketing.cost[past.indexes] + toReturn$leases.booked[past.indexes]*3
toReturn$misc.cost[past.indexes] <- toReturn$misc.cost[past.indexes] + toReturn$leases.booked[past.indexes]*3
past.months <- unique(format.Date(toReturn$dates[past.indexes], format = "%m %y"))
for (b in 1 : length(past.months)){
this.month <- which(format.Date(toReturn$dates, format = "%m %y") == past.months[b])
toReturn$apps.per.month[this.month] <- toReturn$apps.per.month[this.month] + sum(toReturn$leases.booked[this.month]) / assumptions$app.conversion.rt
toReturn$it.cost[this.month] <- toReturn$it.cost[this.month] + (sum(toReturn$leases.booked[this.month]) / assumptions$app.conversion.rt)^.7 * assumptions$it.rate / 365 * 12
}
for (x in 1: length(lease.growth$date)) {
start.index <- which(toReturn$dates == lease.growth$date[x])
rel.indexes1 <- which(average.lease$payment.due != 0)
toReturn$payment.due[start.index + rel.indexes1 - 1] <-
toReturn$payment.due[start.index + rel.indexes1 - 1] +
lease.growth$booked[x]*average.lease$payment.due[rel.indexes1]
rel.indexes2 <- which(average.lease$payment.expected != 0)
toReturn$payment.expected[start.index + rel.indexes2 - 1] <-
toReturn$payment.expected[start.index + rel.indexes2 - 1] +
lease.growth$booked[x]*average.lease$payment.expected[rel.indexes2]
rel.indexes3 <- which(average.lease$asset.acq.outflow != 0)
toReturn$asset.acq.outflow[start.index + rel.indexes3 - 1] <-
toReturn$asset.acq.outflow[start.index + rel.indexes3 - 1] +
lease.growth$booked[x]*average.lease$asset.acq.outflow[rel.indexes3]
rel.indexes4 <- which(average.lease$payment.process.cost != 0)
toReturn$payment.process.cost[start.index + rel.indexes4 - 1] <-
toReturn$payment.process.cost[start.index + rel.indexes4 - 1] +
lease.growth$booked[x]*average.lease$payment.process.cost[rel.indexes4]
rel.indexes5 <- which(average.lease$total.assets.linear != 0)
toReturn$total.assets.linear[start.index + rel.indexes5 - 1] <-
toReturn$total.assets.linear[start.index + rel.indexes5 - 1] +
lease.growth$booked[x]*average.lease$total.assets.linear[rel.indexes5]
rel.indexes6 <- which(average.lease$total.assets.loan != 0)
toReturn$total.assets.loan[start.index + rel.indexes6 - 1] <-
toReturn$total.assets.loan[start.index + rel.indexes6 - 1] +
lease.growth$booked[x]*average.lease$total.assets.loan[rel.indexes6]
rel.indexes7 <- which(average.lease$lease.depreciation != 0)
toReturn$lease.depreciation[start.index + rel.indexes7 - 1] <-
toReturn$lease.depreciation[start.index + rel.indexes7 - 1] +
lease.growth$booked[x]*average.lease$lease.depreciation[rel.indexes7]
rel.indexes8 <- which(average.lease$payments.sum != 0)
toReturn$payments.sum[start.index + rel.indexes8 - 1] <-
toReturn$payments.sum[start.index + rel.indexes8 - 1] +
lease.growth$booked[x]*average.lease$payments.sum[rel.indexes8]
# Third party data costs increase with number of apps, so they increase whenever a new lease happens
toReturn$third.pt.data.cost[start.index] <- toReturn$third.pt.data.cost[start.index] +
lease.growth$booked[x]*assumptions$third.pt.data/assumptions$app.conversion.rt
# Legal costs generally increases with growth of business, small constant ties it to each lease
toReturn$legal.cost[start.index] <- toReturn$legal.cost[start.index] + lease.growth$booked[x]*assumptions$add.legal.cost
# Marketing
toReturn$marketing.cost[start.index] <- toReturn$marketing.cost[start.index] + lease.growth$booked[x] * 3
# Misc
toReturn$misc.cost[start.index] <- toReturn$misc.cost[start.index] + lease.growth$booked[x]*2
# Leases booked
toReturn$leases.booked[which(toReturn$dates == lease.growth$date[x])] <- toReturn$leases.booked[which(toReturn$dates == lease.growth$date[x])] +
lease.growth$booked[x]
# Number of stores
if (x == 1){
toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] <- toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] +
lease.growth$booked[x]/assumptions$leases.per.store
} else if (x == 2) {
toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] <- toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] +
max(lease.growth$booked[x]/assumptions$leases.per.store,lease.growth$booked[x-1]/assumptions$leases.per.store)
} else if (x > 2){
toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] <- toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] +
max(lease.growth$booked[x]/assumptions$leases.per.store,lease.growth$booked[x-1]/assumptions$leases.per.store,lease.growth$booked[x-2]/assumptions$leases.per.store)
}
# # New stores
# if (x = 1){
# toReturn$new.stores[which(toReturn$dates == lease.growth$date[x])] <- toReturn$new.stores[which(toReturn$dates == lease.growth$date[x])] +
# ceiling(lease.growth$booked[x]/5)
# } else {
# toReturn$new.Stores[which(toReturn$dates == lease.growth$date[x])] <- toReturn$new.stores[which(toReturn$dates == lease.growth$date[x])] +
# toReturn$no.stores[which(toReturn$dates == lease.growth$date[x])] - toReturn$no.stores[which(toReturn$dates == lease.growth$date[x-1])]
# }
# Applications for month, for each lease started in that month increment apps per month by 1 divided by app-to-lease conversion rate
relevant.dates <- which(format.Date(toReturn$dates, format = "%m %y") == format.Date(lease.growth$date[x], format = "%m %y"))
toReturn$apps.per.month[relevant.dates] <- toReturn$apps.per.month[relevant.dates] + lease.growth$booked[x]/ assumptions$app.conversion.rt
# Number of ongoing leases on any day
toReturn$ongoing.leases[which(toReturn$dates >= lease.growth$date[x] &
toReturn$dates < (lease.growth$date[x] + assumptions$avg.lease.length * 365 / 12))] <-
toReturn$ongoing.leases[which(toReturn$dates >= lease.growth$date[x] &
toReturn$dates < (lease.growth$date[x] + assumptions$avg.lease.length * 365 / 12))] + lease.growth$booked[x]
# additional monthly IT cost depending on number of new applications in that month
relevant.dates2 <- which(format.Date(toReturn$dates, format = "%m %y") == format.Date(lease.growth$date[x], format = "%m %y"))
toReturn$it.cost[relevant.dates2] <- toReturn$it.cost[relevant.dates2] + toReturn$apps.per.month[relevant.dates2]^.7 * assumptions$it.rate / 365 * 12
}
# First of month costs
toReturn$payment.process.cost[which(format.Date(toReturn$dates, format = "%d") == "01")] <- assumptions$pay.process.month
# Accounting for employees
# Hired Employees, not csm or salespeople
emp.sheet$start.date <- as.Date(emp.sheet$start.date, "%m/%d/%y")
emp.sheet$end.date <- as.Date(emp.sheet$end.date, "%m/%d/%y")
for (i in 1:nrow(emp.sheet)) {
toReturn$no.employees[which(toReturn$dates >= as.vector(emp.sheet[i,]$start.date) &
toReturn$dates < as.vector(emp.sheet[i,]$end.date))] <-
toReturn$no.employees[which(toReturn$dates >= as.vector(emp.sheet[i,]$start.date) &
toReturn$dates < as.vector(emp.sheet[i,]$end.date))] + 1
toReturn$other.salaries[which(toReturn$dates >= as.vector(emp.sheet[i,]$start.date) &
toReturn$dates < as.vector(emp.sheet[i,]$end.date))] <-
toReturn$other.salaries[which(toReturn$dates >= as.vector(emp.sheet[i,]$start.date) &
toReturn$dates < as.vector(emp.sheet[i,]$end.date))] +
emp.sheet[i,]$salary / 365
}
firsts.of.month <- toReturn$dates[which(format.Date(toReturn$dates, format = "%d") == "01" &
format.Date(toReturn$dates, format = "%m %y") != format.Date(first.of.month, format = "%m %y"))]
#Average.apps.per.day
for (i in seq_along(c(first.of.month,firsts.of.month))) {
toReturn$average.app.per.day[which(format.Date(toReturn$dates, format = "%m %y") == format.Date(c(first.of.month,firsts.of.month)[i], format = "%m %y"))] =
sum(toReturn$leases.booked[which(format.Date(toReturn$dates, format = "%m %y") == format.Date(c(first.of.month,firsts.of.month)[i], format = "%m %y"))] / assumptions$app.conversion.rt)/
length(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(c(first.of.month,firsts.of.month)[i], format = "%m %y")))
}
#Change in average apps per day
toReturn$average.app.per.day.diff[which(format.Date(toReturn$dates, format= "%m %y") == format.Date(first.of.month, format = "%m %y"))] <- toReturn$average.app.per.day[1]
for (i in seq_along(firsts.of.month)){
toReturn$average.app.per.day.diff[which(format.Date(toReturn$dates, format = "%m %y") == format.Date(firsts.of.month[i], format = "%m %y"))] <-
toReturn$average.app.per.day[which(toReturn$dates == firsts.of.month[i])] - toReturn$average.app.per.day[which(toReturn$dates == firsts.of.month[i]) - 1]
}
# Number of customer service managers, tied to the number of ongoing leases
toReturn$no.csm[which(toReturn$ongoing.leases != 0)] <- ceiling(toReturn$ongoing.leases[which(toReturn$ongoing.leases != 0)] / assumptions$leases.per.csm)
# Number of salespeople, tied to apps per month and app difference per month
toReturn$no.salesperson[which(toReturn$average.app.per.day.diff > 0)] <- ceiling(toReturn$average.app.per.day[which(toReturn$average.app.per.day.diff > 0)] / assumptions$apps.per.salesp +
toReturn$average.app.per.day.diff[which(toReturn$average.app.per.day.diff > 0)] / assumptions$n.apps.per.salesp)
toReturn$no.salesperson[which(toReturn$average.app.per.day.diff<= 0)] <- ceiling(toReturn$average.app.per.day[which(toReturn$average.app.per.day.diff<= 0)] / assumptions$apps.per.salesp)
# increment number of employees and total salaries based on number of csm and salespeople
toReturn$no.employees <- toReturn$no.employees + toReturn$no.csm + toReturn$no.salesperson
toReturn$csm.salaries <- floor(toReturn$total.salaries + toReturn$no.csm * assumptions$csm.salary / 365 * 100) / 100
toReturn$sales.salaries <- floor(toReturn$no.salesperson * assumptions$sales.salary / 365 * 100) / 100
toReturn$total.salaries <- toReturn$csm.salaries + toReturn$sales.salaries + toReturn$other.salaries
# Employee benefits
toReturn$employee.tax <- toReturn$total.salaries * assumptions$employee.tax
toReturn$employee.benefit <- toReturn$total.salaries * assumptions$employee.benefits
# #Travel costs
# toReturn$travel.cost <- toReturn$travel.cost + toReturn$no.employees * 5
#
# #Misc
# toReturn$misc.cost <- toReturn$misc.cost + toReturn$no.employees * 4
# Round everything
toReturn$apps.per.month <- round(toReturn$apps.per.month)
toReturn$average.app.per.day <- floor(toReturn$average.app.per.day * 100) / 100
toReturn$average.app.per.day.diff <- floor(toReturn$average.app.per.day.diff * 1000) / 1000
toReturn$payment.due <- floor(toReturn$payment.due * 1000)/1000
toReturn$payment.expected <- floor(toReturn$payment.expected * 100) / 100
toReturn$payment.process.cost <- floor(toReturn$payment.process.cost * 100) / 100
toReturn$asset.acq.outflow <- floor(toReturn$asset.acq.outflow * 100) / 100
toReturn$total.assets.linear <- floor(toReturn$total.assets.linear * 100) / 100
toReturn$total.assets.loan <- floor(toReturn$total.assets.loan * 100) / 100
toReturn$lease.depreciation <- floor(toReturn$lease.depreciation * 100) / 100
toReturn$third.pt.data.cost <- floor(toReturn$third.pt.data.cost * 100) / 100
toReturn$it.cost <- floor(toReturn$it.cost * 100)/100
toReturn$legal.cost <- floor(toReturn$legal.cost * 100) / 100
toReturn$ops.cost <- floor(toReturn$ops.cost * 100) / 100
toReturn$cash.flow <- toReturn$payment.expected - toReturn$ops.cost - toReturn$asset.acq.outflow
toReturn <- filter(toReturn, dates < last(lease.growth$date))
temp = data.frame(dates = c(first.of.month, firsts.of.month[which(firsts.of.month < last(lease.growth$date))]),
# month = 1:length(c(first.of.month, firsts.of.month[which(firsts.of.month < last(lease.growth$date))])),
apps.per.month = 0,
leases.booked = 0,
no.stores = 0,
new.stores = 0,
average.app.per.day = 0,
average.app.per.day.diff = 0,
ongoing.leases = 0,
payment.due = 0,
payment.expected = 0,
asset.acq.outflow = 0,
total.assets.linear = 0,
total.assets.loan = 0,
lease.depreciation = 0,
payment.process.cost = 0,
no.employees = 0,
no.csm = 0,
no.salesperson = 0,
total.salaries = 0,
other.salaries = 0,
sales.salaries = 0,
csm.salaries = 0,
employee.tax = 0,
employee.benefit = 0,
rent.cost = 0,
travel.cost = 0,
utilities.cost = 0,
marketing.cost = 0,
third.pt.data.cost = 0,
it.cost = 0,
legal.cost = 0,
ops.cost = 0,
cash.flow = 0,
payments.sum = 0,
legal.base = assumptions$legal.base.month,
it.base = assumptions$it.base
)
for (i in 1:nrow(temp)){
temp$apps.per.month[i] <- toReturn$apps.per.month[(which(toReturn$dates == temp$dates[i]))]
temp$leases.booked[i] <- sum(toReturn$leases.booked[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
if (i == 1) {
temp$no.stores[i] <- ceiling(sum(toReturn$leases.booked[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])/assumptions$leases.per.store)
} else {
temp$no.stores[i] <- max(temp$no.stores[i-1],ceiling(sum(toReturn$leases.booked[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])/assumptions$leases.per.store))
}
#ceiling(sum(toReturn$no.stores[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))]))
temp$average.app.per.day[i] <-toReturn$average.app.per.day[(which(toReturn$dates == temp$dates[i]))]
temp$average.app.per.day.diff[i] <-toReturn$average.app.per.day.diff[(which(toReturn$dates == temp$dates[i]))]
temp$ongoing.leases[i] <- round(sum(toReturn$ongoing.leases[which(toReturn$dates == temp$dates[i])]) / length(which(toReturn$dates == temp$dates[i])))
temp$payment.due[i] <- sum(toReturn$payment.due[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$payment.expected[i] <- sum(toReturn$payment.expected[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$asset.acq.outflow[i] <- sum(toReturn$asset.acq.outflow[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$total.assets.linear[i] <- toReturn$total.assets.linear[(max(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y"))))]
temp$total.assets.loan[i] <- toReturn$total.assets.loan[(max(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y"))))]
temp$lease.depreciation[i] <- sum(toReturn$lease.depreciation[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$payment.process.cost[i] <- sum(toReturn$payment.process.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$no.employees[i] <- round(sum(toReturn$no.employees[which(toReturn$dates == temp$dates[i])]) / length(which(toReturn$dates == temp$dates[i])))
temp$no.csm[i] <- round(sum(toReturn$no.csm[which(toReturn$dates == temp$dates[i])]) / length(which(toReturn$dates == temp$dates[i])))
temp$no.salesperson[i] <- round(sum(toReturn$no.salesperson[which(toReturn$dates == temp$dates[i])]) / length(which(toReturn$dates == temp$dates[i])))
temp$total.salaries[i] <- sum(toReturn$total.salaries[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$other.salaries[i] <- sum(toReturn$other.salaries[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$csm.salaries[i] <- sum(toReturn$csm.salaries[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$sales.salaries[i] <- sum(toReturn$sales.salaries[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$employee.tax[i] <- sum(toReturn$employee.tax[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$employee.benefit[i] <- sum(toReturn$employee.benefit[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
# temp$rent.cost[i] <- sum(toReturn$rent.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
# temp$travel.cost[i] <- sum(toReturn$travel.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$marketing.cost[i] <- sum(toReturn$marketing.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$misc.cost[i] <- sum(toReturn$misc.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$third.pt.data.cost[i] <- sum(toReturn$third.pt.data.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$it.cost[i] <- sum(toReturn$it.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$legal.cost[i] <- sum(toReturn$legal.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$ops.cost[i] <- sum(toReturn$ops.cost[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$cash.flow[i] <- sum(toReturn$cash.flow[(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y")))])
temp$payments.sum[i] <- toReturn$payments.sum[(max(which(format.Date(toReturn$dates, format = "%m %y") == format.Date(temp$dates[i], format = "%m %y"))))]
# temp$year = ceiling((temp$month-6)/12) - 1
}
temp$new.stores[1] <- temp$no.stores[1]
temp$new.stores[2:nrow(temp)] <- temp$no.stores[2:nrow(temp)] - temp$no.stores[1:nrow(temp)-1]
#Calculate costs
temp$rent.cost = temp$no.employees * 150
temp$travel.cost = temp$no.employees * 150
temp$utilities.cost = temp$rent.cost * 0.08
temp$misc.cost = temp$misc.cost + temp$no.employees * 120
#adjust marketing cost by new stores
temp$marketing.cost = temp$marketing.cost + temp$new.stores*40
# Add up all the costs
temp$ops.cost = temp$payment.process.cost + temp$total.salaries + temp$employee.tax +
temp$employee.benefit + temp$rent.cost + temp$third.pt.data.cost + temp$it.cost + temp$legal.cost +
temp$travel.cost + temp$marketing.cost + temp$utilities.cost + temp$misc.cost
toReturn <- temp
toReturn
}
test.cash.flow = cash.flow()
#' The debt.calc function
#'
#' This function calculates debt metrics given cash flow data
#'
#' @param df, the data frame output from the cash.flow function
#' @param assumptions, a list of constant values
#' @param il.sheet, information about interest and leverage
#' @return a data frame with debt metrics added on to cash flow metrics
#' @export
debt.calc <- function (df = test.cash.flow,
assumptions = default.constants.list,
il.sheet = default.int.lev) {
total.assets = df$total.assets.linear
find.index <- function(a.date){
toReturn = 1
for (i in 2: length(il.sheet$Date)) {
if (a.date >= as.Date(il.sheet$Date[i], "%m/%d/%Y")){
toReturn = i
}
}
toReturn
}
il.sheet.indexes <- sapply(df$dates, find.index)
debt.borrowed <- if (assumptions$depr.method == 2) df$total.assets.loan * il.sheet$Leverage[il.sheet.indexes]
else if (assumptions$depr.method == 1) df$total.assets.linear * il.sheet$Leverage[il.sheet.indexes]
debt.difference <- c(debt.borrowed[1],
diff(debt.borrowed))
debt.cost <- debt.borrowed * (il.sheet$Interest[il.sheet.indexes] / 12)
asset.change <- rep(0, length(debt.borrowed))
asset.change[1] = total.assets[1]
for (i in 2:length(asset.change)){
asset.change[i] = total.assets[i] - total.assets[i-1]
}
df$ebitda = df$payment.expected - df$ops.cost - df$asset.acq.outflow + asset.change
df$gross.profit = df$ebitda + df$ops.cost
df$pre.tax.profit = floor((df$ebitda - debt.cost) * 100) / 100
calendar.years = unique(format.Date(df$dates, format = "%y"))
profit.by.year = rep(0,length(calendar.years))
for (i in 1: length(calendar.years)){
profit.by.year[i] = sum(df$pre.tax.profit[which(format.Date(df$dates, format = "%y") == calendar.years[i])])
}
income.tax = rep(0, length(profit.by.year))
income.tax[1] = if (profit.by.year[1] > 0) profit.by.year[1] * fed.tax.rate else 0
for (i in 2: length(income.tax)){
if (sum(profit.by.year[1:i]) < 0) income.tax[i] = 0
else if (sum(profit.by.year[1:i]) > 0 && income.tax[i-1] == 0) income.tax[i] = sum(profit.by.year[1:i]) * assumptions$fed.tax.rate
else if (sum(profit.by.year[1:i]) > 0 && income.tax[i-1] > 0) income.tax[i] = profit.by.year[i] * assumptions$fed.tax.rate
}
df$taxed.income = rep(0, length(df$dates))
for (i in 1: length(profit.by.year)) {
rel.months <- which((format.Date(df$dates, format = "%m-%y") == paste("03-",calendar.years[i], sep = "") |
format.Date(df$dates, format = "%m-%y") == paste("06-",calendar.years[i], sep = "") |
format.Date(df$dates, format = "%m-%y") == paste("09-",calendar.years[i], sep = "") |
format.Date(df$dates, format = "%m-%y") == paste("12-",calendar.years[i], sep = "")))
df$taxed.income[rel.months] = floor(income.tax[i] / 4 * 100) / 100
}
df$net.income = df$pre.tax.profit - df$taxed.income
df$cash.flow = df$ cash.flow - df$taxed.income
df$total.assets = floor(total.assets)
df$cash.flow.debt = floor((df$cash.flow + debt.difference - debt.cost) * 100)/100
df$debt.interest = floor(debt.cost * 100) / 100
df$debt.borrowed = floor(debt.borrowed * 100) / 100
df$cum.cash.with.debt <- cumsum(df$cash.flow.debt)
df$cum.cash.without.debt <- cumsum(df$cash.flow)
df$MoneyForEmp <- df$payment.expected - df$asset.acq.outflow +
debt.difference -
df$payment.process.cost - df$rent.cost - df$third.pt.data.cost -
df$it.cost - df$legal.cost
df
}
test.debt.calc = debt.calc()
#' The output.subset function
#'
#' This function subsets a data frame to a desired time frame
#'
#' @param df, the data frame to subset
#' @param first.month, the first month to be shown
#' @param last.month, the last month to be shown
#' @return the subset of df within first.month and last.month
#' @export
output.subset <- function(df= test.debt.calc, first.month=default.output.start.month, last.month=default.output.end.month) {
out.df <- df[which(df$dates >= first.month & df$dates <= last.month),]
out.df$month <- c(1:nrow(out.df))
out.df$year <- ceiling((out.df$month)/12)
return(out.df)
}
test.output.subset <- output.subset()
#' The mthSummary function
#'
#' Summarizes cash flow data by month
#'
#' @param df, cash flow data
#' @return a data.frame with data organized by month
#' @export
mthSummary <- function(df = test.output.subset){
toReturn <- df %>%
group_by(month) %>%
summarise(Date = dates,
EmployeesMonthEnd = no.employees,
AdministrativeEmployees = no.employees - no.csm - no.salesperson,
ServicingEmplomployees = no.csm,
SalesEmployees = no.salesperson,
AppsPerMonth = apps.per.month,
TotalLeasesBooked = leases.booked,
OngoingLeases = ongoing.leases,
TotalLeaseAssetsMonthEnd = total.assets,
SumOfPaymentsDue = payments.sum,
PaymentDue = payment.due,
Revenue = payment.expected,
LeaseDepreciation = lease.depreciation,
GrossProfit = gross.profit,
TotalExpenses = ops.cost,
MoneyForEmployee = MoneyForEmp,
._TotalLabor = total.salaries + employee.tax + employee.benefit,
.___LaborSales = sales.salaries,
.___LaborServicing = csm.salaries,
.___LaborNonOps = other.salaries,
.___LaborBenefitsTaxes = employee.tax + employee.benefit,
._StoreMarketing = marketing.cost,
._Rent = rent.cost,
._Legal = legal.cost,
._Travel = travel.cost,
._Utilities = utilities.cost,
._Misc = misc.cost,
._ITinfrastructure = it.cost,
._ThirdPartyData = third.pt.data.cost,
._PaymentProcessing = payment.process.cost,
EBITDA = ebitda,
._Interest = debt.interest,
Profit = pre.tax.profit,
LeaseAcquisition = asset.acq.outflow,
CashFlowWithoutDebt = cash.flow + taxed.income,
DebtBorrowed = debt.borrowed,
CashFlowWithDebt = cash.flow.debt + taxed.income)
toReturn
}
test.mthSummary <- mthSummary()
#' The mthIncomeSummary function
#'
#' Summarizes cash flow data by month
#'
#' @param df, cash flow data
#' @return a data.frame with data organized by month
#' @export
mthIncomeSummary <- function(df = test.output.subset){
df$quarters = as.numeric(format.Date(df$dates, format = "%m"))
df$quarters <- floor((df$quarters-1)/3)+1
# df$quarters[which(df$quarters %% 12 != 0)] = ceiling(df$quarters[which(df$quarters %% 12 != 0)]/3) %% 4
# df$quarters[which(df$quarters %% 12 == 0)] = 4
df$quarters = paste(format.Date(df$dates, format = "%Y"), "Q", df$quarters)
toReturn <- df %>%
group_by(quarters) %>%
summarise(Date = dates[which.min(dates)],
#Revenues
TotalLeasesBooked = sum(leases.booked),
Revenue = sum(payment.expected),
# Cost of Sales
LeaseDepreciation = sum(lease.depreciation),
# Profit = revenues - cost of sales
GrossProfit = Revenue - LeaseDepreciation,
# Operating Expenses
# Non Labor Expenses
ThirdPartyData = sum(third.pt.data.cost),
PaymentProcessing = sum(payment.process.cost),
Legal = sum(legal.cost),
IT = sum(it.cost),
StoreMarketing = 3 * TotalLeasesBooked + 40 * sum(new.stores),
TravelExpense = 150 * 3 * round(mean(no.employees)),
Rent = 150 * 3 *round(mean(no.employees)),
Utilities = .08 * Rent,
Misc = 3 * (120 * round(mean(no.employees))) + 2 * TotalLeasesBooked,
TotalNonLaborExpenses = ThirdPartyData + PaymentProcessing + Legal + IT +
StoreMarketing + TravelExpense + Rent + Utilities + Misc,
# Labor Expenses
SalesLabor = sum(sales.salaries),
ServicingLabor = sum(csm.salaries),
AdministrativeLabor = sum(other.salaries),
BenefitsTaxes = sum(employee.tax + employee.benefit),
TotalLaborExpenses = SalesLabor + ServicingLabor + AdministrativeLabor + BenefitsTaxes,
# Total Expenses
TotalExpenses = TotalNonLaborExpenses + TotalLaborExpenses,
# Earnings
EBIT = GrossProfit - TotalExpenses,
Interest = sum(debt.interest),
EBT = EBIT - Interest,
IncomeTaxes = sum(taxed.income),
NetEarnings = EBT - IncomeTaxes)
toReturn
}
test.incomeSummary = mthIncomeSummary()
#' The yrSummary function
#'
#' Summarizes cash flow data by year
#'
#' @param df, cash flow data
#' @return a data.frame with data organized by year
#' @export
yrSummary <- function(df = test.output.subset){
toReturn <- df %>%
group_by(year) %>%
summarise(EmployeesYearEnd = no.employees[which.max(dates)],
AdministrativeEmployees = no.employees[which.max(dates)] - no.csm[which.max(dates)] - no.salesperson[which.max(dates)],
ServicingEmplomployees = no.csm[which.max(dates)],
SalesEmployees = no.salesperson[which.max(dates)],
TotalLeasesBooked = sum(leases.booked),
TotalLeaseAssetsYearEnd = total.assets[which.max(dates)],
SumOfPaymentsDue = payments.sum[which.max(dates)],
Revenue = sum(payment.expected),
LeaseDepreciation = sum(lease.depreciation), #"not sure"
GrossProfit = sum(gross.profit),
TotalExpenses = sum(ops.cost),
._TotalLabor = sum(total.salaries) + sum(employee.tax) + sum(employee.benefit),
.___LaborSales = sum(sales.salaries),
.___LaborServicing = sum(csm.salaries),
.___LaborNonOps = sum(other.salaries),
.___LaborBenefitsTaxes = sum(employee.tax) + sum(employee.benefit),
._StoreMarketing = sum(marketing.cost),
._Rent = sum(rent.cost),
._Legal = sum(legal.cost),
._Travel = sum(travel.cost),
._Utilities = sum(utilities.cost),
._Misc = sum(misc.cost),
._ITinfrastructure = sum(it.cost),
._ThirdPartyData = sum(third.pt.data.cost),
._PaymentProcessing = sum(payment.process.cost),
EBITDA = sum(ebitda), #not sure
._Interest = sum(debt.interest),
PreTaxProfit = sum(pre.tax.profit), #not sure
._Taxes = sum(taxed.income),
NetIncome = sum(net.income),
LeaseAcquisition = sum(asset.acq.outflow), #not sure
CashFlowWithoutDebt = sum(cash.flow),
DebtBorrowed = debt.borrowed[which.max(dates)],
CashFlowWithDebt = sum(cash.flow.debt)
)
toReturn$SalesExpense_NumLeases = floor(toReturn$.___LaborSales / toReturn$TotalLeasesBooked * 100) / 100
toReturn$Labor_Assets = floor(toReturn$._TotalLabor / toReturn$TotalLeaseAssetsYearEnd * 100) / 100
toReturn$TotalExpenses_Assets = floor(toReturn$TotalExpenses / toReturn$TotalLeaseAssetsYearEnd * 100) / 100
toReturn$Revenue_Assets = floor(toReturn$Revenue / toReturn$TotalLeaseAssetsYearEnd * 100) / 100
toReturn$TotalExpenses_Revenue = floor(toReturn$TotalExpenses / toReturn$Revenue * 100) / 100
toReturn$EBITDA_Revenue = floor(toReturn$EBITDA / toReturn$Revenue * 100) / 100
toReturn
}
test.yrSummary <- yrSummary()
#' The lease.returns function
#'
#' This calculates 12 month, 18 month, and total returns given average lease data
#'
#' @param a.lease, data on cash metrics of the average lease
#' @param assumption.list, a list of constant values
#' @return a list with 12 month, 18 month, and total returns
#' @export
lease.returns <- function(a.lease = test.average.lease,
assumption.list = default.constants.list){
toReturn <- list()
toReturn$twelve.m.return <-round(sum(a.lease$payment.expected[c(2:365)])/(sum(a.lease$asset.acq.outflow[c(2:365)])) , 2)
toReturn$eighteen.m.return <- round(sum(a.lease$payment.expected[c(2:547)]) / (sum(a.lease$asset.acq.outflow[c(2:547)])), 2)
toReturn$total.return <- round(sum(a.lease$payment.expected[c(2:1000)]) / (sum(a.lease$asset.acq.outflow[c(2:1000)])),2)
toReturn
}
#' The irr.day function
#'
#' Calculates IRR on a by-day basis
#'
#' @param df, average.lease data
#' @param no.days, number of days to calculate for
#' @return a number, the IRR
#' @export
irr.day <- function(df = test.average.lease,
no.days = 1000) {
f <- function(x){
cashflows <- sum(df$payment.expected / (1 + x)^(1:no.days))
cashflows - sum(df$asset.acq.outflow)
}
uniroot(f, c(-.5,1), tol=.000001)$root * 365
}
#' The irr.month function
#'
#' Calculates IRR on a by-month basis
#'
#' @param df, average.lease data
#' @param no.days, number of days to calculate for
#' @return a number, the IRR
#' @export
irr.month <- function(df = test.average.lease,
no.months = 24) {
f <- function (y){
days.index = (1:no.months) * 28
cashflows = rep(0, no.months)
cashflows[1] = sum(df$payment.expected[which(df$days <= days.index[1])])
for (z in 2 : no.months){
cashflows[z] = sum(df$payment.expected[which(df$days <= days.index[z] & df$days > days.index[z-1])])
}
cashflows2 <- sum(cashflows / ((1 + y)^((1:no.months)-0.5)))
cashflows2 - sum(df$asset.acq.outflow)
}
uniroot(f, c(-.6,.2))$root * 13
}
#' The cash.by.day function
#'
#' Graphs cumulative cash received per lease by day
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @param assumptions, a list of constant values
#' @return The graph of cumulative cash received per lease by day
#' @export
cash.by.day <- function(a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4,
assumptions = default.constants.list) {
cash <- cumsum(a.lease$payment.expected - a.lease$asset.acq.outflow)
df <- data.frame(days = 1:1000, cash = cash)
toReturn <- (ggplot(data = df, aes(x = days)) + geom_line(aes(y = cash, colour = "cumulative cash"))) + theme_bw()
toReturn$labels$x <- "Time in Days"
toReturn$labels$y <- "Cumulative Cash"
toReturn$labels$title <- "Cumulative Cash over Time"
toReturn$labels$colour <- ""
toReturn <- toReturn +
annotate("text", label = paste("Min:", as.character(floor(min(toReturn$data$cash) * 100)/100), "on day", as.character(which.min(toReturn$data$cash))), x = 600, y = min(toReturn$data$cash), size = small.text.size,colour = "black") +
annotate("text", label = paste("Max:", as.character(floor(max(toReturn$data$cash) * 100)/100), "from day", as.character(which.max(toReturn$data$cash)), "on"), x = 600, y = min(toReturn$data$cash)+100, size = small.text.size,colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The cash.by.month function
#'
#' Graphs cumulative cash received per lease by month
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @param assumptions, a list of constant values
#' @return The graph of cumulative cash received per lease by month
#' @export
cash.by.month <- function(a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4,
assumptions = default.constants.list) {
cash <- cumsum(a.lease$payment.expected - a.lease$asset.acq.outflow)
df <- data.frame(months = 1:26, cash = cash[(1:26) * 28 - 14])
toReturn <- (ggplot(data = df, aes(x = months)) + geom_line(aes( y = cash, colour = "cumulative cash"))) + theme_bw()
toReturn$labels$x <- "Time in Months"
toReturn$labels$y <- "Cumulative Cash"
toReturn$labels$title <- "Cumulative Cash over Time"
toReturn$labels$colour <- ""
toReturn <- toReturn +
annotate("text", label = paste("Min:", as.character(floor(min(toReturn$data$cash) * 100)/100), "on month", as.character(which.min(toReturn$data$cash))), x = 21, y = min(toReturn$data$cash), size = small.text.size,colour = "black") +
annotate("text", label = paste("Max:", as.character(floor(max(toReturn$data$cash) * 100)/100), "from month", as.character(which.max(toReturn$data$cash)), "on"), x = 21, y = min(toReturn$data$cash) + 100, size = small.text.size,colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The cash.by.month function
#'
#' Graphs cumulative cash received per lease by month
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @return The graph of cumulative cash received per lease by month
#' @export
expected.vs.due <- function(a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4) {
expected <- cumsum(a.lease$payment.expected)
due <- cumsum(a.lease$payment.due)
df <- data.frame(months = 1:26, expected = expected[(1:26) * 28], due = due[(1:26)*28])
toReturn <- (ggplot(df, aes(months)) +
geom_line(aes(y = expected, colour = "actual payment")) +
geom_line(aes(y = due, colour = "payment due"))) + theme_bw()
toReturn$labels$x <- "Time in Months"
toReturn$labels$y <- "Cumulative Cash"
toReturn$labels$title <- "Expected Cash Flow vs. Cash Flow Due"
toReturn$labels$colour <- ""
toReturn <- toReturn +
geom_text(x = 7, y = 300, label = paste("Min:",as.character(floor(min(toReturn$data$due) * 100) / 100), "on month", as.character(which.min(toReturn$data$due))), size = small.text.size, colour = 5) +
geom_text(x = 7, y = 400, label = paste("Min:",as.character(floor(min(toReturn$data$expected) * 100) / 100), "on month", as.character(which.min(toReturn$data$expected))), size = small.text.size, colour = 2) +
geom_text(x = 21, y = 2350, label = paste("Max:",as.character(floor(max(toReturn$data$due) * 100) / 100), "from month", as.character(which.max(toReturn$data$due)), "on"), size = small.text.size, colour = 5) +
geom_text(x = 21, y = 1700, label = paste("Max:",as.character(floor(max(toReturn$data$expected) * 100) / 100), "from month", as.character(which.max(toReturn$data$expected)), "on"), size = small.text.size, colour = 2)
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The bad.debt.month function
#'
#' Graphs bad debt received as a percentage of asset value on a by-month basis
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @return The graph of bad debt by month
#' @export
bad.debt.month <- function (a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4) {
bad.debt <- c(rep(0,120), cumsum(a.lease$bad.debt / sum(a.lease$asset.acq.outflow)))
df <- data.frame(months = 1:30, bad.debt = bad.debt[(1:30)*28])
toReturn <- (ggplot(data = df, aes(x = months)) + geom_line(aes(y = bad.debt, colour = "bad debt as % of assets"))) + theme_bw()
toReturn$labels$x <- "Time in Months"
toReturn$labels$y <- "Bad Debt as Percent of Assets"
toReturn$labels$title <- "Cumulative Bad Debt Over Time"
toReturn$labels$colour <- ""
toReturn <- toReturn +
annotate("text", label = paste("Min: 0 from months", as.character(min(which(toReturn$data$bad.debt == 0))), "to", as.character(max(which(toReturn$data$bad.debt == 0)))), x = 25, y = 0.1, size = small.text.size, colour = "black") +
annotate("text", label = paste("Max:", as.character(floor(max(toReturn$data$bad.debt) * 100) / 100), "from month", as.character(which.max(toReturn$data$bad.debt)), "on"), x = 25, y = 0, size = small.text.size,colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The bad.debt.to.pay function
#'
#' Graphs bad debt received as a percentage of payment expected at that point
#' on a by-month basis
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @return The graph of bad debt by month
#' @export
bad.debt.to.pay <- function (a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4){
toReturn <- ggplot(data = a.lease, aes(x = days)) +
geom_line(aes(y = cumsum(bad.debt) / cumsum(payment.expected),
colour = "Bad debt as cumulative % of expected payments")) + theme_bw()
toReturn$labels$x <- "Time in Days"
toReturn$labels$y <- "% of expected payment that has defaulted"
toReturn$labels$title <- "Bad Debt to Payments over time"
toReturn$labels$colour <- ""
toReturn <- toReturn +
annotate("text", label = paste(as.character(floor(max(cumsum(a.lease$bad.debt) / cumsum(a.lease$payment.expected)) * 100)), "% of payers default by day",
as.character(which.max(cumsum(a.lease$bad.debt) / cumsum(a.lease$payment.expected)))), x = 600, y = 0, size = small.text.size,colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The bad.debt.total.pdue function
#'
#' Graphs bad debt received as a percentag of total payments due on a by-month basis
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @return The graph of bad debt by month
#' @export
bad.debt.total.pdue <- function (a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4) {
bad.debt <- c(rep(0,120), cumsum(a.lease$bad.debt / sum(a.lease$payment.due)))
df <- data.frame(months = 1:30, bad.debt = bad.debt[(1:30)*28])
toReturn <- (ggplot(data = df, aes(x = months)) + geom_line(aes(y = bad.debt, colour = "bad debt as % of total payments due"))) + theme_bw()
toReturn$labels$x <- "Time in Months"
toReturn$labels$y <- "Bad Debt as Percent of Total Payments Due"
toReturn$labels$title <- "Bad Debt Over Payment.due"
toReturn$labels$colour <- ""
toReturn <- toReturn +
annotate("text", label = paste("Min: 0 from months", as.character(min(which(toReturn$data$bad.debt == 0))), "to", as.character(max(which(toReturn$data$bad.debt == 0)))), x = 20, y = 0.05, size = small.text.size, colour = "black") +
annotate("text", label = paste("Max:", as.character(floor(max(toReturn$data$bad.debt) * 100) / 100), "from month", as.character(which.max(toReturn$data$bad.debt)), "on"), x = 20, y = 0, size = small.text.size,colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The cum.default.rate function
#'
#' Graphs the cumulative % of payers who have defaulted by month.
#'
#' @param a.lease, average lease data
#' @param file, if this isn't null, the graph will be saved as this file
#' @param text.size, text size for graph titles and sides
#' @param small.text.size, text size for the smaller text inside the graph
#' @param assumptions, a list of constant values
#' @param default.rate, a vector representing the default rate, must be 1000 in length with values between 0 and 1
#' @return The graph of default rate by month
#' @export
cum.default.rate <- function (a.lease = test.average.lease,
file = NULL,
text.size = 12,
small.text.size = 4,
assumptions = default.constants.list,
default.rate = norm.default.rate) {
df <- data.frame(months = 1:assumptions$avg.lease.length, default.rate = 1- cumprod(default.rate[(0:(assumptions$avg.lease.length-1))*28 + 1]))
toReturn <- (ggplot(data = df, aes(x = months)) + geom_line(aes(y = default.rate, colour = "% of payers who have defaulted"))) + theme_bw()
toReturn$labels$x <- "Time in Months"
toReturn$labels$y <- "% of payers who have defaulted"
toReturn$labels$title <- "Cumulative Default Rate over time"
toReturn$labels$colour <- ""
toReturn <- toReturn + annotate("text", label = paste(as.character(floor(max(toReturn$data$default.rate) * 100)), "% of payers default by month", as.character(assumptions$avg.lease.length)), x = 10, y = 0, size = small.text.size, colour = "black")
toReturn$theme$text$size = text.size
if (!is.null(file)){
ggsave(toReturn, filename = file, width = 5, height = 2.5)
}
toReturn
}
#' The incomeStatement function
#'
#' This function formats results into an income statement sheet, optionally saving it to a file
#'
#' @param file, the name of the file the sheet will be saved as. If null the file won't be esaved
#' and the workbook will be returned.
#' @param yrdata, cash flow information by year, from the yrSummary function
#' @param mthdata, cash flow information by year, from the mthSummary function
#' @param avg.data, data representing an average lease, from the calc.average function
#' @param assumptions, constants represented in the original data frame form
#' @param d.assumptions, constants related to interest and leverage in original data frame form
#' @param emp.data, data on employees
#' @param growth.data, growth.rates data
#' @param d.rate, default rate expressed as length 1000 vector with numbers between 0 and 1
#' @return a data frame with debt metrics added on to cash flow metrics
#' @export
incomeStatement <- function(file = NULL,
mthdata = test.incomeSummary){
mthdates <- data.frame(
Projections = colnames(mthdata)[2]
)
mthtemp <- data.frame(
Projections = colnames(mthdata)[3:length(colnames(mthdata))]
)
for (i in 1 : nrow(mthdata)){
mthdates[,mthdata[i,][1][[1]]] <- mthdata[i,][2]
mthtemp[,mthdata[i,][1][[1]]] <- as.numeric(mthdata[i,][3:length(colnames(mthdata))])
}
# Write final results to one big spreadsheet
wb <- createWorkbook()
boldstyle <- CellStyle(wb) + Font(wb, isBold = TRUE)
currency <- CellStyle(wb) + DataFormat("$#,##0_);[Red]($#,##0)")
comma <- CellStyle(wb) + DataFormat("#,##0.00")
wholecomma <- CellStyle(wb) + DataFormat("#,##0")
#Helper
create.style.list <- function(style, startIndex, endIndex){
toReturn = list()
for (i in startIndex:endIndex){
eval(parse(text = paste("toReturn$`",i,"`<-",style, sep = "")))
}
toReturn
}
mth.sheet <- createSheet(wb, sheetName = "Income Statement")
mGrowthMetrics <- createCell(createRow(mth.sheet, rowIndex = 1), colIndex = 1)[[1,1]]
setCellValue(mGrowthMetrics, "Credda Income Statement")
setCellStyle(mGrowthMetrics, boldstyle)
mProfitAndLoss <- createCell(createRow(mth.sheet, rowIndex = 2), colIndex = 1)[[1,1]]
setCellValue(mProfitAndLoss, "Revenues")
setCellStyle(mProfitAndLoss, boldstyle)
mCashFlow <- createCell(createRow(mth.sheet, rowIndex = 5), colIndex = 1)[[1,1]]
setCellValue(mCashFlow, "Cost of Sales")
setCellStyle(mCashFlow, boldstyle)
mCashFlow <- createCell(createRow(mth.sheet, rowIndex = 7), colIndex = 1)[[1,1]]
setCellValue(mCashFlow, "Gross Profit")
setCellStyle(mCashFlow, boldstyle)
mCashFlow <- createCell(createRow(mth.sheet, rowIndex = 9), colIndex = 1)[[1,1]]
setCellValue(mCashFlow, "Operating Expenses")
setCellStyle(mCashFlow, boldstyle)
mCashFlow <- createCell(createRow(mth.sheet, rowIndex = 28), colIndex = 1)[[1,1]]
setCellValue(mCashFlow, "Earnings")
setCellStyle(mCashFlow, boldstyle)
tempQuarters <- data.frame(Projections = colnames(mthdates)[2:length(colnames(mthdates))])
addDataFrame(colnames(mthdates), mth.sheet, col.names = FALSE, row.names = FALSE, startRow=1,startColumn = 2, colnamesStyle = boldstyle,
colStyle = list('1' = boldstyle), byrow = TRUE)
# addDataFrame(data.frame(mthdates), mth.sheet, col.names = TRUE, row.names = FALSE, startColumn = 2, colnamesStyle = boldstyle,
# colStyle = list(`1` = boldstyle))
# Revenues
addDataFrame(data.frame(mthtemp[1,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 3, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "wholecomma", startIndex = 2, endIndex = ncol(mthtemp))))
addDataFrame(data.frame(mthtemp[2,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 4, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
# Lease Depreciation
addDataFrame(data.frame(mthtemp[3,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 6, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
# Gross Profit
addDataFrame(data.frame(mthtemp[4,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 8, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
# Non Labor
addDataFrame(data.frame(mthtemp[5:14,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 10, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
# Labor
addDataFrame(data.frame(mthtemp[15:19,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 21, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
# Total
addDataFrame(data.frame(mthtemp[20,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 27, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
#EBIT
addDataFrame(data.frame(mthtemp[21,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 29, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
#Interest and EBT
addDataFrame(data.frame(mthtemp[22:23,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 31, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
# Income taxes and Net Earnings
addDataFrame(data.frame(mthtemp[24:25,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 34, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle), create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
autoSizeColumn(sheet = mth.sheet, colIndex = 1:(ncol(mthtemp) +1))
if (!is.null(file)){
saveWorkbook(wb, file = file)
}
wb
}
#' The saveToSheet function
#'
#' This function writes the results into an excel spreadsheet and saves it
#'
#' @param file, the name of the file the sheet will be saved as. If null the file won't be esaved
#' and the workbook will be returned.
#' @param yrdata, cash flow information by year, from the yrSummary function
#' @param mthdata, cash flow information by year, from the mthSummary function
#' @param mth.idata, incomeSummary information, from mthIncomeSummary function
#' @param avg.data, data representing an average lease, from the calc.average function
#' @param assumptions, constants represented in the original data frame form
#' @param d.assumptions, constants related to interest and leverage in original data frame form
#' @param emp.data, data on employees
#' @param growth.data, growth.rates data
#' @param d.rate, default rate expressed as length 1000 vector with numbers between 0 and 1
#' @return a data frame with debt metrics added on to cash flow metrics
#' @export
saveToSheet <- function(file = NULL,
yrdata = test.yrSummary,
mthdata = test.mthSummary,
mth.idata = test.incomeSummary,
avg.data = test.average.lease,
assumptions = default.constants.table,
d.assumptions = default.int.lev,
emp.data = default.employees,
growth.data = default.growth.rates,
d.rate = norm.default.rate){
temp.assumptions.list <- as.list(assumptions$Values)
names(temp.assumptions.list) <- assumptions$Names
yrtemp <- data.frame(
Projections = colnames(yrdata)[2:length(colnames(yrdata))]
)
for (i in 1 : nrow(yrdata)) {
yrtemp[,paste("Year_", i, sep = "")] <- as.numeric(yrdata[i,][2:length(colnames(yrdata))])
}
mthdates <- data.frame(
Projections = colnames(mthdata)[2]
)
mthtemp <- data.frame(
Projections = colnames(mthdata)[3:length(colnames(mthdata))]
)
for (i in 1 : nrow(mthdata)){
mthdates[,paste("Month_",i,sep = "")] <- mthdata[i,][2]
mthtemp[,paste("Month_",i,sep = "")] <- as.numeric(mthdata[i,][3:length(colnames(mthdata))])
}
# Write final results to one big spreadsheet
wb <- incomeStatement(file = NULL, mthdata = mth.idata)
boldstyle <- CellStyle(wb) + Font(wb, isBold = TRUE)
currency <- CellStyle(wb) + DataFormat("$#,##0_);[Red]($#,##0)")
comma <- CellStyle(wb) + DataFormat("#,##0.00")
wholecomma <- CellStyle(wb) + DataFormat("#,##0")
create.style.list <- function(style, startIndex, endIndex){
toReturn = list()
for (i in startIndex:endIndex){
eval(parse(text = paste("toReturn$`",i,"`<-",style, sep = "")))
}
toReturn
}
yr.sheet <- createSheet(wb, sheetName = "Yearly Summary")
yGrowthMetrics <- createCell(createRow(yr.sheet, rowIndex = 2), colIndex = 1)[[1,1]]
setCellValue(yGrowthMetrics, "GrowthMetrics")
setCellStyle(yGrowthMetrics, boldstyle)
yProfitAndLoss <- createCell(createRow(yr.sheet, rowIndex = 9), colIndex = 1)[[1,1]]
setCellValue(yProfitAndLoss, "ProfitAndLoss")
setCellStyle(yProfitAndLoss, boldstyle)
yCashFlow <- createCell(createRow(yr.sheet, rowIndex = 27), colIndex = 1)[[1,1]]
setCellValue(yCashFlow, "CashFlow")
setCellStyle(yCashFlow, boldstyle)
yKeyRatios <- createCell(createRow(yr.sheet, rowIndex = 36), colIndex = 1)[[1,1]]
setCellValue(yKeyRatios, "KeyRatios")
setCellStyle(yKeyRatios, boldstyle)
addDataFrame(data.frame(yrtemp[1:4,]), yr.sheet, col.names = TRUE, row.names = FALSE, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle),
create.style.list(style = "wholecomma", startIndex = 2, endIndex = ncol(yrtemp))))
addDataFrame(data.frame(yrtemp[5:33,]), yr.sheet, col.names = FALSE, row.names = FALSE, startRow = 6, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle),
create.style.list(style = "currency", startIndex = 2, endIndex = ncol(yrtemp))))
addDataFrame(data.frame(yrtemp[34:39,]), yr.sheet, col.names = FALSE, row.names = FALSE, startRow = 35, startColumn = 2, colnamesStyle = boldstyle,
colStyle = list(`1` = boldstyle))
createFreezePane(yr.sheet, rowSplit = 2, colSplit = 3)
autoSizeColumn(sheet=yr.sheet, colIndex = 1: (ncol(yrtemp)+1))
mth.sheet <- createSheet(wb, sheetName = "Monthly Summary")
mGrowthMetrics <- createCell(createRow(mth.sheet, rowIndex = 2), colIndex = 1)[[1,1]]
setCellValue(mGrowthMetrics, "GrowthMetrics")
setCellStyle(mGrowthMetrics, boldstyle)
mProfitAndLoss <- createCell(createRow(mth.sheet, rowIndex = 13), colIndex = 1)[[1,1]]
setCellValue(mProfitAndLoss, "ProfitAndLoss (before taxes)")
setCellStyle(mProfitAndLoss, boldstyle)
mCashFlow <- createCell(createRow(mth.sheet, rowIndex = 32), colIndex = 1)[[1,1]]
setCellValue(mCashFlow, "CashFlow (before taxes)")
setCellStyle(mCashFlow, boldstyle)
addDataFrame(data.frame(mthdates), mth.sheet, col.names = TRUE, row.names = FALSE, startColumn = 2, colnamesStyle = boldstyle,
colStyle = list(`1` = boldstyle))
addDataFrame(data.frame(mthtemp[1:7,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 3, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle),
create.style.list(style = "wholecomma", startIndex = 2, endIndex = ncol(mthtemp))))
addDataFrame(data.frame(mthtemp[8:37,]), mth.sheet, col.names = FALSE, row.names = FALSE, startRow = 10, startColumn = 2, colnamesStyle = boldstyle,
colStyle = append(list(`1` = boldstyle),
create.style.list(style = "currency", startIndex = 2, endIndex = ncol(mthtemp))))
createFreezePane(mth.sheet, rowSplit = 2, colSplit = 3)
autoSizeColumn(sheet = mth.sheet, colIndex = 1:(ncol(mthtemp) +1))
const.sheet <- createSheet(wb, sheetName = "Assumptions")
addDataFrame(assumptions, const.sheet, col.names = TRUE, row.names = FALSE, colnamesStyle = boldstyle, colStyle = list(`2` = comma))
createFreezePane(const.sheet, rowSplit = 2, colSplit = 1)
autoSizeColumn(sheet = const.sheet, colIndex = 1:ncol(assumptions))
debt.c.sheet <- createSheet(wb, sheetName = "Debt Assumptions")
addDataFrame(d.assumptions, debt.c.sheet, col.names = TRUE, row.names = FALSE, colnamesStyle = boldstyle)
createFreezePane(debt.c.sheet, rowSplit = 2, colSplit = 1)
dMethod <- createCell(createRow(debt.c.sheet, rowIndex = (nrow(d.assumptions) + 2)), colIndex = 4)[[1,1]]
if (temp.assumptions.list$depr.method == 1){
setCellValue(dMethod, "Linear Depreciation Method")
} else {
setCellValue(dMethod, "Loan Depreciation Method")
}
autoSizeColumn(sheet = debt.c.sheet, colIndex = 1:ncol(d.assumptions))
irr <- data.frame(AnnualIRR=irr.month(df = avg.data))
irr$BackForEveryDollar <- lease.returns(a.lease = avg.data, assumption.list = temp.assumptions.list)$total.return
irr.sheet <- createSheet(wb, sheetName = "LeaseIRR")
addDataFrame(irr, irr.sheet, col.names = TRUE, row.names = FALSE, colnamesStyle = boldstyle, colStyle = list(`2` = comma))
cash <- cumsum(avg.data$payment.expected - avg.data$asset.acq.outflow)
temp.df <- data.frame(Month = 1:26, Net_Cash = cash[(1:26) * 28 - 14])
addDataFrame(data.frame(temp.df), irr.sheet, col.names = TRUE, row.names = FALSE, startRow = 3, colnamesStyle = boldstyle,
colStyle = list(`2` = currency))
createFreezePane(irr.sheet, rowSplit = 4, colSplit = 1)
autoSizeColumn(sheet = irr.sheet, colIndex = 1:ncol(irr))
emp.sheet <- createSheet(wb, sheetName = "Employees")
addDataFrame(emp.data, emp.sheet, col.names = TRUE, row.names = FALSE, colnamesStyle = boldstyle, colStyle = list(`3` = currency))
createFreezePane(emp.sheet, rowSplit = 2, colSplit = 3)
autoSizeColumn(sheet = emp.sheet, colIndex = 1:ncol(emp.data))
growth.sheet <- createSheet(wb, sheetName = "Growth Projections")
addDataFrame(growth.data, growth.sheet, col.names = TRUE, row.names = FALSE, colnamesStyle = boldstyle, colStyle = list(`2` = wholecomma))
createFreezePane(growth.sheet, rowSplit = 2, colSplit = 1)
autoSizeColumn(sheet = yr.sheet, colIndex = 1:ncol(growth.data))
default.sheet <- createSheet(wb, sheetName = "Default Rate")
cum.default.rate(a.lease = avg.data, file = "dtoAdd.png", small.text.size = 2, text.size = 8, default.rate = d.rate)
addPicture(file = "dtoAdd.png", sheet = default.sheet)
lease.cf.sheet <- createSheet(wb, sheetName = "Lease Cash Flow")
cash.by.month(a.lease = avg.data, file = "cbmtoAdd.png",small.text.size = 2, text.size = 8)
addPicture(file = "cbmtoAdd.png", sheet = lease.cf.sheet)
bad.debt.sheet <- createSheet(wb, sheetName = "Bad Debt")
bad.debt.to.pay(a.lease = avg.data, file = "bdptoAdd.png", small.text.size = 2, text.size = 8)
addPicture(file = "bdptoAdd.png", sheet = bad.debt.sheet, startRow = 1)
bad.debt.total.pdue(a.lease = avg.data, file = "bdtotalAdd.png", small.text.size = 2, text.size = 8)
addPicture(file = "bdtotalAdd.png", sheet = bad.debt.sheet, startRow = 38)
bad.debt.month(a.lease = avg.data, file = "bdtoAdd.png", small.text.size = 2, text.size = 8)
addPicture(file = "bdtoAdd.png", sheet = bad.debt.sheet, startRow = 75)
if (!is.null(file)){
saveWorkbook(wb, file = file)
}
wb
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.