diff --git a/src/Definitions.jl b/src/Definitions.jl index c657ab86..fe58c140 100644 --- a/src/Definitions.jl +++ b/src/Definitions.jl @@ -1991,56 +1991,12 @@ export WealthTypes,net_physical_wealth,net_financial_wealth, @enum WealthTypes net_physical_wealth net_financial_wealth net_housing_wealth net_pension_wealth WealthSet = Set{WealthTypes} -# see https://www.gov.uk/guidance/rates-of-vat-on-different-goods-and-services - -#== NOT USED -export BroadConsumptionCategories, - BroadConsumptionSet, - sports, - sweets, - catered_foods, - other_foods, - alcohol, - live_animals, - sport_and_pe, - leisure_and_gambling, - health_products, - education, - domestic_fuel, - water_and_sewage, - energy_saving_goods, - heating_equipment, - stationery, - books_and_newspapers, - childrens_clothers, - financial_services, - insurance, - all_other_goods - -@enum BroadConsumptionCategories begin - sports - sweets - catered_foods - other_foods - alcohol - live_animals - sport_and_pe - leisure_and_gambling - health_products - education - domestic_fuel - water_and_sewage - energy_saving_goods - heating_equipment - stationery - books_and_newspapers - childrens_clothers - financial_services - insurance - all_other_goods -end - -const BroadConsumptionSet = Set{BroadConsumptionCategories} -=# +export AggregationLevel, individual, benefit_unit, household + +@enum AggregationLevel begin + individual + benefit_unit + household +end end # module diff --git a/src/OtherTaxes.jl b/src/OtherTaxes.jl index 01a2de94..2633ea3d 100644 --- a/src/OtherTaxes.jl +++ b/src/OtherTaxes.jl @@ -14,9 +14,14 @@ Flat rate wealth tax, assigned soley to HH head. function calculate_wealth_tax!( household_result :: HouseholdResult, hh :: Household, - sys :: OtherTaxesSys ) + sys :: WealthTax ) hd = get_head( hh ) + pres = household_result.bus[1].pers[ hd.pid ] wealth = 0.0 + # to individual level + if sys.wealth.abolished > 0 + return + end if net_physical_wealth in sys.included_wealth wealth += hh.net_physical_wealth end @@ -30,9 +35,11 @@ function calculate_wealth_tax!( wealth += hh.net_pension_wealth end - wealth = max( 0.0, wealth - sys.wealth_allowance ) - wt = wealth * sys.wealth_tax - household_result.bus[1].pers[ hd.pid ].income[OTHER_TAX] += wt + wealth = max( 0.0, wealth - sys.allowance ) + wtax = calctaxdue( taxable=wealth, rates=sys.rates, thresholds=sys.thresholds ) + pres.wealth.total = wtax.due + pres.wealth.weekly_equiv = pres.wealth.total * sys.weekly_rate + household_result.bus[1].pers[ hd.pid ].income[OTHER_TAX] += pres.wealth.weekly_equiv end """ @@ -65,10 +72,6 @@ function calculate_other_taxes!( household_result :: HouseholdResult, hh :: Household, sys :: OtherTaxesSys ) - if sys.wealth_tax > 0 - calculate_wealth_tax!( - household_result, hh, sys ) - end if sys.corporation_tax_changed calculate_corporation_tax!( household_result, hh, sys ) end diff --git a/src/Results.jl b/src/Results.jl index 0ad2a6d1..382dfe85 100644 --- a/src/Results.jl +++ b/src/Results.jl @@ -81,7 +81,7 @@ module Results ctr :: RT = zero(RT) recipient :: BigInt = -1 end - + @with_kw mutable struct LMTIncomes{RT<:Real} gross_earnings :: RT = zero(RT) net_earnings :: RT = zero(RT) @@ -188,6 +188,11 @@ module Results it.excise_tobacco end + @with_kw mutable struct WealthTaxResult{RT<:Real} + total_payable:: RT = zero(RT) + weekly_equiv :: RT = zero(RT) + end + @with_kw mutable struct NIResult{RT<:Real} above_lower_earnings_limit :: Bool = false # total_ni :: RT = 0.0 @@ -242,6 +247,7 @@ module Results net_income :: RT = zero(RT) ni = NIResult{RT}() it = ITResult{RT}() + wealth = WealthTaxResult{RT}() metr :: RT = -12345.0 replacement_rate :: RT = zero(RT) income = STBIncomes.make_a( RT ); @@ -416,7 +422,12 @@ module Results end return t end - + + function add_to!( wealth :: WealthTaxResult, wealth2 :: WealthTaxResult ) + wealth.weekly_equiv += wealth2.weekly_equiv + wealth.total_payable += wealth2.total_payable + end + function add_to!( ni :: NIResult, ni2 :: NIResult ) # ni.above_lower_earnings_limit += ni2.above_lower_earnings_limit # ni.total_ni += ni2.total_ni @@ -467,9 +478,11 @@ module Results pids = include_children ? keys( bu.pers ) : bu.adults it = ITResult{T}() ni = NIResult{T}() + wealth = WealthTaxResult{T}() for pid in pids add_to!( it, bu.pers[pid].it ) add_to!( ni, bu.pers[pid].ni ) + add_to!( wealth, bu.pers[pid].wealth ) end return (it,ni) end diff --git a/src/STBParameters.jl b/src/STBParameters.jl index e8bae95a..48339cd3 100644 --- a/src/STBParameters.jl +++ b/src/STBParameters.jl @@ -948,17 +948,30 @@ I More than £424,000 end @with_kw mutable struct OtherTaxesSys{RT<:Real} - wealth_tax :: RT = 0.0 - wealth_allowance :: RT = 1_000_000.0 + corporation_tax_changed = false + implicit_wage_tax :: RT = 0.0 + end + + # these are roughly the parameters + @with_kw mutable struct WealthTaxSys{RT<:Real} + abolished :: Boolean = true + one_off :: Boolean = true + payment_years :: Int = 0 + weekly_rate :: RT = zero(RT) + rates :: RateBands{RT} = [zero(RT)] + thresholds :: RateBands{RT} = [zero(RT)] + allowance :: RT = zero(RT) included_wealth = WealthSet([ net_physical_wealth, net_financial_wealth, net_housing_wealth]) - # see: https://www.wealthandpolicy.com/wp/EP8_TaxBase.pdf - # for arguments for ignoring pensions. Pragmatic one is - # results look silly. net_pension_wealth]) - corporation_tax_changed = false - implicit_wage_tax :: RT = 0.0 + end + + function weeklyise!( wealth :: WealthTaxSys; wpm=WEEKS_PER_MONTH, wpy=WEEKS_PER_YEAR ) + wealth.weekly_rate = 0.0 + if( wealth.payment_years > 0 ) && (!wealth.one_off) + wealth.weekly_rate = 1/(wealth.payment_years*wpy) + end end function weeklyise!( ubi :: UBISys; wpm=WEEKS_PER_MONTH, wpy=WEEKS_PER_YEAR ) @@ -975,7 +988,7 @@ I More than £424,000 othertaxes :: OtherTaxesSys; wpm=WEEKS_PER_MONTH, wpy=WEEKS_PER_YEAR ) - othertaxes.wealth_tax /= 100.0 + # othertaxes.wealth_tax /= 100.0 othertaxes.implicit_wage_tax /= 100.0 end @@ -1022,6 +1035,7 @@ I More than £424,000 nmt_bens = NonMeansTestedSys{RT}() bencap = BenefitCapSys{RT}() ubi = UBISys{RT}() + wealth = WealthTaxSys{RT}() othertaxes = OtherTaxesSys{RT}() indirect = IndirectTaxSystem{RT}() end @@ -1116,6 +1130,7 @@ I More than £424,000 weeklyise!( tb.bencap; wpm=wpm, wpy=wpy ) weeklyise!( tb.ubi; wpm=wpm, wpy=wpy ) weeklyise!( tb.othertaxes; wpm=wpm, wpy=wpy) + weeklyise!( tb.wealth; wpm=wpm, wpy=wpy) weeklyise!( tb.indirect; wpm=wpm, wpy=wpy ) end diff --git a/src/TheEqualiser.jl b/src/TheEqualiser.jl index 613e42c7..b8960851 100644 --- a/src/TheEqualiser.jl +++ b/src/TheEqualiser.jl @@ -81,6 +81,7 @@ function run( x :: T, rparams :: RunParameters{T} ) where T <: AbstractFloat npptrate = rparams.params.loctax.ppt.rate hvals = deepcopy(rparams.params.loctax.ct.house_values) othvals = deepcopy(rparams.params.othertaxes ) + wealth = deepcopy( rparams.params.wealth ) vat = deepcopy(rparams.params.indirect.vat ) if rparams.target in [eq_it, eq_it_ni] @@ -110,7 +111,7 @@ function run( x :: T, rparams :: RunParameters{T} ) where T <: AbstractFloat end if rparams.target == eq_wealth_tax - rparams.params.othertaxes.wealth_tax += x + rparams.params.wealth.rates .+= x end if rparams.target == eq_corporation_tax rparams.params.othertaxes.implicit_wage_tax += x @@ -139,6 +140,7 @@ function run( x :: T, rparams :: RunParameters{T} ) where T <: AbstractFloat rparams.params.loctax.ct.house_values = hvals rparams.params.othertaxes = othvals rparams.params.indirect.vat = vat + rparams.params.wealth = wealth rparams.iterations += 1 summary = summarise_frames!(results, rparams.settings) nc = summary.income_summary[1][1,:net_inc_indirect] diff --git a/test/equaliser_tests.jl b/test/equaliser_tests.jl index a987cbe8..d3fe7690 100644 --- a/test/equaliser_tests.jl +++ b/test/equaliser_tests.jl @@ -91,7 +91,7 @@ end settings, base_cost, obs ) - sys.othertaxes.wealth_tax = eq + sys.wealth.rates .+= = eq println( "VAT change is $eq") ubi_res = do_one_run( settings, @@ -105,7 +105,7 @@ end println( "needs tax rise of $eq") net_cost = ubi_cost - base_cost println( "net_cost=$net_cost" ) - println( "taxrates $(sys.othertaxes.wealth_tax*WEEKS_PER_YEAR*100)%") + println( "taxrates $(sys.wealth.rates.*100)%") println("ubi summary") CSV.write( "ubi_summary.income_summary_wealth.csv", ubi_summary.income_summary[1] ) # pretty_table( ubi_summary.income_summary[1][1,:] ) diff --git a/test/wealth_tests.jl b/test/wealth_tests.jl index 81b655bf..95f2727c 100644 --- a/test/wealth_tests.jl +++ b/test/wealth_tests.jl @@ -22,7 +22,8 @@ using StatsBase @testset "Wealth Tax Examples" begin sys = get_system( year=2023, scotland=true ) - sys.othertaxes.wealth_tax = 0.01 + sys.wealth.rates = [0.01] + sys.wealth.thresholds = [] hh = make_hh() println( INCOME_TAXES ) t = [0,0,0.0,0.0,90_000.00] @@ -31,7 +32,7 @@ using StatsBase hres = init_household_result( hh ) calculate_other_taxes!( hres, hh, sys.othertaxes ) aggregate!( hh, hres ) - @test hres.income[OTHER_TAX] ≈ max(0,w-sys.othertaxes.wealth_allowance) *sys.othertaxes.wealth_tax + @test hres.income[OTHER_TAX] ≈ max(0,w-sys.wealth.allowance) *sys.wealth.rates[1] println( "hres.bhc_net_income=$(hres.bhc_net_income)" ) end end @@ -55,7 +56,8 @@ end # FIXME 2019->2023 sys1 = get_system(year=2023, scotland=false) sys2 = deepcopy(sys1) - sys2.othertaxes.wealth_tax = 0.01/WEEKS_PER_YEAR + sys.wealth.rates = [0.01] + sys.wealth.thresholds = [] sys = [sys1, sys2] results = do_one_run( settings, sys, obs ) outf = summarise_frames!( results, settings )