class PassThrough():
    """
    Constructor for the PassThrough class.
    
    This contains the calculation of pass-through business income. All other
    components of pass-through taxation occur through Tax-Calculator.
    
    For now, a PassThrough object contains 6 different business entities:
        sole proprietorship, positive net income
        sole proprietorship, negative net income
        S corporation, positive net income
        S corporation, negative net income
        partnership, positive net income
        partnership, negative net income
    Therefore, the process for modeling the pass-through sector evolves in 
    two stages. The first, like for the Corporation class, produces a single
    Asset object, Debt object and earnings for the pass-through sector. Once
    these are calculated, they are split between each of the 6 entities. The
    results from these will later be used by the Investor class to distribute
    the changes in business income to individuals in Tax-Calculator. 
    
    The following functions apply to the sector as a whole:
        create_asset()
        create_earnings()
        create_debt()
       real_activity() 
    """
    
    def __init__(self, btax_params):
        # Store policy parameter objects
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')
        # Create Data object
        self.data = Data()
        # Create Asset object and calculate
        self.asset = Asset(self.btax_params, corp=False, data=self.data)
        self.asset.calc_all()
        # Create earnings forecast
        self.create_earnings()
    
    def create_earnings(self):
        """
        Creates the initial forecast for earnings. Static only.
        """
        # Get initial EBITDA for 2014, for those in net income positions
        sp_posinc2014 = np.array(self.data.sp_data['netinc'])[-1]
        part_posinc2014 = np.array(self.data.partner_data['netinc_total'])[-1]
        scorp_posinc2014 = np.array(self.data.Scorp_data['netinc_total'])[-1]
        # Get initial EBITDA for 2014, for those in net loss positions
        sp_neginc2014 = -np.array(self.data.sp_data['netloss'])[-1]
        part_neginc2014 = -np.array(self.data.partner_data['netloss_total'])[-1]
        scorp_neginc2014 = -np.array(self.data.Scorp_data['netloss_total'])[-1]
        # Get growth factor for noncorporate business income and apply it
        gfact_propinc = np.array(self.data.gfactors['propinc_nonfarm'])[1:]
        sp_posinc = sp_posinc2014 / gfact_propinc[0] * gfact_propinc
        part_posinc = part_posinc2014 / gfact_propinc[0] * gfact_propinc
        scorp_posinc = scorp_posinc2014 / gfact_propinc[0] * gfact_propinc
        sp_neginc = sp_neginc2014 / gfact_propinc[0] * gfact_propinc
        part_neginc = part_neginc2014 / gfact_propinc[0] * gfact_propinc
        scorp_neginc = scorp_neginc2014 / gfact_propinc[0] * gfact_propinc
        # Aggregate and save EBITDAs
        total_inc = (sp_posinc + sp_neginc + part_posinc + part_neginc +
                     scorp_posinc + scorp_neginc)
        earnings_result = pd.DataFrame({'year': range(2014,2028),
                                        'total': total_inc,
                                        'SchC_pos': sp_posinc,
                                        'SchC_neg': sp_neginc,
                                        'partner_pos': part_posinc,
                                        'partner_neg': part_neginc,
                                        'Scorp_pos': scorp_posinc, 
                                        'Scorp_neg': scorp_neginc})
        self.earnings = earnings_result
    
    def create_debt(self):
        """
        Creates the Debt object for the pass-through sector. 
        Note: create_asset must have already been called
        """
        self.debt = Debt(self.btax_params, self.asset.get_forecast(),
                         data=self.data, corp=False)
        self.debt.calc_all()
    
    def real_activity(self):
        """
        Produces a DataFrame of the pass-through sector's real activity.
        Real measures are:
            Capital stock
            Investment
            Depreciation (economic)
            Debt
            Interest paid
            Earnings
            Net income
            Cash flow
        Note that unlike for a corporation, the final real activity measures
        (net income and cash flow) are pre-tax, as these would be passed to
        units in Tax-Calculator. 
        """
        real_results = pd.DataFrame({'year': range(2014,2028),
                                     'Earnings': self.earnings['total']})
        real_results['Kstock'] = self.asset.get_forecast()
        real_results['Inv'] = self.asset.get_investment()
        real_results['Depr'] = self.asset.get_truedep()
        real_results['Debt'] = self.debt.get_debt()
        real_results['NIP'] = self.debt.get_nip()
        real_results['NetInc'] = real_results['Earnings'] - real_results['Depr'] - real_results['NIP']
        real_results['CashFlow'] = real_results['Earnings'] - real_results['Inv']
        self.real_results = real_results
    
    def calc_schC(self):
        """
        Calculates net income for sole proprietorships
        """
        SchC_results = pd.DataFrame({'year': range(2014,2028)})
        # Update earnings
        SchC_results['ebitda_pos'] = self.earnings['SchC_pos']
        SchC_results['ebitda_neg'] = self.earnings['SchC_neg']
        # Update tax depreciation
        SchC_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_sp_posinc)
        SchC_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_sp_neginc)
        # Update interest deduction
        SchC_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_sp_posinc)
        SchC_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_sp_neginc)
        # Update business net income
        SchC_results['netinc_pos'] = SchC_results['ebitda_pos'] - SchC_results['dep_pos'] - SchC_results['intded_pos']
        SchC_results['netinc_neg'] = SchC_results['ebitda_neg'] - SchC_results['dep_neg'] - SchC_results['intded_neg']
        self.SchC_results = SchC_results
    
    def calc_partner(self):
        """
        Calculates net income for partnerships
        """
        partner_results = pd.DataFrame({'year': range(2014,2028)})
        # Update earnings
        partner_results['ebitda_pos'] = self.earnings['partner_pos']
        partner_results['ebitda_neg'] = self.earnings['partner_neg']
        # Update tax depreciation
        partner_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_partner_posinc)
        partner_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_partner_neginc)
        # Update interest deduction
        partner_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_partner_posinc)
        partner_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_partner_neginc)
        # Update business net income
        partner_results['netinc_pos'] = partner_results['ebitda_pos'] - partner_results['dep_pos'] - partner_results['intded_pos']
        partner_results['netinc_neg'] = partner_results['ebitda_neg'] - partner_results['dep_neg'] - partner_results['intded_neg']
        self.partner_results = partner_results
    
    def calc_Scorp(self):
        """
        Calculates net income for S corporations
        """
        Scorp_results = pd.DataFrame({'year': range(2014,2028)})
        # Update earnings
        Scorp_results['ebitda_pos'] = self.earnings['Scorp_pos']
        Scorp_results['ebitda_neg'] = self.earnings['Scorp_neg']
        # Update tax depreciation
        Scorp_results['dep_pos'] = (self.asset.get_taxdep() * self.data.depshare_scorp_posinc)
        Scorp_results['dep_neg'] = (self.asset.get_taxdep() * self.data.depshare_scorp_neginc)
        # Update interest deduction
        Scorp_results['intded_pos'] = (self.debt.get_nid() * self.data.intshare_scorp_posinc)
        Scorp_results['intded_neg'] = (self.debt.get_nid() * self.data.intshare_scorp_neginc)
        # Update business net income
        Scorp_results['netinc_pos'] = Scorp_results['ebitda_pos'] - Scorp_results['dep_pos'] - Scorp_results['intded_pos']
        Scorp_results['netinc_neg'] = Scorp_results['ebitda_neg'] - Scorp_results['dep_neg'] - Scorp_results['intded_neg']
        self.Scorp_results = Scorp_results
    
    def calc_netinc(self):
        """
        Runs all calculations for each entity and saves the net income results.
        """
        self.calc_schC()
        self.calc_partner()
        self.calc_Scorp()
        netinc_results = pd.DataFrame({'year': range(2014,2028)})
        netinc_results['SchC_pos'] = self.SchC_results['netinc_pos']
        netinc_results['SchC_neg'] = self.SchC_results['netinc_neg']
        netinc_results['partner_pos'] = self.SchC_results['netinc_pos']
        netinc_results['partner_neg'] = self.SchC_results['netinc_neg']
        netinc_results['Scorp_pos'] = self.SchC_results['netinc_pos']
        netinc_results['Scorp_neg'] = self.SchC_results['netinc_neg']
        self.netinc_results = netinc_results
    
    def calc_static(self):
        """
        Runs the static calculations
        """
        self.create_debt()
        self.real_activity()
        self.calc_netinc()
    
    def update_legal(self, responses):
        """
        Updates the rescale_corp and rescale_noncorp associated with each
        Data associated with each object.
        """
        self.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp)
        self.asset.data.update_rescaling(responses.rescale_corp, responses.rescale_noncorp)
    
    def update_investment(self, responses):
        """
        Updates the Asset object to include investment response.
        """
        # First, save the capital stock by asset type and year (for earnings)
        self.old_capital_history = copy.deepcopy(self.asset.capital_history)
        self.asset.update_response(responses.investment_response)
        self.asset.calc_all()
    
    def update_earnings(self, responses):
        """
        Recalculates earnings using the old capital stock by asset type, the
        new capital stock by asset type (based on the investment response),
        and the marginal product of capital.
        """
        Kstock_base = copy.deepcopy(self.old_capital_history)
        Kstock_ref = copy.deepcopy(self.asset.capital_history)
        deltaK = Kstock_ref - Kstock_base
        changeEarnings = np.zeros((96, 14))
        
        for j in range(14): # for each year
            mpk = np.array(responses.investment_response['MPKnc' + str(j + 2014)])
            for i in range(96): # by asset
                changeEarnings[i,j] = deltaK[i,j] * mpk[i] * self.data.adjfactor_dep_noncorp
        deltaE = np.zeros(14)
        for j in range(14):
            deltaE[j] = changeEarnings[:, j].sum()
        earnings_old = np.array(self.earnings['total'])
        ebitda_chgfactor = (earnings_old + deltaE) * self.data.rescale_noncorp / earnings_old
        keylist = list(self.earnings)
        for key in keylist:
            self.earnings[key] = self.earnings[key] * ebitda_chgfactor
    
    def update_debt(self, responses):
        """
        Replaces the Debt object to use the new asset forecast and Data
        """
        pctch_delta = np.array(responses.debt_response['pchDelta_corp'])
        self.debt = Debt(self.btax_params, self.asset.get_forecast(),
                         data=self.data, response=pctch_delta, corp=False)
        self.debt.calc_all()
    
    def apply_responses(self, responses):
        """
        Updates Data, Asset, earnings, and Debt to include 
        responses.
        """
        assert isinstance(responses, Response)
        self.update_legal(responses)
        self.update_investment(responses)
        self.update_earnings(responses)
        self.update_debt(responses)
        self.real_activity()
        self.calc_netinc()
