Skip to content

Commit

Permalink
Merge pull request #99 from theflyingmachine/dev-optimise-accounts-page
Browse files Browse the repository at this point in the history
Dev React Accounts Page
  • Loading branch information
theflyingmachine authored May 1, 2023
2 parents c2e1cc2 + ece231a commit a203561
Show file tree
Hide file tree
Showing 9 changed files with 908 additions and 194 deletions.
169 changes: 169 additions & 0 deletions register/api_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import calendar
import logging
from datetime import date
from datetime import datetime

from dateutil.relativedelta import relativedelta
from django.contrib.auth.decorators import login_required
from django.db.models import Sum, Q, Prefetch, F, FloatField, Func
from django.db.models.functions import Coalesce
from django.http import JsonResponse

from register.models import Customer
from register.models import Expense
from register.models import Income
from register.models import Register
from register.serializer import CustomerSerializer, DueCustomerSerializer, ExpenseSerializer, \
IncomeSerializer, PaidCustomerSerializer
from register.utils import get_tenant_perf, is_last_day_of_month

logger = logging.getLogger()

from django.shortcuts import redirect


class BaseRegister:
"""
Custom initializer that checks a condition and redirects if it's false
"""

def __init__(self, *args, **kwargs):
# Get Tenant Preference
self.tenant = get_tenant_perf(self.request)
if self.tenant is None:
return redirect('setting')
custom_month = None
print('init')
self.year = kwargs.pop('year',
None) # Get the year parameter and store as instance variable
self.month = kwargs.pop('month',
None) # Get the month parameter and store as instance variable

if self.year and self.month:
date_time_str = f'01/{self.month}/{self.year} 01:01:01'
custom_month = datetime.strptime(date_time_str, '%d/%m/%Y %H:%M:%S')
self.register_date = custom_month if custom_month else date.today()


class RegisterAPI(BaseRegister):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

@login_required()
def get_register_api(request, year, month):
"""
This function returns JSON data for the register entry in a month.
"""

# Get Tenant Preference
tenant = get_tenant_perf(request)
custom_month = None
if year and month:
date_time_str = f'01/{month}/{year} 01:01:01'
custom_month = datetime.strptime(date_time_str, '%d/%m/%Y %H:%M:%S')
register_date = custom_month if custom_month else date.today()

register_filter = {
'tenant_id': request.user.id,
'log_date__month': register_date.month,
'log_date__year': register_date.year
}
m_schedule = Q(schedule__in=['morning-yes', 'morning-no'])
e_schedule = Q(schedule__in=['evening-yes', 'evening-no'])

cust_register_filter = {
'tenant_id': request.user.id,
'register__log_date__month': register_date.month,
'register__log_date__year': register_date.year
}
cust_m_schedule = Q(register__schedule__in=['morning-yes', 'morning-no'])
cust_e_schedule = Q(register__schedule__in=['evening-yes', 'evening-no'])

# Get morning register for given month
m_cust = Customer.objects.prefetch_related(
Prefetch('register_set',
queryset=Register.objects.filter(
m_schedule, **register_filter).order_by('log_date'))
).filter(cust_m_schedule, **cust_register_filter).distinct()

e_cust = Customer.objects.prefetch_related(
Prefetch('register_set',
queryset=Register.objects.filter(
e_schedule, **register_filter).order_by('log_date'))
).filter(cust_e_schedule, **cust_register_filter).distinct()

# plot calendar days
import datetime as dt
# Get the number of days in the month
days_in_month = calendar.monthrange(register_date.year, register_date.month)[1]
# Create a list of date objects in the month
date_list = [dt.date(register_date.year, register_date.month, day) for day in
range(1, days_in_month + 1)]

return JsonResponse({'status': 'success',
'default_price': tenant.milk_price,
'dates': date_list,
'm_register': CustomerSerializer(instance=m_cust, many=True).data,
'e_register': CustomerSerializer(instance=e_cust, many=True).data,
})

@login_required()
def get_account_api(request, year, month):
"""
This function returns JSON data for the accounts.
"""
custom_month = None
current_date = date.today()
if year and month:
date_time_str = f'01/{month}/{year} 01:01:01'
custom_month = datetime.strptime(date_time_str, '%d/%m/%Y %H:%M:%S')
register_date = custom_month if custom_month else date.today()
month_year = register_date.strftime("%B, %Y")

# Get extra income and expenses
income = Income.objects.filter(tenant_id=request.user.id,
log_date__year=register_date.year,
log_date__month=register_date.month).order_by('log_date')
expenses = Expense.objects.filter(tenant_id=request.user.id,
log_date__year=register_date.year,
log_date__month=register_date.month).order_by('log_date')

# Get Paid Customers
paid_customers = Customer.objects.filter(
payment__tenant=request.user.id,
payment__log_date__month=register_date.month,
payment__log_date__year=register_date.year
).annotate(
paid_amount=Sum('payment__amount'),
balance_amount=F('balance__balance_amount')
).order_by('name')

