Skip to content

Commit

Permalink
Merge branch 'release/v1.0.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
RamezIssac committed Aug 30, 2023
2 parents 7b315de + ee46c86 commit 4f2b949
Show file tree
Hide file tree
Showing 37 changed files with 1,454 additions and 227 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to this project will be documented in this file.

## [1.0.2] - 2023-08-31
- Add a demo project for exploration and also containing all documentation code for proofing.
- Revise and Enhancing Tutorial , Group by and Time series documentation.
- Fix issue with error on dev console on report page due to resources duplication
- Fix issue with Custom querysets not being correctly connected in the view
- Fix issue with time series custom dates
- Fix issue with Crosstab on traversing fields


## [1.0.1] - 2023-07-03

Expand All @@ -11,7 +19,7 @@ All notable changes to this project will be documented in this file.
## [1.0.0] - 2023-07-03

- Added crosstab_ids_custom_filters to allow custom filters on crosstab ids
- Added ``group_by_querysets`` to allow custom querysets as group
- Added ``group_by_custom_querysets`` to allow custom querysets as group
- Added ability to have crosstab report in a time series report
- Enhanced Docs content and structure.

Expand Down
66 changes: 42 additions & 24 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,30 @@ You can simply use a code like this
class TotalProductSales(ReportView):
report_model = MySalesItems
date_field = "date_placed"
report_model = SalesTransaction
date_field = "date"
group_by = "product"
columns = [
"title",
SlickReportField.create(Sum, "quantity"),
SlickReportField.create(Sum, "value", name="sum__value"),
"name",
SlickReportField.create(Sum, "quantity", verbose_name="Total quantity sold", is_summable=False),
SlickReportField.create(Sum, "value", name="sum__value", verbose_name="Total Value sold $"),
]
chart_settings = [
Chart(
"Total sold $",
Chart.BAR,
data_source="value__sum",
title_source="title",
data_source=["sum__value"],
title_source=["name"],
),
Chart(
"Total sold $ [PIE]",
Chart.PIE,
data_source=["sum__value"],
title_source=["name"],
),
]
To get something this

.. image:: https://i.ibb.co/SvxTM23/Selection-294.png
Expand Down Expand Up @@ -190,16 +194,38 @@ You can interact with the `ReportGenerator` using same syntax as used with the `
my_report.get_report_data() # -> [{'title':'Product 1', '__total__: 56}, {'title':'Product 2', '__total__: 43}, ]
This is just a scratch, for more please visit the documentation
This is just a scratch of what you can do and customize.

Demo site
---------

Available on `Django Slick Reporting <https://django-slick-reporting.com/>`_


You can also use locally

.. code-block:: console
# clone the repo
# create a virtual environment, activate it, then
cd django-slick-reporting/demo_proj
pip install requirements.txt
python manage.py migrate
python manage.py create_entries
python manage.py runserver
the ``create_entries`` command will generate data for the demo app


Batteries Included
------------------

Slick Reporting comes with

* A Bootstrap Filter Form
* Charting support `Chart.js <https://www.chartjs.org/>`_
* Powerful tables `datatables.net <https://datatables.net/>`_
* An auto-generated, bootstrap-ready Filter Form
* Carts.js Charting support `Chart.js <https://www.chartjs.org/>`_
* Highcharts.js Charting support `Highcharts.js <https://www.highcharts.com//>`_
* Datatables `datatables.net <https://datatables.net/>`_

A Preview:

Expand All @@ -208,11 +234,6 @@ A Preview:
:alt: Shipped in View Page


Demo site
---------

Available on `Django Slick Reporting <https://django-slick-reporting.com/>`_

Documentation
-------------

Expand All @@ -221,11 +242,8 @@ Available on `Read The Docs <https://django-slick-reporting.readthedocs.io/en/la
Road Ahead
----------

This project is young and can use your support.

Some of the ideas / features that ought be added

* Support Other backends like SQL Alchemy & Pandas
* Continue on enriching the demo project
* Add the dashboard capabilities


Running tests
Expand Down Expand Up @@ -264,6 +282,6 @@ If you like this package, chances are you may like those packages too!

`Django Tabular Permissions <https://github.com/RamezIssac/django-tabular-permissions>`_ Display Django permissions in a HTML table that is translatable and easy customized.

`Django Ra ERP Framework <https://github.com/ra-systems/RA>`_ A framework to build business solutions with ease.
`Django ERP Framework <https://github.com/ra-systems/RA>`_ A framework to build business solutions with ease.

If you find this project useful or promising , You can support us by a github ⭐
Empty file added demo_proj/demo_app/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions demo_proj/demo_app/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions demo_proj/demo_app/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class DemoAppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "demo_app"
45 changes: 45 additions & 0 deletions demo_proj/demo_app/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from django import forms
from django.db.models import Q
from slick_reporting.forms import BaseReportForm