Exemple #2
0
class Corporation():
    """
    Constructor for the Corporation class.
    This contains both the real and tax information relevant to the
    corporate income tax.
    """
    def __init__(self, btax_params):
        # Store policy parameter objects
        if isinstance(btax_params, pd.DataFrame):
            self.btax_params = btax_params
        else:
            raise ValueError('btax_params must be DataFrame')
        # Create Data object
        self.data = Data()
        # Create Asset object and calculate
        self.asset = Asset(self.btax_params, corp=True, data=self.data)
        self.asset.calc_all()
        # Create DomesticMNE object
        self.dmne = DomesticMNE(self.btax_params)
        self.dmne.calc_all()
        # Create earnings forecast
        self.create_earnings()

    def create_debt(self):
        """
        Creates the Debt object for the Corporation.
        Note: create_asset must have already been called
        """
        self.debt = Debt(self.btax_params,
                         self.asset.get_forecast(),
                         data=self.data,
                         corp=True)
        self.debt.calc_all()

    def create_earnings(self):
        """
        Creates the initial forecast for earnings. Static only.
        """
        # Grab forecasts of profit growth
        earnings_forecast = np.asarray(self.data.gfactors['profit'])
        gfacts = earnings_forecast[1:] / earnings_forecast[0]
        # 2013 values for non-modeled revenues
        taxitems = np.array(self.data.corp_tax2013['ALL'])
        receipts = taxitems[4] * gfacts
        rent_inc = taxitems[7] * gfacts
        royalties = taxitems[8] * gfacts
        capgains = (taxitems[9] + taxitems[10] + taxitems[11] -
                    taxitems[32]) * gfacts
        domestic_divs = taxitems[12] * gfacts
        other_recs = taxitems[14] * gfacts
        # 2013 values for non-modeled deductions and credits
        cogs = taxitems[16] * gfacts
        execcomp = taxitems[17] * gfacts
        wages = taxitems[18] * gfacts
        repairs = taxitems[19] * gfacts
        baddebt = taxitems[20] * gfacts
        rent_paid = taxitems[21] * gfacts
        statelocaltax = taxitems[22] * gfacts
        charity = taxitems[24] * gfacts
        amortization = taxitems[25] * gfacts
        depletion = taxitems[27] * gfacts
        advertising = taxitems[28] * gfacts
        pensions = taxitems[29] * gfacts
        benefits = taxitems[30] * gfacts
        sec199_base = taxitems[31] * gfacts
        other_ded = taxitems[33] * gfacts
        gbc = taxitems[42] * gfacts
        # Save unodeled tax items
        self.revenues = pd.DataFrame({
            'year': range(START_YEAR, END_YEAR + 1),
            'receipts': receipts,
            'rent': rent_inc,
            'royalties': royalties,
            'capgains': capgains,
            'domestic_divs': domestic_divs,
            'other': other_recs
        })
        self.deductions = pd.DataFrame({
            'year': range(START_YEAR, END_YEAR + 1),
            'cogs': cogs,
            'execcomp': execcomp,
            'wages': wages,
            'repairs': repairs,
            'baddebt': baddebt,
            'rent': rent_paid,
            'statelocaltax': statelocaltax,
            'charity': charity,
            'amortization': amortization,
            'depletion': depletion,
            'advertising': advertising,
            'pensions': pensions,
            'benefits': benefits,
            'sec199share': sec199_base,
            'other': other_ded
        })
        self.credits = pd.DataFrame({
            'year': range(START_YEAR, END_YEAR + 1),
            'gbc': gbc
        })

    def file_taxes(self):
        """
        Creates the CorpTaxReturn object.
        """
        self.taxreturn = CorpTaxReturn(self.btax_params,
                                       self.revenues,
                                       self.deductions,
                                       self.credits,
                                       dmne=self.dmne,
                                       data=self.data,
                                       assets=self.asset,
                                       debts=self.debt)
        self.taxreturn.calc_all()

    def real_activity(self):
        """
        Produces a DataFrame of the corporation's real activity.
        Real measures are:
            Capital stock
            Investment
            Depreciation (economic)
            Net debt
            Net interest paid
            Earnings
            Tax liability
            Net income
            Cash flow
        """

        real_results = pd.DataFrame({'year': range(START_YEAR, END_YEAR + 1)})
        real_results['Earnings'] = (
            self.revenues['receipts'] + self.revenues['rent'] +
            self.revenues['royalties'] + self.revenues['capgains'] +
            self.revenues['domestic_divs'] + self.revenues['other'] -
            self.deductions['cogs'] - self.deductions['execcomp'] -
            self.deductions['wages'] - self.deductions['repairs'] -
            self.deductions['baddebt'] - self.deductions['rent'] -
            self.deductions['charity'] - self.deductions['depletion'] -
            self.deductions['advertising'] - self.deductions['pensions'] -
            self.deductions['benefits'] - self.deductions['other'] +
            self.dmne.dmne_results['foreign_directinc'] +
            self.dmne.dmne_results['foreign_indirectinc'])
        real_results['Kstock'] = self.asset.get_forecast()
        real_results['Inv'] = self.asset.get_investment()
        real_results['Depr'] = self.asset.get_truedep()
        real_results['Debt'] = self.debt.get_debt()
        real_results['NIP'] = self.debt.get_nip()
        real_results['Tax'] = self.taxreturn.get_tax()
        real_results['NetInc'] = (real_results['Earnings'] -
                                  real_results['Depr'] - real_results['NIP'] -
                                  real_results['Tax'] -
                                  self.dmne.dmne_results['foreign_tax'] -
                                  self.deductions['statelocaltax'])
        real_results['CashFlow'] = (real_results['Earnings'] -
                                    real_results['Inv'] - real_results['Tax'] -
                                    self.dmne.dmne_results['foreign_tax'] -
                                    self.deductions['statelocaltax'])
        self.real_results = real_results

    def calc_static(self):
        """
        Runs the static calculations.
        """
        self.create_debt()
        self.file_taxes()
        self.real_activity()

    def update_legal(self, responses):
        """
        Updates the rescale_corp and rescale_noncorp associated with each
        Data associated with each object.
        """
        self.data.update_rescaling(responses.rescale_corp,
                                   responses.rescale_noncorp)
        self.asset.data.update_rescaling(responses.rescale_corp,
                                         responses.rescale_noncorp)

    def update_investment(self, responses):
        """
        Updates the Asset object to include investment response.
        """
        # First, save the capital stock by asset type and year (for earnings)
        self.old_capital_history = copy.deepcopy(self.asset.capital_history)
        self.asset.update_response(responses.investment_response)
        self.asset.calc_all()

    def update_repatriation(self, responses):
        """
        Updates the DomesticMNE object to include the repatriation response.
        Also updates profits to reflect this response.
        """
        # First, save current foreign earnings
        self.dmne.update_profits(responses.repatriation_response,
                                 responses.shifting_response)
        self.dmne.calc_all()

    def update_earnings(self, responses):
        """
        Recalculates earnings using the old capital stock by asset type, the
        new capital stock by asset type (based on the investment response),
        and the marginal product of capital.
        """
        Kstock_base = copy.deepcopy(self.old_capital_history)
        Kstock_ref = copy.deepcopy(self.asset.capital_history)
        changeEarnings = np.zeros((95, NUM_YEARS))
        for iyr in range(NUM_YEARS):  # for each year
            ystr = str(iyr + START_YEAR)
            mpk = np.array(responses.investment_response['MPKc' + ystr])
            for i in range(95):  # by asset
                changeEarnings[i, iyr] = (Kstock_ref[ystr][i] -
                                          Kstock_base[ystr][i]) * mpk[i]
        deltaE = np.zeros(NUM_YEARS)
        for iyr in range(NUM_YEARS):
            deltaE[iyr] = changeEarnings[:, iyr].sum()
        # Update new earnings
        self.revenues['receipts'] = self.revenues['receipts'] + deltaE

    def update_debt(self, responses):
        """
        Replaces the Debt object to use the new asset forecast and Data
        """
        pctch_delta = np.array(responses.debt_response['pchDelta_corp'])
        self.debt = Debt(self.btax_params,
                         self.asset.get_forecast(),
                         data=self.data,
                         response=pctch_delta,
                         corp=True)
        self.debt.calc_all()

    def apply_responses(self, responses):
        """
        Updates Data, Asset, earnings, Debt and CorpTaxReturn to include
        responses. Then calc_all() for each object.
        """
        assert isinstance(responses, Response)
        self.update_legal(responses)
        self.update_investment(responses)
        self.update_repatriation(responses)
        self.update_earnings(responses)
        self.update_debt(responses)
        self.file_taxes()
        self.real_activity()

    def get_netinc(self):
        """
        Returns an array of the corporation's net income (after-tax).
        """
        netinc = np.array(self.real_results['NetInc'])
        return netinc

    def get_taxrev(self):
        """
        Returns an array of the corporation's tax liability.
        """
        taxrev = np.array(self.real_results['Tax'])
        return taxrev