One approach I can think of is, you can customize the amount of donation of some/all employees and distribute the rest to others equally. For example:
I want to donate $10,000 to 10 employees. Originally, each of
them would receive $1000. But I want Employee-A and Employee-B to
receive
$1200 and $1300 respectively. Now I am left with $8500 and 8 employees. So, each 8 of them will receive $1062.5.
Implementation: (AJAX + DRF)
You have to add some input fields in your front-end. This is to customize which employee should receive how much donation. You should keep track of the employeeId as you will need it later while sending the payload to your server.
Create a JSON list (from your form) like this and pass it to the API call.
let payload = [
{"employee_id": 1, "amount": 1300.0},
{"employee_id": 2, "amount": 1200.0},
]
You can use any method to send the data. For example: in AJAX you would something like that:
$.ajax({
type: "POST",
url: "/your/api/endpoint/",
data: {
// Send `donation_amount` too.
// This will help to validate data in backend.
donation_amount: 10000.0,
customized_amounts: payload
},
traditional: true,
beforeSend: function () {
// show some loading animation.
},
success: function (data) {
// show a success toast or redirect.
},
error: function (error) {
// show some error toast.
},
});
In the backend create a serializer:
from rest_framework import serializers
from django.utils.text import gettext_lazy as _
# TODO: from .models import Business
class DonationSerializer(serializers.Serializer):
business = serializers.PrimaryKeyRelatedField(label=_('Business'), queryset=Business.objects.all(), required=True)
donation_amount = serializers.FloatField(label=_('Donation Amount'), required=True, min_value=0.0)
customized_amounts = serializers.JSONField(label=_('Customized Amounts'), default=list, required=False)
def validate(self, attrs):
donation_amount = attrs.get('donation_amount', 0.0)
customized_amounts = attrs.get('customized_amounts', [])
if donation_amount == 0.0:
raise serializers.ValidationError(_('Donation cannot be empty!'))
partial_sum = 0.0
for data in customized_amounts:
# Checking if employee_id is valid or not
employee_id = data.get('employee_id')
if not Employment.objects.filte(id=employee_id).exitst():
raise serializers.ValidationError(_(f'Employee with id: ${employee_id} does not exists!'))
# summing up amount to check if it exceeds total amount
partial_sum += data.get('amount')
if partial_sum > donation_amount:
raise serializers.ValidationError(_('Individual donation amount exceeds total amount!'))
# add any other validation you want.
return attrs
def update(self, instance, validated_data):
pass
def create(self, validated_data):
pass
and an API endpoint:
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
# TODO: from .models import Employment
# TODO: from .tasks import run_employee_donation
class DonationCreateAPIView(GenericAPIView):
def post(self, request, *args, **kwargs):
serializer = DonationSerializer(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
business = serializer.validated_data.get('business')
donation_amount = serializer.validated_data.get('donation_amount')
customized_amounts = serializer.validated_data.get('customized_amounts')
employee_qs = Employment.objects.filter(business=business, active=True)
total_employees = employee_qs.count()
donation_per_employee = donation_amount / (total_employees - len(customized_amounts))
for employee in employee_qs:
customized_amount = [data for data in customized_amounts if data['employee_id'] == employee.id]
if len(customized_amount) > 0:
# Customized donation for this employee found.
run_employee_donation(employee_id=employee.id, amount=customized_amount[0].get('amount'))
else:
run_employee_donation(employee_id=employee.id, amount=donation_per_employee)
return Response({'success': True}, status=status.HTTP_201_CREATED)