[
  {
    "path": ".coveragerc",
    "content": "[run]\nsource = accounting\nomit = *migrations*\n"
  },
  {
    "path": ".gitignore",
    "content": "## Byte-compiled\n__pycache__/\n*.py[cod]\n*.egg-info\n/dist/\n/build/\n\n## Database\n*.sqlite3\n\n## Translations\n*.mo\n\n## Components\ncomponents/\n\n## Testing\n.coverage\n.noseids\ncoverage.xml\nviolations.txt\nnosetests.xml\n/htmlcov/*\n"
  },
  {
    "path": ".travis.yml",
    "content": "# Use the newer container-based infrastructure\n# http://docs.travis-ci.com/user/workers/container-based-infrastructure/\nsudo: false\n\n# Cache pip downloads\ncache:\n    directories:\n      - $HOME/.pip-cache/\n\nlanguage: python\n\npython:\n    - '3.3'\n    - '3.4'\n\ninstall:\n    - pip install -e . -r requirements.txt\n\nscript:\n    - make travis\n\nafter_success:\n    - coveralls\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2013 Pierre Dulac (https://dulacp.com/)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# These targets are not files\n.PHONY: contribute travis test lint coverage\n\nclean:\n\t# Remove files not in source control\n\tfind . -type f -name \"*.pyc\" -delete\n\trm -rf nosetests.xml coverage.xml htmlcov violations.txt\n\ntodo:\n\t# Look for areas of the code that need updating when some event has taken place\n\tgrep --exclude-dir=components -rnH TODO reqs\n\tgrep --exclude-dir=components -rnH TODO accounting\n\tgrep --exclude-dir=components -rnH TODO tests\n\npublish:\n\tgit push --tag origin master\n\trm -rf dist/*\n\tpython setup.py sdist\n\ttwine upload dist/*\n\n\n## Testing\n\nlint:\n\t./lint.sh\n\ntest:\n\t./runtests.py tests\n\ncoverage:\n\tcoverage run ./runtests.py --with-xunit tests\n\tcoverage xml -i\n\n# This target is run on Travis.ci. We lint, test and build.\n# We don't call 'install' first as that is run as a separate part\n# of the Travis build process.\ntravis: lint coverage\n\n\n## Install / Upgrade\n\ninstall:\n\tpip install -r requirements.txt\n\nupgrade:\n\tpip install --upgrade -r requirements.txt\n"
  },
  {
    "path": "README.rst",
    "content": "django-accounting\n=================\n\n    In the beginning God created man, and the costs followed afterwards.\n\n|Build Status| |Coverage Status|\n\nCheck the associated project\n`Accountant <https://github.com/dulacp/Accountant>`__, a concrete\nintegration of the *django-accounting* application that you can deploy\nwith one click to Heroku.\n\nRequirements\n------------\n\n-  Python 3.x\n-  Django 1.7+\n-  `dj-static <https://github.com/kennethreitz/dj-static>`__\n\nFeatures supported\n------------------\n\n*with inspiration from already existing very good services (Xero,\nFreshbooks, etc)*\n\n    Those crossed are not yet supported\n\nBooks\n~~~~~\n\n-  **Estimating** generate estimates that can lead to an invoice or not\n-  **Invoicing** generate invoices\n-  **Billing** share the maximum of logic with the invoicing system\n-  **Payments** to track partial/complete payments of invoices and bills\n-  **ExpenseClaim** for employees of organizations that used their\n   personnal accounts\n-  **Dashboard / Current balance** displayed the current balance\n-  **Dashboard / Overdued invoices & bills** to track what's late\n\nClients\n~~~~~~~\n\n-  **Creation/Update**\n-  [STRIKEOUT:**Deletion** inform the user of the cascade deletion of\n   invoices and bills]\n-  **Professional address** specify the address on the client model\n-  **Linked to organization** to implicitly create the bill when\n   cross-invoicing between organizations\n\nReports\n~~~~~~~\n\n-  **Profit and Loss** to know how much you've collected, and how much\n   you've spent\n-  **Tax Report** to know how much you need to keep for taxes\n   declarations\n-  **Payroll Report** to know how much you need to keep for payroll\n   taxes\n-  **Invoice details Report** to understand the calculations that lead\n   to the tax report and the payroll report\n-  [STRIKEOUT:**Expense claims Report** to compute what the company owes\n   to whom quickly]\n\nContact\n-------\n\n| `Pierre Dulac <http://github.com/dulacp>`_\n| `@_dulacp <https://twitter.com/_dulacp>`_\n\nLicense\n-------\n\nAccounting is available under the MIT license. See the LICENSE file for\nmore info.\n\n.. |Build Status| image:: https://travis-ci.org/dulacp/django-accounting.svg\n   :target: https://travis-ci.org/dulacp/django-accounting\n.. |Coverage Status| image:: https://coveralls.io/repos/dulacp/django-accounting/badge.svg\n   :target: https://coveralls.io/r/dulacp/django-accounting\n"
  },
  {
    "path": "accounting/__init__.py",
    "content": "import os\n\n# Use 'final' as the 4th element to indicate\n# a full release\n\nVERSION = (0, 2, 10)\n\n\ndef get_short_version():\n    return '%s.%s' % (VERSION[0], VERSION[1])\n\n\ndef get_version():\n    version = '%s.%s' % (VERSION[0], VERSION[1])\n    # Append 3rd digit if > 0\n    if VERSION[2]:\n        version = '%s.%s' % (version, VERSION[2])\n    return version\n\n\n# Cheeky setting that allows each template to be accessible by two paths.\n# Eg: the template 'accounting/templates/accounting/base.html' can be accessed\n# via both 'base.html' and 'accounting/base.html'.  This allows Accounting's\n# templates to be extended by templates with the same filename\nACCOUNTING_MAIN_TEMPLATE_DIR = os.path.join(\n    os.path.dirname(os.path.abspath(__file__)), 'templates/accounting')\n\n\nACCOUNTING_APPS = (\n    'accounting',\n    'accounting.libs',\n    'accounting.apps.connect',\n    'accounting.apps.people',\n    'accounting.apps.books',\n    'accounting.apps.reports',\n\n    # Third party apps that accounting depends on\n    'bootstrap3',\n    'django_select2',\n    'datetimewidget',\n)\n\n\nACCOUNTING_TEMPLATE_CONTEXT_PROCESSORS = (\n    'accounting.apps.context_processors.metadata',\n    'accounting.apps.books.context_processors.organizations',\n)\n\n\nACCOUNTING_MIDDLEWARE_CLASSES = (\n    'accounting.apps.books.middlewares.AutoSelectOrganizationMiddleware',\n)\n\n\ndef get_apps():\n    return ACCOUNTING_APPS\n"
  },
  {
    "path": "accounting/apps/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/books/__init__.py",
    "content": "default_app_config = 'accounting.apps.books.apps.FrenchBooksConfig'\n"
  },
  {
    "path": "accounting/apps/books/admin.py",
    "content": "from django.contrib import admin\nfrom django.contrib.contenttypes.admin import GenericTabularInline\n\nfrom . import models\n\n\n@admin.register(models.Organization)\nclass OrganizationAdmin(admin.ModelAdmin):\n    pass\n\n\n@admin.register(models.TaxRate)\nclass TaxRateAdmin(admin.ModelAdmin):\n    pass\n\n\nclass PaymentInline(GenericTabularInline):\n    model = models.Payment\n    extra = 1\n\n\nclass EstimateLineInline(admin.TabularInline):\n    model = models.EstimateLine\n    extra = 1\n\n\n@admin.register(models.Estimate)\nclass EstimateAdmin(admin.ModelAdmin):\n    inlines = (\n        EstimateLineInline,\n    )\n    readonly = (\n        'total_incl_tax', 'total_excl_tax',\n    )\n\n\nclass InvoiceLineInline(admin.TabularInline):\n    model = models.InvoiceLine\n    extra = 1\n\n\n@admin.register(models.Invoice)\nclass InvoiceAdmin(admin.ModelAdmin):\n    inlines = (\n        InvoiceLineInline,\n        PaymentInline,\n    )\n    readonly = (\n        'total_incl_tax', 'total_excl_tax',\n    )\n\n\nclass BillLineInline(admin.TabularInline):\n    model = models.BillLine\n    extra = 1\n\n\n@admin.register(models.Bill)\nclass BillAdmin(admin.ModelAdmin):\n    inlines = (\n        BillLineInline,\n        PaymentInline,\n    )\n    readonly = (\n        'total_incl_tax', 'total_excl_tax',\n    )\n\n\nclass ExpenseClaimLineInline(admin.TabularInline):\n    model = models.ExpenseClaimLine\n    extra = 1\n\n\n@admin.register(models.ExpenseClaim)\nclass ExpenseClaimAdmin(admin.ModelAdmin):\n    inlines = (\n        ExpenseClaimLineInline,\n        PaymentInline,\n    )\n    readonly = (\n        'total_incl_tax', 'total_excl_tax',\n    )\n\n\n@admin.register(models.Payment)\nclass PaymentAdmin(admin.ModelAdmin):\n    pass\n"
  },
  {
    "path": "accounting/apps/books/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass FrenchBooksConfig(AppConfig):\n    name = \"accounting.apps.books\"\n    verbose_name = \"Accounting Books\"\n"
  },
  {
    "path": "accounting/apps/books/calculators.py",
    "content": "from decimal import Decimal as D\n\nfrom accounting.libs.intervals import TimeInterval\n\n\nclass SalePaymentLineProcessed(object):\n    sale = None\n    payment = None\n    amount_excl_tax = None\n    tax_rate = None\n\n    def __init__(self, sale, payment):\n        self.sale = sale\n        self.payment = payment\n        self.amount_excl_tax = D('0')\n\n    def process(self):\n        for line in self.sale.lines.all():\n            tax_rate = line.tax_rate\n            line_factor = line.line_price_incl_tax / self.sale.total_incl_tax\n            portion_amount = self.payment.amount * line_factor\n            portion_amount_excl_tax = portion_amount / (D('1') + tax_rate.rate)\n\n            if self.tax_rate is None:\n                self.tax_rate = tax_rate\n            elif self.tax_rate.pk != tax_rate.pk:\n                raise NotImplementedError(\"the system doesn't support \"\n                                          \"yet multiple tax rates \"\n                                          \"into a same invoice\")\n\n            self.amount_excl_tax += portion_amount_excl_tax\n\n\nclass ProfitsLossCalculator(object):\n    \"\"\"\n    Compute the profits value in the most effective way\n    considering the sum type (collected / accurial)\n    and the given period of time.\n    \"\"\"\n\n    # TODO support Accurial sum\n    # SUM_TYPE_ACCURIAL = 'accurial'\n    SUM_TYPE_COLLECTED = 'collected'\n    SUM_TYPE_CHOICES = (\n        # SUM_TYPE_ACCURIAL,\n        SUM_TYPE_COLLECTED,\n    )\n\n    organization = None\n\n    def __init__(self, organization, sum_type=SUM_TYPE_COLLECTED,\n                 start=None, end=None):\n        assert sum_type in self.SUM_TYPE_CHOICES, \"Not a supported sum type\"\n        self.organization = organization\n        self.period = TimeInterval(start=start, end=end)\n\n    def process_generator(self, sales_queryset):\n        \"\"\"\n        Generator that computes the profits/loss for each sale payment objects\n\n        It's a complex machine because of the partial payments that need\n        to be taken into account with the sum type Collected.\n\n        So it yield a tuple similar to\n\n            (sale, payment, amount)\n\n        \"\"\"\n        sales_queryset = sales_queryset.filter(organization=self.organization)\n\n        if self.period.start:\n            sales_queryset = (sales_queryset\n                .filter(payments__date_paid__gte=self.period.start))\n\n        if self.period.end:\n            sales_queryset = (sales_queryset\n                .filter(payments__date_paid__lte=self.period.end))\n\n        # optimize the queryset\n        sales_queryset = (sales_queryset\n            .prefetch_related(\n                'lines',\n                'lines__tax_rate',\n                'payments')\n            .distinct())\n\n        for sale in sales_queryset:\n            for pay in sale.payments.all():\n\n                # NB: even with the queryset filters we can still get payments\n                #     outside the period interval [start, end], because\n                #     `self.payements.all()` is uncorrelated with the filters\n                if self.period.start and pay.date_paid < self.period.start:\n                    continue\n                if self.period.end and pay.date_paid > self.period.end:\n                    continue\n\n                output = SalePaymentLineProcessed(sale, pay)\n                output.process()\n\n                yield output\n\n    def total_collected(self):\n        collected = D('0')\n        invoices_queryset = self.organization.invoices.all()\n        for output in self.process_generator(invoices_queryset):\n            collected += output.amount_excl_tax\n        return collected\n\n    def total_expenses(self):\n        expenses = D('0')\n        bills_queryset = self.organization.bills.all()\n        for output in self.process_generator(bills_queryset):\n            expenses += output.amount_excl_tax\n        return expenses\n\n    def profits(self):\n        return self.total_collected() - self.total_expenses()\n"
  },
  {
    "path": "accounting/apps/books/context_processors.py",
    "content": "from .utils import organization_manager\n\n\ndef organizations(request):\n    \"\"\"\n    Add some generally useful metadata to the template context\n    \"\"\"\n    # selected organization\n    orga = organization_manager.get_selected_organization(request)\n\n    # all user authorized organizations\n    if not request.user or not request.user.is_authenticated():\n        user_organizations = None\n    else:\n        user = request.user\n        user_organizations = organization_manager.get_user_organizations(user)\n\n    return {\n        'user_organizations': user_organizations,\n        'selected_organization': orga,\n    }\n"
  },
  {
    "path": "accounting/apps/books/forms.py",
    "content": "from django.forms import ModelForm, BaseInlineFormSet\nfrom django.forms.models import inlineformset_factory\n\nfrom .models import (\n    Organization,\n    TaxRate,\n    Estimate,\n    EstimateLine,\n    Invoice,\n    InvoiceLine,\n    Bill,\n    BillLine,\n    ExpenseClaim,\n    ExpenseClaimLine,\n    Payment)\nfrom .utils import organization_manager\nfrom accounting.apps.people.models import Client, Employee\nfrom accounting.apps.people.forms import UserMultipleChoices\n\nfrom django_select2.fields import AutoModelSelect2Field\nfrom datetimewidget.widgets import DateWidget\n\n\nclass RequiredFirstInlineFormSet(BaseInlineFormSet):\n    \"\"\"\n    Used to make empty formset forms required\n    See http://stackoverflow.com/questions/2406537/django-formsets-\\\n        make-first-required/4951032#4951032\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        if len(self.forms) > 0:\n            first_form = self.forms[0]\n            first_form.empty_permitted = False\n\n\nclass SaleInlineLineFormSet(RequiredFirstInlineFormSet):\n\n    def __init__(self, *args, **kwargs):\n        orga = kwargs.pop('organization')\n        super().__init__(*args, **kwargs)\n        for f in self.forms:\n            f.restrict_to_organization(orga)\n\n\nclass ClientForOrganizationChoices(AutoModelSelect2Field):\n    queryset = Client.objects.all()\n    search_fields = (\n        'name__icontains',\n    )\n\n    def prepare_qs_params(self, request, search_term, search_fields):\n        \"\"\"restrict to the current selected organization\"\"\"\n        params = super().prepare_qs_params(request, search_term, search_fields)\n        orga = organization_manager.get_selected_organization(request)\n        params['and']['organization'] = orga\n        return params\n\n\nclass EmployeeForOrganizationChoices(AutoModelSelect2Field):\n    queryset = Employee.objects.all()\n    search_fields = (\n        'first_name__icontains',\n        'last_name__icontains',\n        'email__icontains',\n    )\n\n    def prepare_qs_params(self, request, search_term, search_fields):\n        \"\"\"restrict to the current selected organization\"\"\"\n        params = super().prepare_qs_params(request, search_term, search_fields)\n        orga = organization_manager.get_selected_organization(request)\n        params['and']['organization'] = orga\n        return params\n\n\nclass OrganizationForm(ModelForm):\n    members = UserMultipleChoices(required=False)\n\n    class Meta:\n        model = Organization\n        fields = (\n            \"display_name\",\n            \"legal_name\",\n            \"members\",\n        )\n\n\nclass TaxRateForm(ModelForm):\n    class Meta:\n        model = TaxRate\n        fields = (\n            \"name\",\n            \"rate\",\n        )\n\n\nclass RestrictLineFormToOrganizationMixin(object):\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        instance = kwargs.get('instance', None)\n        if instance:\n            if isinstance(instance, InvoiceLine):\n                organization = instance.invoice.organization\n            elif isinstance(instance, BillLine):\n                organization = instance.bill.organization\n            elif isinstance(instance, ExpenseClaimLine):\n                organization = instance.expense_claim.organization\n            else:\n                raise NotImplementedError(\"The mixin has been applied to a \"\n                                          \"form model that is not supported\")\n            self.restrict_to_organization(organization)\n\n    def restrict_to_organization(self, organization):\n        self.fields['tax_rate'].queryset = organization.tax_rates.all()\n\n\nclass EstimateForm(ModelForm):\n    client = ClientForOrganizationChoices()\n\n    class Meta:\n        model = Estimate\n        fields = (\n            \"number\",\n            \"client\",\n            \"date_issued\",\n            \"date_dued\",\n        )\n        widgets = {\n            'date_issued': DateWidget(\n                attrs={'id': \"id_date_issued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n            'date_dued': DateWidget(\n                attrs={'id': \"id_date_dued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n        }\n\n\nclass EstimateLineForm(RestrictLineFormToOrganizationMixin,\n                       ModelForm):\n    class Meta:\n        model = EstimateLine\n        fields = (\n            \"label\",\n            \"description\",\n            \"unit_price_excl_tax\",\n            \"quantity\",\n            \"tax_rate\",\n        )\n\n\nEstimateLineFormSet = inlineformset_factory(Estimate,\n                                            EstimateLine,\n                                            form=EstimateLineForm,\n                                            formset=SaleInlineLineFormSet,\n                                            min_num=1,\n                                            extra=0)\n\n\nclass InvoiceForm(ModelForm):\n    client = ClientForOrganizationChoices()\n\n    class Meta:\n        model = Invoice\n        fields = (\n            \"number\",\n            \"client\",\n            \"date_issued\",\n            \"date_dued\",\n        )\n        widgets = {\n            'date_issued': DateWidget(\n                attrs={'id': \"id_date_issued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n            'date_dued': DateWidget(\n                attrs={'id': \"id_date_dued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n        }\n\n\nclass InvoiceLineForm(RestrictLineFormToOrganizationMixin,\n                      ModelForm):\n    class Meta:\n        model = InvoiceLine\n        fields = (\n            \"label\",\n            \"description\",\n            \"unit_price_excl_tax\",\n            \"quantity\",\n            \"tax_rate\",\n        )\n\n\nInvoiceLineFormSet = inlineformset_factory(Invoice,\n                                           InvoiceLine,\n                                           form=InvoiceLineForm,\n                                           formset=SaleInlineLineFormSet,\n                                           min_num=1,\n                                           extra=0)\n\n\nclass BillForm(ModelForm):\n    client = ClientForOrganizationChoices()\n\n    class Meta:\n        model = Bill\n        fields = (\n            \"number\",\n            \"client\",\n            \"date_issued\",\n            \"date_dued\",\n        )\n        widgets = {\n            'date_issued': DateWidget(\n                attrs={'id': \"id_date_issued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n            'date_dued': DateWidget(\n                attrs={'id': \"id_date_dued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n        }\n\n\nclass BillLineForm(RestrictLineFormToOrganizationMixin,\n                   ModelForm):\n    class Meta:\n        model = BillLine\n        fields = (\n            \"label\",\n            \"description\",\n            \"unit_price_excl_tax\",\n            \"quantity\",\n            \"tax_rate\",\n        )\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\nBillLineFormSet = inlineformset_factory(Bill,\n                                        BillLine,\n                                        form=BillLineForm,\n                                        formset=SaleInlineLineFormSet,\n                                        min_num=1,\n                                        extra=0)\n\n\nclass ExpenseClaimForm(ModelForm):\n    employee = EmployeeForOrganizationChoices()\n\n    class Meta:\n        model = ExpenseClaim\n        fields = (\n            \"number\",\n            \"employee\",\n            \"date_issued\",\n            \"date_dued\",\n        )\n        widgets = {\n            'date_issued': DateWidget(\n                attrs={'id': \"id_date_issued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n            'date_dued': DateWidget(\n                attrs={'id': \"id_date_dued\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3),\n        }\n\n\nclass ExpenseClaimLineForm(RestrictLineFormToOrganizationMixin,\n                           ModelForm):\n    class Meta:\n        model = ExpenseClaimLine\n        fields = (\n            \"label\",\n            \"description\",\n            \"unit_price_excl_tax\",\n            \"quantity\",\n            \"tax_rate\",\n        )\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\nExpenseClaimLineFormSet = inlineformset_factory(ExpenseClaim,\n                                                ExpenseClaimLine,\n                                                form=ExpenseClaimLineForm,\n                                                formset=SaleInlineLineFormSet,\n                                                min_num=1,\n                                                extra=0)\n\n\nclass PaymentForm(ModelForm):\n    class Meta:\n        model = Payment\n        fields = (\n            \"amount\",\n            \"reference\",\n            \"detail\",\n            \"date_paid\",\n        )\n        widgets = {\n            'date_paid': DateWidget(\n                attrs={'id': \"id_date_paid\"},\n                options={'clearBtn': 'false'},\n                usel10n=True,\n                bootstrap_version=3,),\n        }\n"
  },
  {
    "path": "accounting/apps/books/managers.py",
    "content": "from datetime import date\n\nfrom django.db import models\nfrom django.db.models import Sum\n\n\nclass TotalQuerySetMixin(object):\n\n    def _get_total(self, prop):\n        return self.aggregate(sum=Sum(prop))[\"sum\"]\n\n    def total_paid(self):\n        return self._get_total('payments__amount')\n\n\nclass InvoiceQuerySetMixin(object):\n\n    def dued(self):\n        return self.filter(date_dued__lte=date.today())\n\n\nclass EstimateQuerySet(TotalQuerySetMixin, models.QuerySet):\n    pass\n\n\nclass InvoiceQuerySet(TotalQuerySetMixin,\n                      InvoiceQuerySetMixin,\n                      models.QuerySet):\n\n    def turnover_excl_tax(self):\n        return self._get_total('total_excl_tax')\n\n    def turnover_incl_tax(self):\n        return self._get_total('total_incl_tax')\n\n\nclass BillQuerySet(TotalQuerySetMixin,\n                   InvoiceQuerySetMixin,\n                   models.QuerySet):\n\n    def debts_excl_tax(self):\n        return self._get_total('total_excl_tax')\n\n    def debts_incl_tax(self):\n        return self._get_total('total_incl_tax')\n\n\nclass ExpenseClaimQuerySet(TotalQuerySetMixin,\n                           InvoiceQuerySetMixin,\n                           models.QuerySet):\n\n    def debts_excl_tax(self):\n        return self._get_total('total_excl_tax')\n\n    def debts_incl_tax(self):\n        return self._get_total('total_incl_tax')\n"
  },
  {
    "path": "accounting/apps/books/middlewares.py",
    "content": "from .utils import organization_manager\n\n\nclass AutoSelectOrganizationMiddleware(object):\n\n    def process_request(self, request):\n        if not request.user or not request.user.is_authenticated():\n            return\n\n        orga = organization_manager.get_selected_organization(request)\n        if orga is not None:\n            return\n\n        user_orgas = organization_manager.get_user_organizations(request.user)\n        if user_orgas.count():\n            orga = user_orgas.first()\n            organization_manager.set_selected_organization(request, orga)\n"
  },
  {
    "path": "accounting/apps/books/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nimport accounting.apps.books.utils\nfrom django.conf import settings\nimport datetime\nimport accounting.libs.checks\nimport django.core.validators\nfrom decimal import Decimal\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        migrations.swappable_dependency(settings.AUTH_USER_MODEL),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Organization',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)),\n                ('display_name', models.CharField(help_text='Name that you communicate', max_length=150)),\n                ('legal_name', models.CharField(help_text='Official name to appear on your reports, sales invoices and bills', max_length=150)),\n                ('members', models.ManyToManyField(null=True, blank=True, related_name='organizations', to=settings.AUTH_USER_MODEL)),\n                ('owner', models.ForeignKey(related_name='owned_organizations', to=settings.AUTH_USER_MODEL)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0002_auto_20141029_1606.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nimport django.core.validators\nimport accounting.apps.books.utils\nfrom decimal import Decimal\nimport datetime\nimport accounting.libs.checks\n\n\ndef next_invoice_number():\n    return 100\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('contenttypes', '0001_initial'),\n        ('books', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Bill',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('number', models.CharField(default=next_invoice_number, max_length=6)),\n                ('total_incl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (inc. tax)', max_digits=12)),\n                ('total_excl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (excl. tax)', max_digits=12)),\n                ('draft', models.BooleanField(default=False)),\n                ('sent', models.BooleanField(default=False)),\n                ('paid', models.BooleanField(default=False)),\n                ('date_issued', models.DateField(default=datetime.date.today)),\n                ('date_dued', models.DateField(null=True, help_text='The date when the total amount should have been collected', verbose_name='Due date', blank=True)),\n                ('date_paid', models.DateField(null=True, blank=True)),\n            ],\n            options={\n                'ordering': ('-date_issued', 'id'),\n            },\n            bases=(accounting.libs.checks.CheckingModelMixin, models.Model),\n        ),\n        migrations.CreateModel(\n            name='BillLine',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('label', models.CharField(max_length=255)),\n                ('description', models.TextField(null=True, blank=True)),\n                ('unit_price_excl_tax', models.DecimalField(decimal_places=2, max_digits=8)),\n                ('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=8)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='Estimate',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('number', models.CharField(default=next_invoice_number, max_length=6)),\n                ('total_incl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (inc. tax)', max_digits=12)),\n                ('total_excl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (excl. tax)', max_digits=12)),\n                ('draft', models.BooleanField(default=False)),\n                ('sent', models.BooleanField(default=False)),\n                ('paid', models.BooleanField(default=False)),\n                ('date_issued', models.DateField(default=datetime.date.today)),\n                ('date_dued', models.DateField(null=True, help_text='The date when the total amount should have been collected', verbose_name='Due date', blank=True)),\n                ('date_paid', models.DateField(null=True, blank=True)),\n            ],\n            options={\n                'ordering': ('-date_issued', 'id'),\n            },\n            bases=(accounting.libs.checks.CheckingModelMixin, models.Model),\n        ),\n        migrations.CreateModel(\n            name='EstimateLine',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('label', models.CharField(max_length=255)),\n                ('description', models.TextField(null=True, blank=True)),\n                ('unit_price_excl_tax', models.DecimalField(decimal_places=2, max_digits=8)),\n                ('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=8)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='Invoice',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('number', models.CharField(default=next_invoice_number, max_length=6)),\n                ('total_incl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (inc. tax)', max_digits=12)),\n                ('total_excl_tax', models.DecimalField(decimal_places=2, default=Decimal('0'), verbose_name='Total (excl. tax)', max_digits=12)),\n                ('draft', models.BooleanField(default=False)),\n                ('sent', models.BooleanField(default=False)),\n                ('paid', models.BooleanField(default=False)),\n                ('date_issued', models.DateField(default=datetime.date.today)),\n                ('date_dued', models.DateField(null=True, help_text='The date when the total amount should have been collected', verbose_name='Due date', blank=True)),\n                ('date_paid', models.DateField(null=True, blank=True)),\n            ],\n            options={\n                'ordering': ('-date_issued', 'id'),\n            },\n            bases=(accounting.libs.checks.CheckingModelMixin, models.Model),\n        ),\n        migrations.CreateModel(\n            name='InvoiceLine',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('label', models.CharField(max_length=255)),\n                ('description', models.TextField(null=True, blank=True)),\n                ('unit_price_excl_tax', models.DecimalField(decimal_places=2, max_digits=8)),\n                ('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=8)),\n                ('invoice', models.ForeignKey(to='books.Invoice', related_name='lines')),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='Payment',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('amount', models.DecimalField(decimal_places=2, verbose_name='Amount', max_digits=12)),\n                ('detail', models.CharField(null=True, blank=True, max_length=255)),\n                ('date_paid', models.DateField(default=datetime.date.today)),\n                ('reference', models.CharField(null=True, blank=True, max_length=255)),\n                ('object_id', models.PositiveIntegerField()),\n                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),\n            ],\n            options={\n                'ordering': ('-date_paid',),\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='TaxRate',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('name', models.CharField(max_length=50)),\n                ('rate', models.DecimalField(decimal_places=5, validators=[django.core.validators.MinValueValidator(Decimal('0')), django.core.validators.MaxValueValidator(Decimal('1'))], max_digits=6)),\n                ('organization', models.ForeignKey(related_name='tax_rates', to='books.Organization', verbose_name='Attached to Organization')),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.AddField(\n            model_name='invoiceline',\n            name='tax_rate',\n            field=models.ForeignKey(to='books.TaxRate'),\n            preserve_default=True,\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0003_auto_20141029_1606.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0002_auto_20141029_1606'),\n        ('people', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='invoice',\n            name='client',\n            field=models.ForeignKey(to='people.Client', verbose_name='To Client'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='invoice',\n            name='organization',\n            field=models.ForeignKey(related_name='invoices', to='books.Organization', verbose_name='From Organization'),\n            preserve_default=True,\n        ),\n        migrations.AlterUniqueTogether(\n            name='invoice',\n            unique_together=set([('number', 'organization')]),\n        ),\n        migrations.AddField(\n            model_name='estimateline',\n            name='invoice',\n            field=models.ForeignKey(to='books.Estimate', related_name='lines'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='estimateline',\n            name='tax_rate',\n            field=models.ForeignKey(to='books.TaxRate'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='estimate',\n            name='client',\n            field=models.ForeignKey(to='people.Client', verbose_name='To Client'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='estimate',\n            name='organization',\n            field=models.ForeignKey(related_name='estimates', to='books.Organization', verbose_name='From Organization'),\n            preserve_default=True,\n        ),\n        migrations.AlterUniqueTogether(\n            name='estimate',\n            unique_together=set([('number', 'organization')]),\n        ),\n        migrations.AddField(\n            model_name='billline',\n            name='bill',\n            field=models.ForeignKey(to='books.Bill', related_name='lines'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='billline',\n            name='tax_rate',\n            field=models.ForeignKey(to='books.TaxRate'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='bill',\n            name='client',\n            field=models.ForeignKey(to='people.Client', verbose_name='From Client'),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='bill',\n            name='organization',\n            field=models.ForeignKey(related_name='bills', to='books.Organization', verbose_name='To Organization'),\n            preserve_default=True,\n        ),\n        migrations.AlterUniqueTogether(\n            name='bill',\n            unique_together=set([('number', 'organization')]),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0004_auto_20141104_1026.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nimport accounting.apps.books.utils\n\n\ndef next_invoice_number():\n    return 100\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0003_auto_20141029_1606'),\n    ]\n\n    operations = [\n        migrations.AlterModelOptions(\n            name='bill',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.AlterModelOptions(\n            name='estimate',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.AlterModelOptions(\n            name='invoice',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.AlterField(\n            model_name='bill',\n            name='number',\n            field=models.CharField(max_length=6, db_index=True, default=next_invoice_number),\n        ),\n        migrations.AlterField(\n            model_name='estimate',\n            name='number',\n            field=models.CharField(max_length=6, db_index=True, default=next_invoice_number),\n        ),\n        migrations.AlterField(\n            model_name='invoice',\n            name='number',\n            field=models.CharField(max_length=6, db_index=True, default=next_invoice_number),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0005_auto_20150128_1458.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0004_auto_20141104_1026'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='bill',\n            name='number',\n            field=models.CharField(default=1, max_length=6, db_index=True),\n        ),\n        migrations.AlterField(\n            model_name='estimate',\n            name='number',\n            field=models.CharField(default=1, max_length=6, db_index=True),\n        ),\n        migrations.AlterField(\n            model_name='invoice',\n            name='number',\n            field=models.CharField(default=1, max_length=6, db_index=True),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0006_auto_20150206_1836.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0005_auto_20150128_1458'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='bill',\n            name='number_int',\n            field=models.IntegerField(default=1, db_index=True),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='estimate',\n            name='number_int',\n            field=models.IntegerField(default=1, db_index=True),\n            preserve_default=True,\n        ),\n        migrations.AddField(\n            model_name='invoice',\n            name='number_int',\n            field=models.IntegerField(default=1, db_index=True),\n            preserve_default=True,\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0007_auto_20150206_1836.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\ndef _migrate_sale_numbers(sales):\n    for s in sales:\n        s.number_int = int(s.number.strip())\n        s.save()\n\n\ndef migrate_estimate_numbers(apps, schema_editor):\n    Estimate = apps.get_model(\"books\", \"Estimate\")\n    _migrate_sale_numbers(Estimate.objects.all())\n\n\ndef migrate_invoice_numbers(apps, schema_editor):\n    Invoice = apps.get_model(\"books\", \"Invoice\")\n    _migrate_sale_numbers(Invoice.objects.all())\n\n\ndef migrate_bill_numbers(apps, schema_editor):\n    Bill = apps.get_model(\"books\", \"Bill\")\n    _migrate_sale_numbers(Bill.objects.all())\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0006_auto_20150206_1836'),\n    ]\n\n    operations = [\n        migrations.RunPython(migrate_estimate_numbers),\n        migrations.RunPython(migrate_invoice_numbers),\n        migrations.RunPython(migrate_bill_numbers)\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0008_auto_20150206_1843.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0007_auto_20150206_1836'),\n    ]\n\n    operations = [\n        migrations.AlterModelOptions(\n            name='bill',\n            options={'ordering': ('-number_int',)},\n        ),\n        migrations.AlterModelOptions(\n            name='estimate',\n            options={'ordering': ('-number_int',)},\n        ),\n        migrations.AlterModelOptions(\n            name='invoice',\n            options={'ordering': ('-number_int',)},\n        ),\n        migrations.AlterUniqueTogether(\n            name='bill',\n            unique_together=set([('number_int', 'organization')]),\n        ),\n        migrations.RemoveField(\n            model_name='bill',\n            name='number',\n        ),\n        migrations.AlterUniqueTogether(\n            name='estimate',\n            unique_together=set([('number_int', 'organization')]),\n        ),\n        migrations.RemoveField(\n            model_name='estimate',\n            name='number',\n        ),\n        migrations.AlterUniqueTogether(\n            name='invoice',\n            unique_together=set([('number_int', 'organization')]),\n        ),\n        migrations.RemoveField(\n            model_name='invoice',\n            name='number',\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0009_auto_20150206_1850.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0008_auto_20150206_1843'),\n    ]\n\n    operations = [\n        migrations.AlterModelOptions(\n            name='bill',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.AlterModelOptions(\n            name='estimate',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.AlterModelOptions(\n            name='invoice',\n            options={'ordering': ('-number',)},\n        ),\n        migrations.RenameField(\n            model_name='bill',\n            old_name='number_int',\n            new_name='number',\n        ),\n        migrations.RenameField(\n            model_name='estimate',\n            old_name='number_int',\n            new_name='number',\n        ),\n        migrations.RenameField(\n            model_name='invoice',\n            old_name='number_int',\n            new_name='number',\n        ),\n        migrations.AlterUniqueTogether(\n            name='bill',\n            unique_together=set([('number', 'organization')]),\n        ),\n        migrations.AlterUniqueTogether(\n            name='estimate',\n            unique_together=set([('number', 'organization')]),\n        ),\n        migrations.AlterUniqueTogether(\n            name='invoice',\n            unique_together=set([('number', 'organization')]),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0010_auto_20150210_1449.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0009_auto_20150206_1850'),\n    ]\n\n    operations = [\n        migrations.RemoveField(\n            model_name='bill',\n            name='draft',\n        ),\n        migrations.RemoveField(\n            model_name='bill',\n            name='paid',\n        ),\n        migrations.RemoveField(\n            model_name='bill',\n            name='sent',\n        ),\n        migrations.RemoveField(\n            model_name='estimate',\n            name='draft',\n        ),\n        migrations.RemoveField(\n            model_name='estimate',\n            name='paid',\n        ),\n        migrations.RemoveField(\n            model_name='estimate',\n            name='sent',\n        ),\n        migrations.RemoveField(\n            model_name='invoice',\n            name='draft',\n        ),\n        migrations.RemoveField(\n            model_name='invoice',\n            name='paid',\n        ),\n        migrations.RemoveField(\n            model_name='invoice',\n            name='sent',\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/0011_auto_20150324_1430.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nfrom decimal import Decimal\nimport datetime\nimport accounting.libs.checks\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('people', '0005_auto_20141029_2308'),\n        ('books', '0010_auto_20150210_1449'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='ExpenseClaim',\n            fields=[\n                ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),\n                ('number', models.IntegerField(db_index=True, default=1)),\n                ('total_incl_tax', models.DecimalField(verbose_name='Total (inc. tax)', max_digits=12, default=Decimal('0'), decimal_places=2)),\n                ('total_excl_tax', models.DecimalField(verbose_name='Total (excl. tax)', max_digits=12, default=Decimal('0'), decimal_places=2)),\n                ('date_issued', models.DateField(default=datetime.date.today)),\n                ('date_dued', models.DateField(verbose_name='Due date', blank=True, null=True, help_text='The date when the total amount should have been collected')),\n                ('date_paid', models.DateField(blank=True, null=True)),\n                ('employee', models.ForeignKey(verbose_name='Paid by employee', to='people.Employee')),\n                ('organization', models.ForeignKey(related_name='expense_claims', to='books.Organization', verbose_name='From Organization')),\n            ],\n            options={\n                'ordering': ('-number',),\n            },\n            bases=(accounting.libs.checks.CheckingModelMixin, models.Model),\n        ),\n        migrations.CreateModel(\n            name='ExpenseClaimLine',\n            fields=[\n                ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),\n                ('label', models.CharField(max_length=255)),\n                ('description', models.TextField(blank=True, null=True)),\n                ('unit_price_excl_tax', models.DecimalField(max_digits=8, decimal_places=2)),\n                ('quantity', models.DecimalField(max_digits=8, default=1, decimal_places=2)),\n                ('expense_claim', models.ForeignKey(related_name='lines', to='books.ExpenseClaim')),\n                ('tax_rate', models.ForeignKey(to='books.TaxRate')),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.AlterUniqueTogether(\n            name='expenseclaim',\n            unique_together=set([('number', 'organization')]),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/books/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/books/mixins.py",
    "content": "from django.db.models.fields import FieldDoesNotExist\nfrom django.views import generic\nfrom django.http import HttpResponseRedirect\nfrom django.core.urlresolvers import reverse\n\nfrom .utils import organization_manager\n\n\nclass RestrictToSelectedOrganizationQuerySetMixin(object):\n    \"\"\"\n    To restrict objects to the current selected organization\n    \"\"\"\n\n    def get_restriction_filters(self):\n        # check for the field\n        meta = self.model._meta\n        field, model, direct, m2m = meta.get_field_by_name('organization')\n\n        # build the restriction\n        orga = organization_manager.get_selected_organization(self.request)\n        return {field.name: orga.pk}\n\n    def get_queryset(self):\n        filters = self.get_restriction_filters()\n        queryset = super().get_queryset()\n        queryset = queryset.filter(**filters)\n        return queryset\n\n    def get(self, request, *args, **kwargs):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return HttpResponseRedirect(reverse('books:organization-selector'))\n        return super().get(request, *args, **kwargs)\n\n\nclass RestrictToOrganizationFormRelationsMixin(object):\n    \"\"\"\n    To restrict relations choices to the organization linked instances\n    \"\"\"\n    relation_name = 'organization'\n\n    def _restrict_fields_choices(self, model, organization, fields):\n        for source in fields:\n            field, m, direct, m2m = model._meta.get_field_by_name(source)\n            rel = field.rel\n            if not rel:\n                # next field\n                continue\n\n            rel_model = rel.to\n            try:\n                rel_model._meta.get_field_by_name(self.relation_name)\n            except FieldDoesNotExist:\n                # next field\n                continue\n\n            form_field = fields[source]\n            form_field.queryset = (form_field.choices.queryset\n                .filter(**{self.relation_name: organization}))\n\n    def restrict_fields_choices_to_organization(self, form, organization):\n        assert organization is not None, \"no organization to restrict to\"\n        model = form._meta.model\n        self._restrict_fields_choices(model, organization, form.fields)\n\n\nclass SaleListQuerySetMixin(object):\n\n    def get_queryset(self):\n        queryset = super().get_queryset()\n        queryset = (queryset\n            .select_related(\n                'organization')\n            .prefetch_related(\n                'lines',\n                'lines__tax_rate'))\n\n        try:\n            # to raise the exception\n            self.model._meta.get_field_by_name('client')\n            queryset = queryset.select_related('client')\n        except FieldDoesNotExist:\n            pass\n\n        try:\n            # to raise the exception\n            self.model._meta.get_field_by_name('payments')\n            queryset = queryset.prefetch_related('payments')\n        except FieldDoesNotExist:\n            pass\n\n        return queryset\n\n\nclass AutoSetSelectedOrganizationMixin(object):\n\n    def form_valid(self, form):\n        obj = form.save(commit=False)\n        orga = organization_manager.get_selected_organization(self.request)\n        obj.organization = orga\n\n        return super().form_valid(form)\n\n\nclass AbstractSaleCreateUpdateMixin(RestrictToOrganizationFormRelationsMixin,\n                                    object):\n    formset_class = None\n\n    def get_context_data(self, **kwargs):\n        assert self.formset_class is not None, \"No formset class specified\"\n        context = super().get_context_data(**kwargs)\n        orga = organization_manager.get_selected_organization(self.request)\n        if self.request.POST:\n            context['line_formset'] = self.formset_class(\n                self.request.POST,\n                instance=self.object,\n                organization=orga)\n        else:\n            context['line_formset'] = self.formset_class(\n                instance=self.object,\n                organization=orga)\n        return context\n\n    def get_form(self, form_class=None):\n        \"\"\"Restrict the form relations to the current organization\"\"\"\n        form = super().get_form(form_class)\n        orga = organization_manager.get_selected_organization(self.request)\n        self.restrict_fields_choices_to_organization(form, orga)\n        return form\n\n    def form_valid(self, form):\n        context = self.get_context_data()\n        line_formset = context['line_formset']\n        if not line_formset.is_valid():\n            return super().form_invalid(form)\n\n        self.object = form.save()\n        line_formset.instance = self.object\n        line_formset.save()\n\n        # update totals\n        self.object.compute_totals()\n\n        return super().form_valid(form)\n\n\nclass AbstractSaleDetailMixin(object):\n\n    def get_queryset(self):\n        queryset = super().get_queryset()\n        queryset = queryset.select_related('organization')\n\n        try:\n            # to raise the exception\n            self.model._meta.get_field_by_name('client')\n            queryset = queryset.select_related('client')\n        except FieldDoesNotExist:\n            pass\n\n        return queryset\n\n    def get_object(self):\n        # save some db queries by caching the fetched object\n        if hasattr(self, '_object'):\n            return getattr(self, '_object')\n\n        obj = super().get_object()\n        setattr(self, '_object', obj)\n        return obj\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        obj = self.get_object()\n        ctx[\"checklist\"] = obj.full_check()\n        ctx[\"lines\"] = (obj.lines.all()\n            .select_related(\n                'tax_rate'))\n        return ctx\n\n\nclass PaymentFormMixin(generic.edit.FormMixin):\n    payment_form_class = None\n\n    def get_context_data(self, **kwargs):\n        assert self.payment_form_class is not None, \\\n            \"No formset class specified\"\n        self.object = self.get_object()\n        context = super().get_context_data(**kwargs)\n        form = self.get_form(self.payment_form_class)\n        context['payment_form'] = form\n        return context\n\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Handles POST requests, instantiating a form instance with the passed\n        POST variables and then checked for validity.\n        \"\"\"\n        form = self.get_form(self.payment_form_class)\n        if form.is_valid():\n            return self.form_valid(form)\n        else:\n            return self.form_invalid(form)\n\n    def form_valid(self, form):\n        self.object = self.get_object()\n\n        # save payment\n        payment = form.save(commit=False)\n        payment.content_object = self.object\n        payment.save()\n        return super().form_valid(form)\n"
  },
  {
    "path": "accounting/apps/books/models.py",
    "content": "from decimal import Decimal as D\nfrom datetime import date\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.core.urlresolvers import reverse\nfrom django.core.validators import MaxValueValidator, MinValueValidator\nfrom django.contrib.contenttypes.fields import (\n    GenericForeignKey,\n    GenericRelation)\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.utils import timezone\n\nfrom accounting.libs import prices\nfrom accounting.libs.checks import CheckingModelMixin\nfrom accounting.libs.templatetags.currency_filters import currency_formatter\nfrom accounting.libs.templatetags.format_filters import percentage_formatter\nfrom .managers import (\n    EstimateQuerySet,\n    InvoiceQuerySet,\n    BillQuerySet,\n    ExpenseClaimQuerySet)\n\nTWO_PLACES = D(10) ** -2\n\n\nclass Organization(models.Model):\n    display_name = models.CharField(max_length=150,\n        help_text=\"Name that you communicate\")\n    legal_name = models.CharField(max_length=150,\n        help_text=\"Official name to appear on your reports, sales \"\n                  \"invoices and bills\")\n\n    owner = models.ForeignKey(settings.AUTH_USER_MODEL,\n                              related_name=\"owned_organizations\")\n    members = models.ManyToManyField(settings.AUTH_USER_MODEL,\n                                     related_name=\"organizations\",\n                                     blank=True, null=True)\n\n    class Meta:\n        pass\n\n    def __str__(self):\n        return self.legal_name\n\n    def get_absolute_url(self):\n        return reverse('books:organization-detail', args=[self.pk])\n\n    @property\n    def turnover_excl_tax(self):\n        return self.invoices.turnover_excl_tax() or D('0.00')\n\n    @property\n    def turnover_incl_tax(self):\n        return self.invoices.turnover_incl_tax() or D('0.00')\n\n    @property\n    def debts_excl_tax(self):\n        return self.bills.debts_excl_tax() or D('0.00')\n\n    @property\n    def debts_incl_tax(self):\n        return self.bills.debts_incl_tax() or D('0.00')\n\n    @property\n    def profits(self):\n        return self.turnover_excl_tax - self.debts_excl_tax\n\n    @property\n    def collected_tax(self):\n        return self.turnover_incl_tax - self.turnover_excl_tax\n\n    @property\n    def deductible_tax(self):\n        return self.debts_incl_tax - self.debts_excl_tax\n\n    @property\n    def tax_provisionning(self):\n        return self.collected_tax - self.deductible_tax\n\n    @property\n    def overdue_total(self):\n        due_invoices = self.invoices.dued()\n        due_turnonver = due_invoices.turnover_incl_tax()\n        total_paid = due_invoices.total_paid()\n        return due_turnonver - total_paid\n\n\nclass TaxRate(models.Model):\n    \"\"\"\n    Every transaction line item needs a Tax Rate.\n    Tax Rates can have multiple Tax Components.\n\n    For instance, you can have an item that is charged a Tax Rate\n    called \"City Import Tax (8%)\" that has two components:\n        - a city tax of 5%\n        - an import tax of 3%.\n\n    *inspired by Xero*\n    \"\"\"\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"tax_rates\",\n                                     verbose_name=\"Attached to Organization\")\n\n    name = models.CharField(max_length=50)\n    rate = models.DecimalField(max_digits=6,\n                               decimal_places=5,\n                               validators=[MinValueValidator(D('0')),\n                                           MaxValueValidator(D('1'))])\n\n    class Meta:\n        pass\n\n    def __str__(self):\n        return \"{} ({})\".format(self.name, percentage_formatter(self.rate))\n\n\nclass AbstractSale(CheckingModelMixin, models.Model):\n    number = models.IntegerField(default=1,\n                                 db_index=True)\n\n    # Total price needs to be stored with and wihtout taxes\n    # because the tax percentage can vary depending on the associated lines\n    total_incl_tax = models.DecimalField(\"Total (inc. tax)\",\n                                         decimal_places=2,\n                                         max_digits=12,\n                                         default=D('0'))\n    total_excl_tax = models.DecimalField(\"Total (excl. tax)\",\n                                         decimal_places=2,\n                                         max_digits=12,\n                                         default=D('0'))\n\n    # tracking\n    date_issued = models.DateField(default=date.today)\n    date_dued = models.DateField(\"Due date\",\n                                 blank=True, null=True,\n                                 help_text=\"The date when the total amount \"\n                                           \"should have been collected\")\n    date_paid = models.DateField(blank=True, null=True)\n\n    class Meta:\n        abstract = True\n\n    class CheckingOptions:\n        fields = (\n            'total_incl_tax',\n            'total_excl_tax',\n            'date_dued',\n        )\n\n    def __str__(self):\n        return \"#{} ({})\".format(self.number, self.total_incl_tax)\n\n    def get_detail_url(self):\n        raise NotImplementedError\n\n    def get_edit_url(self):\n        raise NotImplementedError\n\n    def compute_totals(self):\n        self.total_excl_tax = self.get_total_excl_tax()\n        self.total_incl_tax = self.get_total_incl_tax()\n\n    def _get_total(self, prop):\n        \"\"\"\n        For executing a named method on each line of the basket\n        and returning the total.\n        \"\"\"\n        total = D('0.00')\n        line_queryset = self.lines.all()\n        for line in line_queryset:\n            total = total + getattr(line, prop)\n        return total\n\n    @property\n    def total_tax(self):\n        return self.total_incl_tax - self.total_excl_tax\n\n    def get_total_excl_tax(self):\n        return self._get_total('line_price_excl_tax')\n\n    def get_total_incl_tax(self):\n        return self._get_total('line_price_incl_tax')\n\n    @property\n    def total_paid(self):\n        total = D('0')\n        for p in self.payments.all():\n            total += p.amount\n        return total\n\n    @property\n    def total_due_incl_tax(self):\n        due = self.total_incl_tax\n        due -= self.total_paid\n        return due\n\n    def is_fully_paid(self):\n        paid = self.total_paid.quantize(TWO_PLACES)\n        total = self.total_incl_tax.quantize(TWO_PLACES)\n        return paid >= total\n\n    def is_partially_paid(self):\n        paid = self.total_paid.quantize(TWO_PLACES)\n        total = self.total_incl_tax.quantize(TWO_PLACES)\n        return paid and paid > 0 and paid < total\n\n    @property\n    def payroll_taxes(self):\n        # TODO implement collected/accurial\n        paid = self.total_paid\n        payroll = D('0')\n        for emp in self.organization.employees.all():\n            if not emp.salary_follows_profits:\n                continue\n            payroll += paid * emp.shares_percentage * emp.payroll_tax_rate\n        return payroll\n\n    def _check_total(self, check, total, computed_total):\n        if total.quantize(TWO_PLACES) != computed_total.quantize(TWO_PLACES):\n            check.mark_fail(level=check.LEVEL_ERROR,\n                            message=\"The computed amount isn't correct, it \"\n                                    \"should be {}, please edit and save the \"\n                                    \"{} to fix it.\".format(\n                                        currency_formatter(total),\n                                        self._meta.verbose_name))\n        else:\n            check.mark_pass()\n        return check\n\n    def check_total_excl_tax(self, check):\n        total = self.get_total_excl_tax()\n        return self._check_total(check, total, self.total_excl_tax)\n\n    def check_total_incl_tax(self, check):\n        total = self.get_total_incl_tax()\n        return self._check_total(check, total, self.total_incl_tax)\n\n    def check_date_dued(self, check):\n        if self.date_dued is None:\n            check.mark_fail(message=\"No due date specified\")\n            return check\n\n        if self.total_excl_tax == D('0'):\n            check.mark_fail(message=\"The invoice has no value\")\n            return check\n\n        if self.is_fully_paid():\n            last_payment = self.payments.all().first()\n            formatted_date = last_payment.date_paid.strftime('%B %d, %Y')\n            check.mark_pass(message=\"Has been paid on the {}\"\n                .format(formatted_date))\n            return check\n\n        if timezone.now().date() > self.date_dued:\n            check.mark_fail(message=\"The due date has been exceeded.\")\n        else:\n            check.mark_pass()\n        return check\n\n\nclass AbstractSaleLine(models.Model):\n    label = models.CharField(max_length=255)\n    description = models.TextField(blank=True, null=True)\n    unit_price_excl_tax = models.DecimalField(max_digits=8,\n                                              decimal_places=2)\n    quantity = models.DecimalField(max_digits=8,\n                                   decimal_places=2,\n                                   default=1)\n\n    class Meta:\n        abstract = True\n\n    def __str__(self):\n        return self.label\n\n    @property\n    def unit_price(self):\n        \"\"\"Returns the `Price` instance representing the instance\"\"\"\n        unit = self.unit_price_excl_tax\n        tax = unit * self.tax_rate.rate\n        p = prices.Price(settings.ACCOUNTING_DEFAULT_CURRENCY, unit, tax=tax)\n        return p\n\n    @property\n    def line_price_excl_tax(self):\n        return self.quantity * self.unit_price.excl_tax\n\n    @property\n    def line_price_incl_tax(self):\n        return self.quantity * self.unit_price.incl_tax\n\n    @property\n    def taxes(self):\n        return self.line_price_incl_tax - self.line_price_excl_tax\n\n    def from_client(self):\n        raise NotImplementedError\n\n    def to_client(self):\n        raise NotImplementedError\n\n\nclass Estimate(AbstractSale):\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"estimates\",\n                                     verbose_name=\"From Organization\")\n    client = models.ForeignKey('people.Client',\n                               verbose_name=\"To Client\")\n\n    objects = EstimateQuerySet.as_manager()\n\n    class Meta:\n        unique_together = ((\"number\", \"organization\"),)\n        ordering = ('-number',)\n\n    def get_detail_url(self):\n        return reverse('books:estimate-detail', args=[self.pk])\n\n    def get_edit_url(self):\n        return reverse('books:estimate-edit', args=[self.pk])\n\n    def from_client(self):\n        return self.organization\n\n    def to_client(self):\n        return self.client\n\n\nclass EstimateLine(AbstractSaleLine):\n    invoice = models.ForeignKey('books.Estimate',\n                                related_name=\"lines\")\n    tax_rate = models.ForeignKey('books.TaxRate')\n\n    class Meta:\n        pass\n\n\nclass Invoice(AbstractSale):\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"invoices\",\n                                     verbose_name=\"From Organization\")\n    client = models.ForeignKey('people.Client',\n                               verbose_name=\"To Client\")\n    payments = GenericRelation('books.Payment')\n\n    objects = InvoiceQuerySet.as_manager()\n\n    class Meta:\n        unique_together = ((\"number\", \"organization\"),)\n        ordering = ('-number',)\n\n    def get_detail_url(self):\n        return reverse('books:invoice-detail', args=[self.pk])\n\n    def get_edit_url(self):\n        return reverse('books:invoice-edit', args=[self.pk])\n\n    def from_client(self):\n        return self.organization\n\n    def to_client(self):\n        return self.client\n\n\nclass InvoiceLine(AbstractSaleLine):\n    invoice = models.ForeignKey('books.Invoice',\n                                related_name=\"lines\")\n    tax_rate = models.ForeignKey('books.TaxRate')\n\n    class Meta:\n        pass\n\n\nclass Bill(AbstractSale):\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"bills\",\n                                     verbose_name=\"To Organization\")\n    client = models.ForeignKey('people.Client',\n                               verbose_name=\"From Client\")\n    payments = GenericRelation('books.Payment')\n\n    objects = BillQuerySet.as_manager()\n\n    class Meta:\n        unique_together = ((\"number\", \"organization\"),)\n        ordering = ('-number',)\n\n    def get_detail_url(self):\n        return reverse('books:bill-detail', args=[self.pk])\n\n    def get_edit_url(self):\n        return reverse('books:bill-edit', args=[self.pk])\n\n    def from_client(self):\n        return self.client\n\n    def to_client(self):\n        return self.organization\n\n\nclass BillLine(AbstractSaleLine):\n    bill = models.ForeignKey('books.Bill',\n                             related_name=\"lines\")\n    tax_rate = models.ForeignKey('books.TaxRate')\n\n    class Meta:\n        pass\n\n\nclass ExpenseClaim(AbstractSale):\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"expense_claims\",\n                                     verbose_name=\"From Organization\")\n    employee = models.ForeignKey('people.Employee',\n                                 verbose_name=\"Paid by employee\")\n    payments = GenericRelation('books.Payment')\n\n    objects = ExpenseClaimQuerySet.as_manager()\n\n    class Meta:\n        unique_together = ((\"number\", \"organization\"),)\n        ordering = ('-number',)\n\n    def get_detail_url(self):\n        return reverse('books:expense_claim-detail', args=[self.pk])\n\n    def get_edit_url(self):\n        return reverse('books:expense_claim-edit', args=[self.pk])\n\n    def from_client(self):\n        return self.employee\n\n    def to_client(self):\n        return self.organization\n\n\nclass ExpenseClaimLine(AbstractSaleLine):\n    expense_claim = models.ForeignKey('books.ExpenseClaim',\n                                      related_name=\"lines\")\n    tax_rate = models.ForeignKey('books.TaxRate')\n\n    class Meta:\n        pass\n\n\nclass Payment(models.Model):\n    amount = models.DecimalField(\"Amount\",\n                                 decimal_places=2,\n                                 max_digits=12)\n    detail = models.CharField(max_length=255,\n                              blank=True,\n                              null=True)\n    date_paid = models.DateField(default=date.today)\n    reference = models.CharField(max_length=255,\n                                 blank=True,\n                                 null=True)\n\n    # relationship to an object\n    content_type = models.ForeignKey(ContentType)\n    object_id = models.PositiveIntegerField()\n    content_object = GenericForeignKey('content_type', 'object_id')\n\n    class Meta:\n        ordering = ('-date_paid',)\n\n    def __str__(self):\n        if self.detail:\n            return self.detail\n        return \"Payment of {}\".format(currency_formatter(self.amount))\n"
  },
  {
    "path": "accounting/apps/books/templatetags/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/books/templatetags/status_filters.py",
    "content": "from django import template\n\nregister = template.Library()\n\n\n@register.filter('status_to_css_classname')\ndef _invoice_or_bill_status_to_classname(invoice_or_bill):\n    \"\"\"\n    Return the appropriated css classname for the invoice/bill status\n    \"\"\"\n    if not invoice_or_bill.pass_full_checking():\n        checks = invoice_or_bill.full_check()\n        for c in checks:\n            if c.level == c.LEVEL_ERROR:\n                return 'danger'\n        return 'warning'\n\n    if invoice_or_bill.is_fully_paid():\n        return 'success'\n    elif invoice_or_bill.is_partially_paid():\n        return 'info'\n    else:\n        return ''\n"
  },
  {
    "path": "accounting/apps/books/urls.py",
    "content": "from django.conf.urls import patterns, url\n\nfrom . import views\n\n\nurlpatterns = patterns('',\n    url(r'^$',\n        views.DashboardView.as_view(),\n        name=\"dashboard\"),\n\n    # Organizations\n    url(r'^organization/$',\n        views.OrganizationListView.as_view(),\n        name=\"organization-list\"),\n    url(r'^organization/selector/$',\n        views.OrganizationSelectorView.as_view(),\n        name=\"organization-selector\"),\n    url(r'^organization/create/$',\n        views.OrganizationCreateView.as_view(),\n        name=\"organization-create\"),\n    url(r'^organization/(?P<pk>\\d+)/edit/$',\n        views.OrganizationUpdateView.as_view(),\n        name=\"organization-edit\"),\n    url(r'^organization/(?P<pk>\\d+)/detail/$',\n        views.OrganizationDetailView.as_view(),\n        name=\"organization-detail\"),\n    url(r'^organization/(?P<pk>\\d+)/select/$',\n        views.OrganizationSelectionView.as_view(),\n        name=\"organization-select\"),\n\n    # Tax Rates\n    url(r'^tax_rates/$',\n        views.TaxRateListView.as_view(),\n        name=\"tax_rate-list\"),\n    url(r'^tax_rates/create/$',\n        views.TaxRateCreateView.as_view(),\n        name=\"tax_rate-create\"),\n    url(r'^tax_rates/(?P<pk>\\d+)/edit/$',\n        views.TaxRateUpdateView.as_view(),\n        name=\"tax_rate-edit\"),\n    url(r'^tax_rates/(?P<pk>\\d+)/delete/$',\n        views.TaxRateDeleteView.as_view(),\n        name=\"tax_rate-delete\"),\n\n    # Estimates\n    url(r'^estimate/$',\n        views.EstimateListView.as_view(),\n        name=\"estimate-list\"),\n    url(r'^estimate/create/$',\n        views.EstimateCreateView.as_view(),\n        name=\"estimate-create\"),\n    url(r'^estimate/(?P<pk>\\d+)/edit/$',\n        views.EstimateUpdateView.as_view(),\n        name=\"estimate-edit\"),\n    url(r'^estimate/(?P<pk>\\d+)/delete/$',\n        views.EstimateDeleteView.as_view(),\n        name=\"estimate-delete\"),\n    url(r'^estimate/(?P<pk>\\d+)/detail/$',\n        views.EstimateDetailView.as_view(),\n        name=\"estimate-detail\"),\n\n    # Invoices\n    url(r'^invoice/$',\n        views.InvoiceListView.as_view(),\n        name=\"invoice-list\"),\n    url(r'^invoice/create/$',\n        views.InvoiceCreateView.as_view(),\n        name=\"invoice-create\"),\n    url(r'^invoice/(?P<pk>\\d+)/edit/$',\n        views.InvoiceUpdateView.as_view(),\n        name=\"invoice-edit\"),\n    url(r'^invoice/(?P<pk>\\d+)/delete/$',\n        views.InvoiceDeleteView.as_view(),\n        name=\"invoice-delete\"),\n    url(r'^invoice/(?P<pk>\\d+)/detail/$',\n        views.InvoiceDetailView.as_view(),\n        name=\"invoice-detail\"),\n\n    # Bills\n    url(r'^bill/$',\n        views.BillListView.as_view(),\n        name=\"bill-list\"),\n    url(r'^bill/create/$',\n        views.BillCreateView.as_view(),\n        name=\"bill-create\"),\n    url(r'^bill/(?P<pk>\\d+)/edit/$',\n        views.BillUpdateView.as_view(),\n        name=\"bill-edit\"),\n    url(r'^bill/(?P<pk>\\d+)/delete/$',\n        views.BillDeleteView.as_view(),\n        name=\"bill-delete\"),\n    url(r'^bill/(?P<pk>\\d+)/detail/$',\n        views.BillDetailView.as_view(),\n        name=\"bill-detail\"),\n\n    # ExpenseClaims\n    url(r'^expense-claim/$',\n        views.ExpenseClaimListView.as_view(),\n        name=\"expense_claim-list\"),\n    url(r'^expense-claim/create/$',\n        views.ExpenseClaimCreateView.as_view(),\n        name=\"expense_claim-create\"),\n    url(r'^expense-claim/(?P<pk>\\d+)/edit/$',\n        views.ExpenseClaimUpdateView.as_view(),\n        name=\"expense_claim-edit\"),\n    url(r'^expense-claim/(?P<pk>\\d+)/delete/$',\n        views.ExpenseClaimDeleteView.as_view(),\n        name=\"expense_claim-delete\"),\n    url(r'^expense-claim/(?P<pk>\\d+)/detail/$',\n        views.ExpenseClaimDetailView.as_view(),\n        name=\"expense_claim-detail\"),\n\n    # Payments\n    url(r'^payment/(?P<pk>\\d+)/edit/$',\n        views.PaymentUpdateView.as_view(),\n        name=\"payment-edit\"),\n    url(r'^payment/(?P<pk>\\d+)/delete/$',\n        views.PaymentDeleteView.as_view(),\n        name=\"payment-delete\"),\n)\n"
  },
  {
    "path": "accounting/apps/books/utils.py",
    "content": "from django.db.models import Q\n\n\nclass OrganizationManager(object):\n    selected_organization_key = 'selected_organization_pk'\n\n    def get_user_organizations(self, user):\n        # To avoid circular imports\n        from .models import Organization\n\n        orgas = (Organization.objects\n            .filter(Q(members=user) | Q(owner=user))\n            .distinct())\n        return orgas\n\n    def set_selected_organization(self, request, organization):\n        key = self.selected_organization_key\n        request.session[key] = organization.pk\n\n    def get_selected_organization(self, request):\n        key = self.selected_organization_key\n        if key not in request.session:\n            return\n\n        # To avoid circular imports\n        from .models import Organization\n\n        pk = request.session[key]\n        organization = Organization.objects.get(pk=pk)\n        return organization\n\n\norganization_manager = OrganizationManager()\n\n\nclass BaseNumberGenerator(object):\n    \"\"\"\n    Simple object for generating sale numbers.\n    \"\"\"\n\n    def next_number(self, organization):\n        raise NotImplementedError\n\n\nclass EstimateNumberGenerator(BaseNumberGenerator):\n\n    def next_number(self, organization):\n        last = organization.estimates.all().order_by('-number').first()\n        if last is not None:\n            last_number = int(last.number)\n        else:\n            last_number = 0\n        return last_number + 1\n\n\nclass InvoiceNumberGenerator(BaseNumberGenerator):\n\n    def next_number(self, organization):\n        last = organization.invoices.all().order_by('-number').first()\n        if last is not None:\n            last_number = int(last.number)\n        else:\n            last_number = 0\n        return last_number + 1\n\n\nclass BillNumberGenerator(BaseNumberGenerator):\n\n    def next_number(self, organization):\n        last = organization.bills.all().order_by('-number').first()\n        if last is not None:\n            last_number = int(last.number)\n        else:\n            last_number = 0\n        return last_number + 1\n\n\nclass ExpenseClaimNumberGenerator(BaseNumberGenerator):\n\n    def next_number(self, organization):\n        last = organization.expense_claims.all().order_by('-number').first()\n        if last is not None:\n            last_number = int(last.number)\n        else:\n            last_number = 0\n        return last_number + 1\n"
  },
  {
    "path": "accounting/apps/books/views.py",
    "content": "import logging\nfrom decimal import Decimal as D\n\nfrom django.views import generic\nfrom django.core.urlresolvers import reverse, reverse_lazy\nfrom django.db.models import Sum\nfrom django.http import HttpResponseRedirect\n\nfrom .mixins import (\n    RestrictToSelectedOrganizationQuerySetMixin,\n    SaleListQuerySetMixin,\n    AutoSetSelectedOrganizationMixin,\n    AbstractSaleCreateUpdateMixin,\n    AbstractSaleDetailMixin,\n    PaymentFormMixin)\nfrom .models import (\n    Organization,\n    TaxRate,\n    Estimate,\n    Invoice,\n    Bill,\n    ExpenseClaim,\n    Payment)\nfrom .forms import (\n    OrganizationForm,\n    TaxRateForm,\n    EstimateForm,\n    EstimateLineFormSet,\n    InvoiceForm,\n    InvoiceLineFormSet,\n    BillForm,\n    BillLineFormSet,\n    ExpenseClaimForm,\n    ExpenseClaimLineFormSet,\n    PaymentForm)\nfrom .utils import (\n    organization_manager,\n    EstimateNumberGenerator,\n    InvoiceNumberGenerator,\n    BillNumberGenerator,\n    ExpenseClaimNumberGenerator)\n\nlogger = logging.getLogger(__name__)\n\n\nclass OrganizationSelectorView(generic.TemplateView):\n    template_name = \"books/organization_selector.html\"\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n\n        user = self.request.user\n        orgas = organization_manager.get_user_organizations(user)\n        cumulated_turnovers = (orgas\n            .aggregate(sum=Sum('invoices__total_excl_tax'))[\"sum\"]) or D('0')\n        cumulated_debts = (orgas\n            .aggregate(sum=Sum('bills__total_excl_tax'))[\"sum\"]) or D('0')\n        cumulated_profits = cumulated_turnovers - cumulated_debts\n\n        context[\"organizations_count\"] = orgas.count()\n        context[\"organizations_cumulated_turnovers\"] = cumulated_turnovers\n        context[\"organizations_cumulated_profits\"] = cumulated_profits\n        context[\"organizations_cumulated_active_days\"] = 0\n\n        context[\"organizations\"] = orgas\n        context[\"last_invoices\"] = Invoice.objects.all()[:10]\n\n        return context\n\n\nclass DashboardView(generic.DetailView):\n    template_name = \"books/dashboard.html\"\n    model = Organization\n    context_object_name = \"organization\"\n\n    def get_object(self):\n        return organization_manager.get_selected_organization(self.request)\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        organization = self.get_object()\n        ctx['invoices'] = (organization.invoices.all()\n            .select_related(\n                'client',\n                'organization')\n            .prefetch_related(\n                'lines',\n                'lines__tax_rate',\n                'payments')\n            .distinct())\n        ctx['bills'] = (organization.bills.all()\n            .select_related(\n                'client',\n                'organization')\n            .prefetch_related(\n                'lines',\n                'lines__tax_rate',\n                'payments')\n            .distinct())\n        return ctx\n\n    def get(self, request, *args, **kwargs):\n        orga = organization_manager.get_selected_organization(self.request)\n        if orga is None:\n            return HttpResponseRedirect(reverse('books:organization-selector'))\n        return super().get(request, *args, **kwargs)\n\n\nclass OrganizationListView(generic.ListView):\n    template_name = \"books/organization_list.html\"\n    model = Organization\n    context_object_name = \"organizations\"\n\n    def get_queryset(self):\n        # only current authenticated user organizations\n        return organization_manager.get_user_organizations(self.request.user)\n\n\nclass OrganizationCreateView(generic.CreateView):\n    template_name = \"books/organization_create_or_update.html\"\n    model = Organization\n    form_class = OrganizationForm\n    success_url = reverse_lazy(\"books:organization-list\")\n\n    def form_valid(self, form):\n        obj = form.save(commit=False)\n        obj.owner = self.request.user\n        return super().form_valid(form)\n\n\nclass OrganizationUpdateView(generic.UpdateView):\n    template_name = \"books/organization_create_or_update.html\"\n    model = Organization\n    form_class = OrganizationForm\n    success_url = reverse_lazy(\"books:organization-list\")\n\n    def get_queryset(self):\n        # only current authenticated user organizations\n        return organization_manager.get_user_organizations(self.request.user)\n\n\nclass OrganizationDetailView(generic.DetailView):\n    template_name = \"books/organization_detail.html\"\n    model = Organization\n    context_object_name = \"organization\"\n\n    def get_queryset(self):\n        # only current authenticated user organizations\n        return organization_manager.get_user_organizations(self.request.user)\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        organization = self.get_object()\n        ctx['invoices'] = (organization.invoices.all()\n            .select_related('client', 'organization')\n            .prefetch_related('lines'))\n        ctx['bills'] = (organization.bills.all()\n            .select_related('client', 'organization')\n            .prefetch_related('lines'))\n        return ctx\n\n\nclass OrganizationSelectionView(generic.DetailView):\n    model = Organization\n\n    def get_queryset(self):\n        # only current authenticated user organizations\n        return organization_manager.get_user_organizations(self.request.user)\n\n    def post(self, request, *args, **kwargs):\n        orga = self.get_object()\n        organization_manager.set_selected_organization(self.request, orga)\n        return HttpResponseRedirect(reverse('books:dashboard'))\n\n\nclass TaxRateListView(RestrictToSelectedOrganizationQuerySetMixin,\n                      generic.ListView):\n    template_name = \"books/tax_rate_list.html\"\n    model = TaxRate\n    context_object_name = \"tax_rates\"\n\n\nclass TaxRateCreateView(AutoSetSelectedOrganizationMixin,\n                        generic.CreateView):\n    template_name = \"books/tax_rate_create_or_update.html\"\n    model = TaxRate\n    form_class = TaxRateForm\n    success_url = reverse_lazy(\"books:tax_rate-list\")\n\n\nclass TaxRateUpdateView(AutoSetSelectedOrganizationMixin,\n                        generic.UpdateView):\n    template_name = \"books/tax_rate_create_or_update.html\"\n    model = TaxRate\n    form_class = TaxRateForm\n    success_url = reverse_lazy(\"books:tax_rate-list\")\n\n\nclass TaxRateDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = TaxRate\n    success_url = reverse_lazy('books:tax_rate-list')\n\n\nclass PaymentUpdateView(generic.UpdateView):\n    template_name = \"books/payment_create_or_update.html\"\n    model = Payment\n    form_class = PaymentForm\n\n    def get_success_url(self):\n        related_obj = self.object.content_object\n        if isinstance(related_obj, Invoice):\n            return reverse(\"books:invoice-detail\", args=[related_obj.pk])\n        elif isinstance(related_obj, Bill):\n            return reverse(\"books:bill-detail\", args=[related_obj.pk])\n\n        logger.warning(\"Unsupported related object '{}' for \"\n                       \"payment '{}'\".format(self.object, related_obj))\n        return reverse(\"books:dashboard\")\n\n\nclass PaymentDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = Payment\n    success_url = reverse_lazy('books:invoice-list')\n\n\nclass EstimateListView(RestrictToSelectedOrganizationQuerySetMixin,\n                       SaleListQuerySetMixin,\n                       generic.ListView):\n    template_name = \"books/estimate_list.html\"\n    model = Estimate\n    context_object_name = \"estimates\"\n\n\nclass EstimateCreateView(AutoSetSelectedOrganizationMixin,\n                         AbstractSaleCreateUpdateMixin,\n                         generic.CreateView):\n    template_name = \"books/bill_create_or_update.html\"\n    model = Estimate\n    form_class = EstimateForm\n    formset_class = EstimateLineFormSet\n    success_url = reverse_lazy(\"books:estimate-list\")\n\n    def get_form(self, form_class=None):\n        form = super().get_form(form_class)\n        orga = organization_manager.get_selected_organization(self.request)\n        self.restrict_fields_choices_to_organization(form, orga)\n        return form\n\n    def get_initial(self):\n        initial = super().get_initial()\n\n        orga = organization_manager.get_selected_organization(self.request)\n        initial['number'] = EstimateNumberGenerator().next_number(orga)\n\n        return initial\n\n\nclass EstimateUpdateView(AutoSetSelectedOrganizationMixin,\n                         AbstractSaleCreateUpdateMixin,\n                         generic.UpdateView):\n    template_name = \"books/estimate_create_or_update.html\"\n    model = Estimate\n    form_class = EstimateForm\n    formset_class = EstimateLineFormSet\n    success_url = reverse_lazy(\"books:estimate-list\")\n\n\nclass EstimateDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = Estimate\n    success_url = reverse_lazy('books:estimate-list')\n\n\nclass EstimateDetailView(AbstractSaleDetailMixin,\n                         generic.DetailView):\n    template_name = \"books/estimate_detail.html\"\n    model = Estimate\n    context_object_name = \"estimate\"\n\n    def get_success_url(self):\n        return reverse('books:estimate-detail', args=[self.object.pk])\n\n\nclass InvoiceListView(RestrictToSelectedOrganizationQuerySetMixin,\n                      SaleListQuerySetMixin,\n                      generic.ListView):\n    template_name = \"books/invoice_list.html\"\n    model = Invoice\n    context_object_name = \"invoices\"\n\n\nclass InvoiceCreateView(AutoSetSelectedOrganizationMixin,\n                        AbstractSaleCreateUpdateMixin,\n                        generic.CreateView):\n    template_name = \"books/invoice_create_or_update.html\"\n    model = Invoice\n    form_class = InvoiceForm\n    formset_class = InvoiceLineFormSet\n    success_url = reverse_lazy(\"books:invoice-list\")\n\n    def get_form(self, form_class=None):\n        form = super().get_form(form_class)\n        orga = organization_manager.get_selected_organization(self.request)\n        self.restrict_fields_choices_to_organization(form, orga)\n        return form\n\n    def get_initial(self):\n        initial = super().get_initial()\n\n        orga = organization_manager.get_selected_organization(self.request)\n        initial['number'] = InvoiceNumberGenerator().next_number(orga)\n\n        return initial\n\n\nclass InvoiceUpdateView(AutoSetSelectedOrganizationMixin,\n                        AbstractSaleCreateUpdateMixin,\n                        generic.UpdateView):\n    template_name = \"books/invoice_create_or_update.html\"\n    model = Invoice\n    form_class = InvoiceForm\n    formset_class = InvoiceLineFormSet\n    success_url = reverse_lazy(\"books:invoice-list\")\n\n\nclass InvoiceDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = Invoice\n    success_url = reverse_lazy('books:invoice-list')\n\n\nclass InvoiceDetailView(PaymentFormMixin,\n                        AbstractSaleDetailMixin,\n                        generic.DetailView):\n    template_name = \"books/invoice_detail.html\"\n    model = Invoice\n    context_object_name = \"invoice\"\n    payment_form_class = PaymentForm\n\n    def get_success_url(self):\n        return reverse('books:invoice-detail', args=[self.object.pk])\n\n\nclass BillListView(RestrictToSelectedOrganizationQuerySetMixin,\n                   SaleListQuerySetMixin,\n                   generic.ListView):\n    template_name = \"books/bill_list.html\"\n    model = Bill\n    context_object_name = \"bills\"\n\n\nclass BillCreateView(AutoSetSelectedOrganizationMixin,\n                     AbstractSaleCreateUpdateMixin,\n                     generic.CreateView):\n    template_name = \"books/bill_create_or_update.html\"\n    model = Bill\n    form_class = BillForm\n    formset_class = BillLineFormSet\n    success_url = reverse_lazy(\"books:bill-list\")\n\n    def get_form(self, form_class=None):\n        form = super().get_form(form_class)\n        orga = organization_manager.get_selected_organization(self.request)\n        self.restrict_fields_choices_to_organization(form, orga)\n        return form\n\n    def get_initial(self):\n        initial = super().get_initial()\n\n        orga = organization_manager.get_selected_organization(self.request)\n        initial['number'] = BillNumberGenerator().next_number(orga)\n\n        return initial\n\n\nclass BillUpdateView(AutoSetSelectedOrganizationMixin,\n                     AbstractSaleCreateUpdateMixin,\n                     generic.UpdateView):\n    template_name = \"books/bill_create_or_update.html\"\n    model = Bill\n    form_class = BillForm\n    formset_class = BillLineFormSet\n    success_url = reverse_lazy(\"books:bill-list\")\n\n\nclass BillDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = Bill\n    success_url = reverse_lazy('books:bill-list')\n\n\nclass BillDetailView(PaymentFormMixin,\n                     AbstractSaleDetailMixin,\n                     generic.DetailView):\n    template_name = \"books/bill_detail.html\"\n    model = Bill\n    context_object_name = \"bill\"\n    payment_form_class = PaymentForm\n\n    def get_success_url(self):\n        return reverse('books:bill-detail', args=[self.object.pk])\n\n\nclass ExpenseClaimListView(RestrictToSelectedOrganizationQuerySetMixin,\n                           SaleListQuerySetMixin,\n                           generic.ListView):\n    template_name = \"books/expense_claim_list.html\"\n    model = ExpenseClaim\n    context_object_name = \"expense_claims\"\n\n\nclass ExpenseClaimCreateView(AutoSetSelectedOrganizationMixin,\n                             AbstractSaleCreateUpdateMixin,\n                             generic.CreateView):\n    template_name = \"books/expense_claim_create_or_update.html\"\n    model = ExpenseClaim\n    form_class = ExpenseClaimForm\n    formset_class = ExpenseClaimLineFormSet\n    success_url = reverse_lazy(\"books:expense_claim-list\")\n\n    def get_form(self, form_class=None):\n        form = super().get_form(form_class)\n        orga = organization_manager.get_selected_organization(self.request)\n        self.restrict_fields_choices_to_organization(form, orga)\n        return form\n\n    def get_initial(self):\n        initial = super().get_initial()\n\n        orga = organization_manager.get_selected_organization(self.request)\n        initial['number'] = ExpenseClaimNumberGenerator().next_number(orga)\n\n        return initial\n\n\nclass ExpenseClaimUpdateView(AutoSetSelectedOrganizationMixin,\n                             AbstractSaleCreateUpdateMixin,\n                             generic.UpdateView):\n    template_name = \"books/expense_claim_create_or_update.html\"\n    model = ExpenseClaim\n    form_class = ExpenseClaimForm\n    formset_class = ExpenseClaimLineFormSet\n    success_url = reverse_lazy(\"books:expense_claim-list\")\n\n\nclass ExpenseClaimDeleteView(generic.DeleteView):\n    template_name = \"_generics/delete_entity.html\"\n    model = ExpenseClaim\n    success_url = reverse_lazy('books:expense_claim-list')\n\n\nclass ExpenseClaimDetailView(PaymentFormMixin,\n                             AbstractSaleDetailMixin,\n                             generic.DetailView):\n    template_name = \"books/expense_claim_detail.html\"\n    model = ExpenseClaim\n    context_object_name = \"expense_claim\"\n    payment_form_class = PaymentForm\n\n    def get_success_url(self):\n        return reverse('books:expense_claim-detail', args=[self.object.pk])\n"
  },
  {
    "path": "accounting/apps/connect/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/connect/middlewares.py",
    "content": "class ForceGettingStartedMiddleware(object):\n\n    def process_request(self, request):\n        pass\n"
  },
  {
    "path": "accounting/apps/connect/models.py",
    "content": ""
  },
  {
    "path": "accounting/apps/connect/steps.py",
    "content": "import logging\n\nfrom django.core.urlresolvers import reverse\nfrom django.core.exceptions import ValidationError\n\nfrom accounting.apps.books.utils import organization_manager\nfrom accounting.apps.reports.models import (\n    BusinessSettings,\n    FinancialSettings,\n    PayRunSettings)\n\nlogger = logging.getLogger(__name__)\n\n\nclass StepOptions(object):\n    \"\"\"\n    Meta class options for a `BaseStep` subclass\n    \"\"\"\n    def __init__(self, meta):\n        self.name = getattr(meta, 'name', None)\n        assert isinstance(self.name, str), \\\n            '`name` must be a string instance'\n        self.description = getattr(meta, 'description', \"\")\n        assert isinstance(self.description, str), \\\n            '`description` must be a string instance'\n\n\nclass BaseStep(object):\n    \"\"\"\n    Abstract class to subclass to create a getting started step\n    \"\"\"\n    user = None\n\n    _completion = None\n    _options_class = StepOptions\n\n    class StepOptions:\n        name = \"<Abstract>\"\n        description = None\n\n    def __init__(self, user):\n        super().__init__()\n        self.opts = self._options_class(getattr(self, 'StepOptions', None))\n        self.user = user\n\n    def completed(self, request):\n        if self._completion is None:\n            self._completion = self.check_completion(request)\n        return self._completion\n\n    def is_completed(self):\n        \"\"\"pre computed value, to be called in templates\"\"\"\n        if self._completion is None:\n            logger.error(\"`completed` needs to be run before using \"\n                         \"this method\")\n            return False\n        return self._completion\n\n    def check_completion(self, request):\n        \"\"\"\n        Implement the logic of the step\n        and returns a boolean\n        \"\"\"\n        raise NotImplementedError\n\n    def get_action_url(self):\n        \"\"\"Returns the url to complete the step\"\"\"\n        pass\n\n\nclass CreateOrganizationStep(BaseStep):\n    \"\"\"\n    At least one organization has been created\n    \"\"\"\n\n    class StepOptions:\n        name = \"Create an Organization\"\n        description = \"the organization is the foundation of the accounting \" \\\n                      \"system, tell Accountant-x more about it\"\n\n    def check_completion(self, request):\n        orgas = organization_manager.get_user_organizations(request.user)\n        count = orgas.count()\n        return count > 0\n\n    def get_action_url(self):\n        return reverse('books:organization-create')\n\n\nclass ConfigureTaxRatesStep(BaseStep):\n    \"\"\"\n    At least one tax rate has been added (even if the rate is 0)\n    \"\"\"\n\n    class StepOptions:\n        name = \"Configure Tax Rates\"\n        description = \"even if you are not subject to tax collecting rules \" \\\n                      \"you should create a 0% tax entry\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        count = orga.tax_rates.all().count()\n        return count > 0\n\n    def get_action_url(self):\n        return reverse('books:tax_rate-create')\n\n\nclass ConfigureBusinessSettingsStep(BaseStep):\n    \"\"\"\n    The associated business settings has been completed\n    \"\"\"\n\n    class StepOptions:\n        name = \"Configure Business Settings\"\n        description = \"for now there is not much thing, but please create it\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        try:\n            settings = orga.business_settings\n            settings.full_clean()\n        except BusinessSettings.DoesNotExist:\n            return False\n        except ValidationError:\n            return False\n        return True\n\n    def get_action_url(self):\n        return reverse('reports:settings-business')\n\n\nclass ConfigureFinancialSettingsStep(BaseStep):\n\n    class StepOptions:\n        name = \"Configure Financial Settings\"\n        description = \"tell Accountant-x what is your financial rulling rule\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        try:\n            settings = orga.financial_settings\n            settings.full_clean()\n        except FinancialSettings.DoesNotExist:\n            return False\n        except ValidationError:\n            return False\n        return True\n\n    def get_action_url(self):\n        return reverse('reports:settings-financial')\n\n\nclass AddEmployeesStep(BaseStep):\n\n    class StepOptions:\n        name = \"Add Employees\"\n        description = \"add at least one *employee*, even if you are giving \" \\\n                      \"yourself a salary that follows the profits\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        count = orga.employees.all().count()\n        return count > 0\n\n    def get_action_url(self):\n        return reverse('people:employee-create')\n\n\nclass ConfigurePayRunSettingsStep(BaseStep):\n\n    class StepOptions:\n        name = \"Configure Pay Run Settings\"\n        description = \"tell to Accountant-x how you distribute salaries\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        try:\n            settings = orga.payrun_settings\n            settings.full_clean()\n        except PayRunSettings.DoesNotExist:\n            return False\n        except ValidationError:\n            return False\n        return True\n\n    def get_action_url(self):\n        return reverse('reports:settings-payrun')\n\n\nclass AddFirstClientStep(BaseStep):\n\n    class StepOptions:\n        name = \"Add the first Client\"\n        description = \"close to the first invoice\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        count = orga.clients.all().count()\n        return count > 0\n\n    def get_action_url(self):\n        return reverse('people:client-create')\n\n\nclass AddFirstInvoiceStep(BaseStep):\n\n    class StepOptions:\n        name = \"Add the first Invoice\"\n        description = \"finally create it !\"\n\n    def check_completion(self, request):\n        orga = organization_manager.get_selected_organization(request)\n        if orga is None:\n            return False\n        count = orga.invoices.all().count()\n        return count > 0\n\n    def get_action_url(self):\n        return reverse('books:invoice-create')\n"
  },
  {
    "path": "accounting/apps/connect/urls.py",
    "content": "from django.conf.urls import patterns, url\n\nfrom . import views\n\n\nurlpatterns = patterns('',\n\n    url(r'^$',\n        views.RootRedirectionView.as_view(),\n        name=\"root\"),\n\n    # Step by step\n    url(r'^getting-started/$',\n        views.GettingStartedView.as_view(),\n        name=\"getting-started\")\n)\n"
  },
  {
    "path": "accounting/apps/connect/views.py",
    "content": "from django.views import generic\nfrom django.http import HttpResponseRedirect\nfrom django.core.urlresolvers import reverse\n\nfrom accounting.apps.books.models import Organization\nfrom .steps import (\n    CreateOrganizationStep,\n    ConfigureTaxRatesStep,\n    ConfigureBusinessSettingsStep,\n    ConfigureFinancialSettingsStep,\n    AddEmployeesStep,\n    ConfigurePayRunSettingsStep,\n    AddFirstClientStep,\n    AddFirstInvoiceStep)\n\n\nclass RootRedirectionView(generic.View):\n    \"\"\"\n    Redirect to the books if an organization is already configured\n\n    Otherwise we begin the step by step creation process to help the user\n    begin and configure his books\n    \"\"\"\n\n    def get(self, *args, **kwargs):\n        if Organization.objects.all().count():\n            return HttpResponseRedirect(reverse('books:dashboard'))\n\n\nclass GettingStartedView(generic.TemplateView):\n    template_name = \"connect/getting_started.html\"\n\n    def get_steps(self, request):\n        user = request.user\n        steps = steps = [\n            CreateOrganizationStep(user),\n            ConfigureTaxRatesStep(user),\n            ConfigureBusinessSettingsStep(user),\n            ConfigureFinancialSettingsStep(user),\n            AddEmployeesStep(user),\n            ConfigurePayRunSettingsStep(user),\n            AddFirstClientStep(user),\n            AddFirstInvoiceStep(user),\n        ]\n        return steps\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n\n        request = self.request\n        steps = self.get_steps(self.request)\n\n        def uncomplete_filter(s):\n            return not s.completed(request)\n\n        uncompleted_steps = list(filter(uncomplete_filter, steps))\n        try:\n            next_step = next(s for s in uncompleted_steps)\n        except StopIteration:\n            next_step = None\n\n        ctx['steps'] = steps\n        ctx['next_step'] = next_step\n        ctx['all_steps_completed'] = bool(next_step is None)\n\n        return ctx\n\n    def post(self, request, *args, **kwargs):\n        steps = self.get_steps(request)\n        uncompleted_steps = filter(lambda s: not s.completed(request), steps)\n        if not len(uncompleted_steps):\n            return super().post(request, *args, **kwargs)\n\n        # unmark the session as getting started\n        request.sessions['getting_started_done'] = True\n        return HttpResponseRedirect(reverse('books:dashboard'))\n"
  },
  {
    "path": "accounting/apps/context_processors.py",
    "content": "from django.conf import settings\n\n\ndef metadata(request):\n    \"\"\"\n    Add some generally useful metadata to the template context\n    \"\"\"\n    return {\n        'display_version': getattr(settings,\n            'DISPLAY_VERSION', 'N/A'),\n        'display_short_version': getattr(settings,\n            'DISPLAY_SHORT_VERSION', 'N/A'),\n        'version': getattr(settings,\n            'VERSION', 'N/A'),\n    }\n"
  },
  {
    "path": "accounting/apps/people/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/people/admin.py",
    "content": "from django.contrib import admin\n\nfrom . import models\n\n\n@admin.register(models.Client)\nclass ClientAdmin(admin.ModelAdmin):\n    pass\n\n\n@admin.register(models.Employee)\nclass EmployeeAdmin(admin.ModelAdmin):\n    pass\n"
  },
  {
    "path": "accounting/apps/people/forms.py",
    "content": "from django.forms import ModelForm\nfrom django.contrib.auth import get_user_model\n\nfrom .models import Client, Employee\n\nfrom django_select2.fields import (\n    AutoModelSelect2Field,\n    AutoModelSelect2MultipleField)\n\n\nclass ClientForm(ModelForm):\n    class Meta:\n        model = Client\n        fields = (\n            \"name\",\n            \"address_line_1\",\n            \"address_line_2\",\n            \"city\",\n            \"postal_code\",\n            \"country\",\n        )\n\n\nclass EmployeeForm(ModelForm):\n    class Meta:\n        model = Employee\n        fields = (\n            \"first_name\",\n            \"last_name\",\n            \"email\",\n\n            \"payroll_tax_rate\",\n\n            \"salary_follows_profits\",\n            \"shares_percentage\",\n\n        )\n\n\n# TODO: avoid calling this in the global scope, can lead to circular imports\nUser = get_user_model()\n\n\nclass UserChoices(AutoModelSelect2Field):\n    queryset = User.objects.all()\n    search_fields = (\n        'first_name__icontains',\n        'last_name__icontains',\n        'username__icontains',\n        'email__icontains',\n    )\n\n\nclass UserMultipleChoices(AutoModelSelect2MultipleField):\n    queryset = User.objects.all()\n    search_fields = (\n        'first_name__icontains',\n        'last_name__icontains',\n        'username__icontains',\n        'email__icontains',\n    )\n"
  },
  {
    "path": "accounting/apps/people/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nfrom decimal import Decimal\nimport django.core.validators\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0002_auto_20141029_1606'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Client',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('name', models.CharField(max_length=150)),\n                ('address_line_1', models.CharField(max_length=128)),\n                ('address_line_2', models.CharField(null=True, blank=True, max_length=128)),\n                ('city', models.CharField(max_length=64)),\n                ('postal_code', models.CharField(max_length=7)),\n                ('country', models.CharField(max_length=50)),\n                ('organization', models.ForeignKey(null=True, related_name='orgas', to='books.Organization', blank=True)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='Employee',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),\n                ('first_name', models.CharField(max_length=150)),\n                ('last_name', models.CharField(max_length=150)),\n                ('email', models.EmailField(max_length=254)),\n                ('salaries_follow_profits', models.BooleanField(default=False)),\n                ('shares_percentage', models.DecimalField(decimal_places=5, validators=[django.core.validators.MinValueValidator(Decimal('0')), django.core.validators.MaxValueValidator(Decimal('1'))], max_digits=6)),\n                ('organization', models.ForeignKey(to='books.Organization', related_name='employees')),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/people/migrations/0002_auto_20141029_1609.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('people', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.RenameField(\n            model_name='employee',\n            old_name='salaries_follow_profits',\n            new_name='salary_follows_profits',\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/people/migrations/0003_employee_payroll_tax_rate.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nfrom decimal import Decimal\nimport django.core.validators\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('people', '0002_auto_20141029_1609'),\n    ]\n\n    operations = [\n        migrations.AddField(\n            model_name='employee',\n            name='payroll_tax_rate',\n            field=models.DecimalField(default=0, decimal_places=5, validators=[django.core.validators.MinValueValidator(Decimal('0')), django.core.validators.MaxValueValidator(Decimal('1'))], max_digits=6),\n            preserve_default=False,\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/people/migrations/0004_auto_20141029_2306.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\ndef _link_to_first_organization(apps, schema_editor):\n    Client = apps.get_model(\"people\", \"Client\")\n    Client.objects.update(organization_id=1)\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('people', '0003_employee_payroll_tax_rate'),\n    ]\n\n    operations = [\n        migrations.RunPython(_link_to_first_organization)\n    ]\n"
  },
  {
    "path": "accounting/apps/people/migrations/0005_auto_20141029_2308.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('people', '0004_auto_20141029_2306'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='client',\n            name='organization',\n            field=models.ForeignKey(related_name='clients', to='books.Organization'),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/people/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/people/models.py",
    "content": "from decimal import Decimal as D\n\nfrom django.db import models\nfrom django.core.validators import MinValueValidator, MaxValueValidator\n\n\nclass Client(models.Model):\n    name = models.CharField(max_length=150)\n\n    # address\n    address_line_1 = models.CharField(max_length=128)\n    address_line_2 = models.CharField(max_length=128,\n                                      blank=True, null=True)\n    city = models.CharField(max_length=64)\n    postal_code = models.CharField(max_length=7)\n    country = models.CharField(max_length=50)\n\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"clients\")\n\n    class Meta:\n        pass\n\n    def __str__(self):\n        return self.name\n\n    def active_address_fields(self):\n        \"\"\"\n        Return the non-empty components of the address\n        \"\"\"\n        fields = [self.address_line_1, self.address_line_2,\n                  self.city, self.postal_code, self.country]\n        fields = [f.strip() for f in fields if f]\n        return fields\n\n    def full_address(self, separator=\"\\n\"):\n        return separator.join(filter(bool, self.active_address_fields()))\n\n\nclass Employee(models.Model):\n    first_name = models.CharField(max_length=150)\n    last_name = models.CharField(max_length=150)\n    email = models.EmailField(max_length=254)\n\n    payroll_tax_rate = models.DecimalField(\n        max_digits=6,\n        decimal_places=5,\n        validators=[\n            MinValueValidator(D('0')),\n            MaxValueValidator(D('1'))\n        ]\n    )\n\n    salary_follows_profits = models.BooleanField(default=False)\n    shares_percentage = models.DecimalField(\n        max_digits=6,\n        decimal_places=5,\n        validators=[\n            MinValueValidator(D('0')),\n            MaxValueValidator(D('1'))\n        ]\n    )\n\n    organization = models.ForeignKey('books.Organization',\n                                     related_name=\"employees\")\n\n    class Meta:\n        pass\n\n    def __str__(self):\n        return \"{}\".format(self.composite_name)\n\n    @property\n    def composite_name(self):\n        return \"{} {}\".format(self.first_name, self.last_name)\n"
  },
  {
    "path": "accounting/apps/people/urls.py",
    "content": "from django.conf.urls import patterns, url\n\nfrom . import views\n\n\nurlpatterns = patterns('',\n\n    # Clients\n    url(r'^client/$',\n        views.ClientListView.as_view(),\n        name=\"client-list\"),\n    url(r'^client/create/$',\n        views.ClientCreateView.as_view(),\n        name=\"client-create\"),\n    url(r'^client/(?P<pk>\\d+)/edit/$',\n        views.ClientUpdateView.as_view(),\n        name=\"client-edit\"),\n    url(r'^client/(?P<pk>\\d+)/detail/$',\n        views.ClientDetailView.as_view(),\n        name=\"client-detail\"),\n\n    # Employees\n    url(r'^employee/$',\n        views.EmployeeListView.as_view(),\n        name=\"employee-list\"),\n    url(r'^employee/create/$',\n        views.EmployeeCreateView.as_view(),\n        name=\"employee-create\"),\n    url(r'^employee/(?P<pk>\\d+)/edit/$',\n        views.EmployeeUpdateView.as_view(),\n        name=\"employee-edit\"),\n    url(r'^employee/(?P<pk>\\d+)/detail/$',\n        views.EmployeeDetailView.as_view(),\n        name=\"employee-detail\"),\n)\n"
  },
  {
    "path": "accounting/apps/people/views.py",
    "content": "from django.views import generic\nfrom django.core.urlresolvers import reverse\n\nfrom accounting.apps.books.mixins import (\n    RestrictToSelectedOrganizationQuerySetMixin,\n    AutoSetSelectedOrganizationMixin)\nfrom .models import Client, Employee\nfrom .forms import ClientForm, EmployeeForm\n\n\nclass ClientListView(RestrictToSelectedOrganizationQuerySetMixin,\n                     generic.ListView):\n    template_name = \"people/client_list.html\"\n    model = Client\n    context_object_name = \"clients\"\n\n\nclass ClientCreateView(AutoSetSelectedOrganizationMixin,\n                       generic.CreateView):\n    template_name = \"people/client_create_or_update.html\"\n    model = Client\n    form_class = ClientForm\n\n    def get_success_url(self):\n        return reverse(\"people:client-list\")\n\n\nclass ClientUpdateView(RestrictToSelectedOrganizationQuerySetMixin,\n                       AutoSetSelectedOrganizationMixin,\n                       generic.UpdateView):\n    template_name = \"people/client_create_or_update.html\"\n    model = Client\n    form_class = ClientForm\n\n    def get_success_url(self):\n        return reverse(\"people:client-list\")\n\n\nclass ClientDetailView(RestrictToSelectedOrganizationQuerySetMixin,\n                       generic.DetailView):\n    template_name = \"people/client_detail.html\"\n    model = Client\n    context_object_name = \"client\"\n\n\nclass EmployeeListView(RestrictToSelectedOrganizationQuerySetMixin,\n                       generic.ListView):\n    template_name = \"people/employee_list.html\"\n    model = Employee\n    context_object_name = \"employees\"\n\n\nclass EmployeeCreateView(AutoSetSelectedOrganizationMixin,\n                         generic.CreateView):\n    template_name = \"people/employee_create_or_update.html\"\n    model = Employee\n    form_class = EmployeeForm\n\n    def get_success_url(self):\n        return reverse(\"people:employee-list\")\n\n\nclass EmployeeUpdateView(RestrictToSelectedOrganizationQuerySetMixin,\n                         AutoSetSelectedOrganizationMixin,\n                         generic.UpdateView):\n    template_name = \"people/employee_create_or_update.html\"\n    model = Employee\n    form_class = EmployeeForm\n\n    def get_success_url(self):\n        return reverse(\"people:employee-list\")\n\n\nclass EmployeeDetailView(RestrictToSelectedOrganizationQuerySetMixin,\n                         generic.DetailView):\n    template_name = \"people/employee_detail.html\"\n    model = Employee\n    context_object_name = \"employee\"\n"
  },
  {
    "path": "accounting/apps/reports/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/reports/admin.py",
    "content": "from django.contrib import admin\n\nfrom . import models\n\n\n@admin.register(models.FinancialSettings)\nclass FinancialSettingsAdmin(admin.ModelAdmin):\n    pass\n"
  },
  {
    "path": "accounting/apps/reports/forms.py",
    "content": "from datetime import timedelta\n\nfrom django import forms\n\nfrom .models import (\n    BusinessSettings,\n    FinancialSettings,\n    PayRunSettings)\n\n\nclass BusinessSettingsForm(forms.ModelForm):\n    class Meta:\n        model = BusinessSettings\n        fields = (\n            \"business_type\",\n        )\n\n\nclass FinancialSettingsForm(forms.ModelForm):\n    class Meta:\n        model = FinancialSettings\n        fields = (\n            \"financial_year_end_day\",\n            \"financial_year_end_month\",\n\n            \"tax_id_number\",\n            \"tax_id_display_name\",\n            \"tax_period\",\n        )\n\n\nclass PayRunSettingsForm(forms.ModelForm):\n    class Meta:\n        model = PayRunSettings\n        fields = (\n            \"salaries_follow_profits\",\n            \"payrun_period\",\n        )\n\n\nclass TimePeriodForm(forms.Form):\n    date_from = forms.DateField(required=False,\n                                label=\"From\")\n    date_to = forms.DateField(required=False,\n                              label=\"To\")\n\n    _filters = None\n    _description = None\n\n    def _determine_filter_metadata(self):\n        self._filters = {}\n        self._description = \"All orders\"\n        if self.errors:\n            return\n\n        date_from = self.cleaned_data['date_from']\n        date_to = self.cleaned_data['date_to']\n        if date_from and date_to:\n            # We want to include end date so we adjust the date we\n            # use with the 'range' function.\n            self._filters = {\n                'date_placed__range': [\n                    date_from,\n                    date_to + timedelta(days=1)\n                ]\n            }\n            self._description = (\"Between {} and {}\"\n                .format(date_from, date_to))\n        elif date_from and not date_to:\n            self._filters = {'date_placed__gte': date_from}\n            self._description = \"Since {}\".format(date_from)\n        elif not date_from and date_to:\n            self._filters = {'date_placed__lte': date_to}\n            self._description = \"Until {}\".format(date_to)\n        else:\n            self._filters = {}\n            self._description = \"From the begining to now\"\n\n    def get_filters(self):\n        if self._filters is None:\n            self._determine_filter_metadata()\n        return self._filters\n\n    def get_filter_description(self):\n        if self._description is None:\n            self._determine_filter_metadata()\n        return self._description\n"
  },
  {
    "path": "accounting/apps/reports/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nimport django.core.validators\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('books', '0003_auto_20141029_1606'),\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='BusinessSettings',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),\n                ('business_type', models.CharField(choices=[('sole_proprietorship', 'Sole Proprietorship')], max_length=50)),\n                ('organization', models.OneToOneField(related_name='business_settings', to='books.Organization', null=True, blank=True)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='FinancialSettings',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),\n                ('financial_year_end_day', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(31)])),\n                ('financial_year_end_month', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(12)])),\n                ('tax_id_number', models.CharField(null=True, blank=True, max_length=150)),\n                ('tax_id_display_name', models.CharField(null=True, blank=True, max_length=150)),\n                ('tax_period', models.CharField(verbose_name='Tax Period', choices=[('monthly', '1 month'), ('bimonthly', '2 months'), ('quarter', '3 months'), ('half', '6 months'), ('year', '1 year')], max_length=20)),\n                ('organization', models.OneToOneField(related_name='financial_settings', to='books.Organization', null=True, blank=True)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n        migrations.CreateModel(\n            name='PayRunSettings',\n            fields=[\n                ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),\n                ('salaries_follow_profits', models.BooleanField(default=False)),\n                ('payrun_period', models.CharField(verbose_name='Payrun Period', default='monthly', choices=[('monthly', 'monthly')], max_length=20)),\n                ('organization', models.OneToOneField(related_name='payrun_settings', to='books.Organization', null=True, blank=True)),\n            ],\n            options={\n            },\n            bases=(models.Model,),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/reports/migrations/0002_auto_20150128_1458.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\nimport django.core.validators\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('reports', '0001_initial'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='financialsettings',\n            name='financial_year_end_day',\n            field=models.PositiveSmallIntegerField(default=31, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(31)]),\n        ),\n        migrations.AlterField(\n            model_name='financialsettings',\n            name='financial_year_end_month',\n            field=models.PositiveSmallIntegerField(default=12, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(12)]),\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/reports/migrations/0003_auto_20150131_1902.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nfrom django.db import models, migrations\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        ('reports', '0002_auto_20150128_1458'),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name='businesssettings',\n            name='business_type',\n            field=models.CharField(choices=[('sole_proprietorship', 'Sole Proprietorship'), ('partnership', 'Partnership'), ('corporation', 'Corporation')], max_length=50),\n            preserve_default=True,\n        ),\n    ]\n"
  },
  {
    "path": "accounting/apps/reports/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/apps/reports/models.py",
    "content": "from django.db import models\nfrom django.core.validators import MinValueValidator, MaxValueValidator\n\n\nclass BusinessSettings(models.Model):\n    BUSINESS_TYPE_SOLE_PROPRIETORSHIP = 'sole_proprietorship'\n    BUSINESS_TYPE_PARTNERSHIP = 'partnership'\n    BUSINESS_TYPE_CORPORATION = 'corporation'\n    BUSINESS_TYPE_CHOICES = (\n        (BUSINESS_TYPE_SOLE_PROPRIETORSHIP, \"Sole Proprietorship\"),\n        (BUSINESS_TYPE_PARTNERSHIP, \"Partnership\"),\n        (BUSINESS_TYPE_CORPORATION, \"Corporation\"),\n    )\n    business_type = models.CharField(max_length=50,\n                                     choices=BUSINESS_TYPE_CHOICES)\n\n    # optionnaly linked to an organization\n    # for automated behaviors during cross-organizations invoicing\n    organization = models.OneToOneField('books.Organization',\n                                        related_name=\"business_settings\",\n                                        blank=True, null=True)\n\n    class Meta:\n        pass\n\n\nclass FinancialSettings(models.Model):\n    financial_year_end_day = models.PositiveSmallIntegerField(default=31,\n        validators=[\n            MinValueValidator(1),\n            MaxValueValidator(31)\n        ])\n    financial_year_end_month = models.PositiveSmallIntegerField(default=12,\n        validators=[\n            MinValueValidator(1),\n            MaxValueValidator(12)\n        ])\n\n    tax_id_number = models.CharField(max_length=150,\n                                     blank=True, null=True)\n    tax_id_display_name = models.CharField(max_length=150,\n                                           blank=True, null=True)\n\n    TAX_PERIOD_MONTHLY = 'monthly'      # 1 month\n    TAX_PERIOD_BIMONTHLY = 'bimonthly'  # 2 months\n    TAX_PERIOD_QUARTER = 'quarter'      # 3 months\n    TAX_PERIOD_HALF = 'half'            # 6 months\n    TAX_PERIOD_YEAR = 'year'            # 12 months\n    TAX_PERIOD_CHOICES = (\n        (TAX_PERIOD_MONTHLY, \"1 month\"),\n        (TAX_PERIOD_BIMONTHLY, \"2 months\"),\n        (TAX_PERIOD_QUARTER, \"3 months\"),\n        (TAX_PERIOD_HALF, \"6 months\"),\n        (TAX_PERIOD_YEAR, \"1 year\"),\n    )\n    tax_period = models.CharField(\"Tax Period\",\n                                  max_length=20,\n                                  choices=TAX_PERIOD_CHOICES)\n\n    # optionnaly linked to an organization\n    # for automated behaviors during cross-organizations invoicing\n    organization = models.OneToOneField('books.Organization',\n                                        related_name=\"financial_settings\",\n                                        blank=True, null=True)\n\n    class Meta:\n        pass\n\n\nclass PayRunSettings(models.Model):\n    salaries_follow_profits = models.BooleanField(default=False)\n\n    PAYRUN_MONTHLY = 'monthly'      # 1 month\n    # PAYRUN_QUARTER = 'quarter'      # 3 months\n    PAYRUN_CHOICES = (\n        (PAYRUN_MONTHLY, \"monthly\"),\n    )\n    payrun_period = models.CharField(\"Payrun Period\",\n                                     max_length=20,\n                                     choices=PAYRUN_CHOICES,\n                                     default=PAYRUN_MONTHLY)\n\n    # optionnaly linked to an organization\n    # for automated behaviors during cross-organizations invoicing\n    organization = models.OneToOneField('books.Organization',\n                                        related_name=\"payrun_settings\",\n                                        blank=True, null=True)\n\n    class Meta:\n        pass\n"
  },
  {
    "path": "accounting/apps/reports/urls.py",
    "content": "from django.conf.urls import patterns, url\n\nfrom . import views\n\n\nurlpatterns = patterns('',\n\n    # Reports\n    url(r'^report/$',\n        views.ReportListView.as_view(),\n        name=\"report-list\"),\n    url(r'^report/tax/$',\n        views.TaxReportView.as_view(),\n        name=\"tax-report\"),\n    url(r'^report/profitloss/$',\n        views.ProfitAndLossReportView.as_view(),\n        name=\"profit-and-loss-report\"),\n    url(r'^report/payrun/$',\n        views.PayRunReportView.as_view(),\n        name=\"pay-run-report\"),\n    url(r'^report/invoicedetails/$',\n        views.InvoiceDetailsView.as_view(),\n        name=\"invoice-details-report\"),\n\n    # Settings\n    url(r'^settings/$',\n        views.SettingsListView.as_view(),\n        name=\"settings-list\"),\n    url(r'^settings/business/$',\n        views.BusinessSettingsUpdateView.as_view(),\n        name=\"settings-business\"),\n    url(r'^settings/financial/$',\n        views.FinancialSettingsUpdateView.as_view(),\n        name=\"settings-financial\"),\n    url(r'^settings/payrun/$',\n        views.PayRunSettingsUpdateView.as_view(),\n        name=\"settings-payrun\"),\n)\n"
  },
  {
    "path": "accounting/apps/reports/views.py",
    "content": "from datetime import date\n\nfrom django.views import generic\nfrom django.core.urlresolvers import reverse\nfrom django.utils import timezone\n\nfrom dateutil.relativedelta import relativedelta\n\nfrom accounting.apps.books.utils import organization_manager\nfrom accounting.libs.intervals import TimeInterval\nfrom .models import (\n    BusinessSettings,\n    FinancialSettings,\n    PayRunSettings)\nfrom .forms import (\n    BusinessSettingsForm,\n    FinancialSettingsForm,\n    PayRunSettingsForm,\n    TimePeriodForm)\nfrom .wrappers import (\n    TaxReport,\n    ProfitAndLossReport,\n    PayRunReport,\n    InvoiceDetailsReport)\n\n\nclass TimePeriodFormMixin(object):\n\n    period = None\n\n    def get_initial(self):\n        initial = super().get_initial()\n\n        # currrent quarter\n        now = timezone.now()\n        start = date(\n            year=now.year,\n            month=(now.month - ((now.month - 1) % 3)),\n            day=1\n        )\n        end = start + relativedelta(months=3)\n\n        initial['date_from'] = start\n        initial['date_to'] = end\n\n        return initial\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        if self.request.GET:\n            kwargs.update({\n                'data': self.request.GET,\n            })\n        return kwargs\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n\n        form = ctx['form']\n        if form.is_valid():\n            start = form.cleaned_data['date_from']\n            end = form.cleaned_data['date_to']\n            ctx['form_title'] = form.get_filter_description()\n        else:\n            start = end = None\n            ctx['form_title'] = \"Time Interval\"\n\n        if self.period is None:\n            self.period = TimeInterval(start=start, end=end)\n\n        return ctx\n\n\nclass ReportListView(generic.TemplateView):\n    template_name = \"reports/report_list.html\"\n\n\nclass SettingsListView(generic.TemplateView):\n    template_name = \"reports/settings_list.html\"\n\n\nclass GenericSettingsMixin(object):\n\n    def get_object(self):\n        orga = organization_manager.get_selected_organization(self.request)\n        try:\n            settings = self.model.objects.get(organization=orga)\n        except self.model.DoesNotExist:\n            settings = self.model.objects.create(organization=orga)\n        return settings\n\n    def get_success_url(self):\n        return reverse(\"reports:settings-list\")\n\n\nclass BusinessSettingsUpdateView(GenericSettingsMixin,\n                                 generic.UpdateView):\n    template_name = \"reports/financial_settings_update.html\"\n    model = BusinessSettings\n    form_class = BusinessSettingsForm\n\n\nclass FinancialSettingsUpdateView(GenericSettingsMixin,\n                                  generic.UpdateView):\n    template_name = \"reports/financial_settings_update.html\"\n    model = FinancialSettings\n    form_class = FinancialSettingsForm\n\n\nclass PayRunSettingsUpdateView(GenericSettingsMixin,\n                               generic.UpdateView):\n    template_name = \"reports/payrun_settings_update.html\"\n    model = PayRunSettings\n    form_class = PayRunSettingsForm\n\n\nclass TaxReportView(TimePeriodFormMixin,\n                    generic.FormView):\n    template_name = \"reports/tax_report.html\"\n    form_class = TimePeriodForm\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        orga = organization_manager.get_selected_organization(self.request)\n        report = TaxReport(orga,\n                           start=self.period.start,\n                           end=self.period.end)\n        report.generate()\n        ctx['tax_summaries'] = report.tax_summaries.values()\n        return ctx\n\n\nclass ProfitAndLossReportView(generic.TemplateView):\n    template_name = \"reports/profit_and_loss_report.html\"\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        orga = organization_manager.get_selected_organization(self.request)\n\n        # currrent quarter\n        now = timezone.now()\n        start = date(\n            year=now.year,\n            month=(now.month - ((now.month - 1) % 3)),\n            day=1\n        )\n        end = start + relativedelta(months=3)\n\n        report = ProfitAndLossReport(orga, start=start, end=end)\n        report.generate()\n        ctx['summaries'] = report.summaries\n        ctx['total_summary'] = report.total_summary\n        return ctx\n\n\nclass PayRunReportView(TimePeriodFormMixin,\n                       generic.FormView):\n    template_name = \"reports/pay_run_report.html\"\n    form_class = TimePeriodForm\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        orga = organization_manager.get_selected_organization(self.request)\n\n        report = PayRunReport(orga,\n                              start=self.period.start,\n                              end=self.period.end)\n        report.generate()\n        ctx['summaries'] = report.summaries.values()\n        ctx['total_payroll_taxes'] = report.total_payroll_taxes\n\n        return ctx\n\n\nclass InvoiceDetailsView(TimePeriodFormMixin,\n                         generic.FormView):\n    template_name = \"reports/invoice_details_report.html\"\n    form_class = TimePeriodForm\n\n    def get_context_data(self, **kwargs):\n        ctx = super().get_context_data(**kwargs)\n        orga = organization_manager.get_selected_organization(self.request)\n        report = InvoiceDetailsReport(orga,\n                                      start=self.period.start,\n                                      end=self.period.end)\n        report.generate()\n        ctx['invoices'] = report.invoices\n        ctx['tax_rates'] = report.tax_rates\n        ctx['payrun_settings'] = orga.payrun_settings\n        return ctx\n"
  },
  {
    "path": "accounting/apps/reports/wrappers.py",
    "content": "from decimal import Decimal as D\nfrom collections import defaultdict, OrderedDict\n\nfrom dateutil.relativedelta import relativedelta\n\nfrom accounting.apps.books.models import Invoice, Bill\nfrom accounting.apps.books.calculators import ProfitsLossCalculator\nfrom accounting.libs.intervals import TimeInterval\n\n\nclass BaseReport(object):\n    title = None\n    period = None\n\n    def __init__(self, title, start, end):\n        self.title = title\n        self.period = TimeInterval(start, end)\n\n    def generate(self):\n        raise NotImplementedError\n\n\nclass TaxRateSummary(object):\n    tax_rate = None\n    taxable_amount = D('0')\n    expenses_amount = D('0')\n\n    @property\n    def collected_taxes(self):\n        return self.tax_rate.rate * self.taxable_amount\n\n    @property\n    def deductible_taxes(self):\n        return self.tax_rate.rate * self.expenses_amount\n\n    @property\n    def net_amount(self):\n        return self.taxable_amount - self.expenses_amount\n\n    @property\n    def net_taxes(self):\n        return self.tax_rate.rate * self.net_amount\n\n\nclass TaxReport(BaseReport):\n    # TODO implement 'Billed (Accrual) / Collected (Cash based)'\n    organization = None\n    tax_summaries = None\n\n    def __init__(self, organization, start, end):\n        super().__init__(\"Tax Report\", start, end)\n        self.organization = organization\n        self.tax_summaries = defaultdict(TaxRateSummary)\n\n    def generate(self):\n        invoice_queryset = Invoice.objects.all()\n        bill_queryset = Bill.objects.all()\n        self.generate_for_sales(invoice_queryset)\n        self.generate_for_sales(bill_queryset)\n\n    def generate_for_sales(self, sales_queryset):\n        calculator = ProfitsLossCalculator(self.organization,\n                                           start=self.period.start,\n                                           end=self.period.end)\n\n        for output in calculator.process_generator(sales_queryset):\n            summary = self.tax_summaries[output.tax_rate.pk]\n            summary.tax_rate = output.tax_rate\n\n            if isinstance(output.sale, Invoice):\n                summary.taxable_amount += output.amount_excl_tax\n            elif isinstance(output.sale, Bill):\n                summary.expenses_amount += output.amount_excl_tax\n            else:\n                raise ValueError(\"Unsupported type of sale {}\"\n                    .format(output.sale.__class__))\n\n\nclass ProfitAndLossSummary(object):\n    grouping_date = None\n    sales_amount = D('0')\n    expenses_amount = D('0')\n\n    @property\n    def net_profit(self):\n        return self.sales_amount - self.expenses_amount\n\n\nclass ProfitAndLossReport(BaseReport):\n    # TODO implement 'Billed (Accrual) / Collected (Cash based)'\n    organization = None\n    summaries = None\n    total_summary = None\n\n    RESOLUTION_MONTHLY = 'monthly'\n    RESOLUTION_CHOICES = (\n        RESOLUTION_MONTHLY,\n    )\n    group_by_resolution = RESOLUTION_MONTHLY\n\n    def __init__(self, organization, start, end):\n        super().__init__(\"Profit and Loss\", start, end)\n        self.organization = organization\n        self.summaries = {}\n        steps_interval = relativedelta(end, start)\n\n        assert self.group_by_resolution in self.RESOLUTION_CHOICES, \\\n            \"No a resolution choice\"\n        if self.group_by_resolution == self.RESOLUTION_MONTHLY:\n            for step in range(0, steps_interval.months):\n                key_date = start + relativedelta(months=step)\n                self.summaries[key_date] = ProfitAndLossSummary()\n        else:\n            raise ValueError(\"Unsupported resolution {}\"\n                .format(self.group_by_resolution))\n\n        self.total_summary = ProfitAndLossSummary()\n\n    def group_by_date(self, date):\n        if self.group_by_resolution == self.RESOLUTION_MONTHLY:\n            grouping_date = date.replace(day=1)\n        else:\n            raise ValueError(\"Unsupported resolution {}\"\n                .format(self.group_by_resolution))\n        return grouping_date\n\n    def generate(self):\n        invoice_queryset = Invoice.objects.all()\n        bill_queryset = Bill.objects.all()\n        self.generate_for_sales(invoice_queryset)\n        self.generate_for_sales(bill_queryset)\n\n        # order the results\n        self.summaries = OrderedDict(sorted(self.summaries.items()))\n\n        # compute totals\n        for summary in self.summaries.values():\n            self.total_summary.sales_amount += summary.sales_amount\n            self.total_summary.expenses_amount += summary.expenses_amount\n\n    def generate_for_sales(self, sales_queryset):\n        calculator = ProfitsLossCalculator(self.organization,\n                                           start=self.period.start,\n                                           end=self.period.end)\n\n        for output in calculator.process_generator(sales_queryset):\n            key_date = self.group_by_date(output.payment.date_paid)\n            summary = self.summaries[key_date]\n\n            if isinstance(output.sale, Invoice):\n                summary.sales_amount += output.amount_excl_tax\n            elif isinstance(output.sale, Bill):\n                summary.expenses_amount += output.amount_excl_tax\n            else:\n                raise ValueError(\"Unsupported type of sale {}\"\n                    .format(output.sale.__class__))\n\n\nclass PayRunSummary(object):\n    payroll_tax_rate = None\n    total_excl_tax = D('0')\n\n    @property\n    def payroll_taxes(self):\n        return self.payroll_tax_rate * self.total_excl_tax\n\n\nclass PayRunReport(BaseReport):\n    organization = None\n    summaries = None\n    total_payroll_taxes = D('0')\n\n    def __init__(self, organization, start, end):\n        super().__init__(\"Pay Run Report\", start, end)\n        self.organization = organization\n        self.summaries = defaultdict(PayRunSummary)\n\n    def generate(self):\n        employee_queryset = self.organization.employees.all()\n        self.generate_for_employees(employee_queryset)\n\n    def generate_for_employees(self, employee_queryset):\n        total_payroll_taxes = D('0')\n        calculator = ProfitsLossCalculator(self.organization,\n                                           start=self.period.start,\n                                           end=self.period.end)\n\n        for emp in employee_queryset:\n            summary = self.summaries[emp.composite_name]\n            summary.employee = emp\n            summary.payroll_tax_rate = emp.payroll_tax_rate\n            if emp.salary_follows_profits:\n                # TODO compute profits based on the period interval\n                profits = calculator.profits()\n                summary.total_excl_tax = profits * emp.shares_percentage\n            else:\n                raise ValueError(\"Salary not indexed on the profits \"\n                                 \"are not supported yet\")\n\n            total_payroll_taxes += summary.payroll_taxes\n\n        # Total payroll\n        self.total_payroll_taxes = total_payroll_taxes\n\n\nclass InvoiceDetailsReport(BaseReport):\n    organization = None\n    invoices = None\n    tax_rates = None\n\n    def __init__(self, organization, start, end):\n        super().__init__(\"Pay Run Report\", start, end)\n        self.organization = organization\n        self.tax_rates = organization.tax_rates.all()\n\n    def generate(self):\n        invoice_queryset = self.organization.invoices.all()\n        self.generate_for_invoices(invoice_queryset)\n\n    def generate_for_invoices(self, invoice_queryset):\n        invoice_queryset = (invoice_queryset\n            .filter(payments__date_paid__range=[\n                self.period.start,\n                self.period.end\n            ]))\n\n        # optimize the query\n        invoice_queryset = (invoice_queryset\n            .select_related(\n                'organization')\n            .prefetch_related(\n                'lines',\n                'lines__tax_rate',\n                'payments',\n                'organization__employees',)\n            .distinct())\n\n        self.invoices = invoice_queryset\n"
  },
  {
    "path": "accounting/defaults.py",
    "content": "ACCOUNTING_DEFAULT_CURRENCY = \"EUR\"\n"
  },
  {
    "path": "accounting/libs/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/libs/checks.py",
    "content": "from django.core.validators import EMPTY_VALUES\nfrom django.utils.datastructures import SortedDict\n\n\nclass PrimaryKeyRelatedField(object):\n    pass\n\n\nclass CheckResult(object):\n    \"\"\"\n    Stands for a checking result of a model field\n    \"\"\"\n\n    RESULT_NEUTRAL = 'neutral'\n    RESULT_FAILED = 'failed'\n    RESULT_PASSED = 'passed'\n    RESULT_CHOICES = (\n        (RESULT_NEUTRAL, \"Neutral\"),\n        (RESULT_FAILED, \"Failed\"),\n        (RESULT_PASSED, \"Passed\"),\n    )\n\n    LEVEL_WARNING = 'warning'\n    LEVEL_ERROR = 'error'\n    LEVEL_CHOICES = (\n        (LEVEL_WARNING, \"Warning\"),\n        (LEVEL_ERROR, \"Error\"),\n    )\n\n    def __init__(self, field, result=None, level=None, message=None):\n        self.field = field\n        self.message = message\n\n        if not result:\n            result = self.RESULT_NEUTRAL\n        self.result = result\n\n        if not level:\n            level = self.LEVEL_WARNING\n        self.level = level\n\n    def mark_fail(self, level=LEVEL_WARNING, message=None):\n        self.result = self.RESULT_FAILED\n        self.level = level\n        self.message = message\n\n    def mark_pass(self, message=None):\n        self.result = self.RESULT_PASSED\n        self.message = message\n\n    @property\n    def has_failed(self):\n        return self.result == self.RESULT_FAILED\n\n    @property\n    def has_passed(self):\n        return self.result == self.RESULT_PASSED\n\n\nclass CheckingModelOptions(object):\n    \"\"\"\n    Meta class options for `CheckingModelMixin`\n    \"\"\"\n    def __init__(self, meta):\n        self.fields = getattr(meta, 'fields', ())\n        assert isinstance(self.fields, (list, tuple)), \\\n            '`fields` must be a list or tuple'\n\n        self.exclude = getattr(meta, 'exclude', ())\n        assert isinstance(self.exclude, (list, tuple)), \\\n            '`exclude` must be a list or tuple'\n\n\nclass CheckingModelMixin(object):\n\n    _options_class = CheckingModelOptions\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.opts = self._options_class(getattr(self, 'CheckingOptions', None))\n\n    def has_custom_check_for_field(self, field_name):\n        return hasattr(self, 'check_%s' % field_name)\n\n    def get_check_for_field(self, field_name, checking_fields=None):\n        if checking_fields is None:\n            checking_fields = self.get_checking_fields()\n\n        if field_name not in checking_fields:\n            raise AttributeError(\"Field '%s' not checkable\" % field_name)\n\n        field = checking_fields.get(field_name)\n        check = CheckResult(field=field)\n\n        # custom check method\n        if self.has_custom_check_for_field(field_name):\n            return getattr(self, 'check_%s' % field_name)(check)\n\n        # default check\n        if isinstance(field, PrimaryKeyRelatedField):\n            value = getattr(self, field_name).all()\n            has_failed = bool(value.count() == 0)\n        else:\n            value = getattr(self, field_name)\n            has_failed = bool(value in EMPTY_VALUES)\n\n        if has_failed:\n            check.mark_fail()\n        else:\n            check.mark_pass()\n        return check\n\n    def get_checking_fields(self, special_exclude=['id']):\n        \"\"\"\n        Returns the set of fields on which we perform checkings\n        \"\"\"\n        ret = SortedDict()\n        for f in self._meta.fields:\n            # avoid special_exclude fields\n            if f.attname in special_exclude:\n                continue\n            ret[f.attname] = f\n\n        # Deal with reverse relationships\n        reverse_rels = self._meta.get_all_related_objects()\n        # reverse_rels += self._meta.get_all_related_many_to_many_objects()\n        for relation in reverse_rels:\n            accessor_name = relation.get_accessor_name()\n            to_many = relation.field.rel.multiple\n            if not self.opts.fields or accessor_name not in self.opts.fields:\n                continue\n            if not to_many:\n                raise NotImplementedError\n            ret[accessor_name] = PrimaryKeyRelatedField()\n\n        # If 'fields' is specified, use those fields, in that order.\n        if self.opts.fields:\n            new = SortedDict()\n            for key in self.opts.fields:\n                new[key] = ret[key]\n            ret = new\n\n        # Remove anything in 'exclude'\n        if self.opts.exclude:\n            for key in self.opts.exclude:\n                ret.pop(key, None)\n\n        return ret\n\n    def check_fields(self):\n        \"\"\"\n        First `self.clean_fields` is called to ensure data integrity\n\n        Checks all fields and return a list of `CheckResult` instances\n        \"\"\"\n        # TODO try to reintegrate this one without\n        #      increase the db queries too much\n        # self.clean_fields()\n\n        checks = []\n        fields = self.get_checking_fields()\n        for key, field in fields.items():\n            check = self.get_check_for_field(key, checking_fields=fields)\n            checks.append(check)\n        return checks\n\n    def full_check(self):\n        \"\"\"\n        Calls `self.check_fields`, `self.check` in that order\n\n        NB: no need to call `self.full_clean` because the above\n            methods already made those calls internally\n        \"\"\"\n        # basic field checks\n        checks = self.check_fields()\n\n        # special checks\n        additional_checks = self.check_additionnals()\n        checks.extend(additional_checks)\n\n        return checks\n\n    def check_additionnals(self):\n        \"\"\"Additional checks that the user can implement\"\"\"\n        return []\n\n    def _raw_checking_completion(self):\n        \"\"\"\n        Useful for additional checking completion computations\n        \"\"\"\n        checks = self.full_check()\n        completed = sum(1 for c in checks if c.has_passed)\n        return completed, len(checks)\n\n    def checking_completion(self):\n        \"\"\"\n        Compute the percentage of checking completed\n        on the model instance\n        \"\"\"\n        completed, total = self._raw_checking_completion()\n        return float(completed) / total\n\n    def full_checking_completion(self):\n        \"\"\"\n        Calls `self.checking_completion`\n\n        This method should be used to do checking completion on\n        related objects\n        \"\"\"\n        completion = self.checking_completion()\n        return completion\n\n    def pass_full_checking(self):\n        completion = self.full_checking_completion()\n        return completion == 1.0\n"
  },
  {
    "path": "accounting/libs/decorators.py",
    "content": "# encoding: utf-8\n\n\ndef composed(*decs):\n    \"\"\"\n    Compose multiple decorators\n\n    Example :\n\n    >>> @composed(dec1, dec2)\n    ...     def some(f):\n    ...         pass\n    \"\"\"\n    def deco(f):\n        for dec in reversed(decs):\n            f = dec(f)\n        return f\n    return deco\n\n\ndef order_fields(*field_list):\n    def decorator(form):\n        original_init = form.__init__\n\n        def init(self, *args, **kwargs):\n            original_init(self, *args, **kwargs)\n            for field in field_list[::-1]:\n                self.fields.insert(0, field, self.fields.pop(field))\n        form.__init__ = init\n        return form\n    return decorator\n\n\ndef memoize(func):\n    \"\"\"\n    Memoization decorator for a function taking one or more arguments.\n    \"\"\"\n    class memodict(dict):\n        def __getitem__(self, *key):\n            return dict.__getitem__(self, key)\n\n        def __missing__(self, key):\n            ret = self[key] = func(*key)\n            return ret\n\n    return memodict().__getitem__\n"
  },
  {
    "path": "accounting/libs/exceptions.py",
    "content": ""
  },
  {
    "path": "accounting/libs/fields.py",
    "content": "from django.db import models\nimport uuid\n\n\nclass UUIDField(models.CharField):\n\n    def __init__(self, *args, **kwargs):\n        kwargs['max_length'] = kwargs.get('max_length', 64 )\n        kwargs['blank'] = True\n        models.CharField.__init__(self, *args, **kwargs)\n\n    def _generate_uuid(self):\n        return str(uuid.uuid4())\n\n    def pre_save(self, model_instance, add):\n        if add or not getattr(model_instance, self.attname):\n            value = self._generate_uuid()\n            setattr(model_instance, self.attname, value)\n            return value\n        else:\n            return super(models.CharField, self).pre_save(model_instance, add)\n"
  },
  {
    "path": "accounting/libs/foundation.py",
    "content": "\"\"\"\nPython helpers\n\"\"\"\n\nfrom collections import Mapping\n\n\ndef update(d, u, depth=-1):\n    \"\"\"\n    Recursively merge or update dict-like objects.\n    >>> update({'k1': {'k2': 2}}, {'k1': {'k2': {'k3': 3}}, 'k4': 4})\n    {'k1': {'k2': {'k3': 3}}, 'k4': 4}\n    \"\"\"\n\n    for k, v in u.iteritems():\n        if isinstance(v, Mapping) and not depth == 0:\n            r = update(d.get(k, {}), v, depth=max(depth - 1, -1))\n            d[k] = r\n        elif isinstance(d, Mapping):\n            d[k] = u[k]\n        else:\n            d = {k: u[k]}\n    return d\n"
  },
  {
    "path": "accounting/libs/intervals.py",
    "content": "from datetime import date\n\n\nclass TimeInterval(object):\n    start = None\n    end = None\n\n    def __init__(self, start, end):\n        assert start is None or isinstance(start, date), \\\n            \"start should be a date instance\"\n        assert end is None or isinstance(end, date), \\\n            \"end should be a date instance\"\n        self.start = start\n        self.end = end\n"
  },
  {
    "path": "accounting/libs/prices.py",
    "content": "class TaxNotKnown(Exception):\n    \"\"\"\n    Exception for when a tax-inclusive price is requested but we don't know\n    what the tax applicable is (yet).\n    \"\"\"\n\n\nclass Price(object):\n    \"\"\"\n    Simple price class that encapsulates a price and its tax information\n\n    Attributes:\n        incl_tax (Decimal): Price including taxes\n        excl_tax (Decimal): Price excluding taxes\n        tax (Decimal): Tax amount\n        is_tax_known (bool): Whether tax is known\n        currency (str): 3 character currency code\n    \"\"\"\n\n    def __init__(self, currency, excl_tax, incl_tax=None, tax=None):\n        self.currency = currency\n        self.excl_tax = excl_tax\n        if incl_tax is not None:\n            self.incl_tax = incl_tax\n            self.is_tax_known = True\n        elif tax is not None:\n            self.incl_tax = excl_tax + tax\n            self.is_tax_known = True\n        else:\n            self.incl_tax = None\n            self.is_tax_known = False\n\n    def _get_tax(self):\n        return self.incl_tax - self.excl_tax\n\n    def _set_tax(self, value):\n        self.incl_tax = self.excl_tax + value\n        self.is_tax_known = True\n\n    tax = property(_get_tax, _set_tax)\n\n    def __repr__(self):\n        if self.is_tax_known:\n            return \"%s(currency=%r, excl_tax=%r, incl_tax=%r, tax=%r)\" % (\n                self.__class__.__name__, self.currency, self.excl_tax,\n                self.incl_tax, self.tax)\n        return \"%s(currency=%r, excl_tax=%r)\" % (\n            self.__class__.__name__, self.currency, self.excl_tax)\n\n    def __eq__(self, other):\n        \"\"\"\n        Two price objects are equal if currency, price.excl_tax and tax match.\n        \"\"\"\n        return (self.currency == other.currency and\n                self.excl_tax == other.excl_tax and\n                self.incl_tax == other.incl_tax)\n"
  },
  {
    "path": "accounting/libs/templatetags/__init__.py",
    "content": ""
  },
  {
    "path": "accounting/libs/templatetags/check_filters.py",
    "content": "from django import template\n\nfrom accounting.libs.checks import CheckingModelMixin\n\nregister = template.Library()\n\n\n@register.filter\ndef check(obj, field_name=None):\n    \"\"\"\n    Can check an entire model or just a single model field\n    \"\"\"\n    if isinstance(obj, CheckingModelMixin):\n        if not field_name:\n            check = obj.full_check()\n        else:\n            check = obj.get_check_for_field(field_name)\n    else:\n        return None\n\n    return check\n\n\n@register.filter('level_to_css_classname')\ndef _check_level_to_classname(check):\n    \"\"\"\n    Return the appropriated css classname for the check level\n    \"\"\"\n    if check.has_failed:\n        if check.level == check.LEVEL_ERROR:\n            return 'danger'\n        elif check.level == check.LEVEL_WARNING:\n            return 'warning'\n        else:\n            return 'info'\n\n    return 'default'\n\n\n@register.filter('level_to_glyphicon')\ndef _check_level_to_glyphicon(check):\n    \"\"\"\n    Return the appropriated glyph icon for the check level\n    \"\"\"\n    if check.has_failed:\n        if check.level == check.LEVEL_ERROR:\n            return 'minus-sign'\n        elif check.level == check.LEVEL_WARNING:\n            return 'exclamation-sign'\n        else:\n            return 'question-sign'\n\n    return 'ok'\n"
  },
  {
    "path": "accounting/libs/templatetags/check_tags.py",
    "content": "from django import template\n\nfrom classytags.core import Options\nfrom classytags.arguments import Argument\nfrom classytags.helpers import InclusionTag\n\nregister = template.Library()\n\n\n@register.tag\nclass Check(InclusionTag):\n    name = 'render_check'\n    template = '_generics/check_tag.html'\n    options = Options(\n        Argument('check'),\n    )\n\n    def get_context(self, context, check):\n        context.update({\n            'check': check\n        })\n\n        return context\n"
  },
  {
    "path": "accounting/libs/templatetags/currency_filters.py",
    "content": "# encoding: utf-8\n\nfrom decimal import Decimal as D, InvalidOperation\n\nfrom django import template\nfrom django.conf import settings\nfrom django.utils.translation import to_locale, get_language\n\nfrom babel.numbers import format_currency\n\nregister = template.Library()\n\n\n@register.filter(name='currency')\ndef currency_formatter(value, currency=None):\n    \"\"\"\n    Format decimal value as currency\n    \"\"\"\n    try:\n        value = D(value)\n    except (TypeError, InvalidOperation):\n        return \"\"\n    # Using Babel's currency formatting\n    # http://babel.pocoo.org/docs/api/numbers/#babel.numbers.format_currency\n    currency = currency or settings.ACCOUNTING_DEFAULT_CURRENCY\n    kwargs = {\n        'currency': currency,\n        'format': getattr(settings, 'CURRENCY_FORMAT', None),\n        'locale': to_locale(get_language()),\n    }\n    return format_currency(value, **kwargs)\n"
  },
  {
    "path": "accounting/libs/templatetags/display_tags.py",
    "content": "from django import template\n\nregister = template.Library()\n"
  },
  {
    "path": "accounting/libs/templatetags/distance_filters.py",
    "content": "from django import template\n\nfrom django.contrib.gis.measure import Distance\n\nregister = template.Library()\n\n\n@register.filter\ndef has_distance(search_object):\n    return bool(search_object._point_of_origin)\n\n\n@register.filter\ndef distance(dist):\n    if isinstance(dist, Distance):\n        d = dist.m\n        unit = \"m\"\n\n        if d > 1000:\n            d = dist.km\n            unit = \"km\"\n\n        ctx = {\n            'distance': float('%.2g' % d),\n            'unit': unit,\n        }\n        return u\"%(distance)s %(unit)s\" % ctx\n"
  },
  {
    "path": "accounting/libs/templatetags/float_filters.py",
    "content": "from django.template import Library\nfrom django.utils.numberformat import format\n\nregister = Library()\n\n\n@register.filter(name=\"float_dot\")\ndef do_float_dot(value, decimal_pos=4):\n    return format(value or 0, \".\", decimal_pos)\n\n\ndo_float_dot.is_safe = True\n"
  },
  {
    "path": "accounting/libs/templatetags/form_filters.py",
    "content": "from django import template\nfrom django.forms import ModelForm, BaseFormSet\nfrom django.forms.forms import BoundField\n\n\nregister = template.Library()\n\n\n@register.filter\ndef css_class(field):\n    if isinstance(field, BoundField):\n        field = field.field\n    return field.widget.__class__.__name__.lower()\n\n\n@register.filter\ndef is_disabled(field):\n    if isinstance(field, BoundField):\n        field = field.field\n    return 'disabled' in field.widget.attrs\n\n\n@register.filter\ndef is_readonly(field):\n    if isinstance(field, BoundField):\n        field = field.field\n    return ('readonly' in field.widget.attrs and\n        field.widget.attrs.get('readonly') is True)\n\n\n@register.filter\ndef get_form_model_verbose_name(instance):\n    if isinstance(instance, ModelForm):\n        return instance._meta.model._meta.verbose_name.title()\n    if isinstance(instance, BaseFormSet):\n        return instance.model._meta.verbose_name_plural.title()\n    return '<unknown>'\n"
  },
  {
    "path": "accounting/libs/templatetags/form_tags.py",
    "content": "from django import template\n\nregister = template.Library()\n\n\n@register.tag\ndef annotate_form_field(parser, token):\n    \"\"\"\n    Set an attribute on a form field with the widget type\n\n    This means templates can use the widget type to render things differently\n    if they want to.  Django doesn't make this available by default.\n    \"\"\"\n    args = token.split_contents()\n    if len(args) < 2:\n        raise template.TemplateSyntaxError(\n            \"annotate_form_field tag requires a form field to be passed\")\n    return FormFieldNode(args[1])\n\n\nclass FormFieldNode(template.Node):\n\n    def __init__(self, field_str):\n        self.field = template.Variable(field_str)\n\n    def render(self, context):\n        field = self.field.resolve(context)\n        field.widget_type = field.field.widget.__class__.__name__\n        return ''\n"
  },
  {
    "path": "accounting/libs/templatetags/format_filters.py",
    "content": "import datetime\n\nfrom django import template\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.utils.timezone import now as django_now\nfrom django.utils.translation import to_locale, get_language\n\nfrom babel.numbers import format_percent\n\nregister = template.Library()\n\n\n@register.filter('percentage')\ndef percentage_formatter(value):\n    if value or value == 0:\n        kwargs = {\n            'locale': to_locale(get_language()),\n            'format': \"#,##0.00 %\",\n        }\n        return format_percent(value, **kwargs)\n\n\n@register.filter\ndef smartdate(value):\n    if isinstance(value, datetime.datetime):\n        now = django_now()\n    else:\n        now = datetime.date.today()\n\n    timedelta = value - now\n    format = _(u\"%(delta)s %(unit)s\")\n    delta = abs(timedelta.days)\n\n    if delta > 30:\n        delta = int(delta / 30)\n        unit = _(u\"mois\")\n    else:\n        unit = _(u\"jours\")\n\n    ctx = {\n        'delta': delta,\n        'unit': unit,\n    }\n\n    return format % ctx\n"
  },
  {
    "path": "accounting/libs/templatetags/introspection_filters.py",
    "content": "from django import template\nfrom django.forms import ModelForm, BaseFormSet\nfrom django.db.models import Model\n\nfrom django_select2.fields import (\n    AutoModelSelect2Field,\n    AutoModelSelect2MultipleField)\n\n\nregister = template.Library()\n\n\n@register.filter\ndef get_model_verbose_name(instance):\n    if isinstance(instance, Model):\n        return instance._meta.verbose_name.title()\n    return '<unknown>'\n\n\n@register.filter\ndef get_form_model_verbose_name(instance):\n    if isinstance(instance, ModelForm):\n        return instance._meta.model._meta.verbose_name.title()\n    if isinstance(instance, BaseFormSet):\n        return instance.model._meta.verbose_name_plural.title()\n    return '<unknown>'\n\n\n@register.filter\ndef is_select2_field(form, field):\n    select2_classes = (AutoModelSelect2Field, AutoModelSelect2MultipleField)\n    res = any(isinstance(field.field, cls) for cls in select2_classes)\n    return res\n"
  },
  {
    "path": "accounting/libs/templatetags/my_filters.py",
    "content": "from django import template\n\nregister = template.Library()\n\n\n@register.filter(name='times')\ndef times(number):\n    return range(number)\n\n\n@register.filter\ndef get_object(l, index):\n    return l[index]\n\n\n@register.filter\ndef get_item(d, key, default=None):\n    if default:\n        d.get(key, None)\n    return d.get(key)\n"
  },
  {
    "path": "accounting/libs/templatetags/nav.py",
    "content": "# encoding: utf-8\n\nimport re\n\nfrom django import template\nregister = template.Library()\n\n\n@register.simple_tag\ndef active(request, pattern, exact_match=False):\n    if exact_match:\n        if not pattern.startswith('^'):\n            pattern = '^' + pattern\n        if not pattern.endswith('$'):\n            pattern = pattern + '$'\n    if hasattr(request, 'path') and re.search(pattern, request.path):\n        return 'active'\n    return ''\n"
  },
  {
    "path": "accounting/libs/templatetags/url_tags.py",
    "content": "# encoding: utf-8\n\nfrom django import template\nfrom django.http import QueryDict\n\nfrom classytags.core import Tag, Options\nfrom classytags.arguments import MultiKeywordArgument, MultiValueArgument\n\nregister = template.Library()\n\n\nclass QueryParameters(Tag):\n    name = 'query'\n    options = Options(\n        MultiKeywordArgument('kwa'),\n    )\n\n    def render_tag(self, context, kwa):\n        q = QueryDict('').copy()\n        q.update(kwa)\n        return q.urlencode()\n\n\nregister.tag(QueryParameters)\n\n\nclass GetParameters(Tag):\n\n    \"\"\"\n    {% get_parameters [except_field, ] %}\n    \"\"\"\n    name = 'get_parameters'\n    options = Options(\n        MultiValueArgument('except_fields', required=False),\n    )\n\n    def render_tag(self, context, except_fields):\n        try:\n            # If there's an exception (500), default context_processors may not\n            # be called.\n            request = context['request']\n        except KeyError:\n            return context\n\n        getvars = request.GET.copy()\n\n        for field in except_fields:\n            if field in getvars:\n                del getvars[field]\n\n        return getvars.urlencode()\n\n\nregister.tag(GetParameters)\n"
  },
  {
    "path": "accounting/libs/utils.py",
    "content": "import os\nimport uuid\nimport datetime\nimport random\nimport hashlib\nimport copy\nimport decimal\n\n\ndef banker_round(decimal_value):\n    \"\"\"\n    Force the value to be rounded with the `ROUND_HALF_EVEN` method,\n    also called the Banking Rounding due to the heavy use in the\n    banking system\n    \"\"\"\n    return decimal_value.quantize(decimal.Decimal('0.01'),\n                                  rounding=decimal.ROUND_HALF_EVEN)\n\n\ndef random_token(extra=None, hash_func=hashlib.sha256):\n    \"\"\"\n    Extracted from `django-user-accounts`\n    \"\"\"\n    if extra is None:\n        extra = []\n    bits = extra + [str(random.SystemRandom().getrandbits(512))]\n    return hash_func(\"\".join(bits)).hexdigest()\n\n\ndef create_hash(string, hash_func=hashlib.sha256):\n    \"\"\"\n    Create a 10-caracters string hash\n    \"\"\"\n    _hash = hash_func(string)\n    return _hash.hexdigest()[:10]\n\n\ndef nested_hash(data):\n    \"\"\"\n    Make a hash from a nested dictionnary\n    \"\"\"\n\n    if isinstance(data, (set, tuple, list)):\n        return tuple(nested_hash(d) for d in data)\n\n    elif not isinstance(data, dict):\n        return data\n\n    new_data = copy.deepcopy(data)\n    for k, v in new_data.items():\n        new_data[k] = nested_hash(v)\n\n    return hash(tuple(frozenset(sorted(new_data.items()))))\n\n\ndef unique_filename(path):\n    \"\"\"\n    Return a unique filename, which is usefull for image upload for instance\n    \"\"\"\n    def _unique_path(obj, name):\n        parts = name.split('.')\n        extension = parts[-1]\n        directory_path = os.path.normpath(\n            datetime.datetime.now().strftime(path))\n        unique_name = \"{0}.{1}\".format(uuid.uuid4(), extension)\n        return os.path.join(directory_path, unique_name)\n    return _unique_path\n\n\ndef queryset_iterator(queryset, chunksize=1000, reverse=False):\n    \"\"\"\n    Execute the request by chunks to avoid database memory error\n    \"\"\"\n    ordering = '-' if reverse else ''\n    queryset = queryset.order_by(ordering + 'pk')\n    last_pk = None\n    new_items = True\n    while new_items:\n        new_items = False\n        chunk = queryset\n        if last_pk is not None:\n            func = 'lt' if reverse else 'gt'\n            chunk = chunk.filter(**{'pk__' + func: last_pk})\n        chunk = chunk[:chunksize]\n        row = None\n        for row in chunk:\n            yield row\n        if row is not None:\n            last_pk = row.pk\n            new_items = True\n"
  },
  {
    "path": "accounting/static/accounting/css/main.css",
    "content": "/*\n * Base structure\n */\n\nbody {\n  padding-top: 0px;\n}\n\n\n/*\n * Utils\n */\n\n.overflow-box {\n  overflow: auto;\n}\n\n.table .empty-line > td {\n  border-top: none;\n}\n.table .empty-line + tr > td {\n  border-top: none;\n}\n\n.table .empty-cell {\n  border-top: none;\n}\n\n\n/*\n * Global add-ons\n */\n\n.sub-header {\n  padding-bottom: 10px;\n  border-bottom: 1px solid #eee;\n}\n\n/*\n * Top navigation\n * Hide default border to remove 1px line.\n */\n.navbar-fixed-top {\n  border: 0;\n}\n.navbar-inverse {\n  background: #222;\n}\n.navbar-nav > li {\n  border-right: 1px solid rgba(255, 255, 255, 0.15);\n}\n.navbar-nav > li > a {\n  padding-left: 2em;\n  padding-right: 2em;\n}\n.navbar-nav > li > a:hover {\n  background: rgba(255, 255, 255, 0.06) !important;\n}\n@media (min-width: 768px) {\n  .nav .breadcrumb {\n    margin: 7px 10px 7px 0px;\n  }\n}\n\n/*\n * Sidebar\n */\n\n/* Hide for mobile, show later */\n.sidebar {\n  display: none;\n}\n@media (min-width: 768px) {\n  .sidebar {\n    position: fixed;\n    top: 0px;\n    bottom: 0;\n    left: 0;\n    z-index: 1000;\n    display: block;\n    padding: 80px 20px 20px 20px;\n    overflow-x: hidden;\n    overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */\n    background-color: #f5f5f5;\n    border-right: 1px solid #eee;\n  }\n}\n\n/* Sidebar navigation */\n.nav-sidebar {\n  font-weight: 500;\n\n  margin-right: -21px; /* 20px padding + 1px border */\n  margin-bottom: 20px;\n  margin-left: -20px;\n}\n.nav-sidebar > li > a {\n  padding-right: 20px;\n  padding-left: 20px;\n}\n.nav-sidebar > .active > a,\n.nav-sidebar > .active > a:hover,\n.nav-sidebar > .active > a:focus {\n  color: #fff;\n  background-color: #428bca;\n}\n\n\n/*\n * Main content\n */\n\n.main {\n  padding: 20px;\n}\n@media (min-width: 768px) {\n  .main {\n    padding-right: 40px;\n    padding-left: 40px;\n  }\n}\n.main .page-header {\n  margin-top: 0;\n}\n\n\n/*\n * Placeholder dashboard ideas\n */\n\n.placeholders {\n  margin-bottom: 30px;\n  text-align: center;\n}\n.placeholders h4 {\n  margin-bottom: 0;\n}\n.placeholder {\n  margin-bottom: 20px;\n}\n.placeholder img {\n  display: inline-block;\n  border-radius: 50%;\n}\n\n\n/*\n * Figure\n */\n.figure {\n  margin-bottom: 1em;\n  padding: 0.8em 0.5em 1.5em 0.5em;\n  background: white;\n  background: rgba(255, 255, 255, 0.50);\n  border: 1px solid rgba(0, 0, 0, 0.06);\n  border-radius: 4px;\n}\n\n\n/*\n * Panels\n */\n.panel-link {\n  display: block;\n}\n.panel-link:hover {\n  background: #f0f0f0;\n  text-decoration: none;\n}\n\n\n/*\n * Check list\n */\n.check-list {\n\n}\n.check-item {\n  margin-right: 10px;\n}\n\n/*\n * Form labels\n */\n\n.label-inlineblock {\n    display: inline-block;\n}\n\n.control-label-block {\n    display: block;\n}\n"
  },
  {
    "path": "accounting/static/accounting/js/books/invoice_or_bill_create.js",
    "content": "$(function() {\n    $('.formset-form').formset({\n        prefix: 'lines',\n        addText: 'add another line',\n        deleteText: 'remove line',\n        addCssClass: 'btn btn-primary btn-sm',\n        deleteCssClass: 'btn btn-danger btn-sm',\n        added: function($row) {\n            // update line title\n            var index = $row.index('.formset-form') + 1;\n            $row.find('.counter').text(index);\n        }\n    });\n})\n"
  },
  {
    "path": "accounting/static/accounting/js/jquery.formset.js",
    "content": "/**\n * jQuery Dynamic Formset\n * Inspired from the jQuery Formset plugin of Stanislaus Madueke\n */\n;(function($) {\n    $.fn.formset = function(opts)\n    {\n        var options = $.extend({}, $.fn.formset.defaults, opts),\n            flatExtraClasses = options.extraClasses.join(' '),\n            totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS'),\n            maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS'),\n            childElementSelector = 'input,select,textarea,label,div',\n            $$ = $(this),\n\n            applyExtraClasses = function(row, ndx) {\n                if (options.extraClasses) {\n                    row.removeClass(flatExtraClasses);\n                    row.addClass(options.extraClasses[ndx % options.extraClasses.length]);\n                }\n            },\n\n            updateElementIndex = function(elem, prefix, ndx) {\n                var idRegex = new RegExp(prefix + '-(\\\\d+|__prefix__)-'),\n                    replacement = prefix + '-' + ndx + '-';\n                if (elem.attr(\"for\")) elem.attr(\"for\", elem.attr(\"for\").replace(idRegex, replacement));\n                if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));\n                if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));\n            },\n\n            hasChildElements = function(row) {\n                return row.find(childElementSelector).length > 0;\n            },\n\n            showAddButton = function() {\n                return maxForms.length == 0 ||   // For Django versions pre 1.2\n                    (maxForms.val() == '' || (maxForms.val() - totalForms.val() > 0));\n            },\n\n            insertDeleteLink = function(row) {\n                var delCssSelector = options.deleteCssClass.trim().replace(/\\s+/g, '.'),\n                    addCssSelector = options.addCssClass.trim().replace(/\\s+/g, '.');\n                if (row.is('TR')) {\n                    // If the forms are laid out in table rows, insert\n                    // the remove button into the last table cell:\n                    row.children(':last').append('<a class=\"' + options.deleteCssClass +'\" href=\"javascript:void(0)\">' + options.deleteText + '</a>');\n                } else if (row.is('UL') || row.is('OL')) {\n                    // If they're laid out as an ordered/unordered list,\n                    // insert an <li> after the last list item:\n                    row.append('<li><a class=\"' + options.deleteCssClass + '\" href=\"javascript:void(0)\">' + options.deleteText +'</a></li>');\n                } else {\n                    // Otherwise, just insert the remove button as the\n                    // last child element of the form's container:\n                    row.append('<a class=\"' + options.deleteCssClass + '\" href=\"javascript:void(0)\">' + options.deleteText +'</a>');\n                }\n                row.find('a.' + delCssSelector).click(function() {\n                    var row = $(this).parents('.' + options.formCssClass),\n                        del = row.find('input:hidden[id $= \"-DELETE\"]'),\n                        buttonRow = row.siblings(\"a.\" + addCssSelector + ', .' + options.formCssClass + '-add'),\n                        forms;\n                    if (del.length) {\n                        // We're dealing with an inline formset.\n                        // Rather than remove this form from the DOM, we'll mark it as deleted\n                        // and hide it, then let Django handle the deleting:\n                        del.val('on');\n                        row.hide();\n                        forms = $('.' + options.formCssClass).not(':hidden');\n                    } else {\n                        row.remove();\n                        // Update the TOTAL_FORMS count:\n                        forms = $('.' + options.formCssClass).not('.formset-custom-template');\n                        totalForms.val(forms.length);\n                    }\n                    for (var i=0, formCount=forms.length; i<formCount; i++) {\n                        // Apply `extraClasses` to form rows so they're nicely alternating:\n                        applyExtraClasses(forms.eq(i), i);\n                        if (!del.length) {\n                            // Also update names and IDs for all child controls (if this isn't\n                            // a delete-able inline formset) so they remain in sequence:\n                            forms.eq(i).find(childElementSelector).each(function() {\n                                updateElementIndex($(this), options.prefix, i);\n                            });\n                        }\n                    }\n                    // Check if we need to show the add button:\n                    if (buttonRow.is(':hidden') && showAddButton()) buttonRow.show();\n                    // If a post-delete callback was provided, call it with the deleted form:\n                    if (options.removed) options.removed(row);\n                    return false;\n                });\n            };\n\n        $$.each(function(i) {\n            var row = $(this),\n                del = row.find('input:checkbox[id $= \"-DELETE\"]');\n            if (del.length) {\n                // If you specify \"can_delete = True\" when creating an inline formset,\n                // Django adds a checkbox to each form in the formset.\n                // Replace the default checkbox with a hidden field:\n                if (del.is(':checked')) {\n                    // If an inline formset containing deleted forms fails validation, make sure\n                    // we keep the forms hidden (thanks for the bug report and suggested fix Mike)\n                    del.before('<input type=\"hidden\" name=\"' + del.attr('name') +'\" id=\"' + del.attr('id') +'\" value=\"on\" />');\n                    row.hide();\n                } else {\n                    del.before('<input type=\"hidden\" name=\"' + del.attr('name') +'\" id=\"' + del.attr('id') +'\" />');\n                }\n                // Hide any labels associated with the DELETE checkbox:\n                $('label[for=\"' + del.attr('id') + '\"]').hide();\n                del.remove();\n            }\n            if (hasChildElements(row)) {\n                row.addClass(options.formCssClass);\n                if (row.is(':visible')) {\n                    insertDeleteLink(row);\n                    applyExtraClasses(row, i);\n                }\n            }\n        });\n\n        if ($$.length) {\n            var hideAddButton = !showAddButton(),\n                addButton, template;\n            if (options.formTemplate) {\n                // If a form template was specified, we'll clone it to generate new form instances:\n                template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);\n                template.removeAttr('id').addClass(options.formCssClass + ' formset-custom-template');\n                template.find(childElementSelector).each(function() {\n                    updateElementIndex($(this), options.prefix, '__prefix__');\n                });\n                insertDeleteLink(template);\n            } else {\n                // Otherwise, use the last form in the formset; this works much better if you've got\n                // extra (>= 1) forms (thnaks to justhamade for pointing this out):\n                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');\n                template.find('input:hidden[id $= \"-DELETE\"]').remove();\n                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):\n                template.find(childElementSelector).not(options.keepFieldValues).each(function() {\n                    var elem = $(this);\n                    // If this is a checkbox or radiobutton, uncheck it.\n                    // This fixes Issue 1, reported by Wilson.Andrew.J:\n                    if (elem.is('input:checkbox') || elem.is('input:radio')) {\n                        elem.attr('checked', false);\n                    } else {\n                        elem.val('');\n                    }\n                });\n            }\n            // FIXME: Perhaps using $.data would be a better idea?\n            options.formTemplate = template;\n\n            if ($$.is('TR')) {\n                // If forms are laid out as table rows, insert the\n                // \"add\" button in a new table row:\n                var numCols = $$.eq(0).children().length,   // This is a bit of an assumption :|\n                    buttonRow = $('<tr><td colspan=\"' + numCols + '\"><a class=\"' + options.addCssClass + '\" href=\"javascript:void(0)\">' + options.addText + '</a></tr>')\n                                .addClass(options.formCssClass + '-add');\n                $$.parent().append(buttonRow);\n                if (hideAddButton) buttonRow.hide();\n                addButton = buttonRow.find('a');\n            } else {\n                // Otherwise, insert it immediately after the last form:\n                $$.filter(':last').after('<a class=\"' + options.addCssClass + '\" href=\"javascript:void(0)\">' + options.addText + '</a>');\n                addButton = $$.filter(':last').next();\n                if (hideAddButton) addButton.hide();\n            }\n            addButton.click(function() {\n                var formCount = parseInt(totalForms.val() || 0),\n                    row = options.formTemplate.clone(true).removeClass('formset-custom-template'),\n                    buttonRow = $($(this).parents('tr.' + options.formCssClass + '-add').get(0) || this);\n                applyExtraClasses(row, formCount);\n                row.insertBefore(buttonRow).show();\n                row.find(childElementSelector).each(function() {\n                    updateElementIndex($(this), options.prefix, formCount);\n                });\n                totalForms.val(formCount + 1);\n                // Check if we've exceeded the maximum allowed number of forms:\n                if (!showAddButton()) buttonRow.hide();\n                // If a post-add callback was supplied, call it with the added form:\n                if (options.added) options.added(row);\n                return false;\n            });\n        }\n\n        return $$;\n    };\n\n    /* Setup plugin defaults */\n    $.fn.formset.defaults = {\n        prefix: 'form',                  // The form prefix for your django formset\n        formTemplate: null,              // The jQuery selection cloned to generate new form instances\n        addText: 'add another',          // Text for the add link\n        deleteText: 'remove',            // Text for the delete link\n        addCssClass: 'add-row',          // CSS class applied to the add link\n        deleteCssClass: 'delete-row',    // CSS class applied to the delete link\n        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset\n        extraClasses: [],                // Additional CSS classes, which will be applied to each form in turn\n        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned\n        added: null,                     // Function called each time a new form is added\n        removed: null                    // Function called each time a form is deleted\n    };\n})(jQuery);\n"
  },
  {
    "path": "accounting/static/accounting/js/main.js",
    "content": "$('[data-toggle=\"tooltip\"]').tooltip();"
  },
  {
    "path": "accounting/templates/accounting/_generics/check_tag.html",
    "content": "{% load check_filters %}\n\n{% if check.message %}\n    <h4 class=\"list-group-item-heading\">\n        <span class=\"check-item\"><span class=\"glyphicon glyphicon-{{ check|level_to_glyphicon }}\"></span></span>\n        {{ check.field.verbose_name }}\n    </h4>\n    <p class=\"list-group-item-text\">\n        <small>{{ check.message }}</small>\n    </p>\n{% else %}\n    <span class=\"check-item\"><span class=\"glyphicon glyphicon-{{ check|level_to_glyphicon }}\"></span></span>\n    {{ check.field.verbose_name }}\n{% endif %}"
  },
  {
    "path": "accounting/templates/accounting/_generics/delete_entity.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load bootstrap3 introspection_filters %}\n\n{% block sidebar %}{% endblock %}\n\n{% block container %}\n\n<div class=\"container-fluid\">\n    <div class=\"row\">\n        <div class=\"col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 main\">\n\n            <h1 class=\"page-header\">You are about to delete...</h1>\n\n            <div class=\"panel panel-danger\">\n                <div class=\"panel-heading\">\n                    <h3 class=\"panel-title\">{{ object|get_model_verbose_name }}</h3>\n                </div>\n                <div class=\"panel-body\">\n                    {{ object }}\n                </div>\n            </div>\n\n            <form action=\".\" method=\"post\" class=\"form\">\n                {% csrf_token %}\n                {% buttons %}\n                    <button type=\"submit\" class=\"btn btn-danger\">\n                        {% bootstrap_icon \"trash\" %} Delete\n                    </button>\n                    <a href=\"#\" onclick=\"window.history.back(); return false;\" class=\"btn btn-warning pull-right\">\n                        Cancel\n                    </a>\n                {% endbuttons %}\n            </form>\n\n        </div>\n    </div>\n</div>\n{% endblock container %}\n"
  },
  {
    "path": "accounting/templates/accounting/_generics/form.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    {% if object.pk %}\n        <h1 class=\"page-header\">Edit a {{ form|get_form_model_verbose_name }}</h1>\n    {% else %}\n        <h1 class=\"page-header\">Create a {{ form|get_form_model_verbose_name }}</h1>\n    {% endif %}\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% include \"accounting/_partials/form_fields.html\" with form=form %}\n\n        {% buttons %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% if object.pk %}\n                    {% bootstrap_icon \"hand-right\" %} Save changes\n                {% else %}\n                    {% bootstrap_icon \"thumbs-up\" %} Send creation\n                {% endif %}\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/_partials/form_fields.html",
    "content": "{% load bootstrap3 introspection_filters %}\n\n{% if return_url %}\n<input type=\"hidden\" name=\"_return_url\" value=\"{{ return_url }}\">\n{% endif %}\n\n{% bootstrap_form_errors form %}\n\n{% for field in form %}\n    {% if form|is_select2_field:field %}\n        <div class=\"form-group\">\n            <label class=\"control-label control-label-block\" for=\"{{ field.id_for_label }}\">{{ field.label }}</label>\n            {% bootstrap_field field %}\n        </div>\n    {% else %}\n        {% bootstrap_field field %}\n    {% endif %}\n{% endfor %}"
  },
  {
    "path": "accounting/templates/accounting/base.html",
    "content": "{% load static %}<!DOCTYPE html>\n<!--[if lt IE 7]>      <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>         <html class=\"no-js lt-ie9 lt-ie8\"> <![endif]-->\n<!--[if IE 8]>         <html class=\"no-js lt-ie9\"> <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\"> <!--<![endif]-->\n    <head>\n        <meta charset=\"utf-8\">\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        <title></title>\n        <meta name=\"description\" content=\"\">\n\n        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->\n\n        <link rel=\"stylesheet\" href=\"{% static 'bootstrap/dist/css/bootstrap.css' %}\">\n        <link rel=\"stylesheet\" href=\"{% static 'bootstrap/dist/css/bootstrap-theme.css' %}\">\n\n        <style>\n            @import url(http://fonts.googleapis.com/css?family=Bree+Serif);\n            body {\n                font-family: 'Helvetica Neue', sans-serif;\n            }\n            h1, h2, h3, h4, h5, h6{\n                font-family: 'Bree Serif', serif;\n            }\n        </style>\n\n        <!-- Custom styles for this template -->\n        <link rel=\"stylesheet\" href=\"{% static 'accounting/css/main.css' %}\">\n\n        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->\n        <!--[if lt IE 9]>\n          <script src=\"https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js\"></script>\n          <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n        <![endif]-->\n\n        <script src=\"{% static 'modernizr/modernizr.js' %}\"></script>\n\n        {% block head %}{% endblock %}\n    </head>\n    <body>\n        <!--[if lt IE 7]>\n            <p class=\"browsehappy\">You are using an <strong>outdated</strong> browser. Please <a href=\"http://browsehappy.com/\">upgrade your browser</a> to improve your experience.</p>\n        <![endif]-->\n\n        {% block maincontent %}{% endblock %}\n\n        {% block scripts %}\n            <script src=\"{% static 'jquery/dist/jquery.js' %}\"></script>\n            <script src=\"{% static 'bootstrap/dist/js/bootstrap.min.js' %}\"></script>\n            <script src=\"{% static 'accounting/js/main.js' %}\"></script>\n        {% endblock %}\n    </body>\n</html>\n"
  },
  {
    "path": "accounting/templates/accounting/books/_generics/sale_content.html",
    "content": "{% load currency_filters format_filters %}\n\n<div class=\"row\">\n    <div class=\"col-xs-5\">\n        <div class=\"panel panel-default\">\n            {% with client=object.from_client %}\n            <div class=\"panel-heading\">\n                <h4>From: <a href=\"{{ client.get_absolute_url }}\">{{ client }}</a></h4>\n            </div>\n            <div class=\"panel-body\">\n                <address>\n                    <strong>{{ client.name }}</strong><br>\n                    {{ client.full_address|linebreaksbr }}<br>\n                </address>\n            </div>\n            {% endwith %}\n        </div>\n    </div>\n    <div class=\"col-xs-5 col-xs-offset-2 text-right\">\n        <div class=\"panel panel-default\">\n            {% with client=object.to_client %}\n            <div class=\"panel-heading\">\n                <h4>To: <a href=\"{{ client.get_absolute_url }}\">{{ client }}</a></h4>\n            </div>\n            <div class=\"panel-body\">\n                <address>\n                    <strong>{{ client.name }}</strong><br>\n                    {{ client.full_address|linebreaksbr }}<br>\n                </address>\n            </div>\n            {% endwith %}\n        </div>\n    </div>\n</div>\n<!-- / end client details section -->\n<table class=\"table table-striped table-bordered\">\n    <thead>\n        <tr class=\"row\">\n            <th>#</th>\n            <th>Label</th>\n            <th class=\"col-sm-4\">Description</th>\n            <th class=\"col-sm-2\">Unit (excl. tax)</th>\n            <th class=\"col-sm-1\">Qt.</th>\n            <th class=\"col-sm-1\">Tax rate</th>\n            <th class=\"col-sm-2 text-right\">Amount</th>\n        </tr>\n    </thead>\n    <tbody>\n        {% for line in lines.all %}\n        <tr class=\"row\">\n            <td>{{ forloop.counter }}</td>\n            <td>{{ line.label }}</td>\n            <td class=\"col-sm-4\">{{ line.description|linebreaks }}</td>\n            <td class=\"col-sm-2\">{{ line.unit_price_excl_tax|currency }}</td>\n            <td class=\"col-sm-1\">{{ line.quantity }}</td>\n            <td class=\"col-sm-1\">{{ line.tax_rate.rate|percentage }}</td>\n            <td class=\"col-sm-2 text-right\">{{ line.line_price_excl_tax|currency }}</td>\n        </tr>\n        {% endfor %}\n    </tbody>\n</table>\n<div class=\"row text-right\">\n    <div class=\"col-xs-2 col-xs-offset-8\">\n        <p>\n            <strong>\n                Sub Total : <br>\n                Tax : <br>\n                Total : <br>\n            </strong>\n        </p>\n    </div>\n    <div class=\"col-xs-2\">\n        <strong>\n            {{ object.total_excl_tax|currency }} <br>\n            {{ object.total_tax|currency }} <br>\n            {{ object.total_incl_tax|currency }} <br>\n        </strong>\n    </div>\n</div>\n"
  },
  {
    "path": "accounting/templates/accounting/books/_generics/sale_detail.html",
    "content": "{% load currency_filters bootstrap3 form_filters check_filters check_tags %}\n\n<div class=\"row placeholders\">\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.total_incl_tax|currency|default:\"-\" }}</h4>\n            <span class=\"text-muted\">Total (incl. tax)</span>\n        </div>\n    </div>\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.total_excl_tax|currency|default:\"-\" }}</h4>\n            <span class=\"text-muted\">Total (excl. tax)</span>\n        </div>\n    </div>\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.total_tax|currency }}</h4>\n            <span class=\"text-muted\">Tax</span>\n        </div>\n    </div>\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.date_issued|default:\"-\" }}</h4>\n            <span class=\"text-muted\">Date issued</span>\n        </div>\n    </div>\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.total_due_incl_tax|currency|default:\"-\" }}</h4>\n            <span class=\"text-muted\">Total still due (incl. tax)</span>\n        </div>\n    </div>\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"figure\">\n            <h4>{{ object.date_dued|default:\"-\" }}</h4>\n            <span class=\"text-muted\">Date dued</span>\n        </div>\n    </div>\n</div>\n\n{% if checklist %}\n<h3 class=\"page-header\">Checklist</h3>\n<div class=\"row\">\n    <div class=\"col-xs-6 col-sm-4\">\n        <div class=\"list-group check-list\">\n        {% for check in checklist %}\n            <div class=\"list-group-item list-group-item-{{ check|level_to_css_classname }}\">\n                {% render_check check %}\n            </div>\n        {% endfor %}\n        </div>\n    </div>\n</div>\n{% endif %}\n\n<h3 class=\"page-header\">Content</h3>\n{% include \"books/_generics/sale_content.html\" with object=object %}\n\n<hr>\n\n{% if payment_form %}\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <h4>Payments</h4>\n    </div>\n\n    {% include \"books/_partials/payment_list.html\" with payments=payments %}\n\n    <div class=\"panel-footer\">\n        <form action=\".\" method=\"post\" class=\"form\">\n            {% csrf_token %}\n\n            {{ payment_form.non_field_errors }}\n            <div class=\"row\">\n                <div class=\"col-md-2\">\n                    {% bootstrap_field payment_form.date_paid show_label=False %}\n                </div>\n                <div class=\"col-md-2\">\n                    {% bootstrap_field payment_form.reference show_label=False %}\n                </div>\n                <div class=\"col-md-4\">\n                    {% bootstrap_field payment_form.detail show_label=False %}\n                </div>\n                <div class=\"col-md-2\">\n                    {% bootstrap_field payment_form.amount show_label=False %}\n                </div>\n                <div class=\"col-md-2 text-right\">\n                    <button type=\"submit\" class=\"btn btn-success\">Add payment</button>\n                </div>\n            </div>\n        </form>\n    </div>\n</div>\n{% endif %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/_generics/sale_list.html",
    "content": "{% load currency_filters status_filters %}\n\n<table class=\"table table-striped\">\n    <thead>\n        <tr class=\"row\">\n            <th>#</th>\n            <th>Client</th>\n            {% if detailed %}\n            <th>Description</th>\n            {% endif %}\n            <th class=\"col-sm-2\">Total</th>\n            <th class=\"text-right col-sm-4\">Actions</th>\n        </tr>\n    </thead>\n    <tbody>\n        {% for sale in sales %}\n        <tr class=\"row {{ sale|status_to_css_classname }}\">\n            <td>{{ sale.number }}</td>\n            <td>{{ sale.client }}</td>\n            {% if detailed %}\n            <td>{{ sale.description }}</td>\n            {% endif %}\n            <td class=\"col-sm-2\">{{ sale.total_excl_tax|currency }}</td>\n            <td class=\"text-right col-sm-4\">\n                <a href=\"{{ sale.get_detail_url }}\" class=\"btn btn-success btn-sm\" role=\"button\">View</a>\n                {% if not hide_edit %}\n                <a href=\"{{ sale.get_edit_url }}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                {% endif %}\n            </td>\n        </tr>\n        {% endfor %}\n    </tbody>\n</table>\n"
  },
  {
    "path": "accounting/templates/accounting/books/_partials/expense_claim_list.html",
    "content": "{% load currency_filters status_filters %}\n\n<table class=\"table table-striped\">\n    <thead>\n        <tr class=\"row\">\n            <th>#</th>\n            <th>Paid by employee</th>\n            <th>On</th>\n            <th class=\"col-sm-2\">Total</th>\n            <th class=\"text-right col-sm-4\">Actions</th>\n        </tr>\n    </thead>\n    <tbody>\n        {% for sale in sales %}\n        <tr class=\"row {{ sale|status_to_css_classname }}\">\n            <td>{{ sale.number }}</td>\n            <td>{{ sale.employee }}</td>\n            <td>{{ sale.date_issued }}</td>\n            <td class=\"col-sm-2\">{{ sale.total_excl_tax|currency }}</td>\n            <td class=\"text-right col-sm-4\">\n                <a href=\"{{ sale.get_detail_url }}\" class=\"btn btn-success btn-sm\" role=\"button\">View</a>\n                {% if not hide_edit %}\n                <a href=\"{{ sale.get_edit_url }}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                {% endif %}\n            </td>\n        </tr>\n        {% endfor %}\n    </tbody>\n</table>\n"
  },
  {
    "path": "accounting/templates/accounting/books/_partials/payment_list.html",
    "content": "{% load currency_filters %}\n\n<table class=\"table table-striped\">\n    <thead>\n        <tr class=\"row\">\n            <th class=\"col-sm-2\">Date</th>\n            <th class=\"col-sm-2\">Ref</th>\n            <th class=\"col-sm-4\">Detail</th>\n            <th class=\"col-sm-2\">Amount</th>\n            <th class=\"text-right col-sm-2\">Actions</th>\n        </tr>\n    </thead>\n    <tbody>\n        {% for paym in payments %}\n        <tr class=\"row\">\n            <td class=\"col-sm-2\">{{ paym.date_paid }}</td>\n            <td class=\"col-sm-2\">{{ paym.reference|default:\"-\" }}</td>\n            <td class=\"col-sm-4\">{{ paym.detail }}</td>\n            <td class=\"col-sm-2\">{{ paym.amount|currency }}</td>\n            <td class=\"text-right col-sm-4\">\n                <a href=\"{% url 'books:payment-edit' paym.pk %}\" class=\"btn btn-default btn-xs\" role=\"button\">Edit</a>\n                <a href=\"{% url 'books:payment-delete' paym.pk %}\" class=\"btn btn-danger btn-xs\" role=\"button\">Delete</a>\n            </td>\n        </tr>\n        {% endfor %}\n    </tbody>\n</table>\n"
  },
  {
    "path": "accounting/templates/accounting/books/_partials/tax_rate_list.html",
    "content": "{% load currency_filters format_filters %}\n\n<div class=\"table-responsive\">\n    <table class=\"table table-striped\">\n        <thead>\n            <tr class=\"row\">\n                <th>#</th>\n                <th>Name</th>\n                <th>Rate (%)</th>\n                <th class=\"text-right col-sm-4\">Actions</th>\n            </tr>\n        </thead>\n        <tbody>\n            {% for tax_rate in tax_rates %}\n            <tr class=\"row\">\n                <td>{{ forloop.counter }}</td>\n                <td>{{ tax_rate.name }}</td>\n                <td>{{ tax_rate.rate|percentage }}</td>\n                <td class=\"text-right col-sm-4\">\n                    <a href=\"{% url 'books:tax_rate-edit' tax_rate.pk %}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                    <a href=\"{% url 'books:tax_rate-delete' tax_rate.pk %}\" class=\"btn btn-danger btn-sm\" role=\"button\">Delete</a>\n                </td>\n            </tr>\n            {% endfor %}\n        </tbody>\n    </table>\n</div>\n"
  },
  {
    "path": "accounting/templates/accounting/books/bill_create_or_update.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">Create a {{ form|get_form_model_verbose_name }}</h1>\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% include \"accounting/_partials/form_fields.html\" with form=form %}\n\n        <h2 class=\"page-header\">Content</h2>\n        {{ line_formset.management_form }}\n        {{ line_formset.non_field_errors }}\n        <table class=\"table table-striped table-bordered\">\n            <thead>\n                <th>#</th>\n                <th>Label</th>\n                <th>Description</th>\n                <th>Unit (excl. tax)</th>\n                <th>Qt.</th>\n                <th>Tax rate</th>\n                <th>Total</th>\n            </thead>\n            <tbody>\n            {% for line_form in line_formset %}\n                <tr class=\"formset-form\">\n                    <td class=\"col-md-0 counter\">\n                        {{ forloop.counter }}\n                        {{ line_form.id }}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.label show_label=False %}\n                    </td>\n                    <td class=\"col-md-4\">\n                        {% bootstrap_field line_form.description show_label=False %}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.unit_price_excl_tax show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.quantity show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.tax_rate show_label=False %}\n                    </td>\n                    <td></td>\n                </tr>\n            {% endfor %}\n            </tbody>\n        </table>\n\n        {% buttons layout='vertical' %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% bootstrap_icon \"star\" %} Create\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n\n{% block scripts %}\n    {{ block.super }}\n    <script src=\"{% static 'accounting/js/jquery.formset.js' %}\"></script>\n    <script src=\"{% static 'accounting/js/books/invoice_or_bill_create.js' %}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/bill_detail.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static %}\n\n{% block head %}\n    {{ block.super }}\n\n    {# NB: because the payment form is a subform it won't output the correct assets, so we explicitly put it there #}\n    <link rel=\"stylesheet\" href=\"{% static 'css/datetimepicker.css' %}\">\n    <script src=\"{% static 'js/bootstrap-datetimepicker.js' %}\"></script>\n\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        Bill #{{ bill.number }} <small>/ detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:bill-edit' bill.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n            <a href=\"{% url 'books:bill-delete' bill.pk %}\" class=\"btn btn-danger\" role=\"button\">Supprimer</a>\n        </div>\n    </h1>\n\n    {% include \"books/_generics/sale_detail.html\" with object=bill lines=lines payments=bill.payments.all form=form %}\n\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/bill_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Bills <small>which belong to you</small></h1>\n\n    {% include \"books/_generics/sale_list.html\" with sales=bills detailed=True %}\n\n    <a href=\"{% url 'books:bill-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add a bill\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/dashboard.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        {{ organization.display_name }} <small>/ organization detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:organization-edit' organization.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n        </div>\n    </h1>\n\n    <div class=\"row placeholders\">\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.turnover_excl_tax|currency|default:\"-\" }}</h4>\n                <span class=\"text-muted\">Turnover</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.profits|currency|default:\"-\" }}</h4>\n                <span class=\"text-muted\">Profits</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.tax_provisionning|currency|default:0 }}</h4>\n                <span class=\"text-muted\">Tax Provisionning</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.overdue_total|currency|default:0 }}</h4>\n                <span class=\"text-muted\">Due payments</span>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"row\">\n        <div class=\"col-xs-12 col-sm-6\">\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading overflow-box\">\n                    <h4 class=\"pull-left\">\n                        Invoices <small>/ what you earn</small>\n                    </h4>\n                    <div class=\"btn-group pull-right\">\n                        <a href=\"{% url 'books:invoice-create' %}\" class=\"btn btn-primary btn-md\" role=\"button\">\n                            Add an invoice\n                        </a>\n                    </div>\n                </div>\n                {% include \"books/_generics/sale_list.html\" with sales=invoices hide_edit=True %}\n            </div>\n        </div>\n        <div class=\"col-xs-12 col-sm-6\">\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading overflow-box\">\n                    <h4 class=\"pull-left\">Bills <small> / what you owe</small></h4>\n                    <div class=\"btn-group pull-right\">\n                        <a href=\"{% url 'books:bill-create' %}\" class=\"btn btn-primary btn-md\" role=\"button\">\n                            Add an bill\n                        </a>\n                    </div>\n                </div>\n                {% include \"books/_generics/sale_list.html\" with sales=bills hide_edit=True %}\n            </div>\n        </div>\n    </div>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/estimate_create_or_update.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">Create a {{ form|get_form_model_verbose_name }}</h1>\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% include \"accounting/_partials/form_fields.html\" with form=form %}\n\n        <h2 class=\"page-header\">Content</h2>\n        {{ line_formset.management_form }}\n        {{ line_formset.non_field_errors }}\n        <table class=\"table table-striped table-bordered\">\n            <thead>\n                <th>#</th>\n                <th>Label</th>\n                <th>Description</th>\n                <th>Unit (excl. tax)</th>\n                <th>Qt.</th>\n                <th>Tax rate</th>\n                <th>Total</th>\n            </thead>\n            <tbody>\n            {% for line_form in line_formset %}\n                <tr class=\"formset-form\">\n                    <td class=\"col-md-0 counter\">\n                        {{ forloop.counter }}\n                        {{ line_form.id }}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.label show_label=False %}\n                    </td>\n                    <td class=\"col-md-4\">\n                        {% bootstrap_field line_form.description show_label=False %}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.unit_price_excl_tax show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.quantity show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.tax_rate show_label=False %}\n                    </td>\n                    <td></td>\n                </tr>\n            {% endfor %}\n            </tbody>\n        </table>\n\n        {% buttons layout='vertical' %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% bootstrap_icon \"star\" %} Create\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n\n{% block scripts %}\n    {{ block.super }}\n    <script src=\"{% static 'accounting/js/jquery.formset.js' %}\"></script>\n    <script src=\"{% static 'accounting/js/books/invoice_or_bill_create.js' %}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/estimate_detail.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block head %}\n    {{ block.super }}\n\n    {# NB: because the payment form is a subform it won't output the correct assets, so we explicitly put it there #}\n    <link rel=\"stylesheet\" href=\"{% static 'css/datetimepicker.css' %}\">\n    <script src=\"{% static 'js/bootstrap-datetimepicker.js' %}\"></script>\n\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        Estimate #{{ estimate.number }} <small>/ detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:estimate-edit' estimate.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n            <a href=\"{% url 'books:estimate-delete' estimate.pk %}\" class=\"btn btn-danger\" role=\"button\">Supprimer</a>\n        </div>\n    </h1>\n\n    {% include \"books/_generics/sale_detail.html\" with object=estimate lines=lines form=form %}\n\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/estimate_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Estimates <small>which belong to you</small></h1>\n\n    {% include \"books/_generics/sale_list.html\" with sales=estimates detailed=True %}\n\n    <a href=\"{% url 'books:estimate-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add a estimate\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/expense_claim_create_or_update.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">Create a {{ form|get_form_model_verbose_name }}</h1>\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% include \"accounting/_partials/form_fields.html\" with form=form %}\n\n        <h2 class=\"page-header\">Content</h2>\n        {{ line_formset.management_form }}\n        {{ line_formset.non_field_errors }}\n        <table class=\"table table-striped table-bordered\">\n            <thead>\n                <th>#</th>\n                <th>Label</th>\n                <th>Description</th>\n                <th>Unit (excl. tax)</th>\n                <th>Qt.</th>\n                <th>Tax rate</th>\n                <th>Total</th>\n            </thead>\n            <tbody>\n            {% for line_form in line_formset %}\n                <tr class=\"formset-form\">\n                    <td class=\"col-md-0 counter\">\n                        {{ forloop.counter }}\n                        {{ line_form.id }}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.label show_label=False %}\n                    </td>\n                    <td class=\"col-md-4\">\n                        {% bootstrap_field line_form.description show_label=False %}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.unit_price_excl_tax show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.quantity show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.tax_rate show_label=False %}\n                    </td>\n                    <td></td>\n                </tr>\n            {% endfor %}\n            </tbody>\n        </table>\n\n        {% buttons layout='vertical' %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% bootstrap_icon \"star\" %} Create\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n\n{% block scripts %}\n    {{ block.super }}\n    <script src=\"{% static 'accounting/js/jquery.formset.js' %}\"></script>\n    <script src=\"{% static 'accounting/js/books/invoice_or_bill_create.js' %}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/expense_claim_detail.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static %}\n\n{% block head %}\n    {{ block.super }}\n\n    {# NB: because the payment form is a subform it won't output the correct assets, so we explicitly put it there #}\n    <link rel=\"stylesheet\" href=\"{% static 'css/datetimepicker.css' %}\">\n    <script src=\"{% static 'js/bootstrap-datetimepicker.js' %}\"></script>\n\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        Expense claim #{{ expense_claim.number }} <small>/ detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:expense_claim-edit' expense_claim.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n            <a href=\"{% url 'books:expense_claim-delete' expense_claim.pk %}\" class=\"btn btn-danger\" role=\"button\">Supprimer</a>\n        </div>\n    </h1>\n\n    {% include \"books/_generics/sale_detail.html\" with object=expense_claim lines=lines payments=expense_claim.payments.all form=form %}\n\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/expense_claim_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Expense claims <small>which belong to you</small></h1>\n\n    {% include \"books/_partials/expense_claim_list.html\" with sales=expense_claims detailed=True %}\n\n    <a href=\"{% url 'books:expense_claim-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add an Expense claim\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/invoice_create_or_update.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">Create an {{ form|get_form_model_verbose_name }}</h1>\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% include \"accounting/_partials/form_fields.html\" with form=form %}\n\n        <h2 class=\"page-header\">Content</h2>\n        {{ line_formset.management_form }}\n        {{ line_formset.non_field_errors }}\n        <table class=\"table table-striped table-bordered\">\n            <thead>\n                <th>#</th>\n                <th>Label</th>\n                <th>Description</th>\n                <th>Unit (excl. tax)</th>\n                <th>Qt.</th>\n                <th>Tax rate</th>\n                <th>Total</th>\n            </thead>\n            <tbody>\n            {% for line_form in line_formset %}\n                <tr class=\"formset-form\">\n                    <td class=\"col-md-0 counter\">\n                        {{ forloop.counter }}\n                        {{ line_form.id }}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.label show_label=False %}\n                    </td>\n                    <td class=\"col-md-4\">\n                        {% bootstrap_field line_form.description show_label=False %}\n                    </td>\n                    <td class=\"col-md-2\">\n                        {% bootstrap_field line_form.unit_price_excl_tax show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.quantity show_label=False %}\n                    </td>\n                    <td class=\"col-md-1\">\n                        {% bootstrap_field line_form.tax_rate show_label=False %}\n                    </td>\n                    <td>{{ line_form.DELETE }}</td>\n                </tr>\n            {% endfor %}\n            </tbody>\n        </table>\n\n        {% buttons layout='vertical' %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% bootstrap_icon \"star\" %} Create\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n\n{% block scripts %}\n    {{ block.super }}\n    <script src=\"{% static 'accounting/js/jquery.formset.js' %}\"></script>\n    <script src=\"{% static 'accounting/js/books/invoice_or_bill_create.js' %}\"></script>\n{% endblock %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/invoice_detail.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static %}\n\n{% block head %}\n    {{ block.super }}\n\n    {# NB: because the payment form is a subform it won't output the correct assets, so we explicitly put it there #}\n    <link rel=\"stylesheet\" href=\"{% static 'css/datetimepicker.css' %}\">\n    <script src=\"{% static 'js/bootstrap-datetimepicker.js' %}\"></script>\n\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        Invoice #{{ invoice.number }} <small>/ detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:invoice-edit' invoice.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n            <a href=\"{% url 'books:invoice-delete' invoice.pk %}\" class=\"btn btn-danger\" role=\"button\">Supprimer</a>\n        </div>\n    </h1>\n\n    {% include \"books/_generics/sale_detail.html\" with object=invoice lines=lines payments=invoice.payments.all form=form %}\n\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/invoice_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Invoices <small>which belong to you</small></h1>\n\n    {% include \"books/_generics/sale_list.html\" with sales=invoices detailed=True %}\n\n    <a href=\"{% url 'books:invoice-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add an invoice\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/organization_create_or_update.html",
    "content": "{% extends \"_generics/form.html\" %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/organization_detail.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">\n        {{ organization.display_name }} <small>/ organization detail</small>\n        <div class=\"btn-group pull-right\">\n            <a href=\"{% url 'books:organization-edit' organization.pk %}\" class=\"btn btn-default\" role=\"button\">Edit</a>\n        </div>\n    </h1>\n\n    <div class=\"row placeholders\">\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.turnover_excl_tax|currency|default:\"-\" }}</h4>\n                <span class=\"text-muted\">Turnover</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.profits|currency|default:\"-\" }}</h4>\n                <span class=\"text-muted\">Profits</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.tax_provisionning|currency|default:0 }}</h4>\n                <span class=\"text-muted\">Tax Provisionning</span>\n            </div>\n        </div>\n        <div class=\"col-xs-6 col-sm-3\">\n            <div class=\"figure\">\n                <h4>{{ organization.overdue_total|currency|default:0 }}</h4>\n                <span class=\"text-muted\">Due payments</span>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"row\">\n        <div class=\"col-xs-12 col-sm-6\">\n            {% include \"books/_partials/invoice_list.html\" with invoices=invoices hide_edit=True %}\n            <a href=\"{% url 'books:invoice-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n                Add an invoice\n            </a>\n        </div>\n        <div class=\"col-xs-12 col-sm-6\">\n            {% include \"books/_partials/bill_list.html\" with bills=bills hide_edit=True %}\n            <a href=\"{% url 'books:bill-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n                Add an bill\n            </a>\n        </div>\n    </div>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/organization_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Organizations <small>which belong to you</small></h1>\n\n    <table class=\"table table-striped\">\n        <thead>\n            <tr>\n                <th>#</th>\n                <th>Display name</th>\n                <th>Legal name</th>\n                <th>Turnover</th>\n                <th class=\"text-right\">Actions</th>\n            </tr>\n        </thead>\n        <tbody>\n            {% for orga in organizations %}\n            <tr>\n                <td>{{ orga.id }}</td>\n                <td>{{ orga.display_name }}</td>\n                <td>{{ orga.legal_name }}</td>\n                <td>{{ orga.turnover_excl_tax|currency|default:\"-\" }}</td>\n                <td class=\"text-right\">\n                    <a href=\"{% url 'books:organization-detail' orga.pk %}\" class=\"btn btn-success btn-sm\" role=\"button\">View</a>\n                    <a href=\"{% url 'books:organization-edit' orga.pk %}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                </td>\n            </tr>\n            {% endfor %}\n        </tbody>\n    </table>\n\n    <a href=\"{% url 'books:organization-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add an organization\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/organization_selector.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block container %}\n<div class=\"container-fluid\">\n    <div class=\"row\">\n        <div class=\"col-sm-12 main\">\n            <h1 class=\"page-header text-center\">Organization Selector</h1>\n\n            <div class=\"row\">\n                {% for orga in organizations %}\n                <div class=\"col-md-4\">\n                    <div class=\"panel panel-primary\">\n                        <div class=\"panel-heading\">\n                            <h3 class=\"panel-title\">\n                                {% ifequal orga.owner request.user %}\n                                <span class=\"label label-warning pull-right\">owned</span>\n                                {% else %}\n                                <span class=\"label label-info pull-right\">member</span>\n                                {% endifequal %}\n                                {{ orga.display_name }}\n                            </h3>\n                        </div>\n                        <div class=\"panel-body\">\n                            <dl class=\"dl-horizontal\">\n\n                                <dt>Turn over (excl. tax)</dt>\n                                <dd>{{ orga.turnover_excl_tax|currency|default:\"-\" }}</dd>\n\n                                <dt>Due payments</dt>\n                                <dd>{{ orga.overdue_total|currency|default:0 }}</dd>\n\n                            </dl>\n                            <form action=\"{% url 'books:organization-select' orga.pk %}\" method=\"post\">\n                                {% csrf_token %}\n                                <button type=\"submit\" class=\"btn btn-success btn-block\" role=\"button\">Select</button>\n                            </form>\n                        </div>\n                    </div>\n                </div>\n                {% endfor %}\n                <div class=\"col-md-4\">\n                    <div class=\"panel panel-default\">\n                        <div class=\"panel-heading\">\n                            <h3 class=\"panel-title\">Add an organization</h3>\n                        </div>\n                        <div class=\"panel-body\">\n                            <a class=\"btn btn-default btn-block\" role=\"button\" href=\"{% url 'books:organization-create' %}\">New organization</a>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n{% endblock container %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/payment_create_or_update.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load static bootstrap3 introspection_filters %}\n\n{% block head %}\n    {{ block.super }}\n    {{ form.media }}\n{% endblock %}\n\n{% block content %}\n    <h1 class=\"page-header\">Create a {{ form|get_form_model_verbose_name }}</h1>\n\n    <form action=\".\" method=\"post\" class=\"form\">\n        {% csrf_token %}\n\n        {% bootstrap_form form %}\n\n        {{ payment_formset.management_form }}\n        {{ payment_formset.non_field_errors }}\n        {% for subform in payment_formset.forms %}\n            <div class=\"formset-form\">\n                {% bootstrap_form subform layout='vertical' %}\n            </div>\n        {% endfor %}\n\n        {% buttons layout='vertical' %}\n            <button type=\"submit\" class=\"btn btn-success\">\n                {% bootstrap_icon \"star\" %} Create\n            </button>\n        {% endbuttons %}\n    </form>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/books/tax_rate_create_or_update.html",
    "content": "{% extends \"_generics/form.html\" %}"
  },
  {
    "path": "accounting/templates/accounting/books/tax_rate_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Tax Rates <small>which belong to you</small></h1>\n\n    {% include \"books/_partials/tax_rate_list.html\" with tax_rates=tax_rates %}\n\n    <a href=\"{% url 'books:tax_rate-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add a Tax rate\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/connect/getting_started.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block content %}\n<div class=\"container-fluid\">\n    <div class=\"row\">\n        <div class=\"col-sm-8 col-sm-offset-2 main\">\n            <h1 class=\"page-header text-center\">Getting Started</h1>\n\n            <div class=\"row\">\n                <ol class=\"list-group check-list\">\n                    {% for step in steps %}\n                    {% if not step.is_completed %}\n                    <li class=\"list-group-item clearfix\">\n                        <a href=\"{{ step.get_action_url }}\" class=\"btn btn-success pull-right\">Take care of that</a>\n                        <h4>{{ step.opts.name }}</h4>\n                        <p>{{ step.opts.description }}</p>\n                    </li>\n                    {% else %}\n                    <li class=\"list-group-item clearfix disabled\">\n                        <h4>\n                            <span class=\"check-item pull-right\">\n                                <span class=\"glyphicon glyphicon-ok\"></span>\n                            </span>\n                            {{ step.opts.name }}\n                        </h4>\n                        <p>{{ step.opts.description }}</p>\n                    </li>\n                    {% endif %}\n                    {% endfor %}\n                </ol>\n\n                {% if not all_steps_completed %}\n                <a href=\"#\" disabled class=\"btn btn-default btn-lg btn-block\">Please complete the above steps for your own sake</a>\n                {% else %}\n                <a href=\"{% url 'books:dashboard' %}\" class=\"btn btn-success btn-lg btn-block\">All Good! Go make some money</a>\n                {% endif %}\n            </div>\n        </div>\n    </div>\n</div>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/layout.html",
    "content": "{% extends \"accounting/base.html\" %}\n{% load nav bootstrap3 %}\n\n{% block maincontent %}\n    {% block nav %}\n    <div class=\"navbar navbar-inverse\" role=\"navigation\">\n        <div class=\"container-fluid\">\n            <div class=\"navbar-header\">\n                {% url 'books:organization-selector' as books_organization_selector_url %}\n                {% url 'books:dashboard' as books_dashboard_url %}\n                <div class=\"navbar-collapse collapse\">\n                    <ul class=\"nav navbar-nav\">\n                        <li>\n                            <a type=\"btn\" href=\"{{ books_organization_selector_url }}\">\n                                <span class=\"glyphicon glyphicon-home\"></span>\n                            </a>\n                        </li>\n                        {% if selected_organization %}\n                        <li><a href=\"{{ books_dashboard_url }}\">{{ selected_organization.display_name }}</a></li>\n                        {% endif %}\n                    </ul>\n                </div>\n            </div>\n            <div class=\"navbar-collapse collapse\">\n                {% url 'connect:getting-started' as getting_started_url %}\n                <div class=\"navbar-collapse navbar-right\">\n                    <ul class=\"nav navbar-nav\">\n                        <li><a href=\"{{ getting_started_url }}\">Getting started</a></li></li>\n                    </ul>\n                    <p class=\"navbar-text\">Accounting {{ display_version }}</p>\n                </div>\n            </div>\n        </div>\n    </div>\n    {% endblock nav %}\n\n    {% block container %}\n    <div class=\"container-fluid\">\n        <div class=\"row\">\n            {% block sidebar %}\n            <div class=\"col-sm-3 col-md-2 sidebar\">\n                <ul class=\"nav nav-sidebar\">\n                    {% url 'books:dashboard' as books_dashboard_url %}\n                    <li class=\"{% active request books_dashboard_url exact_match=True %}\"><a href=\"{{ books_dashboard_url }}\">Overview</a></li>\n                </ul>\n                <ul class=\"nav nav-sidebar\">\n                    {% url 'books:estimate-list' as books_estimate_list_url %}\n                    {% url 'books:invoice-list' as books_invoice_list_url %}\n                    {% url 'books:bill-list' as books_bill_list_url %}\n                    {% url 'books:expense_claim-list' as books_exepense_claim_list_url %}\n                    {% url 'books:tax_rate-list' as books_tax_rate_list_url %}\n                    <li class=\"{% active request books_estimate_list_url exact_match=True %}\"><a href=\"{{ books_estimate_list_url }}\">Estimates</a></li>\n                    <li class=\"{% active request books_invoice_list_url exact_match=True %}\"><a href=\"{{ books_invoice_list_url }}\">Invoices</a></li>\n                    <li class=\"{% active request books_bill_list_url exact_match=True %}\"><a href=\"{{ books_bill_list_url }}\">Bills</a></li>\n                    <li class=\"{% active request books_exepense_claim_list_url exact_match=True %}\"><a href=\"{{ books_exepense_claim_list_url }}\">Expense claims</a></li>\n                    <li class=\"{% active request books_tax_rate_list_url exact_match=True %}\"><a href=\"{{ books_tax_rate_list_url }}\">Tax Rates</a></li>\n                </ul>\n                <ul class=\"nav nav-sidebar\">\n                    {% url 'people:client-list' as clients_client_list_url %}\n                    {% url 'people:employee-list' as employees_employee_list_url %}\n                    <li class=\"{% active request clients_client_list_url exact_match=True %}\"><a href=\"{{ clients_client_list_url }}\">Clients</a></li>\n                    <li class=\"{% active request employees_employee_list_url exact_match=True %}\"><a href=\"{{ employees_employee_list_url }}\">Employees</a></li>\n                </ul>\n                <ul class=\"nav nav-sidebar\">\n                    {% url 'reports:report-list' as reports_report_list_url %}\n                    {% url 'reports:settings-list' as reports_settings_list_url %}\n                    <li class=\"{% active request reports_report_list_url exact_match=True %}\"><a href=\"{{ reports_report_list_url }}\">Reports</a></li>\n                    <li class=\"{% active request reports_settings_list_url exact_match=True %}\"><a href=\"{{ reports_settings_list_url }}\">Settings</a></li>\n                </ul>\n                <ul class=\"nav nav-sidebar\">\n                    <li class=\"disabled\"><a href=\"\">Reconciliation</a></li>\n                </ul>\n            </div>\n            {% endblock sidebar %}\n            <div class=\"col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main\">\n                {% bootstrap_messages %}\n                {% block content %}{% endblock %}\n            </div>\n        </div>\n    </div>\n    {% endblock container %}\n{% endblock maincontent %}\n"
  },
  {
    "path": "accounting/templates/accounting/people/client_create_or_update.html",
    "content": "{% extends \"_generics/form.html\" %}\n"
  },
  {
    "path": "accounting/templates/accounting/people/client_detail.html",
    "content": ""
  },
  {
    "path": "accounting/templates/accounting/people/client_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block content %}\n    <h1 class=\"page-header\">Clients <small>which belong to you</small></h1>\n\n    <table class=\"table table-striped\">\n        <thead>\n            <tr>\n                <th>#</th>\n                <th>Name</th>\n                <th class=\"text-right\">Actions</th>\n            </tr>\n        </thead>\n        <tbody>\n            {% for cli in clients %}\n            <tr>\n                <td>{{ cli.id }}</td>\n                <td>{{ cli.name }}</td>\n                <td class=\"text-right\">\n                    <a href=\"{% url 'people:client-edit' cli.pk %}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                </td>\n            </tr>\n            {% endfor %}\n        </tbody>\n    </table>\n\n    <a href=\"{% url 'people:client-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add a client\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/people/employee_create_or_update.html",
    "content": "{% extends \"_generics/form.html\" %}\n"
  },
  {
    "path": "accounting/templates/accounting/people/employee_detail.html",
    "content": ""
  },
  {
    "path": "accounting/templates/accounting/people/employee_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block content %}\n    <h1 class=\"page-header\">Employees <small>which belong to you</small></h1>\n\n    <table class=\"table table-striped\">\n        <thead>\n            <tr>\n                <th>#</th>\n                <th>First name</th>\n                <th>Last name</th>\n                <th>Email</th>\n                <th class=\"text-right\">Actions</th>\n            </tr>\n        </thead>\n        <tbody>\n            {% for emp in employees %}\n            <tr>\n                <td>{{ emp.id }}</td>\n                <td>{{ emp.first_name }}</td>\n                <td>{{ emp.last_name }}</td>\n                <td>{{ emp.email }}</td>\n                <td class=\"text-right\">\n                    <a href=\"{% url 'people:employee-edit' emp.pk %}\" class=\"btn btn-default btn-sm\" role=\"button\">Edit</a>\n                </td>\n            </tr>\n            {% endfor %}\n        </tbody>\n    </table>\n\n    <a href=\"{% url 'people:employee-create' %}\" class=\"btn btn-primary btn-lg\" role=\"button\">\n        Add an employee\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/_partials/period_form.html",
    "content": "{% load bootstrap3 %}\n<form action=\".\" method=\"get\">\n    {% bootstrap_form_errors form %}\n\n    <div class=\"row\">\n        <div class=\"col-md-5\">\n            {% bootstrap_field form.date_from show_label=False %}\n        </div>\n        <div class=\"col-md-5\">\n            {% bootstrap_field form.date_to show_label=False %}\n        </div>\n        <div class=\"col-md-2\">\n            <button class=\"btn btn-info\" type=\"submit\">\n                Update\n            </button>\n        </div>\n    </div>\n</form>"
  },
  {
    "path": "accounting/templates/accounting/reports/financial_settings_update.html",
    "content": "{% extends \"_generics/form.html\" %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/invoice_details_report.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters bootstrap3 %}\n\n{% block content %}\n    <h1 class=\"page-header\">Invoice Details</h1>\n\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title\">{{ form_title }}</h3>\n        </div>\n        <div class=\"panel-body\">\n            <form action=\".\" method=\"get\">\n                {% bootstrap_form_errors form %}\n\n                <div class=\"row\">\n                    <div class=\"col-md-5\">\n                        {% bootstrap_field form.date_from show_label=False %}\n                    </div>\n                    <div class=\"col-md-5\">\n                        {% bootstrap_field form.date_to show_label=False %}\n                    </div>\n                    <div class=\"col-md-2\">\n                        <button class=\"btn btn-info\" type=\"submit\">\n                            Update\n                        </button>\n                    </div>\n                </div>\n            </form>\n        </div>\n    </div>\n\n    <hr>\n\n    <table class=\"table\">\n        <thead>\n            <tr>\n                <th>Invoice #</th>\n                <th>Issue Date</th>\n                <th>Status</th>\n                <th>Item</th>\n                <th>Unit Cost</th>\n                <th>Quantity</th>\n                {% for t in tax_rates %}\n                <th>{{ t.name }}</th>\n                {% endfor %}\n                <th>Amount</th>\n            </tr>\n        </thead>\n        <tbody>\n        {% for inv in invoices %}\n            <tr>\n                <td>{{ inv.number }}</td>\n                <td>{{ inv.date_issued }}</td>\n                <td>{{ inv.status }}</td>\n            {% for line in inv.lines.all %}\n                <td>{{ line.label }}</td>\n                <td>{{ line.unit_price.excl_tax }}</td>\n                <td>{{ line.quantity }}</td>\n                {% for t in tax_rates %}\n                {% if t.pk == line.tax_rate_id %}\n                <td>{{ line.taxes }}</td>\n                {% else %}\n                <td>-</td>\n                {% endif %}\n                {% endfor %}\n                <td>{{ line.line_price_excl_tax|currency }}</td>\n            {% if not forloop.last %}\n            <tr>\n                <td colspan=3></td>\n            {% endif %}\n            {% endfor %}\n            </tr>\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }}></td>\n                <td class=\"text-right\">Subtotal</td>\n                <td>{{ inv.total_excl_tax|currency }}</td>\n            </tr>\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }} class=\"empty-cell\"></td>\n                <td class=\"text-right\">Taxes</td>\n                <td>{{ inv.total_tax|currency }}</td>\n            </tr>\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }} class=\"empty-cell\"></td>\n                <td class=\"text-right\"><strong>Total</strong></td>\n                <td><strong>{{ inv.total_incl_tax|currency }}</strong></td>\n            </tr>\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }} class=\"empty-cell\"></td>\n                <td class=\"text-right\">Paid</td>\n                <td>{{ inv.total_paid|currency }}</td>\n            </tr>\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }} class=\"empty-cell\"></td>\n                <td class=\"text-right\"><strong>Balance</strong></td>\n                <td><strong>{{ inv.total_due_incl_tax|currency }}</strong></td>\n            </tr>\n            {% if payrun_settings.salaries_follow_profits %}\n            <tr>\n                <td colspan={{ tax_rates|length|add:\"5\" }} class=\"empty-cell\"></td>\n                <td class=\"text-right\">Payroll taxes</td>\n                <td>{{ inv.payroll_taxes|currency }}</td>\n            </tr>\n            {% endif %}\n            <tr class=\"empty-line\"><td></td></tr>\n        {% if not forloop.last %}\n        </tbody>\n        <tbody>\n        {% endif %}\n        {% endfor %}\n        </tbody>\n    </table>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/pay_run_report.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters format_filters bootstrap3 %}\n\n{% block content %}\n    <h1 class=\"page-header\">Pay Run Report <small>don't spend that money neither</small></h1>\n\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title\">{{ form_title }}</h3>\n        </div>\n        <div class=\"panel-body\">\n            {% include \"accounting/reports/_partials/period_form.html\" with form=form %}\n        </div>\n    </div>\n\n    <hr>\n\n    <table class=\"table table-striped table-bordered\">\n        <thead>\n            <tr>\n                <th>Employee</th>\n                <th>Gross pay</th>\n                <th>Payroll Tax Rate</th>\n                <th class=\"text-right\">Payroll Taxes</th>\n            </tr>\n        </thead>\n        <tbody>\n            {% for summary in summaries %}\n            <tr>\n                <td><strong>{{ summary.employee }}</strong></td>\n                <td>{{ summary.total_excl_tax|currency }}</td>\n                <td>{{ summary.payroll_tax_rate|percentage }}</td>\n                <td class=\"text-right\">{{ summary.payroll_taxes|currency }}</td>\n            <tr>\n            {% endfor %}\n        </tbody>\n    </table>\n\n    <div class=\"row text-right\">\n        <div class=\"col-xs-2 col-xs-offset-8\">\n            <p>\n                <strong>\n                    Total Taxes : <br>\n                </strong>\n            </p>\n        </div>\n        <div class=\"col-xs-2\">\n            <strong>\n                {{ total_payroll_taxes|currency }} <br>\n            </strong>\n        </div>\n    </div>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/payrun_settings_update.html",
    "content": "{% extends \"_generics/form.html\" %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/profit_and_loss_report.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Profit and Loss <small>how ur doin'?</small></h1>\n\n    <table class=\"table\">\n        <thead>\n            <tr>\n                <th></th>\n                {% for key_date in summaries.keys %}\n                <th class=\"text-right\">{{ key_date|date:\"b\" }}</th>\n                {% endfor %}\n                <th class=\"text-right\">Total</th>\n            </tr>\n        </thead>\n        <tbody>\n            <tr class=\"empty-line\"><td></td></tr>\n            <tr>\n                <td colspan=\"{{ summaries.keys|length|add:'2' }}\"><strong>Income</strong></td>\n            </tr>\n            <tr class=\"text-right\">\n                <td></td>\n                {% for summary in summaries.values %}\n                <td>{{ summary.sales_amount|currency }}</td>\n                {% endfor %}\n                <td>{{ total_summary.sales_amount|currency }}</td>\n            </tr>\n        </tbody>\n        <tbody>\n            <tr class=\"empty-line\"><td></td></tr>\n            <tr>\n                <td colspan=\"{{ summaries.keys|length|add:'2' }}\"><strong>Expenses</strong></td>\n            </tr>\n            <tr class=\"text-right\">\n                <td></td>\n                {% for summary in summaries.values %}\n                <td>{{ summary.expenses_amount|currency }}</td>\n                {% endfor %}\n                <td>{{ total_summary.expenses_amount|currency }}</td>\n            </tr>\n        </tbody>\n        <tbody>\n            <tr class=\"empty-line\"><td></td></tr>\n            <tr>\n                <td colspan=\"{{ summaries.keys|length|add:'2' }}\"><strong>Net Profit</strong></td>\n            </tr>\n            <tr class=\"text-right\">\n                <td></td>\n                {% for summary in summaries.values %}\n                <td>{{ summary.net_profit|currency }}</td>\n                {% endfor %}\n                <td>{{ total_summary.net_profit|currency }}</td>\n            </tr>\n        </tbody>\n    </table>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/report_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block content %}\n    <h1 class=\"page-header\">Reports <small>which belong to you</small></h1>\n\n    <div class=\"panel panel-default panel-link\">\n        <div class=\"panel-heading\">\n            <a href=\"{% url 'reports:tax-report' %}\"><h3 class=\"panel-title\">Tax Report</h3></a>\n        </div>\n        <div class=\"panel-body\">\n            Prepare the tax report for your tax period (defined in the <a href=\"{% url 'reports:settings-financial' %}\">financial settings</a>)\n        </div>\n    </div>\n\n    <div class=\"panel panel-default panel-link\">\n        <div class=\"panel-heading\">\n            <a href=\"{% url 'reports:profit-and-loss-report' %}\"><h3 class=\"panel-title\">Profit and Loss</h3></a>\n        </div>\n        <div class=\"panel-body\">\n            Know how your business is doing\n        </div>\n    </div>\n\n    <div class=\"panel panel-default panel-link\">\n        <div class=\"panel-heading\">\n            <a href=\"{% url 'reports:pay-run-report' %}\"><h3 class=\"panel-title\">Pay run</h3></a>\n        </div>\n        <div class=\"panel-body\">\n            How much payroll you should keep\n        </div>\n    </div>\n\n    <div class=\"panel panel-default panel-link\">\n        <div class=\"panel-heading\">\n            <a href=\"{% url 'reports:invoice-details-report' %}\"><h3 class=\"panel-title\">Invoice details</h3></a>\n        </div>\n        <div class=\"panel-body\">\n            How much payroll you should keep\n        </div>\n    </div>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/settings_list.html",
    "content": "{% extends \"accounting/layout.html\" %}\n\n{% block content %}\n    <h1 class=\"page-header\">Settings <small>for powerful reports</small></h1>\n\n    <a href=\"{% url 'reports:settings-business' %}\" class=\"panel panel-default panel-link\">\n        <div class=\"panel-body\">\n            Business settings\n        </div>\n    </a>\n\n    <a href=\"{% url 'reports:settings-financial' %}\" class=\"panel panel-default panel-link\">\n        <div class=\"panel-body\">\n            Financial settings\n        </div>\n    </a>\n\n    <a href=\"{% url 'reports:settings-payrun' %}\" class=\"panel panel-default panel-link\">\n        <div class=\"panel-body\">\n            Payrun settings\n        </div>\n    </a>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/templates/accounting/reports/tax_report.html",
    "content": "{% extends \"accounting/layout.html\" %}\n{% load currency_filters %}\n\n{% block content %}\n    <h1 class=\"page-header\">Tax Report <small>don't spend that money</small></h1>\n\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title\">{{ form_title }}</h3>\n        </div>\n        <div class=\"panel-body\">\n            {% include \"accounting/reports/_partials/period_form.html\" with form=form %}\n        </div>\n    </div>\n\n    <hr>\n\n    <table class=\"table\">\n        <thead>\n            <tr>\n                <th>Tax Name</th>\n                <th>Taxable Amount</th>\n                <th>Taxes</th>\n            </tr>\n        </thead>\n        {% for summary in tax_summaries %}\n        <tbody>\n            <tr class=\"empty-line\"><td></td></tr>\n            <tr>\n                <td><strong>{{ summary.tax_rate }}</strong></td>\n                <td></td>\n                <td></td>\n            <tr>\n                <td>\n                    <abbr href=\"#\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"The amount includes fully or partially paid invoices\">\n                        Collected\n                    </abbr>\n                </td>\n                <td>{{ summary.taxable_amount|currency }}</td>\n                <td>{{ summary.collected_taxes|currency }}</td>\n            </tr>\n            <tr>\n                <td>Expenses</td>\n                <td>{{ summary.expenses_amount|currency }}</td>\n                <td>{{ summary.deductible_taxes|currency }}</td>\n            </tr>\n            <tr>\n                <td>NET</td>\n                <td>{{ summary.net_amount|currency }}</td>\n                <td>{{ summary.net_taxes|currency }}</td>\n            </tr>\n        </tbody>\n        {% endfor %}\n    </table>\n{% endblock content %}\n"
  },
  {
    "path": "accounting/urls.py",
    "content": "from django.conf import settings\nfrom django.conf.urls import patterns, include, url\nfrom django.conf.urls.static import static\n\n\nurlpatterns = patterns('',\n    url(r'^', include('accounting.apps.connect.urls',\n        namespace=\"connect\")),\n    url(r'^books/', include('accounting.apps.books.urls',\n        namespace=\"books\")),\n    url(r'^people/', include('accounting.apps.people.urls',\n        namespace=\"people\")),\n    url(r'^reports/', include('accounting.apps.reports.urls',\n        namespace=\"reports\")),\n\n    # third party\n    url(r'^select2/', include('django_select2.urls')),\n)\n\nif settings.DEBUG:\n    urlpatterns += static(settings.MEDIA_URL,\n                          document_root=settings.MEDIA_ROOT)\n"
  },
  {
    "path": "accounting/wsgi.py",
    "content": "\"\"\"\nWSGI config for accounting project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/\n\"\"\"\n\nimport os\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"accounting.settings.dev\")\n\nfrom django.core.wsgi import get_wsgi_application # NOQA\nfrom dj_static import Cling # NOQA\napplication = Cling(get_wsgi_application())\n"
  },
  {
    "path": "lint.sh",
    "content": "#/usr/bin/env bash\n#\n# Run static analysis of the codebase\n#\n# This is run on Travis to ensure that pull requests conform to the project coding standards.\n\n# Ideally, this figure should be < 100.  I'll keep reducing it as the\n# codebase gets tidied up incrementally.\nTHRESHOLD=10\n\n# Some warnings aren't worth worrying about...\nIGNORE=\"W292,E202,E128,E124\"\n\n# Run flake8 and convert the output into a format that the \"violations\" plugin\n# for Jenkins/Hudson can understand.  Ignore warnings from migrations we we don't\n# really care about those.\nERROR_FILE=\"violations.txt\"\nflake8 --ignore=$IGNORE accounting --exclude migrations | perl -ple \"s/: /: [E] /\" > $ERROR_FILE\ncat $ERROR_FILE\n\n\n# Check that the number of violations is acceptable\nNUMERRORS=`cat $ERROR_FILE | wc -l`\nif [ $NUMERRORS -gt $THRESHOLD ]\nthen\n    echo \"Too many flake8 errors - maximum allowed is $THRESHOLD, found $NUMERRORS\"\n    exit 1\nfi\n"
  },
  {
    "path": "requirements.txt",
    "content": "## Testing\ncoverage==4.3.4\ndjango-dynamic-fixture>=1.7,<1.8\ndjango-nose>=1.4,<1.5\n\nmock>=1.0.1,<1.1.0\nspec>=0.11.1,<0.12\nWebTest==2.0.12\ndjango-webtest>=1.7,<1.8\ncoveralls>=0.4,<0.5\n\n## Misc\nflake8>=2.2.2\nipdb>=0.8,<0.9\nipdbplugin>=1.4\nipython>=1.1.0,<1.2.0\n"
  },
  {
    "path": "runtests.py",
    "content": "#!/usr/bin/env python\n\"\"\"\nCustom test runner\n\nIf args or options, we run the testsuite as quickly as possible.\n\nIf args but no options, we default to using the spec plugin and aborting on\nfirst error/failure.\n\nIf options, we ignore defaults and pass options onto Nose.\n\nExamples:\n\nRun all tests (as fast as possible)\n$ ./runtests.py\n\nRun all unit tests (using spec output)\n$ ./runtests.py tests/unit\n\nRun all books unit tests (using spec output)\n$ ./runtests.py tests/unit/books\n\nRun all tests relating to books\n$ ./runtests.py --attr=books\n\nRe-run failing tests (needs to be run twice to first build the index)\n$ ./runtests.py ... --failed\n\nDrop into pdb when a test fails\n$ ./runtests.py ... --pdb-failures\n\"\"\"\n\nimport sys\nimport logging\nimport warnings\n\nimport django\nfrom django.utils.six.moves import map\n\nfrom tests.config import configure\n\n\n# No logging\nlogging.disable(logging.CRITICAL)\n\n\ndef run_tests(verbosity, *test_args):\n    from django_nose import NoseTestSuiteRunner\n    test_runner = NoseTestSuiteRunner(verbosity=verbosity)\n    if not test_args:\n        test_args = ['tests']\n    num_failures = test_runner.run_tests(test_args)\n    if num_failures:\n        sys.exit(num_failures)\n\n\nif __name__ == '__main__':\n    args = sys.argv[1:]\n\n    verbosity = 1\n    if not args:\n        # If run with no args, try and run the testsuite as fast as possible.\n        # That means across all cores and with no high-falutin' plugins.\n        import multiprocessing\n        try:\n            num_cores = multiprocessing.cpu_count()\n        except NotImplementedError:\n            num_cores = 4  # Guess\n        args = ['--ipdb',\n                '--nocapture',\n                '--stop',\n                '--processes=%s' % num_cores]\n    else:\n        # Some args/options specified.  Check to see if any nose options have\n        # been specified.  If they have, then don't set any\n        has_options = any(map(lambda x: x.startswith('--'), args))\n        if not has_options:\n            # Default options:\n            # --stop Abort on first error/failure\n            # --nocapture Don't capture STDOUT\n            args.extend(['--ipdb',\n                         '--nocapture',\n                         '--stop',\n                         '--with-specplugin'])\n        else:\n            # Remove options as nose will pick these up from sys.argv\n            for arg in args:\n                if arg.startswith('--verbosity'):\n                    verbosity = int(arg[-1])\n            args = [arg for arg in args if not arg.startswith('-')]\n\n    configure()\n    django.setup()  # initialise app registry of Django 1.7+\n    run_tests(verbosity, *args)\n"
  },
  {
    "path": "setup.cfg",
    "content": "[wheel]\n# accounting is not Python2 ready for now, so we cannot build universal wheels.\nuniversal = 0\npython-tag = py32"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n\"\"\"\nInstallation script:\n\nTo release a new version to PyPi:\n- Ensure the version is correctly set in accounting.__init__.py\n- Run:\n    `python setup.py sdist`\n    `twine upload dist/*`\n\"\"\"\nfrom setuptools import setup, find_packages\nimport os\nimport sys\n\nfrom accounting import get_version\n\nPROJECT_DIR = os.path.dirname(__file__)\n\nsetup(name='django-accounting',\n      version=get_version().replace(' ', '-'),\n      url='https://github.com/dulacp/django-accounting',\n      author=\"Pierre Dulac\",\n      author_email=\"dulacpi@gmail.com\",\n      description=\"Accounting made accessible for small businesses and \"\n                  \"sole proprietorships through a simple Django project\",\n      long_description=open(os.path.join(PROJECT_DIR, 'README.rst')).read(),\n      keywords=\"Accounting, Django, Money, Cashflow\",\n      license='MIT',\n      platforms=['linux'],\n      packages=find_packages(exclude=[\"tests*\"]),\n      include_package_data=True,\n      install_requires=[\n          'django>=1.8.0,<1.9',\n          # Used to render the forms\n          'django-bootstrap3==4.11.0',\n          # Used to improve the forms\n          'django_select2==5.8.10',\n          # Used for date/time form fields\n          'django-datetime-widget>=0.9,<1.0',\n          # Define beautiful tags\n          'django-classy-tags==0.5.1',\n          # Internationalization\n          'Babel>=1.0,<1.4',\n          # Date utilities\n          'python-dateutil>=2.2,<2.3',\n          # Select2\n          'django-select2>=4.3,<4.4',\n      ],\n      # See http://pypi.python.org/pypi?%3Aaction=list_classifiers\n      classifiers=[\n          'Development Status :: 2 - Pre-Alpha',\n          'Environment :: Web Environment',\n          'Framework :: Django',\n          'Intended Audience :: Developers',\n          'License :: OSI Approved :: MIT License',\n          'Operating System :: Unix',\n          'Programming Language :: Python',\n          'Programming Language :: Python :: 3',\n          'Programming Language :: Python :: 3.3',\n          'Programming Language :: Python :: 3.4',\n          'Topic :: Software Development :: Libraries :: Application Frameworks']\n      )\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/_site/__init__.py",
    "content": ""
  },
  {
    "path": "tests/_site/model_tests_app/__init__.py",
    "content": ""
  },
  {
    "path": "tests/_site/model_tests_app/models.py",
    "content": "from django.test import TestCase\nfrom django.db import models\nfrom django.db.models.query import QuerySet\nfrom django.conf import settings\n\nfrom accounting.libs.fields import UUIDField\n\n\nclass MockModelWitNoFields(models.Model):\n    \"\"\"No fields\"\"\"\n    pass\n\n\nclass MockModelWithUUIDField(models.Model):\n    dymmy = models.CharField(max_length=254)\n    uid = UUIDField(blank=True)\n"
  },
  {
    "path": "tests/config.py",
    "content": "import os\nimport sys\n\n\ndef configure():\n    os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'\n    from django.conf import settings, global_settings\n\n    # Helper function to extract absolute path\n    location = lambda x: os.path.join(\n        os.path.dirname(os.path.realpath(__file__)), x)\n\n    sys.path.append(location('../accounting'))\n"
  },
  {
    "path": "tests/functional/__init__.py",
    "content": ""
  },
  {
    "path": "tests/functional/libs/__init__.py",
    "content": ""
  },
  {
    "path": "tests/functional/libs/context_processors_tests.py",
    "content": "from django.test import TestCase\nfrom django.test.client import RequestFactory\n\nfrom accounting.apps.context_processors import metadata\n\n\nclass TestLibsMetadata(TestCase):\n\n    def setUp(self):\n        factory = RequestFactory()\n        self.request = factory.get('/')\n        self.metadata = metadata(self.request)\n\n    def test_has_version(self):\n        self.assertTrue('version' in self.metadata)\n        self.assertTrue('display_version' in self.metadata)\n"
  },
  {
    "path": "tests/functional/libs/template_tags_tests.py",
    "content": "from decimal import Decimal as D\n\nfrom django.test import TestCase\nfrom django.test.client import RequestFactory\nfrom django.template import Template, Context, RequestContext\nfrom django.contrib.auth.models import AnonymousUser\nfrom django import forms\n\nfrom accounting.libs.templatetags.form_filters import is_disabled, is_readonly\n\n\nclass TestGetParameterTemplateTag(TestCase):\n\n    def setUp(self):\n        factory = RequestFactory()\n        self.request = factory.get('/', {'page': 3, 'sort': 'asc'})\n        self.request.user = AnonymousUser()\n        # Simulate that we get throught the middleware\n        self.request.franchise = None\n\n    def test_retrieve_get_param(self):\n        out = Template(\n            \"{% load url_tags %}\"\n            \"{% get_parameters %}\"\n        ).render(RequestContext(self.request, {}))\n        self.assertTrue(out == \"page=3&sort=asc\" or out == \"sort=asc&page=3\")\n\n    def test_except_fields(self):\n        out = Template(\n            \"{% load url_tags %}\"\n            \"{% get_parameters 'sort' %}\"\n        ).render(RequestContext(self.request, {}))\n        self.assertEqual(out, \"page=3\")\n\n\nclass TestFormFilterCssClass(TestCase):\n\n    def setUp(self):\n        class MockForm(forms.Form):\n            text_field = forms.CharField()\n            date_field = forms.DateField()\n        self.form_class = MockForm\n        self.form = self.form_class()\n\n    def test_text_field_class_name(self):\n        out = Template(\n            \"{% load form_filters %}\"\n            \"{% for field in form %}\"\n            \"{{ field|css_class }},\"\n            \"{% endfor %}\"\n        ).render(Context({\n            'form': self.form\n        }))\n        self.assertEqual(out, \"textinput,dateinput,\")\n\n\nclass TestFormFilterIsDisable(TestCase):\n\n    def setUp(self):\n        class MockForm(forms.Form):\n            enabled_field = forms.CharField()\n            disabled_field = forms.CharField(\n                widget=forms.TextInput(attrs={'disabled': True}))\n        self.form_class = MockForm\n        self.form = self.form_class()\n\n    def test_return_true_for_disable_fields(self):\n        self.assertFalse(is_disabled(self.form.fields['enabled_field']))\n        self.assertTrue(is_disabled(self.form.fields['disabled_field']))\n\n    def test_return_true_for_disable_bounded_fields(self):\n        \"\"\"\n        Bounded fields are used when we iterate directly through\n        a form instance\n        \"\"\"\n        bounded_fields = dict((f.name, f) for f in self.form)\n        self.assertFalse(is_disabled(bounded_fields['enabled_field']))\n        self.assertTrue(is_disabled(bounded_fields['disabled_field']))\n\n\nclass TestFormFilterIsReadonly(TestCase):\n\n    def setUp(self):\n        class MockForm(forms.Form):\n            writable_field = forms.CharField()\n            readonly_field = forms.CharField(\n                widget=forms.TextInput(attrs={'readonly': True}))\n        self.form_class = MockForm\n        self.form = self.form_class()\n\n    def test_return_true_for_readonly_fields(self):\n        self.assertFalse(is_readonly(self.form.fields['writable_field']))\n        self.assertTrue(is_readonly(self.form.fields['readonly_field']))\n\n    def test_return_true_for_readonly_bounded_fields(self):\n        \"\"\"\n        Bounded fields are used when we iterate directly through\n        a form instance\n        \"\"\"\n        bounded_fields = dict((f.name, f) for f in self.form)\n        self.assertFalse(is_readonly(bounded_fields['writable_field']))\n        self.assertTrue(is_readonly(bounded_fields['readonly_field']))\n\n\nclass TestMyFilterTimes(TestCase):\n\n    def test_simple_times_filter_loop(self):\n        out = Template(\n            \"{% load my_filters %}\"\n            \"{% for i in 5|times %}\"\n            \"{{ i }},\"\n            \"{% endfor %}\"\n        ).render(Context())\n        self.assertEqual(out, \"0,1,2,3,4,\")\n\n\nclass TestMyFilterGetItem(TestCase):\n\n    def test_wrong_type_should_raise_exception(self):\n        with self.assertRaises(AttributeError):\n            Template(\n                \"{% load my_filters %}\"\n                \"{{ d|get_item:'foo' }}\"\n            ).render(Context({\n                'd': list(range(3)),\n            }))\n\n    def test_simple_dict_value_for_key(self):\n        out = Template(\n            \"{% load my_filters %}\"\n            \"{{ d|get_item:'foo' }}\"\n        ).render(Context({\n            'd': dict(foo=\"bar\"),\n        }))\n        self.assertEqual(out, \"bar\")\n\n\nclass TestMyFilterGetObject(TestCase):\n\n    def test_simple_list_value_for_index(self):\n        out = Template(\n            \"{% load my_filters %}\"\n            \"{{ list|get_object:1 }}\"\n        ).render(Context({\n            'list': list(range(3)),\n        }))\n        self.assertEqual(out, \"1\")\n\n\nclass TestFormatFilterPercentage(TestCase):\n\n    def test_basic_value(self):\n        out = Template(\n            \"{% load format_filters %}\"\n            \"{{ f|percentage }}\"\n        ).render(Context({\n            'f': 0.2345678\n        }))\n        self.assertEqual(out, \"23,46 %\")\n\n    def test_zero_value(self):\n        out = Template(\n            \"{% load format_filters %}\"\n            \"{{ f|percentage }}\"\n        ).render(Context({\n            'f': 0\n        }))\n        self.assertEqual(out, \"0,00 %\")\n\n\nclass TestUrlTagQuery(TestCase):\n\n    def test_no_parameter_raises_exception(self):\n        from classytags.exceptions import ArgumentRequiredError\n        with self.assertRaises(ArgumentRequiredError):\n            out = Template(\n                \"{% load url_tags %}\"\n                \"{% query %}\"\n            ).render(Context({}))\n\n    def test_multiple_parameters(self):\n        out = Template(\n            \"{% load url_tags %}\"\n            \"{% query a=1 b=2 %}\"\n        ).render(Context({}))\n        self.assertTrue(out == \"a=1&b=2\" or out == \"b=2&a=1\")\n\n    def test_url_encode_spaces(self):\n        out = Template(\n            \"{% load url_tags %}\"\n            \"{% query q='I got some spaces' %}\"\n        ).render(Context({}))\n        self.assertEqual(out, \"q=I+got+some+spaces\")\n\n\nclass TestCurrencyFilter(TestCase):\n\n    def setUp(self):\n        self.template = Template(\n            \"{% load currency_filters %}\"\n            \"{{ price|currency }}\"\n        )\n\n    def test_renders_price_correctly(self):\n        out = self.template.render(Context({\n            'price': D('10.23'),\n        }))\n        # remove spaces (from comparision sake)\n        out = out.replace(\"\\xa0\", '').replace(' ', '')\n        self.assertEqual(out, '10,23€')\n\n    def test_handles_none_price_gracefully(self):\n        self.template.render(Context({\n            'price': None\n        }))\n\n    def test_handles_string_price_gracefully(self):\n        self.template.render(Context({\n            'price': ''\n        }))\n"
  },
  {
    "path": "tests/functional/libs/utils_tests.py",
    "content": "# encoding: utf-8\n\nimport datetime\n\nfrom django.test import TransactionTestCase, TestCase\nfrom django.test.utils import override_settings\nfrom django.core.urlresolvers import ResolverMatch\n\nfrom accounting.libs.utils import queryset_iterator\n\nfrom tests._site.model_tests_app.models import MockModelWitNoFields\n\nimport mock\n\n\nclass TestQuerysetIteratorHelper(TransactionTestCase):\n\n    def setUp(self):\n        self.model = MockModelWitNoFields\n        # generate a bunch of objects\n        for index in range(21):\n            self.model.objects.create()\n\n    ######################################################################\n    # The two following tests are skipped because it fails for an\n    # unknown reason\n    #\n    # EDIT: the displayed error is variable and changed times to times\n    #\n    # TODO fix those 2 tests\n    #\n    # CommandError: Database test_ledej_development couldn't be flushed.\n    # Possible reasons:\n    #   * The database isn't running or isn't configured correctly.\n    #   * At least one of the expected database tables doesn't exist.\n    #   * The SQL was invalid.\n    # Hint: Look at the output of 'django-admin.py sqlflush'. That's the\n    # SQL this command wasn't able to run.\n    ######################################################################\n\n    # def test_get_every_objects_with_small_chunksize(self):\n    #     counter = 0\n    #     for obj in queryset_iterator(self.model.objects.all(),\n    #                                  chunksize=10):\n    #         counter += 1\n    #     self.assertEqual(counter, 21)\n\n    # def test_cut_the_queryset_into_chunks(self):\n    #     def chunkify():\n    #         for obj in queryset_iterator(self.model.objects.all(),\n    #                                      chunksize=10):\n    #             pass\n    # an extra call is made to check that there is no more rows\n    # so it cuts into 3 chunks + 1 last call\n    #     self.assertNumQueries(4, chunkify)\n"
  },
  {
    "path": "tests/integration/__init__.py",
    "content": ""
  },
  {
    "path": "tests/settings.py",
    "content": "import os\nimport logging\n\nimport accounting\nfrom accounting.defaults import *\n\n\nBASE_DIR = os.path.dirname(os.path.dirname(__file__))\n\nSECRET_KEY = \"abcdef\"\n\nLANGUAGE_CODE = 'fr-fr'\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': ':memory:',\n    },\n}\n\nEMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'\n\nINSTALLED_APPS = (\n    'django.contrib.auth',\n    'django.contrib.admin',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.sites',\n    'django.contrib.flatpages',\n    'django.contrib.staticfiles',\n\n    'tests._site.model_tests_app',  # contains models we need for testing\n) + accounting.get_apps()\n\n# convert INSTALL_APPS to `list`\nINSTALLED_APPS = list(INSTALLED_APPS)\n\n# Remove 'debug_toolbar'\ntry:\n    INSTALLED_APPS.remove('debug_toolbar')\nexcept ValueError:\n    pass\n\n# Add the 'tests' app, to load test models\nINSTALLED_APPS.append('tests')\n\nTEMPLATE_CONTEXT_PROCESSORS = (\n    'django.contrib.auth.context_processors.auth',\n    'django.core.context_processors.debug',\n    'django.core.context_processors.i18n',\n    'django.core.context_processors.media',\n    'django.core.context_processors.static',\n    'django.core.context_processors.tz',\n    'django.contrib.messages.context_processors.messages',\n    'django.core.context_processors.request',\n\n    'accounting.apps.context_processors.metadata',\n)\n\nMIDDLEWARE_CLASSES = (\n    'django.middleware.common.CommonMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n)\n\nADMINS = ('admin@example.com',)\nDEBUG = False\nTEMPLATE_DEBUG = False\nSITE_ID = 1\n\n\n## Speed up tests\n\n# disable logging\nlogging.disable(logging.CRITICAL)\n\n# use a cheaper hashing method\nPASSWORD_HASHERS = (\n    'django.contrib.auth.hashers.MD5PasswordHasher',\n)\n\n# Override default fixtures folder\nFIXTURE_DIRS = (\n    os.path.normpath(os.path.join(BASE_DIR, '../tests/fixtures')),\n)\n"
  },
  {
    "path": "tests/unit/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/books/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/books/bill_tests.py",
    "content": "from decimal import Decimal as D\n\nfrom django.test import TestCase\n\nfrom django_dynamic_fixture import G\nimport mock\n\nfrom accounting.apps.books.models import Bill\n\n\nclass TestBillQuerySetMethods(TestCase):\n\n    def setUp(self):\n        pass\n\n    def test_returns_correct_turnovers(self):\n        invoice1 = G(Bill,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n\n        invoice2 = G(Bill,\n            number=102,\n            total_excl_tax=D('5.00'),\n            total_incl_tax=D('6.00'))\n\n        queryset = Bill.objects.all()\n        self.assertEqual(queryset.debts_excl_tax(), D('10.00') + D('5.00'))\n        self.assertEqual(queryset.debts_incl_tax(), D('12.00') + D('6.00'))\n"
  },
  {
    "path": "tests/unit/books/invoice_tests.py",
    "content": "from decimal import Decimal as D\n\nfrom django.test import TestCase\n\nfrom django_dynamic_fixture import G\nimport mock\n\nfrom accounting.apps.books.models import Invoice\n\n\nclass TestInvoiceQuerySetMethods(TestCase):\n\n    def setUp(self):\n        pass\n\n    def test_returns_correct_turnovers(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('5.00'),\n            total_incl_tax=D('6.00'))\n\n        queryset = Invoice.objects.all()\n        self.assertEqual(queryset.turnover_excl_tax(), D('10.00') + D('5.00'))\n        self.assertEqual(queryset.turnover_incl_tax(), D('12.00') + D('6.00'))\n"
  },
  {
    "path": "tests/unit/clients/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/clients/organization_tests.py",
    "content": "from decimal import Decimal as D\n\nfrom django.test import TestCase\n\nfrom django_dynamic_fixture import G\n\nfrom accounting.apps.books.models import Organization, Invoice, Bill\n\n\nclass TestOrganizationCalcultation(TestCase):\n\n    def setUp(self):\n        self.organization = G(Organization)\n\n    def tearDown(self):\n        pass\n\n    def test_turnover_excl_tax_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.assertEqual(self.organization.turnover_excl_tax,\n            D('10.00') + D('30.00'))\n\n    def test_turnover_incl_tax_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.assertEqual(self.organization.turnover_incl_tax,\n            D('12.00') + D('40.00'))\n\n    def test_debts_excl_tax_is_valid(self):\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        bill2 = G(Bill,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        self.organization.bills.add(bill1)\n        self.organization.bills.add(bill2)\n        self.assertEqual(self.organization.debts_excl_tax,\n            D('10.00') + D('30.00'))\n\n    def test_debts_incl_tax_is_valid(self):\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        bill2 = G(Bill,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        self.organization.bills.add(bill1)\n        self.organization.bills.add(bill2)\n        self.assertEqual(self.organization.debts_incl_tax,\n            D('12.00') + D('40.00'))\n\n    def test_profits_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('15.00'),\n            total_incl_tax=D('18.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.organization.bills.add(bill1)\n        self.assertEqual(self.organization.profits,\n            D('10.00') + D('30.00') - D('15.00'))\n\n    def test_collected_tax_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('15.00'),\n            total_incl_tax=D('18.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.organization.bills.add(bill1)\n        self.assertEqual(self.organization.collected_tax,\n            D('2.00') + D('10.00'))\n\n    def test_deductible_tax_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('15.00'),\n            total_incl_tax=D('18.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.organization.bills.add(bill1)\n        self.assertEqual(self.organization.deductible_tax,\n            D('3.00'))\n\n    def test_tax_provisionning_is_valid(self):\n        invoice1 = G(Invoice,\n            number=101,\n            total_excl_tax=D('10.00'),\n            total_incl_tax=D('12.00'))\n        invoice2 = G(Invoice,\n            number=102,\n            total_excl_tax=D('30.00'),\n            total_incl_tax=D('40.00'))\n        bill1 = G(Bill,\n            number=101,\n            total_excl_tax=D('15.00'),\n            total_incl_tax=D('18.00'))\n        self.organization.invoices.add(invoice1)\n        self.organization.invoices.add(invoice2)\n        self.organization.bills.add(bill1)\n        self.assertEqual(self.organization.tax_provisionning,\n            D('2.00') + D('10.00') - D('3.00'))\n"
  },
  {
    "path": "tests/unit/clients/user_tests.py",
    "content": "import datetime\n\nfrom django.contrib.auth import get_user_model\nfrom django.test import TestCase\n\nfrom django_dynamic_fixture import G\n\nfrom accounting.apps.books.models import Organization\n\n\nclass TestUserBelongsToOrganization(TestCase):\n\n    def setUp(self):\n        User = get_user_model()\n        self.user = G(User)\n\n    def tearDown(self):\n        self.user.delete()\n\n    def test_no_organization_by_default(self):\n        self.assertEquals(self.user.organizations.all().count(), 0)\n\n    def test_belongs_to_an_organization(self):\n        orga = G(Organization)\n        orga.members.add(self.user)\n        self.assertEquals(self.user.organizations.all().count(), 1)\n"
  },
  {
    "path": "tests/unit/libs/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/libs/prices_tests.py",
    "content": "from decimal import Decimal as D\nfrom itertools import product\nfrom django.test import TestCase\n\nfrom accounting.libs.prices import Price\n\n\nclass TestPriceObject(TestCase):\n\n    def test_can_be_instantiated_with_tax_amount(self):\n        price = Price('USD', D('10.00'), tax=D('2.00'))\n        self.assertTrue(price.is_tax_known)\n        self.assertEqual(D('12.00'), price.incl_tax)\n\n    def test_can_have_tax_set_later(self):\n        price = Price('USD', D('10.00'))\n        price.tax = D('2.00')\n        self.assertEqual(D('12.00'), price.incl_tax)\n\n    def test_price_equals_reflexivity(self):\n        for price in (\n            Price(currency='USD', excl_tax=D('10.00')),\n            Price(currency='USD', excl_tax=D('10.00'), tax=D('2.00')),\n            Price(currency='USD', excl_tax=D('10.00'), incl_tax=D('12.00')),\n            ):\n            self.assertEqual(price, price)\n\n    def test_price_equals_formats(self):\n        price1 = Price(currency='USD', excl_tax=D('10.00'), tax=D('2.00'))\n        price2 = Price(currency='USD', excl_tax=D('10.00'), incl_tax=D('12.00'))\n        self.assertEqual(price1, price2)\n\n    def test_price_equals_currency_matters(self):\n        price1 = Price(currency='EUR', excl_tax=D('10.00'), tax=D('2.00'))\n        price2 = Price(currency='USD', excl_tax=D('10.00'), tax=D('2.00'))\n        self.assertNotEqual(price1, price2)\n\n    def test_price_equals_transitivity(self):\n        prices = (\n            Price(currency='EUR', excl_tax=D('10.00'), tax=D('2.00')),\n            Price(currency='USD', excl_tax=D('10.00'), tax=D('2.00')),\n            Price(currency='USD', excl_tax=D('10.00'), incl_tax=D('12.00')),\n            Price(currency='USD', excl_tax=D('10.00'), tax=D('8.00'))\n        )\n        prices_product = product(prices, prices)\n        for price1, price2 in prices_product:\n            self.assertEqual(price1 == price2, price2 == price1)\n"
  }
]