Skip to content

Commit

Permalink
FFT-86 Payroll table react components (#534)
Browse files Browse the repository at this point in the history
  • Loading branch information
CaitBarnard authored Oct 21, 2024
1 parent f7561ed commit 7a56f3e
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 46 deletions.
41 changes: 35 additions & 6 deletions front_end/src/Apps/Payroll.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,50 @@ 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 <EditPayroll payroll={payroll} onLogPayroll={handleLogPayroll} />;
return (
<EditPayroll
payroll={payroll}
onSavePayroll={handleSavePayroll}
onTogglePayPeriods={handleTogglePayPeriods}
/>
);
}

function payrollReducer(payroll, action) {
switch (action.type) {
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;
});
}
}
}
35 changes: 8 additions & 27 deletions front_end/src/Components/EditPayroll/EmployeeRow/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<tr className="govuk-table__row" key={row.employee_no}>
<tr className="govuk-table__row">
<td className="govuk-table__cell">{row.name}</td>
<td className="govuk-table__cell">{row.employee_no}</td>

{periods.map((period, index) => {
{row.pay_periods.map((enabled, index) => {
return (
<td className="govuk-table__cell" key={period.key}>
<td className="govuk-table__cell" key={index}>
<input
type="checkbox"
checked={period.value}
onChange={() => handleCheckboxChange(index)}
checked={enabled}
onChange={() =>
onTogglePayPeriods(row.employee_no, index, enabled)
}
/>
</td>
);
Expand Down
18 changes: 15 additions & 3 deletions front_end/src/Components/EditPayroll/PayrollTable/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<table className="govuk-table">
Expand All @@ -16,8 +22,14 @@ export default function PayrollTable({ headers, payrollData }) {
</tr>
</thead>
<tbody className="govuk-table__body">
{payrollData.map((row) => {
return <EmployeeRow row={row} />;
{payroll.map((row) => {
return (
<EmployeeRow
row={row}
key={row.employee_no}
onTogglePayPeriods={onTogglePayPeriods}
/>
);
})}
</tbody>
</table>
Expand Down
4 changes: 2 additions & 2 deletions front_end/src/Components/EditPayroll/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
16 changes: 13 additions & 3 deletions front_end/src/Components/EditPayroll/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -27,8 +31,14 @@ export default function EditPayroll({ payroll, onLogPayroll }) {
return (
<>
<h1>Edit payroll</h1>
{/* <button onClick={onLogPayroll}>Log payroll</button> */}
<PayrollTable headers={headers} payrollData={payroll}></PayrollTable>
<PayrollTable
headers={headers}
payroll={payroll}
onTogglePayPeriods={onTogglePayPeriods}
></PayrollTable>
<button className="govuk-button" onClick={onSavePayroll}>
Save payroll
</button>
</>
);
}
2 changes: 1 addition & 1 deletion front_end/src/Components/EditPayroll/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
9 changes: 5 additions & 4 deletions payroll/services/payroll.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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(
Expand All @@ -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)
Expand Down
33 changes: 33 additions & 0 deletions payroll/templates/payroll/page/edit_payroll.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,39 @@

{% block content %}
<div id="payroll-app"></div>

<h1>Forecast</h1>


<table class="govuk-table">
<thead class="govuk-table__head">
<tr class="govuk-table__row">
<th scope="col" class="govuk-table__header">Pay type</th>
{% for month in months %}
<th scope="col" class="govuk-table__header">{{ month }}</th>
{% endfor %}
</tr>
</thead>
<tbody class="govuk-table__body">
{% for row in payroll_forecast_report %}
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header">{{ row.pay_element__type__group__name }}</th>
<td class="govuk-table__cell">{{ row.period_1_sum }}</td>
<td class="govuk-table__cell">{{ row.period_2_sum }}</td>
<td class="govuk-table__cell">{{ row.period_3_sum }}</td>
<td class="govuk-table__cell">{{ row.period_4_sum }}</td>
<td class="govuk-table__cell">{{ row.period_5_sum }}</td>
<td class="govuk-table__cell">{{ row.period_6_sum }}</td>
<td class="govuk-table__cell">{{ row.period_7_sum }}</td>
<td class="govuk-table__cell">{{ row.period_8_sum }}</td>
<td class="govuk-table__cell">{{ row.period_9_sum }}</td>
<td class="govuk-table__cell">{{ row.period_10_sum }}</td>
<td class="govuk-table__cell">{{ row.period_11_sum }}</td>
<td class="govuk-table__cell">{{ row.period_12_sum }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}

{% block scripts %}
Expand Down
18 changes: 18 additions & 0 deletions payroll/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 7a56f3e

Please sign in to comment.