class TotalSalesFilterForm(BaseReportForm, forms.Form):
PRODUCT_SIZE_CHOICES = (
("all", "All"),
("big-only", "Big Only"),
("small-only", "Small Only"),
("medium-only", "Medium Only"),
("all-except-extra-big", "All except extra Big"),
)
start_date = forms.DateField(
required=False,
label="Start Date",
widget=forms.DateInput(attrs={"type": "date"}),
)
end_date = forms.DateField(
required=False, label="End Date", widget=forms.DateInput(attrs={"type": "date"})
)
product_size = forms.ChoiceField(
choices=PRODUCT_SIZE_CHOICES, required=False, label="Product Size", initial="all"
)

def get_filters(self):
# return the filters to be used in the report
# Note: the use of Q filters and kwargs filters
kw_filters = {}
q_filters = []
if self.cleaned_data["product_size"] == "big-only":
kw_filters["product__size__in"] = ["extra_big", "big"]
elif self.cleaned_data["product_size"] == "small-only":
kw_filters["product__size__in"] = ["extra_small", "small"]
elif self.cleaned_data["product_size"] == "medium-only":
kw_filters["product__size__in"] = ["medium"]
elif self.cleaned_data["product_size"] == "all-except-extra-big":
q_filters.append(~Q(product__size__in=["extra_big", "big"]))
return q_filters, kw_filters

def get_start_date(self):
return self.cleaned_data["start_date"]

def get_end_date(self):
return self.cleaned_data["end_date"]
90 changes: 90 additions & 0 deletions demo_proj/demo_app/management/commands/create_entries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import datetime
import random
from datetime import timedelta

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand

# from expense.models import Expense, ExpenseTransaction
from ...models import Client, Product, SalesTransaction, ProductCategory

User = get_user_model()


def date_range(start_date, end_date):
for i in range((end_date - start_date).days + 1):
yield start_date + timedelta(i)


class Command(BaseCommand):
help = "Create Sample entries for the demo app"

def handle(self, *args, **options):
# create clients
models_list = [
Client,
Product,
]
client_countries = [
"US",
"DE",
"EG",
"IN",
"KW",
"RA"
]
product_category = [
"extra_big",
"big",
"medium",
"small",
"extra-small"
]
SalesTransaction.objects.all().delete()
Client.objects.all().delete()
Product.objects.all().delete()
ProductCategory.objects.all().delete()
User.objects.filter(is_superuser=False).delete()
for i in range(10):
User.objects.create_user(username=f"user {i}", password="password")

users_id = list(User.objects.values_list("id", flat=True))
for i in range(1, 4):
ProductCategory.objects.create(name=f"Product Category {i}")

product_category_ids = list(ProductCategory.objects.values_list("id", flat=True))
for i in range(1, 10):
Client.objects.create(name=f"Client {i}",
country=random.choice(client_countries),
# owner_id=random.choice(users_id)
)
clients_ids = list(Client.objects.values_list("pk", flat=True))
# create products
for i in range(1, 10):
Product.objects.create(name=f"Product {i}",
product_category_id=random.choice(product_category_ids),
size=random.choice(product_category))
products_ids = list(Product.objects.values_list("pk", flat=True))

current_year = datetime.datetime.today().year
start_date = datetime.datetime(current_year, 1, 1)
end_date = datetime.datetime(current_year + 1, 1, 1)

for date in date_range(start_date, end_date):
for i in range(1, 10):
SalesTransaction.objects.create(
client_id=random.choice(clients_ids),
product_id=random.choice(products_ids),
quantity=random.randint(1, 10),
price=random.randint(1, 100),
date=date,
number=f"Sale {date.strftime('%Y-%m-%d')} #{i}",
)
# ExpenseTransaction.objects.create(
# expense_id=random.choice(expense_ids),
# value=random.randint(1, 100),
# date=date,
# number=f"Expense {date.strftime('%Y-%m-%d')} #{i}",
# )

self.stdout.write(self.style.SUCCESS("Entries Created Successfully"))
94 changes: 94 additions & 0 deletions demo_proj/demo_app/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Generated by Django 4.2 on 2023-08-02 09:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="Client",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100, verbose_name="Client Name")),
],
options={
"verbose_name": "Client",
"verbose_name_plural": "Clients",
},
),
migrations.CreateModel(
name="Product",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100, verbose_name="Product Name")),
],
options={
"verbose_name": "Product",
"verbose_name_plural": "Products",
},
),
migrations.CreateModel(
name="SalesTransaction",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"number",
models.CharField(
max_length=100, verbose_name="Sales Transaction #"
),
),
("date", models.DateTimeField()),
("notes", models.TextField(blank=True, null=True)),
("value", models.DecimalField(decimal_places=2, max_digits=9)),
(
"client",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="demo_app.client",
verbose_name="Client",
),
),
(
"product",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="demo_app.product",
verbose_name="Product",
),
),
],
options={
"verbose_name": "Sales Transaction",
"verbose_name_plural": "Sales Transactions",
},
),
]

0 comments on commit 4f2b949

Please sign in to comment.