========================
 Adding a Custom Report
========================

We'll start with a simple report which shows all departments and the number of
products for each.

Each type of report has a "key" which uniquely identifies it.  For this example
we'll use ``poser_dept_prod_counts`` for the key.  Note that it's a good idea
to always use an app-specific prefix (e.g. ``poser_``) in the key.

Typically you will create a new Python module which is named according to the
key.  Here we'll create ``~/src/poser/poser/reports/dept_prod_counts.py``, and
in it we'll define the report::

   from sqlalchemy import orm

   from rattail.reporting import ExcelReport


   class DepartmentProductCounts(ExcelReport):
       """
       Shows all departments and the number of products for each.
       """
       type_key = 'poser_dept_prod_counts'
       name = "Department Product Counts"
       output_fields = [
           'department_number',
           'department_name',
           'product_count',
       ]

       def make_data(self, session, params, progress=None, **kwargs):
           model = self.model

           # fetch all departments, with product lists pre-loaded
           departments = session.query(model.Department)\
                                .order_by(model.Department.number)\
                                .options(orm.joinedload(model.Department.products))\
                                .all()
           rows = []

           def add_row(department, i):
               rows.append({
                   'department_number': department.number,
                   'department_name': department.name,
                   'product_count': len(department.products),
               })

           self.progress_loop(add_row, departments, progress,
                              message="Fetching data for report")
           return rows

Then you must register your new report type, to make it available to the app.
This is done within your project's ``setup.py`` file, for instance::

   setup(
       name = "Poser",

       # ...

       entry_points = {

           'rattail.reports': [
               'poser_dept_prod_counts = poser.reports.dept_prod_counts:DepartmentProductCounts',
           ],
       },
   )

Once you've added that you must re-install the app to your virtual environment,
for instance:

.. code-block:: sh

   cd /srv/envs/poser
   source bin/activate
   pip install -e ~/src/poser

At this point the report should be available for running within the app.  See
:doc:`generate` for more info.