Last active
August 2, 2023 15:03
-
-
Save georgescumihai/8f6a490bad9256a52f8f77cb13f8bb0a to your computer and use it in GitHub Desktop.
Calculator Taxation of VV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum Constant { | |
static let igic: Double = 0.07 | |
} | |
struct CostStructure { | |
let grossIncome: Double | |
let netIncome: Double | |
let otaCommission: Double | |
let managementCommission: Double | |
let cleaningAndSuppliesPerNight: Double | |
let igic: Double | |
var expenses: Double { | |
otaCommission + managementCommission + cleaningAndSuppliesPerNight | |
} | |
var igicForExpenses: Double { | |
expenses * Constant.igic | |
} | |
var igicToPay: Double { | |
let negativeIgic = igicForExpenses | |
let igicToPay = igic - negativeIgic | |
return igicToPay | |
} | |
} | |
struct Calculator { | |
let otaCommissionPercentage: Double | |
let managementCommissionPercentage: Double | |
let suppliesCostPerStay: Double | |
let cleaningCostPerStay: Double | |
func calculateDayRate(gross: Double, averageLength: UInt) -> CostStructure { | |
var income = gross | |
let otaCommission = calculateOTACCommission(income: gross) | |
// Remove OTA Comission | |
income -= otaCommission | |
let cleaningAndSuppliesCost = calculateCleaningAndSuppliesCost(averageLength: averageLength) | |
income -= cleaningAndSuppliesCost | |
let managementCommission = calculateManagementCommission(income: income) | |
income -= managementCommission | |
return CostStructure( | |
grossIncome: gross, | |
netIncome: income, | |
otaCommission: otaCommission, | |
managementCommission: managementCommission, | |
cleaningAndSuppliesPerNight: cleaningAndSuppliesCost, | |
igic: calculateIGIC(priceIncludingIGIC: gross) | |
) | |
} | |
func calculateDayRate(netIncome: Double, averageLength: UInt) -> CostStructure { | |
var income = netIncome | |
// Reverse Management Commission | |
income = income / (1 - managementCommissionPercentage / 100) | |
let managementCommission = income * managementCommissionPercentage / 100 | |
// Add Cleaning and Supplies Cost | |
let cleaningAndSuppliesCost = (suppliesCostPerStay + cleaningCostPerStay) / Double(averageLength) | |
income += cleaningAndSuppliesCost | |
// Reverse OTA Commission | |
income = income / (1 - otaCommissionPercentage / 100) | |
let otaCommission = income * otaCommissionPercentage / 100 | |
// IGIC | |
let grossIncome = income | |
let igic = calculateIGIC(priceIncludingIGIC: grossIncome) | |
return CostStructure( | |
grossIncome: grossIncome, | |
netIncome: netIncome, | |
otaCommission: otaCommission, | |
managementCommission: managementCommission, | |
cleaningAndSuppliesPerNight: cleaningAndSuppliesCost, | |
igic: igic | |
) | |
} | |
func calculateYearlyRate( | |
averageGrossDayRate: Double, | |
occupancy: Double, | |
averageLength: Double, | |
cleaningCost: Double | |
) -> CostStructure { | |
guard (0.0...1.0).contains(occupancy) else { | |
fatalError("Wrong occupancy") | |
} | |
let totalNumberOfNights = 365 * occupancy | |
let grossIncome = averageGrossDayRate * totalNumberOfNights | |
var income = grossIncome | |
let otaCommission = calculateOTACCommission(income: income) | |
// Remove OTA Comission | |
income -= otaCommission | |
var cleaningAndSuppliesCost = floor(totalNumberOfNights / averageLength) * cleaningCost | |
income -= cleaningAndSuppliesCost | |
let managementCommission = calculateManagementCommission(income: income) | |
income -= managementCommission | |
return CostStructure( | |
grossIncome: grossIncome, | |
netIncome: income, | |
otaCommission: otaCommission, | |
managementCommission: managementCommission, | |
cleaningAndSuppliesPerNight: cleaningAndSuppliesCost, | |
igic: calculateIGIC(priceIncludingIGIC: grossIncome) | |
) | |
} | |
private func calculateOTACCommission(income: Double) -> Double { | |
return income * otaCommissionPercentage / 100 | |
} | |
private func calculateManagementCommission(income: Double) -> Double { | |
return income * managementCommissionPercentage / 100 | |
} | |
private func calculateCleaningAndSuppliesCost(averageLength: UInt) -> Double { | |
return (suppliesCostPerStay + cleaningCostPerStay) / Double(averageLength) | |
} | |
private func calculateIGIC(priceIncludingIGIC: Double) -> Double { | |
let priceWithoutIGIC = priceIncludingIGIC / (1 + Constant.igic) | |
let igic = priceIncludingIGIC - priceWithoutIGIC | |
return igic | |
} | |
} | |
let standardCalculator = Calculator( | |
otaCommissionPercentage: 15, | |
managementCommissionPercentage: 18, | |
suppliesCostPerStay: 5, | |
cleaningCostPerStay: 50 | |
) | |
let income = standardCalculator.calculateDayRate(gross: 166, averageLength: 5) | |
let incomeFromNet = standardCalculator.calculateDayRate(netIncome: 107, averageLength: 5) | |
extension NumberFormatter { | |
static let currencyFormatter: NumberFormatter = { | |
let formatter = NumberFormatter() | |
formatter.numberStyle = .currency | |
formatter.currencySymbol = "€" | |
formatter.minimumFractionDigits = 2 | |
formatter.maximumFractionDigits = 2 | |
return formatter | |
}() | |
static let percentageFormatter: NumberFormatter = { | |
let formatter = NumberFormatter() | |
formatter.numberStyle = .percent | |
return formatter | |
}() | |
} | |
enum Printer { | |
static let currencyFormatter = NumberFormatter.currencyFormatter | |
static func logCost(_ cost: CostStructure) { | |
print( | |
""" | |
# Income details | |
Gross (Including IGIC): \(currencyFormatter.string(from: NSNumber(value: cost.grossIncome)) ?? "N/A") | |
Net (Including IGIC): \(currencyFormatter.string(from: NSNumber(value: cost.netIncome)) ?? "N/A") | |
Airbnb / Bookings (without IGIC): \(currencyFormatter.string(from: NSNumber(value: cost.otaCommission)) ?? "N/A") | |
Cleaning and supplies (without IGIC): \(currencyFormatter.string(from: NSNumber(value: cost.cleaningAndSuppliesPerNight)) ?? "N/A") | |
Pambnb Management (without IGIC): \(currencyFormatter.string(from: NSNumber(value: cost.managementCommission)) ?? "N/A") | |
IGIC on expenses: \(currencyFormatter.string(from: NSNumber(value: cost.igicForExpenses)) ?? "N/A") | |
IGIC to Pay: \(currencyFormatter.string(from: NSNumber(value: cost.igicToPay)) ?? "N/A") | |
## Total for owner (After IGIC was paid) | |
\(currencyFormatter.string(from: NSNumber(value: cost.netIncome - cost.igic)) ?? "N/A") | |
""" | |
) | |
} | |
} | |
func calculateYearly( | |
rates: [Double], | |
occupancy: Double, | |
averageLength: Double, | |
cleaningCost: Double, | |
monthlyUtilities: Double | |
) { | |
print("Occupancy \(NumberFormatter.percentageFormatter.string(from: NSNumber(value: occupancy))!)") | |
print("Average booking length \(averageLength) nights") | |
print("Cleaning and supply costs per booking \(NumberFormatter.currencyFormatter.string(from: NSNumber(value: cleaningCost))!)") | |
print("Monthly utilities (Electricity, Water, Internet, Cable): \(NumberFormatter.currencyFormatter.string(from: NSNumber(value: monthlyUtilities))!)") | |
rates.forEach { | |
let cost = standardCalculator.calculateYearlyRate( | |
averageGrossDayRate: $0, | |
occupancy: occupancy, | |
averageLength: averageLength, | |
cleaningCost: cleaningCost | |
) | |
if let dailyRate = NumberFormatter.currencyFormatter.string(from: NSNumber(value: $0)) { | |
print("\nAverageDailyRate: \(dailyRate)") | |
} | |
Printer.logCost(cost) | |
let yearlyUtilities = monthlyUtilities * 12 | |
let incomeTaxNonResidentHisLicense = (cost.grossIncome - cost.igic) * 0.24 | |
let incomeTaxNonResidentOurLicense = (cost.netIncome - cost.igic - yearlyUtilities) * 0.24 | |
print("Income Tax NonResident 24% (Owner License) \(NumberFormatter.currencyFormatter.string(from: NSNumber(value: incomeTaxNonResidentHisLicense))!)") | |
print("Income Tax NonResident 24% (Pambnb License) \(NumberFormatter.currencyFormatter.string(from: NSNumber(value: incomeTaxNonResidentOurLicense))!)") | |
} | |
} | |
calculateYearly(rates: [70, 80, 90, 110], occupancy: 0.7, averageLength: 4, cleaningCost: 50, monthlyUtilities: 110) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment