Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprint 48 into main #558

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.ci
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ AUTHBROKER_URL=
SENTRY_ENVIRONMENT=ci
SENTRY_DSN=
CSP_REPORT_URI=
PAYROLL={"BASIC_PAY_NAC": "71111001", "PENSION_NAC": "71111002", "ERNIC_NAC": "71111003", "VACANCY_NAC": "71111001"}
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ CSP_REPORT_URI=
# Vite
VITE_DEV=True

PAYROLL={"BASIC_PAY_NAC": "71111001", "PENSION_NAC": "71111002", "ERNIC_NAC": "71111003", "VACANCY_NAC": "71111001"}

# Not documented (needed?)
# RESTRICT_ADMIN=True
# PUBLIC_PATH="http://localhost:8000"
Expand Down
14 changes: 14 additions & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""

import os
from dataclasses import dataclass
from pathlib import Path

import dj_database_url
Expand Down Expand Up @@ -414,3 +415,16 @@ def FILTERS_VERBOSE_LOOKUPS():

CSP_REPORT_ONLY = True
CSP_REPORT_URI = env.str("CSP_REPORT_URI", default=None)


# Payroll
@dataclass
class Payroll:
BASIC_PAY_NAC: str | None = None
PENSION_NAC: str | None = None
ERNIC_NAC: str | None = None
VACANCY_NAC: str | None = None
AVERAGE_SALARY_THRESHOLD: int = 2


PAYROLL: Payroll = Payroll(**env.json("PAYROLL", default={}))
4 changes: 4 additions & 0 deletions config/settings/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@
AXES_ENABLED = False

STORAGES["default"]["BACKEND"] = "django.core.files.storage.FileSystemStorage"

# I'm not aware of any case where we need the history whilst running tests. This should
# hopefully speed up the tests a little bit.
SIMPLE_HISTORY_ENABLED = False
21 changes: 20 additions & 1 deletion core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.views.decorators.csrf import csrf_exempt

from core.export_data import export_logentry_iterator
from core.models import CommandLog, FinancialYear
from core.models import CommandLog, FinancialYear, PayUplift
from core.utils.export_helpers import (
export_csv_from_import,
export_to_csv,
Expand Down Expand Up @@ -368,6 +368,25 @@ def has_delete_permission(self, request, obj=None):
return False


class PayUpliftAdmin(admin.ModelAdmin):
list_display = (
"financial_year",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
"jan",
"feb",
"mar",
)


admin.site.register(LogEntry, LogEntryAdmin)
admin.site.register(FinancialYear, FinancialYearAdmin)
admin.site.register(CommandLog, CustomLogModelAdmin)
admin.site.register(PayUplift, PayUpliftAdmin)
17 changes: 17 additions & 0 deletions core/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .types import Months


MONTHS: Months = (
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
"jan",
"feb",
"mar",
)
47 changes: 47 additions & 0 deletions core/migrations/0014_payuplift.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 5.1.3 on 2024-12-06 15:33

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0013_alter_historicalgroup_options_and_more"),
]

operations = [
migrations.CreateModel(
name="PayUplift",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("apr", models.FloatField(default=1.0)),
("may", models.FloatField(default=1.0)),
("jun", models.FloatField(default=1.0)),
("jul", models.FloatField(default=1.0)),
("aug", models.FloatField(default=1.0)),
("sep", models.FloatField(default=1.0)),
("oct", models.FloatField(default=1.0)),
("nov", models.FloatField(default=1.0)),
("dec", models.FloatField(default=1.0)),
("jan", models.FloatField(default=1.0)),
("feb", models.FloatField(default=1.0)),
("mar", models.FloatField(default=1.0)),
(
"financial_year",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="core.financialyear",
),
),
],
),
]
25 changes: 25 additions & 0 deletions core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.db import models
from simple_history import register

from core.constants import MONTHS

from .metamodels import BaseModel


Expand Down Expand Up @@ -87,6 +89,29 @@ def __str__(self):
return str(self.financial_year_display)


class PayUplift(models.Model):
@property
def periods(self) -> list[float]:
return [getattr(self, month) for month in MONTHS]

financial_year = models.ForeignKey(
FinancialYear,
on_delete=models.PROTECT,
)
apr = models.FloatField(default=1.0)
may = models.FloatField(default=1.0)
jun = models.FloatField(default=1.0)
jul = models.FloatField(default=1.0)
aug = models.FloatField(default=1.0)
sep = models.FloatField(default=1.0)
oct = models.FloatField(default=1.0)
nov = models.FloatField(default=1.0)
dec = models.FloatField(default=1.0)
jan = models.FloatField(default=1.0)
feb = models.FloatField(default=1.0)
mar = models.FloatField(default=1.0)


# Track changes to permissions
register(Permission, app=__package__, inherit=True)
register(get_user_model(), app=__package__, inherit=True)
Expand Down
25 changes: 18 additions & 7 deletions core/templates/base_generic.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{% load util %}
{% load breadcrumbs %}
{% load forecast_permissions %}
{% load payroll_permissions %}
{% load upload_permissions %}
{% load download_permissions %}
{% load upload_percentage_permissions %}
Expand Down Expand Up @@ -128,16 +129,26 @@
</a>
</li>

{% can_edit_payroll user as can_edit_payroll %}
{% if can_edit_payroll %}
<li class="internal-header__navigation__item">
<a class="internal-header__navigation__item__link {% if request.path|startswith:'/payroll/edit/' %}internal-header__navigation__item__link--active{% endif %}"
href="{% url 'payroll:choose_cost_centre' %}">
Edit payroll
</a>
</li>
{% endif %}

{% is_forecast_user user as is_forecast_user %}
{% if is_forecast_user == True %}
{% if is_forecast_user %}
<li class="internal-header__navigation__item">
<a class="internal-header__navigation__item__link {% if request.path|startswith:'/forecast/view/' %}internal-header__navigation__item__link--active{% endif %}"
href="{% url 'forecast_dit' 0 %}">
View forecast/historical outturn
</a>
</li>
{% can_edit_at_least_one_cost_centre user as can_edit_at_least_one_cost_centre %}
{% if can_edit_at_least_one_cost_centre == True %}
{% if can_edit_at_least_one_cost_centre %}
<li class="internal-header__navigation__item">
<a class="internal-header__navigation__item__link {% if request.path|startswith:'/forecast/edit/' %}internal-header__navigation__item__link--active{% endif %}"
href="{% url 'choose_cost_centre' %}">
Expand All @@ -146,7 +157,7 @@
</li>
{% endif %}
{% has_mi_report_download_permission user as has_mi_report_download_permission %}
{% if has_mi_report_download_permission == True %}
{% if has_mi_report_download_permission %}
<li class="internal-header__navigation__item {% if request.path == '/download/oscar-return/' %}govuk-header__navigation-item--active{% endif %}">
<a class="internal-header__navigation__item__link"
href="/download_file/download_mi_report/">
Expand All @@ -156,7 +167,7 @@
{% endif %}

{% has_oscar_download_permission user as has_oscar_download_permission %}
{% if has_oscar_download_permission == True %}
{% if has_oscar_download_permission %}
<li class="internal-header__navigation__item {% if request.path == '/download/mi-report/' %}govuk-header__navigation-item--active{% endif %}">
<a class="internal-header__navigation__item__link"
href="/download_file/download_oscar_report/">
Expand All @@ -165,7 +176,7 @@
</li>
{% endif %}
{% has_upload_permission user as has_upload_permission %}
{% if has_upload_permission == True %}
{% if has_upload_permission %}
<li class="internal-header__navigation__item">
<a class="internal-header__navigation__item__link {% if request.path|startswith:'/upload/' %}internal-header__navigation__item__link--active{% endif %}"
href="{% url 'uploaded_files' %}">
Expand All @@ -175,7 +186,7 @@
{% endif %}
{% endif %}
{% has_project_percentage_permission user as has_project_percentage_permission %}
{% if has_project_percentage_permission == True %}
{% if has_project_percentage_permission %}
<li class="internal-header__navigation__item
{% if request.path == '/upload_split_file/project_percentage/' %}govuk-header__navigation-item--active{% endif %}">
<a id="split_project" class="internal-header__navigation__item__link"
Expand All @@ -186,7 +197,7 @@
{% endif %}

{% has_end_of_month_archive_permissions request.user as has_end_of_month_archive_permissions %}
{% if has_end_of_month_archive_permissions == True %}
{% if has_end_of_month_archive_permissions %}
<li class="internal-header__navigation__item">
<a id="end_of_month" class="internal-header__navigation__item__link"
href="{% url 'end_of_month' %}">
Expand Down
46 changes: 46 additions & 0 deletions core/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import Literal, TypedDict


Month = Literal[
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
"jan",
"feb",
"mar",
]
Months = tuple[
Literal["apr"],
Literal["may"],
Literal["jun"],
Literal["jul"],
Literal["aug"],
Literal["sep"],
Literal["oct"],
Literal["nov"],
Literal["dec"],
Literal["jan"],
Literal["feb"],
Literal["mar"],
]


class MonthsDict[T](TypedDict):
apr: T
may: T
jun: T
jul: T
aug: T
sep: T
oct: T
nov: T
dec: T
jan: T
feb: T
mar: T
4 changes: 3 additions & 1 deletion forecast/templates/forecast/edit/edit.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "forecast/edit/forecast_base.html" %}
{% load payroll_permissions %}
{% load util vite %}
{% load breadcrumbs %}

Expand Down Expand Up @@ -41,14 +42,15 @@
{% endblock %}
{% block scripts %}
{{ view.get_payroll_forecast_report|json_script:'payroll_forecast_data' }}
{% can_edit_payroll user as can_edit_payroll %}
<script>
window.actuals = {{ actuals|safe }};
window.period_display = {{ period_display|safe }};
window.table_data = {{ forecast_dump|safe }};
window.cost_centre = {{ view.cost_centre_details.cost_centre_code|safe }};
window.financial_year = {{ view.financial_year|safe }};
window.payroll_forecast_data = JSON.parse(document.getElementById("payroll_forecast_data").textContent);
window.can_toggle_payroll = "{{ can_toggle_payroll }}";
window.can_edit_payroll = "{{ can_edit_payroll }}";
</script>
{% vite_dev_client %}
{% vite_js 'src/index.jsx' %}
Expand Down
13 changes: 13 additions & 0 deletions forecast/templatetags/forecast_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@
]


@register.filter
def format_money(value: float) -> str:
"""Format as a monetary value.

`value` is expected to be in pence and will be divided by 100.

Examples:
>>> format_money(1024312)
'10,243.12'
"""
return f"{value / 100:,.2f}"


@register.filter()
def is_forecast_figure(_, column):
if str(column) in forecast_figure_cols:
Expand Down
1 change: 0 additions & 1 deletion forecast/views/edit_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,6 @@ def get_context_data(self, **kwargs):
context["forecast_dump"] = forecast_dump
context["actuals"] = actual_data
context["period_display"] = period_display
context["can_toggle_payroll"] = self.request.user.is_superuser

return context

Expand Down
Loading
Loading