Skip to content

Commit 91e1919

Browse files
committed
Merge branch 'feature/demo_app' into develop
2 parents 65be9f9 + adad5c9 commit 91e1919

34 files changed

+1376
-203
lines changed

README.rst

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,30 @@ You can simply use a code like this
6161
6262
6363
class TotalProductSales(ReportView):
64-
65-
report_model = MySalesItems
66-
date_field = "date_placed"
64+
report_model = SalesTransaction
65+
date_field = "date"
6766
group_by = "product"
6867
columns = [
69-
"title",
70-
SlickReportField.create(Sum, "quantity"),
71-
SlickReportField.create(Sum, "value", name="sum__value"),
68+
"name",
69+
SlickReportField.create(Sum, "quantity", verbose_name="Total quantity sold", is_summable=False),
70+
SlickReportField.create(Sum, "value", name="sum__value", verbose_name="Total Value sold $"),
7271
]
7372
7473
chart_settings = [
7574
Chart(
7675
"Total sold $",
7776
Chart.BAR,
78-
data_source="value__sum",
79-
title_source="title",
77+
data_source=["sum__value"],
78+
title_source=["name"],
79+
),
80+
Chart(
81+
"Total sold $ [PIE]",
82+
Chart.PIE,
83+
data_source=["sum__value"],
84+
title_source=["name"],
8085
),
8186
]
8287
83-
8488
To get something this
8589

8690
.. image:: https://i.ibb.co/SvxTM23/Selection-294.png

demo_proj/demo_app/__init__.py

Whitespace-only changes.

demo_proj/demo_app/admin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.

demo_proj/demo_app/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class DemoAppConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "demo_app"

demo_proj/demo_app/forms.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from django import forms
2+
from django.db.models import Q
3+
from slick_reporting.forms import BaseReportForm
4+
5+
6+
class TotalSalesFilterForm(BaseReportForm, forms.Form):
7+
PRODUCT_SIZE_CHOICES = (
8+
("all", "All"),
9+
("big-only", "Big Only"),
10+
("small-only", "Small Only"),
11+
("medium-only", "Medium Only"),
12+
("all-except-extra-big", "All except extra Big"),
13+
)
14+
start_date = forms.DateField(
15+
required=False,
16+
label="Start Date",
17+
widget=forms.DateInput(attrs={"type": "date"}),
18+
)
19+
end_date = forms.DateField(
20+
required=False, label="End Date", widget=forms.DateInput(attrs={"type": "date"})
21+
)
22+
product_size = forms.ChoiceField(
23+
choices=PRODUCT_SIZE_CHOICES, required=False, label="Product Size", initial="all"
24+
)
25+
26+
def get_filters(self):
27+
# return the filters to be used in the report
28+
# Note: the use of Q filters and kwargs filters
29+
kw_filters = {}
30+
q_filters = []
31+
if self.cleaned_data["product_size"] == "big-only":
32+
kw_filters["product__size__in"] = ["extra_big", "big"]
33+
elif self.cleaned_data["product_size"] == "small-only":
34+
kw_filters["product__size__in"] = ["extra_small", "small"]
35+
elif self.cleaned_data["product_size"] == "medium-only":
36+
kw_filters["product__size__in"] = ["medium"]
37+
elif self.cleaned_data["product_size"] == "all-except-extra-big":
38+
q_filters.append(~Q(product__size__in=["extra_big", "big"]))
39+
return q_filters, kw_filters
40+
41+
def get_start_date(self):
42+
return self.cleaned_data["start_date"]
43+
44+
def get_end_date(self):
45+
return self.cleaned_data["end_date"]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import datetime
2+
import random
3+
from datetime import timedelta
4+
5+
from django.contrib.auth import get_user_model
6+
from django.core.management.base import BaseCommand
7+
8+
# from expense.models import Expense, ExpenseTransaction
9+
from ...models import Client, Product, SalesTransaction, ProductCategory
10+
11+
User = get_user_model()
12+
13+
14+
def date_range(start_date, end_date):
15+
for i in range((end_date - start_date).days + 1):
16+
yield start_date + timedelta(i)
17+
18+
19+
class Command(BaseCommand):
20+
help = "Create Sample entries for the demo app"
21+
22+
def handle(self, *args, **options):
23+
# create clients
24+
models_list = [
25+
Client,
26+
Product,
27+
]
28+
client_countries = [
29+
"US",
30+
"DE",
31+
"EG",
32+
"IN",
33+
"KW",
34+
"RA"
35+
]
36+
product_category = [
37+
"extra_big",
38+
"big",
39+
"medium",
40+
"small",
41+
"extra-small"
42+
]
43+
SalesTransaction.objects.all().delete()
44+
Client.objects.all().delete()
45+
Product.objects.all().delete()
46+
ProductCategory.objects.all().delete()
47+
User.objects.filter(is_superuser=False).delete()
48+
for i in range(10):
49+
User.objects.create_user(username=f"user {i}", password="password")
50+
51+
users_id = list(User.objects.values_list("id", flat=True))
52+
for i in range(1, 4):
53+
ProductCategory.objects.create(name=f"Product Category {i}")
54+
55+
product_category_ids = list(ProductCategory.objects.values_list("id", flat=True))
56+
for i in range(1, 10):
57+
Client.objects.create(name=f"Client {i}",
58+
country=random.choice(client_countries),
59+
# owner_id=random.choice(users_id)
60+
)
61+
clients_ids = list(Client.objects.values_list("pk", flat=True))
62+
# create products
63+
for i in range(1, 10):
64+
Product.objects.create(name=f"Product {i}",
65+
product_category_id=random.choice(product_category_ids),
66+
size=random.choice(product_category))
67+
products_ids = list(Product.objects.values_list("pk", flat=True))
68+
69+
current_year = datetime.datetime.today().year
70+
start_date = datetime.datetime(current_year, 1, 1)
71+
end_date = datetime.datetime(current_year + 1, 1, 1)
72+
73+
for date in date_range(start_date, end_date):
74+
for i in range(1, 10):
75+
SalesTransaction.objects.create(
76+
client_id=random.choice(clients_ids),
77+
product_id=random.choice(products_ids),
78+
quantity=random.randint(1, 10),
79+
price=random.randint(1, 100),
80+
date=date,
81+
number=f"Sale {date.strftime('%Y-%m-%d')} #{i}",
82+
)
83+
# ExpenseTransaction.objects.create(
84+
# expense_id=random.choice(expense_ids),
85+
# value=random.randint(1, 100),
86+
# date=date,
87+
# number=f"Expense {date.strftime('%Y-%m-%d')} #{i}",
88+
# )
89+
90+
self.stdout.write(self.style.SUCCESS("Entries Created Successfully"))
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Generated by Django 4.2 on 2023-08-02 09:14
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
initial = True
9+
10+
dependencies = []
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name="Client",
15+
fields=[
16+
(
17+
"id",
18+
models.BigAutoField(
19+
auto_created=True,
20+
primary_key=True,
21+
serialize=False,
22+
verbose_name="ID",
23+
),
24+
),
25+
("name", models.CharField(max_length=100, verbose_name="Client Name")),
26+
],
27+
options={
28+
"verbose_name": "Client",
29+
"verbose_name_plural": "Clients",
30+
},
31+
),
32+
migrations.CreateModel(
33+
name="Product",
34+
fields=[
35+
(
36+
"id",
37+
models.BigAutoField(
38+
auto_created=True,
39+
primary_key=True,
40+
serialize=False,
41+
verbose_name="ID",
42+
),
43+
),
44+
("name", models.CharField(max_length=100, verbose_name="Product Name")),
45+
],
46+
options={
47+
"verbose_name": "Product",
48+
"verbose_name_plural": "Products",
49+
},
50+
),
51+
migrations.CreateModel(
52+
name="SalesTransaction",
53+
fields=[
54+
(
55+
"id",
56+
models.BigAutoField(
57+
auto_created=True,
58+
primary_key=True,
59+
serialize=False,
60+
verbose_name="ID",
61+
),
62+
),
63+
(
64+
"number",
65+
models.CharField(
66+
max_length=100, verbose_name="Sales Transaction #"
67+
),
68+
),
69+
("date", models.DateTimeField()),
70+
("notes", models.TextField(blank=True, null=True)),
71+
("value", models.DecimalField(decimal_places=2, max_digits=9)),
72+
(
73+
"client",
74+
models.ForeignKey(
75+
on_delete=django.db.models.deletion.PROTECT,
76+
to="demo_app.client",
77+
verbose_name="Client",
78+
),
79+
),
80+
(
81+
"product",
82+
models.ForeignKey(
83+
on_delete=django.db.models.deletion.PROTECT,
84+
to="demo_app.product",
85+
verbose_name="Product",
86+
),
87+
),
88+
],
89+
options={
90+
"verbose_name": "Sales Transaction",
91+
"verbose_name_plural": "Sales Transactions",
92+
},
93+
),
94+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 4.2 on 2023-08-02 09:14
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("demo_app", "0001_initial"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="salestransaction",
14+
name="price",
15+
field=models.DecimalField(decimal_places=2, default=0, max_digits=9),
16+
preserve_default=False,
17+
),
18+
migrations.AddField(
19+
model_name="salestransaction",
20+
name="quantity",
21+
field=models.DecimalField(decimal_places=2, default=0, max_digits=9),
22+
preserve_default=False,
23+
),
24+
]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 4.2 on 2023-08-30 08:06
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("demo_app", "0002_salestransaction_price_salestransaction_quantity"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="product",
14+
name="category",
15+
field=models.CharField(
16+
default="Medium", max_length=100, verbose_name="Product Category"
17+
),
18+
),
19+
]

