Skip to content

Commit e9f4769

Browse files
Merge pull request #110 from theflyingmachine/dev-report-ajax-optimizations
Switch to Report API and Query Optimizations
2 parents bcd53cc + c5bf645 commit e9f4769

File tree

10 files changed

+216
-450
lines changed

10 files changed

+216
-450
lines changed

register/api_views.py

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import calendar
2+
import json
23
import logging
34
from calendar import monthrange
45
from collections import defaultdict
@@ -11,6 +12,7 @@
1112
from django.db.models.functions import Coalesce
1213
from django.http import JsonResponse
1314
from django.urls import reverse
15+
from django.utils.safestring import mark_safe
1416

1517
from register.models import Customer, Payment, Tenant
1618
from register.models import Expense
@@ -21,7 +23,7 @@
2123
IncomeSerializer, PaidCustomerSerializer, CustomerProfileSerializer, TenantSerializer
2224
from register.utils import get_tenant_perf, is_last_day_of_month, get_milk_current_price, \
2325
is_transaction_revertible, customer_register_last_updated, get_active_month, \
24-
get_customer_balance_amount, get_bill_summary
26+
get_customer_balance_amount, get_bill_summary, get_customer_due_amount_by_month
2527

2628
logger = logging.getLogger()
2729

@@ -298,3 +300,155 @@ def get_profile_api(request, customer_id):
298300
'month_year': date.today().strftime("%B, %Y"),
299301
'print_bill_url': reverse('print_bill', args=[customer.id]),
300302
})
303+
304+
@login_required()
305+
def get_report_data_api(request, poll_id):
306+
"""
307+
This function returns JSON data for the Report page.
308+
"""
309+
chart_data = []
310+
d1 = date.today()
311+
percent = 0
312+
milk_delivered = ['morning-yes', 'evening-yes']
313+
twelve_month_ago = d1.replace(day=1).replace(year=d1.year - 1)
314+
# Fetch all Expenses and Incomes
315+
tenant = Q(tenant_id=request.user.id)
316+
expense_data = Expense.objects.filter(tenant).values('log_date__month',
317+
'log_date__year').annotate(
318+
expense=Sum('cost')).values('log_date__month', 'log_date__year', 'expense')
319+
320+
income_data = Income.objects.filter(tenant).values('log_date__month',
321+
'log_date__year').annotate(
322+
income=Sum('amount')).values('log_date__month', 'log_date__year', 'income')
323+
324+
# Fetch all Registers
325+
register_query = Q(tenant, schedule__in=milk_delivered, log_date__gte=twelve_month_ago)
326+
all_register_entry = Register.objects.filter(register_query)
327+
328+
for i in range(-12, 1):
329+
percent += 3.75
330+
graph_month = d1 + relativedelta(months=i)
331+
month_str = graph_month.strftime("%B-%Y")
332+
month_abbr = graph_month.strftime("%b-%y")
333+
request.session[poll_id] = f'Income and Expense ({graph_month.strftime("%B-%Y")})'
334+
request.session[f'{poll_id}_percent'] = percent
335+
request.session.save()
336+
337+
# Retrieve Expense for the current month
338+
month_expense = next((item['expense'] for item in expense_data if
339+
item['log_date__month'] == graph_month.month and item[
340+
'log_date__year'] == graph_month.year), 0)
341+
342+
# Retrieve Income for the current month
343+
month_extra_income = next((item['income'] for item in income_data if
344+
item['log_date__month'] == graph_month.month and item[
345+
'log_date__year'] == graph_month.year), 0)
346+
347+
month_register_sale = sum(
348+
[entry.quantity * entry.current_price for entry in all_register_entry if
349+
entry.log_date.month == graph_month.month and entry.log_date.year == graph_month.year]) / 1000
350+
351+
month_register_sale += month_extra_income
352+
353+
month_paid = sum(
354+
[entry.quantity * entry.current_price for entry in all_register_entry if
355+
entry.log_date.month == graph_month.month and entry.log_date.year == graph_month.year and entry.paid]) / 1000
356+
357+
month_paid += month_extra_income
358+
month_due = month_register_sale - month_paid
359+
360+
profit = float(
361+
max(month_paid - month_expense, 0)) if month_paid > month_expense else False
362+
loss = float(
363+
max(month_expense - month_paid, 0)) if month_paid <= month_expense else False
364+
365+
current_month = {
366+
"monthName": month_str,
367+
"month": month_abbr,
368+
"income": float(month_register_sale),
369+
"paid": float(month_paid),
370+
"due": float(month_due),
371+
"expense": float(month_expense),
372+
"profit": profit,
373+
"loss": loss,
374+
}
375+
chart_data.append(current_month)
376+
377+
# Get milk production over past 365 days
378+
chart_data_milk = []
379+
all_milk_production = defaultdict(
380+
int) # Using defaultdict to automatically initialize values to 0
381+
for entry in all_register_entry:
382+
all_milk_production[(entry.schedule, entry.log_date.date())] += entry.quantity
383+
384+
for i in range(-365, 1):
385+
percent += 0.123
386+
d1 = date.today()
387+
graph_day = d1 + relativedelta(days=i)
388+
request.session[poll_id] = f'Milk Production ({graph_day.strftime("%d-%B-%Y")})'
389+
request.session[f'{poll_id}_percent'] = percent
390+
request.session.save()
391+
milk_production_morning = all_milk_production[('morning-yes', graph_day)]
392+
milk_production_evening = all_milk_production[('evening-yes', graph_day)]
393+
394+
current_day = {
395+
"dayName": graph_day.strftime('%d-%B-%Y'),
396+
'milkMorning': round(float(milk_production_morning / 1000), 2),
397+
'milkEvening': round(float(milk_production_evening / 1000), 2),
398+
"milkQuantity": round(float(milk_production_morning / 1000), 2) + round(
399+
float(milk_production_evening / 1000), 2),
400+
}
401+
chart_data_milk.append(current_day)
402+
403+
percent += 5
404+
request.session[f'{poll_id}_percent'] = percent
405+
request.session.save()
406+
# Calculate all time Expenses
407+
all_time_expense = \
408+
Expense.objects.filter(tenant_id=request.user.id).aggregate(Sum('cost'))[
409+
'cost__sum'] or 0
410+
411+
# Calculate all time Income
412+
all_time_milk_income = \
413+
Payment.objects.filter(tenant_id=request.user.id).aggregate(Sum('amount'))[
414+
'amount__sum'] or 0
415+
all_time_extra_income = \
416+
Income.objects.filter(tenant_id=request.user.id).aggregate(Sum('amount'))[
417+
'amount__sum'] or 0
418+
all_time_income = all_time_milk_income + all_time_extra_income
419+
420+
# Calculate all time profit or loss
421+
is_profit = True if all_time_expense < all_time_income else False
422+
all_time_profit_or_loss = abs(all_time_income - all_time_expense)
423+
percent += 5
424+
request.session[f'{poll_id}_percent'] = percent
425+
request.session.save()
426+
due_list, due_month = get_customer_due_amount_by_month(request)
427+
context = {
428+
'graph_data': mark_safe(json.dumps(chart_data)),
429+
'table_data': chart_data,
430+
'chart_data_milk': mark_safe(json.dumps(chart_data_milk)),
431+
'all_time_expense': all_time_expense,
432+
'all_time_income': all_time_income,
433+
'is_profit': is_profit,
434+
'all_time_profit_or_loss': all_time_profit_or_loss,
435+
'due_customers': mark_safe(json.dumps(due_list)),
436+
'due_month': mark_safe(json.dumps(due_month)),
437+
}
438+
request.session[poll_id] = 'Done'
439+
request.session.save()
440+
return JsonResponse(context)
441+
442+
@login_required()
443+
def get_report_data_status_api(request, poll_id):
444+
retry = 30
445+
status = None
446+
while retry:
447+
status = {'status': request.session.get(poll_id, None),
448+
'percent': request.session.get(f'{poll_id}_percent')
449+
}
450+
if status:
451+
return JsonResponse(status)
452+
else:
453+
retry -= 1
454+
return JsonResponse(status)

