Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3b00129
refactor(kesaseteli): move filter_by_voucher_and_fuzzy_name to manager
nikomakela Jan 7, 2026
3e1494d
test(kesaseteli): remove duplicated test
nikomakela Jan 12, 2026
0c2f2c5
refactor(kesaseteli): add error logging
nikomakela Jan 7, 2026
135b29e
feat(kesaseteli,admin): more features in school admin page
nikomakela Jan 8, 2026
ac00bc9
chore: add antigravity editor's files to gitignore
nikomakela Jan 8, 2026
6849fdf
fix(kesaseteli): add fixture to enable admin site on every unit test
nikomakela Jan 12, 2026
b91aad0
feat(kesaseteli): summer voucher configuration
nikomakela Jan 8, 2026
80baa48
feat(kesaseteli): add API endpoint for summer voucher configuration
nikomakela Jan 8, 2026
147440c
feat(kesaseteli): add API endpoint to list available target groups
nikomakela Jan 5, 2026
9168668
feat(kesaseteli): models and base files for email templates
nikomakela Jan 9, 2026
7a10ac5
docs(kesaseteli): yearly configuration and email templates management
nikomakela Jan 9, 2026
073c313
feat(kesaseteli): reject appl. if no summer voucher config for year
nikomakela Jan 12, 2026
41cfb1f
refactor(kesaseteli): use staticmethods in target group service
nikomakela Jan 12, 2026
c71e963
feat(kesaseteli): add description property to target group
nikomakela Jan 12, 2026
587b550
feat(kesaseteli,admin): add custom admin site for context management
nikomakela Jan 16, 2026
702802f
feat(shared,admin): login form can be hidden if context disables it
nikomakela Jan 16, 2026
b9b96d6
feat(kesaseteli): mngmt.cmd. to create summer voucher config instance
nikomakela Jan 16, 2026
cb4753d
feat(kesaseteli): docker-entrypoint to create summer voucher config
nikomakela Jan 16, 2026
8d5f829
docs(kesaseteli): management command documentation
nikomakela Jan 19, 2026
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ dmypy.json
**/.idea/**
*.iml

# antigravity
.antigravityignore
.agent/**

node_modules

# Local generated certs
Expand Down
47 changes: 46 additions & 1 deletion backend/kesaseteli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Allow user to create test database
* Set the `DEBUG` environment variable to `1`.
* Run `python manage.py migrate`
* Run `python manage.py compilemessages`
* Run `python manage.py ensure_email_templates` (populates email templates)
* Run `python manage.py setup_admin_permissions` (sets up admin permissions)
* Run `python manage.py runserver 0:8000`

The project is now running at [localhost:8000](https://localhost:8000)
Expand Down Expand Up @@ -95,4 +97,47 @@ env variables / settings are provided by Azure blob storage:

- `AZURE_ACCOUNT_NAME`
- `AZURE_ACCOUNT_KEY`
- `AZURE_CONTAINER`

## Environment Variables

| Variable | Description |
| :--- | :--- |
| `PASSWORD_LOGIN_DISABLED` | A boolean value. If set to True, disables username/password login in the admin site. Default is False. |
| `NEXT_PUBLIC_MOCK_FLAG` | A boolean value. If set to True, many aspects of the application are mocked, e.g. ADFS login which is used by the admin site. Default is False. |
| `NEXT_PUBLIC_DISABLE_VTJ` | A boolean value. If set to True, VTJ client usage is disabled. Default is False. |
| `CREATE_SUMMERVOUCHER_CONFIGURATION_CURRENT_YEAR` | A boolean value. If set to True, creates a new `SummerVoucherConfiguration` for the current year. Default is False. |
| `CREATE_SUMMERVOUCHER_CONFIGURATION_2026` | A boolean value. If set to True, creates a new `SummerVoucherConfiguration` for the year 2026. Default is False. |

## Documentation

- [Applications Module](applications/README.md): Documentation for Summer Voucher Configuration, Email Templates, Target Groups, and School Management.
- [Staff Admin Permissions](staff_admin_permissions/README.md): Documentation for handling staff user permissions and AD group mappings.

### Summer Voucher Configuration

A `SummerVoucherConfiguration` for the current year is **required** for creating new `YouthApplication`s. If no configuration exists for the current year, the API will reject creation requests with a 400 Bad Request error.


### Management Commands

#### Create Summer Voucher Configuration

`python manage.py create_summervoucher_configuration`

Creates a new `SummerVoucherConfiguration` for the specified year.

**Arguments:**

* `--year`: Year for the configuration (default: current year)
* `--voucher-value`: Voucher value in euros (default: 350)
* `--min-work-compensation`: Minimum work compensation in euros (default: 500)
* `--min-work-hours`: Minimum work hours (default: 60)
* `--target-groups`: List of target group identifiers (default: all)
* `--force`: Force creation by overwriting existing configuration if it exists

**Docker Entrypoint:**

The `docker-entrypoint.sh` script can automatically run this command on startup using environment variables:

* `CREATE_SUMMERVOUCHER_CONFIGURATION_CURRENT_YEAR=1`: Creates configuration for the current year.
* `CREATE_SUMMERVOUCHER_CONFIGURATION_2026=1`: Creates configuration for the year 2026.
120 changes: 120 additions & 0 deletions backend/kesaseteli/applications/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Applications Module](#applications-module)
- [Summer Voucher Configuration](#summer-voucher-configuration)
- [Target Groups Management](#target-groups-management)
- [Adding a New Target Group](#adding-a-new-target-group)
- [Email Template Handling](#email-template-handling)
- [File-Based Initialization](#file-based-initialization)
- [Restoration and Synchronization](#restoration-and-synchronization)
- [1. Management Command](#1-management-command)
- [2. Admin Interface Action](#2-admin-interface-action)
- [3. Reinitialize Selected Templates](#3-reinitialize-selected-templates)
- [School Management](#school-management)
- [API Endpoint](#api-endpoint)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# Applications Module

This module handles the core logic for youth and employer applications, including configuration and email communication.

## Summer Voucher Configuration

The `SummerVoucherConfiguration` model stores annual configuration settings for the Summer Voucher application process. Key settings include:

- **Year**: The applicable year for the configuration.
- **Voucher Value**: The monetary value of the voucher.
- **Minimum Work Requirements**: Minimum hours and compensation required.
- **Target Groups**: Defines which youth target groups are active for the year (e.g., specific age ranges or schools).

This configuration is managed via the Django Admin interface and is used to validate incoming applications.


### Target Groups Management

The system supports defining different groups of applicants eligible for the voucher (e.g., specific age groups or student statuses). The logic for these groups is consolidated in [`target_groups.py`](target_groups.py).

#### Adding a New Target Group

1. Open `applications/target_groups.py`.
2. Create a new class that inherits from `AbstractTargetGroup`.
3. Define the required properties:
* `name`: The localized user-facing name.
* `identifier`: A unique string identifier (e.g., `"new_student_group"`).
4. Implement the `is_valid` method to define the eligibility logic (e.g., age checks, residency).

**Example:**
```python
class VocationalStudentTargetGroup(AbstractTargetGroup):
name = _("Vocational Student")
identifier = "vocational_student"

def is_valid(self, application):
return application.age == 18 and application.is_helsinkian
```

> [!WARNING]
> The `identifier` string is stored directly in the database to link vouchers to their target group. **Changing an existing class's identifier will break data integrity** for historical records. If you need to rename an identifier, a database migration is required.


## Email Template Handling

The system uses the `EmailTemplate` model to manage localized email content sent to applicants and employers.

### File-Based Initialization

Templates are initially defined as HTML files in `applications/templates/email/`. Each template corresponds to a type (e.g., `activation`, `processing`) and a language (`fi`, `sv`, `en`).

### Restoration and Synchronization

Because templates are stored in the database but sourced from files, a restoration mechanism is available to ensure the database matches the file system.

#### 1. Management Command
Use the following command to create missing templates and populate them with content from the corresponding files:

```bash
python manage.py ensure_email_templates
```

#### 2. Admin Interface Action
Administrators can trigger the restoration process directly from the Django Admin:
1. Navigate to **Applications** > **Email Templates**.
2. Click the **"Reproduce Missing Templates"** button at the top of the list.

Both methods use the `EmailTemplateService.ensure_templates_exist()` method to scan for all supported type/language combinations and create any that are missing.

#### 3. Reinitialize Selected Templates

To update existing templates with the latest content from the file system (e.g., after a code deployment):
1. Navigate to **Applications** > **Email Templates**.
2. Select the templates you wish to update using the checkboxes.
3. Choose **"Reinitialize selected templates from file"** from the **Action** dropdown menu.
4. Click **Go**.

### Validation and Preview

To ensure email quality and prevent errors:

1. **Syntax Validation**: The system validates template syntax (Jinja2/Django) whenever an Email Template is saved. If the syntax is invalid (e.g., unclosed tags), the save is blocked and an error is displayed.
2. **Preview Feature**: A **"Preview"** button is available on the Email Template change form. Clicking this opens a new window showing the rendered email populated with realistic mock data (e.g., test names, dates, links), allowing administrators to verify the layout and variable usage.
3. **Send Test Email**: An admin action **"Send selected email templates to me"** is available in the Email Template list view. This allows administrators to verify the final email delivery by sending the rendered template (with mock data) to their own email address.

## School Management

The `School` model stores the list of schools available for selection in youth applications. The **School Admin** interface allows administrators to:

- View the list of schools.
- Search schools by name.
- Filter schools by creation and modification dates.
- Add or remove schools as needed.

### API Endpoint

Frontend clients can retrieve the list of available schools using the following endpoint:

- **URL**: `/v1/schools/`
- **Method**: `GET`
- **Description**: Returns a list of all schools, sorted by name using Finnish collation rules.
Loading
Loading