diff --git a/front_end/src/Apps/Payroll.jsx b/front_end/src/Apps/Payroll.jsx index e6b75bca..10a6ccb0 100644 --- a/front_end/src/Apps/Payroll.jsx +++ b/front_end/src/Apps/Payroll.jsx @@ -13,11 +13,25 @@ export default function Payroll() { }, []); // Handlers - function handleLogPayroll() { - dispatch({ type: "logged" }); + async function handleSavePayroll() { + try { + api.postPayrollData(payroll); + } catch (error) { + console.error("Error saving payroll: ", error); + } + } + + function handleTogglePayPeriods(employeeNo, index, enabled) { + dispatch({ type: "updatePayPeriods", employeeNo, index, enabled }); } - return ; + return ( + + ); } function payrollReducer(payroll, action) { @@ -25,9 +39,24 @@ function payrollReducer(payroll, action) { case "fetched": { return action.data; } - case "logged": { - console.log(payroll); - return payroll; + case "updatePayPeriods": { + return payroll.map((employeeRow) => { + if (employeeRow.employee_no == action.employeeNo) { + const updatedPayPeriods = employeeRow.pay_periods.map( + (period, index) => { + if (index + 1 >= action.index + 1) { + return !action.enabled; + } + return period; + } + ); + return { + ...employeeRow, + pay_periods: updatedPayPeriods, + }; + } + return employeeRow; + }); } } } diff --git a/front_end/src/Components/EditPayroll/EmployeeRow/index.jsx b/front_end/src/Components/EditPayroll/EmployeeRow/index.jsx index dfb2dcdf..0463ea4d 100644 --- a/front_end/src/Components/EditPayroll/EmployeeRow/index.jsx +++ b/front_end/src/Components/EditPayroll/EmployeeRow/index.jsx @@ -1,38 +1,19 @@ import { useState } from "react"; -const EmployeeRow = ({ row }) => { - const [periods, setPeriods] = useState( - Object.keys(row) - .filter((key) => key.includes("period")) - .map((key) => ({ key: key, value: row[key] })) - ); - - const handleCheckboxChange = (index) => { - const updatedPeriods = [...periods]; - updatedPeriods[index].value = !updatedPeriods[index].value; // Toggle the checkbox value - - // If checkbox is now unchecked, uncheck all following checkboxes - if (!updatedPeriods[index].value) { - for (let i = index + 1; i < 12; i++) { - updatedPeriods[i].value = false; - } - } - - setPeriods(updatedPeriods); - }; - +const EmployeeRow = ({ row, onTogglePayPeriods }) => { return ( - + {row.name} {row.employee_no} - - {periods.map((period, index) => { + {row.pay_periods.map((enabled, index) => { return ( - + handleCheckboxChange(index)} + checked={enabled} + onChange={() => + onTogglePayPeriods(row.employee_no, index, enabled) + } /> ); diff --git a/front_end/src/Components/EditPayroll/PayrollTable/index.jsx b/front_end/src/Components/EditPayroll/PayrollTable/index.jsx index 8c9a431c..71308937 100644 --- a/front_end/src/Components/EditPayroll/PayrollTable/index.jsx +++ b/front_end/src/Components/EditPayroll/PayrollTable/index.jsx @@ -1,6 +1,12 @@ import EmployeeRow from "../EmployeeRow"; -export default function PayrollTable({ headers, payrollData }) { +/** + * + * @param {object} props + * @param {types.PayrollData[]} props.payroll + * @returns + */ +export default function PayrollTable({ headers, payroll, onTogglePayPeriods }) { return ( <> @@ -16,8 +22,14 @@ export default function PayrollTable({ headers, payrollData }) { - {payrollData.map((row) => { - return ; + {payroll.map((row) => { + return ( + + ); })}
diff --git a/front_end/src/Components/EditPayroll/api.js b/front_end/src/Components/EditPayroll/api.js index 78381753..1839378c 100644 --- a/front_end/src/Components/EditPayroll/api.js +++ b/front_end/src/Components/EditPayroll/api.js @@ -14,10 +14,10 @@ export function getPayrollData() { * Post modified payroll data. * * @param {types.PayrollData[]} payrollData - Payroll data to be sent. - * @returns {import("../../Util").PostDataResponse} - Updated payroll data receieved. + * @returns {import("../../Util").PostDataResponse} - Updated payroll data received. */ export function postPayrollData(payrollData) { - return postData(getPayrollApiUrl(), payrollData); + return postData(getPayrollApiUrl(), JSON.stringify(payrollData)); } function getPayrollApiUrl() { diff --git a/front_end/src/Components/EditPayroll/index.jsx b/front_end/src/Components/EditPayroll/index.jsx index 53ed3276..43238c75 100644 --- a/front_end/src/Components/EditPayroll/index.jsx +++ b/front_end/src/Components/EditPayroll/index.jsx @@ -7,7 +7,11 @@ import PayrollTable from "./PayrollTable/index"; * @param {types.PayrollData[]} props.payroll * @returns */ -export default function EditPayroll({ payroll, onLogPayroll }) { +export default function EditPayroll({ + payroll, + onSavePayroll, + onTogglePayPeriods, +}) { const headers = [ "Name", "Employee No", @@ -27,8 +31,14 @@ export default function EditPayroll({ payroll, onLogPayroll }) { return ( <>

Edit payroll

- {/* */} - + + ); } diff --git a/front_end/src/Components/EditPayroll/types.js b/front_end/src/Components/EditPayroll/types.js index 46b95fa7..13c2fada 100644 --- a/front_end/src/Components/EditPayroll/types.js +++ b/front_end/src/Components/EditPayroll/types.js @@ -2,7 +2,7 @@ * @typedef {Object} PayrollData * @property {string} name - The employee's name. * @property {string} employee_no - The employee's number. - * @property {boolean[]} pay_periods - Whether the employee is paid in a period. + * @property {boolean[]} pay_periods - Whether the employee is being paid in periods. */ export const Types = {}; diff --git a/payroll/services/payroll.py b/payroll/services/payroll.py index 642e3566..5f96def1 100644 --- a/payroll/services/payroll.py +++ b/payroll/services/payroll.py @@ -1,8 +1,8 @@ from decimal import Decimal from typing import Iterator, TypedDict -from django.db.models import F, Q, Sum from django.db import transaction +from django.db.models import F, Q, Sum from core.models import FinancialYear from costcentre.models import CostCentre @@ -28,8 +28,9 @@ def create_employee_pay_periods(employee: Employee) -> None: EmployeePayPeriods.objects.get_or_create(employee=employee, year=financial_year) -def payroll_forecast_report(cost_centre: CostCentre) -> None: - current_financial_year = FinancialYear.objects.current() +def payroll_forecast_report( + cost_centre: CostCentre, financial_year: FinancialYear +) -> None: period_sum_annotations = { f"period_{i+1}_sum": Sum( @@ -43,7 +44,7 @@ def payroll_forecast_report(cost_centre: CostCentre) -> None: qs = ( Employee.objects.filter( cost_centre=cost_centre, - pay_periods__year=current_financial_year, + pay_periods__year=financial_year, ) .values("pay_element__type__group", "pay_element__type__group__name") .annotate(**period_sum_annotations) diff --git a/payroll/templates/payroll/page/edit_payroll.html b/payroll/templates/payroll/page/edit_payroll.html index e5746ffe..0f9b8def 100644 --- a/payroll/templates/payroll/page/edit_payroll.html +++ b/payroll/templates/payroll/page/edit_payroll.html @@ -10,6 +10,39 @@ {% block content %}
+ +

Forecast

+ + + + + + + {% for month in months %} + + {% endfor %} + + + + {% for row in payroll_forecast_report %} + + + + + + + + + + + + + + + + {% endfor %} + +
Pay type{{ month }}
{{ row.pay_element__type__group__name }}{{ row.period_1_sum }}{{ row.period_2_sum }}{{ row.period_3_sum }}{{ row.period_4_sum }}{{ row.period_5_sum }}{{ row.period_6_sum }}{{ row.period_7_sum }}{{ row.period_8_sum }}{{ row.period_9_sum }}{{ row.period_10_sum }}{{ row.period_11_sum }}{{ row.period_12_sum }}
{% endblock content %} {% block scripts %} diff --git a/payroll/views.py b/payroll/views.py index 04f09922..f8c50a64 100644 --- a/payroll/views.py +++ b/payroll/views.py @@ -53,10 +53,28 @@ def edit_payroll_page( cost_centre_obj = get_object_or_404(CostCentre, pk=cost_centre_code) financial_year_obj = get_object_or_404(FinancialYear, pk=financial_year) + payroll_forecast_report_data = payroll_service.payroll_forecast_report( + cost_centre_obj, financial_year_obj + ) context = { "cost_centre_code": cost_centre_obj.cost_centre_code, "financial_year": financial_year_obj.financial_year, + "payroll_forecast_report": payroll_forecast_report_data, + "months": [ + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + "Jan", + "Feb", + "Mar", + ], } return TemplateResponse(request, "payroll/page/edit_payroll.html", context)