register/templates/register/broadcast.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,25 +128,25 @@ <h3 className="text-center mt-2 mt-lg-5">Broadcast Bills</h3>
128128

129129
let loading_component = <div className="text-center m-xl-5 p-xl-5">
130130

131-
<div className="spinner-grow text-primary spinner-size-big" role="status">
131+
<div className="spinner-grow text-primary" role="status">
132132
<span className="sr-only">Loading...</span>
133133
</div>
134-
<div className="spinner-grow text-secondary spinner-size-big" role="status">
134+
<div className="spinner-grow text-secondary" role="status">
135135
<span className="sr-only">Loading...</span>
136136
</div>
137-
<div className="spinner-grow text-success spinner-size-big" role="status">
137+
<div className="spinner-grow text-success" role="status">
138138
<span className="sr-only">Loading...</span>
139139
</div>
140-
<div className="spinner-grow text-danger spinner-size-big" role="status">
140+
<div className="spinner-grow text-danger" role="status">
141141
<span className="sr-only">Loading...</span>
142142
</div>
143-
<div className="spinner-grow text-warning spinner-size-big" role="status">
143+
<div className="spinner-grow text-warning" role="status">
144144
<span className="sr-only">Loading...</span>
145145
</div>
146-
<div className="spinner-grow text-info spinner-size-big" role="status">
146+
<div className="spinner-grow text-info" role="status">
147147
<span className="sr-only">Loading...</span>
148148
</div>
149-
<div className="spinner-grow text-dark spinner-size-big" role="status">
149+
<div className="spinner-grow text-dark" role="status">
150150
<span className="sr-only">Loading...</span>
151151
</div>
152152
</div>;

