From f61808d0dec97b90046eff56f669e359e9dc20e9 Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Thu, 11 Jun 2020 16:34:26 +0200
Subject: [PATCH 1/6] Fix is_summable for Crosstab Send computation_field to
 frontend

---
 slick_reporting/generator.py |  9 +++------
 slick_reporting/views.py     |  1 +
 tests/test_generator.py      | 10 ++++++++++
 3 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/slick_reporting/generator.py b/slick_reporting/generator.py
index c746fc8..690b61c 100644
--- a/slick_reporting/generator.py
+++ b/slick_reporting/generator.py
@@ -382,7 +382,7 @@ def _parse(self):
                 magic_field_class = None
 
             if attr:
-                #todo Add testing here
+                # todo Add testing here
                 col_data = {'name': col,
                             'verbose_name': getattr(attr, 'verbose_name', col),
                             # 'type': 'method',
@@ -547,20 +547,17 @@ def get_crosstab_parsed_columns(self):
         ids_length = len(ids) - 1
         for counter, id in enumerate(ids):
             for col in report_columns:
-                # try:
                 magic_field_class = field_registry.get_field_by_name(col)
-                # except:
-                #     magic_field_class = None
-
                 output_cols.append({
                     'name': f'{col}CT{id}',
+                    'original_name': col,
                     'verbose_name': self.get_crosstab_field_verbose_name(magic_field_class, self.crosstab_model, id),
                     'ref': magic_field_class,
                     'id': id,
                     'model': self.crosstab_model,
                     'is_reminder': counter == ids_length,
                     'source': 'magic_field' if magic_field_class else '',
-                    'summable': magic_field_class.is_summable,
+                    'is_summable': magic_field_class.is_summable,
                 })
 
         return output_cols
diff --git a/slick_reporting/views.py b/slick_reporting/views.py
index 37fce22..4158709 100644
--- a/slick_reporting/views.py
+++ b/slick_reporting/views.py
@@ -146,6 +146,7 @@ def get_columns_data(self, columns):
         for col in columns:
             data.append({
                 'name': col['name'],
+                'computation_field': col.get('original_name', ''),
                 'verbose_name': col['verbose_name'],
                 'visible': col.get('visible', True),
                 'type': col.get('type', 'text'),
diff --git a/tests/test_generator.py b/tests/test_generator.py
index b44ec11..5e11069 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -34,6 +34,16 @@ def test_get_crosstab_columns(self):
         columns = report.get_list_display_columns()
         self.assertEqual(len(columns), 8, [x['name'] for x in columns])
 
+    def test_get_crosstab_parsed_columns(self):
+        """
+        Test important attributes are passed .
+        :return:
+        """
+        report = CrosstabOnClient(crosstab_ids=[self.client1.pk], crosstab_compute_reminder=False)
+        columns = report.get_crosstab_parsed_columns()
+        for col in columns:
+            self.assertTrue(col.get('is_summable', False))
+
 
 class GeneratorReportStructureTest(TestCase):
     def test_time_series_columns_inclusion(self):

From 29c12b4ccf4939039fe11ecec9f669f5071427fa Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Thu, 11 Jun 2020 18:17:10 +0200
Subject: [PATCH 2/6] Fix is_summable test

---
 tests/test_generator.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test_generator.py b/tests/test_generator.py
index 5e11069..6d53537 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -42,7 +42,7 @@ def test_get_crosstab_parsed_columns(self):
         report = CrosstabOnClient(crosstab_ids=[self.client1.pk], crosstab_compute_reminder=False)
         columns = report.get_crosstab_parsed_columns()
         for col in columns:
-            self.assertTrue(col.get('is_summable', False))
+            self.assertTrue('is_summable' in col.keys(), col)
 
 
 class GeneratorReportStructureTest(TestCase):

From ded0b5e1c3f02e31036e020650008194d145ae38 Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Sat, 13 Jun 2020 11:48:13 +0200
Subject: [PATCH 3/6] Simplify the default datetime ReportForm date are
 datetime instead of split datetime

---
 slick_reporting/app_settings.py               |  4 +-
 slick_reporting/form_factory.py               | 37 ++++++++-----------
 slick_reporting/helpers.py                    |  5 +++
 .../slick_reporting/simple_report.html        |  6 +--
 .../templates/slick_reporting/table.html      |  2 +-
 5 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/slick_reporting/app_settings.py b/slick_reporting/app_settings.py
index a23adce..0ea4c08 100644
--- a/slick_reporting/app_settings.py
+++ b/slick_reporting/app_settings.py
@@ -7,12 +7,12 @@
 
 def get_first_of_this_year():
     d = datetime.datetime.today()
-    return datetime.datetime(d.year, 1, 1, 0, 0, 0, 0, pytz.timezone(settings.TIME_ZONE))
+    return datetime.datetime(d.year, 1, 1, 0, 0)
 
 
 def get_end_of_this_year():
     d = datetime.datetime.today()
-    return datetime.datetime(d.year + 1, 1, 1, 0, 0, 0, 0, pytz.timezone(settings.TIME_ZONE))
+    return datetime.datetime(d.year + 1, 1, 1, 0, 0)
 
 
 SLICK_REPORTING_DEFAULT_START_DATE = getattr(settings, '', lazy(get_first_of_this_year, datetime.datetime)())
diff --git a/slick_reporting/form_factory.py b/slick_reporting/form_factory.py
index b826be4..088cb81 100644
--- a/slick_reporting/form_factory.py
+++ b/slick_reporting/form_factory.py
@@ -58,8 +58,9 @@ def get_crispy_helper(self, foreign_keys_map=None, crosstab_model=None, **kwargs
         helper.form_class = 'form-horizontal'
         helper.label_class = 'col-sm-2 col-md-2 col-lg-2'
         helper.field_class = 'col-sm-10 col-md-10 col-lg-10'
-        helper.form_tag = False
+        helper.form_tag = True
         helper.disable_csrf = True
+        helper.render_unmentioned_fields = True
 
         foreign_keys_map = foreign_keys_map or self.foreign_keys
 
@@ -69,21 +70,12 @@ def get_crispy_helper(self, foreign_keys_map=None, crosstab_model=None, **kwargs
                     Field('start_date'), css_class='col-sm-6'),
                 Column(
                     Field('end_date'), css_class='col-sm-6'),
-
                 css_class='raReportDateRange'),
             Div(css_class="mt-20", style='margin-top:20px')
         )
 
-        # if crosstab_model:
-        #     entry_point.append(Row(
-        #         Div('matrix_entities', css_class='col-sm-9'),
-        #         Div('matrix_show_other', css_class='col-sm-3')
-        #         , css_class='matrixField')
-        #     )
-
         for k in foreign_keys_map:
-            if k[:-3] != crosstab_model:
-                helper.layout.fields[1].append(Field(k))
+            helper.layout.fields[1].append(Field(k))
 
         return helper
 
@@ -105,17 +97,17 @@ def report_form_factory(model, fkeys_filter_func=None, foreign_key_widget_func=N
     fkeys_list = []
     fields = OrderedDict()
 
-    fields['start_date'] = forms.SplitDateTimeField(required=False, label=_('From date'),
-                                                    initial=app_settings.SLICK_REPORTING_DEFAULT_START_DATE,
-                                                    # widget=RaBootstrapDateTime(),
-                                                    input_date_formats=['%Y-%m-%d', '%Y-%m-%d'],
-                                                    input_time_formats=['%H:%M', '%H:%M:%S'],
-                                                    )
+    fields['start_date'] = forms.DateTimeField(required=False, label=_('From date'),
+                                               initial=app_settings.SLICK_REPORTING_DEFAULT_START_DATE,
+                                               widget=forms.DateTimeInput(format='%m/%d/%Y %H:%M',
+                                                                          attrs={'autocomplete': "off"}),
+                                               )
 
-    fields['end_date'] = forms.SplitDateTimeField(required=False, label=_('To  date'),
-                                                  initial=app_settings.SLICK_REPORTING_DEFAULT_END_DATE,
-                                                  # widget=RaBootstrapDateTime(),
-                                                  )
+    fields['end_date'] = forms.DateTimeField(required=False, label=_('To  date'),
+                                             initial=app_settings.SLICK_REPORTING_DEFAULT_END_DATE,
+                                             widget=forms.DateTimeInput(format='%m/%d/%Y %H:%M',
+                                                                        attrs={'autocomplete': "off"})
+                                             )
 
     for name, f_field in fkeys_map.items():
         fkeys_list.append(name)
@@ -132,6 +124,7 @@ def report_form_factory(model, fkeys_filter_func=None, foreign_key_widget_func=N
                     {"base_fields": fields,
                      '_fkeys': fkeys_list,
                      'foreign_keys': fkeys_map,
-                     'crosstab_model': crosstab_model
+                     'crosstab_model': crosstab_model,
+                     'crosstab_display_compute_reminder': display_compute_reminder,
                      })
     return new_form
diff --git a/slick_reporting/helpers.py b/slick_reporting/helpers.py
index 5d33e59..45263fb 100644
--- a/slick_reporting/helpers.py
+++ b/slick_reporting/helpers.py
@@ -13,6 +13,11 @@ def get_calculation_annotation(calculation_field, calculation_method):
 
 
 def get_foreign_keys(model):
+    """
+    Scans a model and return an Ordered Dictionary with the foreign keys found
+    :param model: the model to scan
+    :return: Ordered Dict
+    """
     from django.db import models
     fields = model._meta.get_fields()
     fkeys = OrderedDict()
diff --git a/slick_reporting/templates/slick_reporting/simple_report.html b/slick_reporting/templates/slick_reporting/simple_report.html
index 76d5437..415ed4e 100644
--- a/slick_reporting/templates/slick_reporting/simple_report.html
+++ b/slick_reporting/templates/slick_reporting/simple_report.html
@@ -35,9 +35,9 @@ <h4 class="py-5">Results</h4>
                             height="100"></canvas>
                 {% endif %}
             </div>
-            <div class="report-table"></div>
-            {% include 'slick_reporting/table.html' with table=report_data %}
-
+            <div class="report-table">
+                {% include 'slick_reporting/table.html' with table=report_data %}
+            </div>
         </div>
     </div>
 
diff --git a/slick_reporting/templates/slick_reporting/table.html b/slick_reporting/templates/slick_reporting/table.html
index 34e0ef9..4c902ea 100644
--- a/slick_reporting/templates/slick_reporting/table.html
+++ b/slick_reporting/templates/slick_reporting/table.html
@@ -1,5 +1,5 @@
 {% load slick_reporting_tags %}
-<table class="table .reportTable ">
+<table class="table reportTable {{ table_class|default:'' }} ">
     <thead>
 <tr>
     {% for column in table.columns %}

From 7c473d718c0bd587aaa2fa73d33553da1e165467 Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Thu, 18 Jun 2020 09:03:07 +0200
Subject: [PATCH 4/6] Better Form organization for Crosstab models Add metadata
 for crosstab

---
 slick_reporting/form_factory.py | 9 ++++++++-
 slick_reporting/views.py        | 6 +++++-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/slick_reporting/form_factory.py b/slick_reporting/form_factory.py
index 088cb81..c804baa 100644
--- a/slick_reporting/form_factory.py
+++ b/slick_reporting/form_factory.py
@@ -74,8 +74,15 @@ def get_crispy_helper(self, foreign_keys_map=None, crosstab_model=None, **kwargs
             Div(css_class="mt-20", style='margin-top:20px')
         )
 
+        # first add the crosstab model and its display reimder then the rest of the fields
+        if self.crosstab_model:
+            helper.layout.fields[1].append(Field(self.crosstab_key_name))
+            if self.crosstab_display_compute_reminder:
+                helper.layout.fields[1].append(Field('crosstab_compute_reminder'))
+
         for k in foreign_keys_map:
-            helper.layout.fields[1].append(Field(k))
+            if k != self.crosstab_key_name:
+                helper.layout.fields[1].append(Field(k))
 
         return helper
 
diff --git a/slick_reporting/views.py b/slick_reporting/views.py
index 4158709..1c76fdc 100644
--- a/slick_reporting/views.py
+++ b/slick_reporting/views.py
@@ -179,10 +179,14 @@ def get_metadata(self, generator):
         :return:
         """
         time_series_columns = generator.get_time_series_parsed_columns()
+        crosstab_columns = generator.get_crosstab_parsed_columns()
         metadata = {
             'time_series_pattern': self.time_series_pattern,
             'time_series_column_names': [x['name'] for x in time_series_columns],
-            'time_series_column_verbose_names': [x['verbose_name'] for x in time_series_columns]
+            'time_series_column_verbose_names': [x['verbose_name'] for x in time_series_columns],
+            'crosstab_model': self.crosstab_model,
+            'crosstab_column_names': [x['name'] for x in crosstab_columns],
+            'crosstab_column_verbose_names': [x['verbose_name'] for x in crosstab_columns],
         }
         return metadata
 

From 0964a88f0a779a812df9240e55797c8c6e431a74 Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Fri, 24 Jul 2020 12:51:38 +0200
Subject: [PATCH 5/6] Rename quan to quantity

---
 slick_reporting/fields.py       |  2 +-
 slick_reporting/form_factory.py | 11 +++++++++++
 tests/report_generators.py      |  8 ++++----
 tests/test_generator.py         |  2 +-
 4 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/slick_reporting/fields.py b/slick_reporting/fields.py
index c1c03ce..6585d2d 100644
--- a/slick_reporting/fields.py
+++ b/slick_reporting/fields.py
@@ -379,7 +379,7 @@ class FirstBalanceQTYReportField(FirstBalanceField):
 
 
 class BalanceQTYReportField(BaseReportField):
-    name = '__balance_quan__'
+    name = '__balance_quantity__'
     verbose_name = _('Cumulative QTY')
     calculation_field = 'quantity'
     requires = ['__fb_quan__']
diff --git a/slick_reporting/form_factory.py b/slick_reporting/form_factory.py
index c804baa..e285721 100644
--- a/slick_reporting/form_factory.py
+++ b/slick_reporting/form_factory.py
@@ -94,6 +94,17 @@ def _default_foreign_key_widget(f_field):
 
 def report_form_factory(model, fkeys_filter_func=None, foreign_key_widget_func=None, crosstab_model=None,
                         display_compute_reminder=True, **kwargs):
+    """
+    Create a Reprot Form based on the report_model passed
+    
+    :param model: 
+    :param fkeys_filter_func: 
+    :param foreign_key_widget_func: 
+    :param crosstab_model: 
+    :param display_compute_reminder: 
+    :param kwargs: 
+    :return: 
+    """
     foreign_key_widget_func = foreign_key_widget_func or _default_foreign_key_widget
     fkeys_filter_func = fkeys_filter_func or (lambda x: x)
 
diff --git a/tests/report_generators.py b/tests/report_generators.py
index cdb1627..21b3ca3 100644
--- a/tests/report_generators.py
+++ b/tests/report_generators.py
@@ -57,7 +57,7 @@ class ProductTotalSales(ReportGenerator):
     report_model = SimpleSales
     date_field = 'doc_date'
     group_by = 'product'
-    columns = ['slug', 'name', '__balance__', '__balance_quan__']
+    columns = ['slug', 'name', '__balance__', '__balance_quantity__']
 
 
 class ClientList(ReportGenerator):
@@ -81,7 +81,7 @@ class ProductClientSales(ReportGenerator):
     header_report = ClientList
 
     group_by = 'product'
-    columns = ['slug', 'name', '__balance_quan__', '__balance__']
+    columns = ['slug', 'name', '__balance_quantity__', '__balance__']
 
 
 class ProductSalesMonthlySeries(ReportGenerator):
@@ -94,13 +94,13 @@ class ProductSalesMonthlySeries(ReportGenerator):
         'group_columns': ['slug', 'name'],
 
         'time_series_pattern': 'monthly',
-        'time_series_columns': ['__balance_quan__', '__balance__'],
+        'time_series_columns': ['__balance_quantity__', '__balance__'],
     }
 
     group_by = 'product'
     columns = ['slug', 'name']
     time_series_pattern = 'monthly',
-    time_series_columns = ['__balance_quan__', '__balance__']
+    time_series_columns = ['__balance_quantity__', '__balance__']
 
     chart_settings = [
         {
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 6d53537..ae0d8bd 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -30,7 +30,7 @@ def test_get_crosstab_columns(self):
         self.assertEqual(len(columns), 4)
 
         report = CrosstabOnClient(crosstab_ids=[self.client1.pk, self.client2.pk],
-                                  crosstab_columns=['__total_quantity__', '__balance_quan__'])
+                                  crosstab_columns=['__total_quantity__', '__balance_quantity__'])
         columns = report.get_list_display_columns()
         self.assertEqual(len(columns), 8, [x['name'] for x in columns])
 

From b542eacf7172f5ac5c5ed6abe87cc0b4a9275735 Mon Sep 17 00:00:00 2001
From: Ramez Issac <ramez@rasystems.io>
Date: Fri, 24 Jul 2020 13:10:35 +0200
Subject: [PATCH 6/6] version 0.2.7

---
 CHANGELOG.md                | 6 ++++++
 docs/source/conf.py         | 2 +-
 slick_reporting/__init__.py | 4 ++--
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89a4489..3081238 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,12 @@
 # Changelog
 All notable changes to this project will be documented in this file.
 
+## [0.2.7] - 2020-07-24
+### Updates
+- Bring back crosstab capability
+- Rename `quan` to the more verbose `quantity` 
+- Minor enhancements around templates 
+
 ## [0.2.6] - 2020-06-06
 ### Added
 
diff --git a/docs/source/conf.py b/docs/source/conf.py
index dab530c..14ab01c 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -24,7 +24,7 @@
 master_doc = 'index'
 
 # The full version, including alpha/beta/rc tags
-release = '0.1.3'
+release = '0.2.7'
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/slick_reporting/__init__.py b/slick_reporting/__init__.py
index 6988fd4..3e3df01 100644
--- a/slick_reporting/__init__.py
+++ b/slick_reporting/__init__.py
@@ -1,6 +1,6 @@
 
 default_app_config = 'slick_reporting.apps.ReportAppConfig'
 
-VERSION = (0, 2, 6)
+VERSION = (0, 2, 7)
 
-__version__ = '0.2.6'
+__version__ = '0.2.7'