demo_proj/demo_app/migrations/__init__.py

Whitespace-only changes.

demo_proj/demo_app/models.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import uuid
2+
3+
from django.db import models
4+
from django.utils.translation import gettext_lazy as _
5+
6+
7+
# Create your models here.
8+
class Client(models.Model):
9+
name = models.CharField(max_length=100, verbose_name="Client Name")
10+
country = models.CharField(_("Country"), max_length=255, default="US")
11+
12+
class Meta:
13+
verbose_name = _("Client")
14+
verbose_name_plural = _("Clients")
15+
16+
def __str__(self):
17+
return self.name
18+
19+
20+
class ProductCategory(models.Model):
21+
name = models.CharField(max_length=100, verbose_name="Product Category Name")
22+
23+
def __str__(self):
24+
return self.name
25+
26+
27+
class Product(models.Model):
28+
name = models.CharField(max_length=100, verbose_name="Product Name")
29+
# category = models.CharField(max_length=100, verbose_name="Product Category", default="Medium")
30+
product_category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE, null=True)
31+
32+
sku = models.CharField(_("SKU"), max_length=255, default=uuid.uuid4)
33+
size = models.CharField(max_length=100, verbose_name="Size", default="Medium")
34+
35+
class Meta:
36+
verbose_name = _("Product")
37+
verbose_name_plural = _("Products")
38+
39+
def __str__(self):
40+
return self.name
41+
42+
43+
class SalesTransaction(models.Model):
44+
number = models.CharField(max_length=100, verbose_name="Sales Transaction #")
45+
date = models.DateTimeField()
46+
notes = models.TextField(blank=True, null=True)
47+
client = models.ForeignKey(
48+
Client, on_delete=models.PROTECT, verbose_name=_("Client")
49+
)
50+
product = models.ForeignKey(
51+
Product, on_delete=models.PROTECT, verbose_name=_("Product")
52+
)
53+
value = models.DecimalField(max_digits=9, decimal_places=2)
54+
quantity = models.DecimalField(max_digits=9, decimal_places=2)
55+
price = models.DecimalField(max_digits=9, decimal_places=2)
56+
57+
class Meta:
58+
verbose_name = _("Sales Transaction")
59+
verbose_name_plural = _("Sales Transactions")
60+
61+
def __str__(self):
62+
return f"{self.number} - {self.date}"
63+
64+
def save(
65+
self, force_insert=False, force_update=False, using=None, update_fields=None
66+
):
67+
self.value = self.price * self.quantity
68+
super().save(force_insert, force_update, using, update_fields)

0 commit comments

Comments
 (0)