register/templates/register/react_account.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -445,25 +445,25 @@ <h5 className="modal-title" id="exampleModalLabel">Accept Payment
445445

446446
render() {
447447
const loadingComp = <div className="text-center m-xl-5 p-xl-5">
448-
<div className="spinner-grow text-primary spinner-size-big" role="status">
448+
<div className="spinner-grow text-primary" role="status">
449449
<span className="sr-only">Loading...</span>
450450
</div>
451-
<div className="spinner-grow text-secondary spinner-size-big" role="status">
451+
<div className="spinner-grow text-secondary" role="status">
452452
<span className="sr-only">Loading...</span>
453453
</div>
454-
<div className="spinner-grow text-success spinner-size-big" role="status">
454+
<div className="spinner-grow text-success" role="status">
455455
<span className="sr-only">Loading...</span>
456456
</div>
457-
<div className="spinner-grow text-danger spinner-size-big" role="status">
457+
<div className="spinner-grow text-danger" role="status">
458458
<span className="sr-only">Loading...</span>
459459
</div>
460-
<div className="spinner-grow text-warning spinner-size-big" role="status">
460+
<div className="spinner-grow text-warning" role="status">
461461
<span className="sr-only">Loading...</span>
462462
</div>
463-
<div className="spinner-grow text-info spinner-size-big" role="status">
463+
<div className="spinner-grow text-info" role="status">
464464
<span className="sr-only">Loading...</span>
465465
</div>
466-
<div className="spinner-grow text-dark spinner-size-big" role="status">
466+
<div className="spinner-grow text-dark" role="status">
467467
<span className="sr-only">Loading...</span>
468468
</div>
469469
</div>

register/templates/register/react_profile.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,25 +1032,25 @@ <h5 className="pt-2 mt-2 text-center">Register Entry</h5>
10321032
render() {
10331033

10341034
const loadingComp = <div className="text-center m-xl-5 p-xl-5">
1035-
<div className="spinner-grow text-primary spinner-size-big" role="status">
1035+
<div className="spinner-grow text-primary" role="status">
10361036
<span className="sr-only">Loading...</span>
10371037
</div>
1038-
<div className="spinner-grow text-secondary spinner-size-big" role="status">
1038+
<div className="spinner-grow text-secondary" role="status">
10391039
<span className="sr-only">Loading...</span>
10401040
</div>
1041-
<div className="spinner-grow text-success spinner-size-big" role="status">
1041+
<div className="spinner-grow text-success" role="status">
10421042
<span className="sr-only">Loading...</span>
10431043
</div>
1044-
<div className="spinner-grow text-danger spinner-size-big" role="status">
1044+
<div className="spinner-grow text-danger" role="status">
10451045
<span className="sr-only">Loading...</span>
10461046
</div>
1047-
<div className="spinner-grow text-warning spinner-size-big" role="status">
1047+
<div className="spinner-grow text-warning" role="status">
10481048
<span className="sr-only">Loading...</span>
10491049
</div>
1050-
<div className="spinner-grow text-info spinner-size-big" role="status">
1050+
<div className="spinner-grow text-info" role="status">
10511051
<span className="sr-only">Loading...</span>
10521052
</div>
1053-
<div className="spinner-grow text-dark spinner-size-big" role="status">
1053+
<div className="spinner-grow text-dark" role="status">
10541054
<span className="sr-only">Loading...</span>
10551055
</div>
10561056
</div>

register/templates/register/react_register.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -320,25 +320,25 @@
320320
}
321321

322322
const loadingComp = <div className="text-center m-xl-5 p-xl-5">
323-
<div className="spinner-grow text-primary spinner-size-big" role="status">
323+
<div className="spinner-grow text-primary" role="status">
324324
<span className="sr-only">Loading...</span>
325325
</div>
326-
<div className="spinner-grow text-secondary spinner-size-big" role="status">
326+
<div className="spinner-grow text-secondary" role="status">
327327
<span className="sr-only">Loading...</span>
328328
</div>
329-
<div className="spinner-grow text-success spinner-size-big" role="status">
329+
<div className="spinner-grow text-success" role="status">
330330
<span className="sr-only">Loading...</span>
331331
</div>
332-
<div className="spinner-grow text-danger spinner-size-big" role="status">
332+
<div className="spinner-grow text-danger" role="status">
333333
<span className="sr-only">Loading...</span>
334334
</div>
335-
<div className="spinner-grow text-warning spinner-size-big" role="status">
335+
<div className="spinner-grow text-warning" role="status">
336336
<span className="sr-only">Loading...</span>
337337
</div>
338-
<div className="spinner-grow text-info spinner-size-big" role="status">
338+
<div className="spinner-grow text-info" role="status">
339339
<span className="sr-only">Loading...</span>
340340
</div>
341-
<div className="spinner-grow text-dark spinner-size-big" role="status">
341+
<div className="spinner-grow text-dark" role="status">
342342
<span className="sr-only">Loading...</span>
343343
</div>
344344
</div>

register/templates/register/report_react_new.html renamed to register/templates/register/react_report.html

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@
8282
let uuid = Math.random().toString(36).substr(2);
8383
this.fetchStatus(hostname, uuid);
8484
const url =
85-
"{{protocol}}://" + hostname + "/milkbasket/report-data/" + uuid;
85+
"{{protocol}}://" + hostname + "/milkbasket/api/v1/report-data/" + uuid;
8686
const responce = await fetch(url);
8787
const data = await responce.json();
8888
this.setState({reportData: data, isLoading: false});
8989
}
9090

9191
async fetchStatus(hostname, token) {
9292
const url =
93-
"{{protocol}}://" + hostname + "/milkbasket/report-data-status/" + token;
93+
"{{protocol}}://" + hostname + "/milkbasket/api/v1/report-data-status/" + token;
9494
const responce = await fetch(url);
9595
const data = await responce.json();
9696
if (data.status !== null) {
@@ -119,27 +119,26 @@
119119
let graph_data = null;
120120
let due_customers = null;
121121
let due_month = null;
122-
let loading_component = <div className="text-center m-xl-5 p-xl-5">
123-
124-
<div className="spinner-grow text-primary spinner-size-big" role="status">
122+
let loading_component = <div className="text-center mt-5 m-xl-5 p-xl-5">
123+
<div className="spinner-grow text-primary" role="status">
125124
<span className="sr-only">Loading...</span>
126125
</div>
127-
<div className="spinner-grow text-secondary spinner-size-big" role="status">
126+
<div className="spinner-grow text-secondary" role="status">
128127
<span className="sr-only">Loading...</span>
129128
</div>
130-
<div className="spinner-grow text-success spinner-size-big" role="status">
129+
<div className="spinner-grow text-success" role="status">
131130
<span className="sr-only">Loading...</span>
132131
</div>
133-
<div className="spinner-grow text-danger spinner-size-big" role="status">
132+
<div className="spinner-grow text-danger" role="status">
134133
<span className="sr-only">Loading...</span>
135134
</div>
136-
<div className="spinner-grow text-warning spinner-size-big" role="status">
135+
<div className="spinner-grow text-warning" role="status">
137136
<span className="sr-only">Loading...</span>
138137
</div>
139-
<div className="spinner-grow text-info spinner-size-big" role="status">
138+
<div className="spinner-grow text-info" role="status">
140139
<span className="sr-only">Loading...</span>
141140
</div>
142-
<div className="spinner-grow text-dark spinner-size-big" role="status">
141+
<div className="spinner-grow text-dark" role="status">
143142
<span className="sr-only">Loading...</span>
144143
</div>
145144
<div>

0 commit comments

Comments
 (0)