Changeset - 5a3ee2458905
[Not reviewed]
0 2 0
Brett Smith - 4 years ago 2020-08-18 20:26:12
brettcsmith@brettcsmith.org
balance_sheet: Correct "release from restrictions" calculation.

The old version was causing Income:Donations:Released postings to be
"double-released." This version gets the bottom line numbers for
Net Assets With/out Donor Restrictions match the corresponding numbers
in the fund report.
2 files changed with 8 insertions and 6 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/balance_sheet.py
Show inline comments
...
 
@@ -372,136 +372,138 @@ class Report(core.BaseODS[Sequence[None], None]):
 
    def write_financial_position(self) -> None:
 
        self.start_sheet("Financial Position")
 
        balance_kwargs: Sequence[KWArgs] = [
 
            {'period': Period.ANY},
 
            {'period': Period.THRU_PRIOR},
 
        ]
 

	
 
        asset_totals = self.write_classifications_by_account('Assets', balance_kwargs)
 
        self.write_totals_row(
 
            "Total Assets", asset_totals, stylename=self.style_bottomline,
 
        )
 
        self.add_row()
 
        self.add_row()
 

	
 
        liabilities = self.write_classifications_by_account('Liabilities', balance_kwargs)
 
        self.write_totals_row(
 
            "Total Liabilities", liabilities, stylename=self.style_totline,
 
        )
 
        self.add_row()
 
        self.add_row()
 

	
 
        equity_totals = [core.MutableBalance() for _ in balance_kwargs]
 
        self.add_row(self.string_cell("Net Assets", stylename=self.style_bold))
 
        self.add_row()
 
        for fund in [Fund.UNRESTRICTED, Fund.RESTRICTED]:
 
            preposition = "Without" if fund is Fund.UNRESTRICTED else "With"
 
            row = self.add_row(self.string_cell(f"{preposition} donor restrictions"))
 
            for kwargs, total_bal in zip(balance_kwargs, equity_totals):
 
                balance = -self.balances.total(account=EQUITY_ACCOUNTS, fund=fund, **kwargs)
 
                row.addElement(self.balance_cell(balance))
 
                total_bal += balance
 
        self.write_totals_row(
 
            "Total Net Assets", equity_totals, stylename=self.style_subtotline,
 
        )
 
        self.write_totals_row(
 
            "Total Liabilities and Net Assets",
 
            liabilities, equity_totals,
 
            stylename=self.style_bottomline,
 
        )
 

	
 
    def write_activities(self) -> None:
 
        self.start_sheet(
 
            "Activities",
 
            ["Without Donor", "Restrictions"],
 
            ["With Donor", "Restrictions"],
 
            totals_prefix=[f"Total {self.period_desc} Ended"],
 
        )
 
        bal_kwargs: Sequence[Dict[str, Any]] = [
 
            {'period': Period.PERIOD, 'fund': Fund.UNRESTRICTED},
 
            {'period': Period.PERIOD, 'fund': Fund.RESTRICTED},
 
            {'period': Period.PERIOD},
 
            {'period': Period.PRIOR},
 
        ]
 

	
 
        self.add_row(self.string_cell("Support and Revenue", stylename=self.style_bold))
 
        self.add_row()
 
        income_totals = self.write_classifications_by_account(
 
            'Income', bal_kwargs, (self.C_SATISFIED,),
 
        )
 
        self.write_totals_row("", income_totals, stylename=self.style_subtotline)
 
        self.add_row()
 
        self.add_row(
 
            self.string_cell("Net Assets released from restrictions:"),
 
        )
 
        released = self.balances.total(
 
        released_expenses = self.balances.total(
 
            account='Expenses', period=Period.PERIOD, fund=Fund.RESTRICTED,
 
        ) - self.balances.total(
 
            classification=self.C_SATISFIED, period=Period.PERIOD, fund=Fund.RESTRICTED,
 
        )
 
        other_totals = [core.MutableBalance() for _ in bal_kwargs]
 
        other_totals[0] += released
 
        other_totals[1] -= released
 
        other_totals[0] += released_expenses - self.balances.total(
 
            classification=self.C_SATISFIED, period=Period.PERIOD, fund=Fund.UNRESTRICTED,
 
        )
 
        other_totals[1] -= released_expenses + self.balances.total(
 
            classification=self.C_SATISFIED, period=Period.PERIOD, fund=Fund.RESTRICTED,
 
        )
 
        self.write_totals_row(self.C_SATISFIED, other_totals)
 
        self.write_totals_row(
 
            "Total Support and Revenue",
 
            income_totals, other_totals,
 
            stylename=self.style_totline,
 
        )
 

	
 
        period_expenses = core.MutableBalance()
 
        prior_expenses = core.MutableBalance()
 
        self.add_row()
 
        self.add_row(self.string_cell("Expenses", stylename=self.style_bold))
 
        self.add_row()
 
        for text, type_value in [
 
                ("Program services", 'program'),
 
                ("Management and administrative services", 'management'),
 
                ("Fundraising", 'fundraising'),
 
        ]:
 
            period_bal = self.balances.total(
 
                account='Expenses', period=Period.PERIOD, post_type=type_value,
 
            )
 
            prior_bal = self.balances.total(
 
                account='Expenses', period=Period.PRIOR, post_type=type_value,
 
            )
 
            self.write_totals_row(text, [
 
                period_bal,
 
                self.NO_BALANCE,
 
                period_bal,
 
                prior_bal,
 
            ], leading_rows=0)
 
            period_expenses += period_bal
 
            prior_expenses += prior_bal
 
        period_bal = self.balances.total(account='Expenses', period=Period.PERIOD)
 
        if (period_expenses - period_bal).clean_copy(1).is_zero():
 
            period_bal = period_expenses
 
        else:
 
            logger.warning("Period functional expenses do not match total; math in columns B+D is wrong")
 
        prior_bal = self.balances.total(account='Expenses', period=Period.PRIOR)
 
        if (prior_expenses - prior_bal).clean_copy(1).is_zero():
 
            prior_bal = prior_expenses
 
        else:
 
            logger.warning("Prior functional expenses do not match total; math in column E is wrong")
 
        self.write_totals_row("Total Expenses", [
 
            period_bal,
 
            self.NO_BALANCE,
 
            period_bal,
 
            prior_bal,
 
        ], stylename=self.style_totline, leading_rows=0)
 

	
 
        other_totals[0] -= period_bal
 
        other_totals[2] -= period_bal
 
        other_totals[3] -= prior_bal
 
        self.write_totals_row("Change in Net Assets", income_totals, other_totals)
 

	
 
        for kwargs in bal_kwargs:
 
            if kwargs['period'] is Period.PERIOD:
 
                kwargs['period'] = Period.THRU_MIDDLE
 
            else:
 
                kwargs['period'] = Period.OPENING
 
        equity_totals = [
 
            -self.balances.total(account=EQUITY_ACCOUNTS, **kwargs)
 
            for kwargs in bal_kwargs
 
        ]
 
        self.write_totals_row("Beginning Net Assets", equity_totals)
 
        self.write_totals_row(
setup.py
Show inline comments
 
#!/usr/bin/env python3
 

	
 
from setuptools import setup
 

	
 
setup(
 
    name='conservancy_beancount',
 
    description="Plugin, library, and reports for reading Conservancy's books",
 
    version='1.8.4',
 
    version='1.8.5',
 
    author='Software Freedom Conservancy',
 
    author_email='info@sfconservancy.org',
 
    license='GNU AGPLv3+',
 

	
 
    install_requires=[
 
        'babel>=2.6',  # Debian:python3-babel
 
        'beancount>=2.2',  # Debian:beancount
 
        'GitPython>=2.0',  # Debian:python3-git
 
        # 1.4.1 crashes when trying to save some documents.
 
        'odfpy>=1.4.0,!=1.4.1',  # Debian:python3-odf
 
        'PyYAML>=3.0',  # Debian:python3-yaml
 
        'regex',  # Debian:python3-regex
 
        'rt>=2.0',
 
    ],
 
    setup_requires=[
 
        'pytest-mypy',
 
        'pytest-runner',  # Debian:python3-pytest-runner
 
    ],
 
    tests_require=[
 
        'mypy>=0.770',  # Debian:python3-mypy
 
        'pytest',  # Debian:python3-pytest
 
    ],
 

	
 
    packages=[
 
        'conservancy_beancount',
 
        'conservancy_beancount.plugin',
 
        'conservancy_beancount.reports',
 
    ],
 
    entry_points={
 
        'console_scripts': [
 
            'accrual-report = conservancy_beancount.reports.accrual:entry_point',
 
            'balance-sheet-report = conservancy_beancount.reports.balance_sheet:entry_point',
 
            'extract-odf-links = conservancy_beancount.tools.extract_odf_links:entry_point',
 
            'fund-report = conservancy_beancount.reports.fund:entry_point',
 
            'ledger-report = conservancy_beancount.reports.ledger:entry_point',
 
            'opening-balances = conservancy_beancount.tools.opening_balances:entry_point',
 
        ],
 
    },
 
)
0 comments (0 inline, 0 general)