# Get Due Customers
first_day_of_month = current_date.replace(day=1)
due_customers = Customer.objects.filter(
register__tenant=request.user.id,
register__paid=0,
register__schedule__endswith='yes',
).annotate(
due_amount=Sum(F('register__current_price') * F('register__quantity'),
output_field=FloatField()),
due_prev_amount=Coalesce(
Sum(F('register__current_price') * F('register__quantity'),
filter=Q(register__log_date__lt=first_day_of_month),
output_field=FloatField()), 0),
balance_amount=Coalesce(F('balance__balance_amount'), 0),
).order_by('name')
due_customers = due_customers.annotate(
abs_balance_amount=Func(F('balance_amount'), function='ABS')
).exclude(abs_balance_amount__gt=F('due_amount') / 1000)

return JsonResponse({
'month_year': month_year,
'previous_month_name': (current_date + relativedelta(months=-1)).strftime("%B"),
'is_last_day_of_month': is_last_day_of_month(),
'due_customers': DueCustomerSerializer(instance=due_customers, many=True).data,
'paid_customers': PaidCustomerSerializer(instance=paid_customers, many=True).data,
'income': IncomeSerializer(instance=income, many=True).data,
'expenses': ExpenseSerializer(instance=expenses, many=True).data,
})
58 changes: 57 additions & 1 deletion register/serializer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import decimal

from rest_framework import serializers

from .models import Customer, Register
from .models import Customer, Register, Expense, Income


class RegisterSerializer(serializers.ModelSerializer):
Expand All @@ -16,3 +18,57 @@ class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['id', 'name', 'm_quantity', 'e_quantity', 'status', 'register_entry']


class ExpenseSerializer(serializers.ModelSerializer):
amount = serializers.CharField(source='cost')

class Meta:
model = Expense
fields = ['id', 'description', 'amount', 'log_date', 'tenant']


class IncomeSerializer(serializers.ModelSerializer):
class Meta:
model = Income
fields = '__all__'


class PaidCustomerSerializer(serializers.ModelSerializer):
paid_amount = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)
balance_amount = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)

class Meta:
model = Customer
fields = ('id', 'name', 'paid_amount', 'balance_amount')


class DueCustomerSerializer(serializers.ModelSerializer):
due_amount = serializers.SerializerMethodField()
due_prev_amount = serializers.SerializerMethodField()
final_due_amount = serializers.SerializerMethodField()
final_due_prev_amount = serializers.SerializerMethodField()
balance_amount = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)

@staticmethod
def get_due_amount(obj):
return decimal.Decimal(obj.due_amount) / 1000

@staticmethod
def get_due_prev_amount(obj):
return decimal.Decimal(obj.due_prev_amount) / 1000

@staticmethod
def get_final_due_amount(obj):
return decimal.Decimal(obj.due_amount / 1000) - abs(obj.balance_amount or 0)

@staticmethod
def get_final_due_prev_amount(obj):
return decimal.Decimal(obj.due_prev_amount / 1000) - abs(obj.balance_amount or 0)

class Meta:
model = Customer
fields = (
'id', 'name', 'contact', 'due_amount', 'balance_amount', 'due_prev_amount',
'final_due_amount',
'final_due_prev_amount')
4 changes: 2 additions & 2 deletions register/templates/register/customer.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

<div class="row mt-2 justify-content-center">
<div class="col-lg-10 col-md-12">
<h2 class="text-center">View Customers</h2>
<h5 class="p-0 m-0 text-center">View Customers</h5>
</div>
</div>

Expand Down Expand Up @@ -126,7 +126,7 @@ <h2 class="text-center">View Customers</h2>
{# INACTIVE CUSTOMERS #}
{% if inactive_customers %}
<hr>
<h3 class="pt-5 mt-4 text-center">Inactive Customers</h3>
<h5 class="p-0 m-0 text-center">Inactive Customers</h5>
{% for customer in inactive_customers %}
{% if forloop.first %}
<div class="row">{% endif %}
Expand Down
10 changes: 6 additions & 4 deletions register/templates/register/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,12 @@ <h5 class="p-2 text-nowrap text-right font-weight-bold">
<tr class="d-flex">
<td class="p-2 col-2">#{{ entry.id }}</td>
<td class="p-2 col-6">{{ entry.log_date }}
{% if entry.payment_mode == 'ONLINE' %}
<a target="_blank"
href="{% url 'check_txn_status' entry.transaction_id %}">{{ entry.payment_mode }}</a>{% else %}
<span class="text-info">{{ entry.payment_mode }}{% endif %}</span></td>
{# {% if entry.payment_mode == 'ONLINE' %}#}
{# <a target="_blank"#}
{# href="{% url 'check_txn_status' entry.transaction_id %}">{{ entry.payment_mode }}</a>{% else %}#}
<span class="text-info">{{ entry.payment_mode }}
{# {% endif %}#}
</span></td>
<td class="p-2 col-4">{{ entry.amount }}
{% if entry.refund_notes %}
<span class="text-info">{{ entry.refund_notes }}</span>
Expand Down
Loading

0 comments on commit a203561

Please sign in to comment.