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 %}
+
+
+ {{ 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 }} |
+
+ {% endfor %}
+
+
{% 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)