Repository: DFE-Digital/register-early-career-teachers-public
Pull request #592: [CPDLP-4250] Service manual for transfers
Author: login: mooktakim
Labels: name: Documentation
description: Improvements or additions to documentation
Created: 2025-05-15T17:09:45Z | Merged: 2025-05-22T09:37:25Z

Ticket: https://dfedigital.atlassian.net/browse/CPDLP-4250

* Service manual for transfers



Diff:
diff --git a/documentation/service-rules/ecf1/lead-provider-api.md b/documentation/service-rules/ecf1/lead-provider-api.md
index 73c0329f9..6000c6582 100644
--- a/documentation/service-rules/ecf1/lead-provider-api.md
+++ b/documentation/service-rules/ecf1/lead-provider-api.md
@@ -20,6 +20,8 @@ Once a participant has been registered to the service by their school, data asso
 
 [Void declarations](/service-rules/ecf1/void-declarations)
 
+[Transfers](/service-rules/ecf1/transfers)
+
 ## API versioning and updates management
 
 We continuously implement improvements and feature enhancements to the API codebase. Internal teams can reference the <a href="https://manage-training-for-early-career-teachers.education.gov.uk/api-reference/release-notes.html" target="_blank">release notes</a> for detailed changelogs and implementation notes.
diff --git a/documentation/service-rules/ecf1/transfers.md b/documentation/service-rules/ecf1/transfers.md
new file mode 100644
index 000000000..6a892615f
--- /dev/null
+++ b/documentation/service-rules/ecf1/transfers.md
@@ -0,0 +1,242 @@
+---
+title: Transfers
+---
+
+# Transfers
+
+A transfer represents participant changing school or lead provider. Transfer can be a switch to a new school with same lead provider, switch to new school with different lead provider or a partial transfer where only leave is reported.
+
+## API Endpoints
+
+### `GET /api/v3/participants/ecf/transfers`
+
+This endpoint allows you to retrieve list of all ECF participant transfers.
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                                                                                                    |
+| --------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------- |
+| filter    | object | No       | Refine participant transfers to return. This consumes a `ListFilter` schema.                                   |
+| page      | object | No       | Pagination options to navigate through the list of participant transfers. This consumes a `Pagination` schema. |
+
+#### Filter parameters (`ListFilter`)
+
+| Name          | Type   | Required | Description                                                                                |
+| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
+| updated_since | string | No       | Return only records that have been updated since this date and time (ISO 8601 date format) |
+
+#### Pagination parameters (`Pagination`)
+
+| Name     | Type    | Required | Description                |
+| -------- | ------- | -------- | -------------------------- |
+| page     | integer | No       | Page number to return      |
+| per_page | integer | No       | Number of records per page |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": [
+    {
+      "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+      "type": "participant-transfer",
+      "attributes": {
+        "updated_at": "2021-05-31T02:22:32.000Z",
+        "transfers": {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2021-05-31"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2021-06-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      }
+    }
+  ]
+}
+```
+
+### GET /api/v3/participants/ecf/{id}/transfers
+
+This endpoint allows you to retrieve a single participant’s transfers
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                    |
+| --------- | ------ | -------- | ------------------------------ |
+| id        | string | Yes      | The ID of the ECF participant. |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": null,
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer Fields
+
+The following describe how the transfer results are generated:
+
+- `id` - is set to `user.id`
+- `updated_at` - most recent `updated_at` from leaving or joining induction record, fallback to `user.updated_at`
+- `training_record_id` - is set to `participant_profile.id`
+- `transfer_type` - `induction_record.induction_programme.partnership.lead_provider` is used to calculate this value
+- `status` - if leaving end date or joining start date is in the past it is set to `incomplete`, otherwise `complete`
+- `created_at` - set to `leaving_induction_record.created_at`
+- `school_urn` - set to `induction_record.induction_programme.school_cohort.school.urn`
+- `provider` - set to `induction_record.induction_programme.partnership.lead_provider.name`
+- `date` - set to `end_date` for leaving and `start_date` for joining induction record.
+
+## Types of Transfers
+
+### `new_school`
+
+Participant changes to a new school but stays with the same lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_school",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `new_provider`
+
+Participant changes to a new school with a different lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `unknown`
+
+Participant is leaving.
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "unknown",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer States
+
+- `incomplete` - both leaving end date and joining (if set) start date are in the future
+- `complete` - both leaving end date and joining (if set) start date are in the past
+
+|                                                   | Leaving Provider     | Leaving Provider                  | Joining Provider     | Joining Provider                  | Same Leaving/Joining Provider | Same Leaving/Joining Provider     |
+| ------------------------------------------------- | -------------------- | --------------------------------- | -------------------- | --------------------------------- | ----------------------------- | --------------------------------- |
+|                                                   | Participant Response | Transfer Response                 | Participant Response | Transfer Response                 | Participant Response          | Transfer Response                 |
+| **Before Transfer**                               | active               | n/a                               | n/a                  | n/a                               | active                        | n/a                               |
+| **Old school SIT reports leaver**                 | leaving              | Shows leaving details             | n/a                  | n/a                               | leaving                       | Shows leaving details             |
+| **New school SIT reports joiner**                 | leaving              | Shows leaving and joining details | joining              | Shows leaving and joining details | joining                       | Shows leaving and joining details |
+| **After transfer (today's date => joining_date)** | left                 | Shows leaving and joining details | active               | Shows leaving and joining details | active                        | Shows leaving and joining details |
+
+## School Induction Tutor (SIT)
+
+Participant transfer is created when SIT report participants as leaving and the new school SIT reports participants as joining.
+
+## Admin User
+
+Admin user is able to see transfer entries in the participants audit log with `School transfer` set to `true`.
+
+## Data Impact and Schema
+
+Participant transfers is dynamically generated using the `Api::V3::ECF::BuildTransfers` service.
+
+Induction record with `induction_status` is set to `leaving` is used for leaving. The next induction record which does not have `induction_status` as `leaving` and has `school_transfer` set to `true` is used for joining.
+
+Take note, old induction records might have incorrect formatting or sequence which could result in the transfer record being incorrect.


Reviews:
user: login: leandroalemao
body: Looks good 👍 tkss
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T10:45:13Z
user: login: ethax-ross
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-19T13:12:18Z
user: login: cwrw
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T13:38:20Z
user: login: cwrw
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T13:39:38Z
user: login: cwrw
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T19:37:45Z

Review comments:
diff_hunk: @@ -0,0 +1,232 @@
+---
+title: Transfers
+---
+
+# Transfers
+
+A transfer represents participant changing school or lead provider. Transfer can be a switch to a new school with same lead provider, switch to new school with different lead provider or a partial transfer where only leave is reported.
+
+## API Endpoints
+
+### `GET /api/v3/participants/ecf/transfers`
+
+This endpoint allows you to retrieve list of all ECF participant transfers.
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                                                                                                    |
+| --------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------- |
+| filter    | object | No       | Refine participant transfers to return. This consumes a `ListFilter` schema.                                   |
+| page      | object | No       | Pagination options to navigate through the list of participant transfers. This consumes a `Pagination` schema. |
+
+#### Filter parameters (`ListFilter`)
+
+| Name          | Type   | Required | Description                                                                                |
+| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
+| updated_since | string | No       | Return only records that have been updated since this date and time (ISO 8601 date format) |
+
+#### Pagination parameters (`Pagination`)
+
+| Name     | Type    | Required | Description                |
+| -------- | ------- | -------- | -------------------------- |
+| page     | integer | No       | Page number to return      |
+| per_page | integer | No       | Number of records per page |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": [
+    {
+      "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+      "type": "participant-transfer",
+      "attributes": {
+        "updated_at": "2021-05-31T02:22:32.000Z",
+        "transfers": {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2021-05-31"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2021-06-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      }
+    }
+  ]
+}
+```
+
+### GET /api/v3/participants/ecf/{id}/transfers
+
+This endpoint allows you to retrieve a single participant’s transfers
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                    |
+| --------- | ------ | -------- | ------------------------------ |
+| id        | string | Yes      | The ID of the ECF participant. |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": null,
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer Fields
+
+The following describe how the transfer results are generated:
+
+- `id` - is set to `user.id`
+- `updated_at` - most recent `updated_at` from leaving or joining induction record, fallback to `user.updated_at`
+- `training_record_id` - is set to `participant_profile.id`
+- `transfer_type` - `induction_record.induction_programme.partnership.lead_provider` is used to calculate this value
+- `status` - if leaving end date or joining start date is in the past it is set to `incomplete`, otherwise `complete`
+- `created_at` - set to `leaving_induction_record.created_at`
+- `school_urn` - set to `induction_record.induction_programme.school_cohort.school.urn`
+- `provider` - set to `induction_record.induction_programme.partnership.lead_provider.name`
+- `date` - set to `end_date` for leaving and `start_date` for joining induction record.
+
+## Types of Transfers
path: documentation/service-rules/ecf1/transfers.md
user: login: ethax-ross
body: Is it worth documenting the logic around how transfers are compiled from induction records in the `BuildTransfers` service? it makes my head hurt every time I look at it so it might be nice to have it written down/explained somewhere for when we come to port it over to RECT 😅 
created_at: 2025-05-19T13:11:58Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,232 @@
+---
+title: Transfers
+---
+
+# Transfers
+
+A transfer represents participant changing school or lead provider. Transfer can be a switch to a new school with same lead provider, switch to new school with different lead provider or a partial transfer where only leave is reported.
+
+## API Endpoints
+
+### `GET /api/v3/participants/ecf/transfers`
+
+This endpoint allows you to retrieve list of all ECF participant transfers.
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                                                                                                    |
+| --------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------- |
+| filter    | object | No       | Refine participant transfers to return. This consumes a `ListFilter` schema.                                   |
+| page      | object | No       | Pagination options to navigate through the list of participant transfers. This consumes a `Pagination` schema. |
+
+#### Filter parameters (`ListFilter`)
+
+| Name          | Type   | Required | Description                                                                                |
+| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
+| updated_since | string | No       | Return only records that have been updated since this date and time (ISO 8601 date format) |
+
+#### Pagination parameters (`Pagination`)
+
+| Name     | Type    | Required | Description                |
+| -------- | ------- | -------- | -------------------------- |
+| page     | integer | No       | Page number to return      |
+| per_page | integer | No       | Number of records per page |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": [
+    {
+      "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+      "type": "participant-transfer",
+      "attributes": {
+        "updated_at": "2021-05-31T02:22:32.000Z",
+        "transfers": {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2021-05-31"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2021-06-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      }
+    }
+  ]
+}
+```
+
+### GET /api/v3/participants/ecf/{id}/transfers
+
+This endpoint allows you to retrieve a single participant’s transfers
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                    |
+| --------- | ------ | -------- | ------------------------------ |
+| id        | string | Yes      | The ID of the ECF participant. |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": null,
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer Fields
+
+The following describe how the transfer results are generated:
+
+- `id` - is set to `user.id`
+- `updated_at` - most recent `updated_at` from leaving or joining induction record, fallback to `user.updated_at`
+- `training_record_id` - is set to `participant_profile.id`
+- `transfer_type` - `induction_record.induction_programme.partnership.lead_provider` is used to calculate this value
+- `status` - if leaving end date or joining start date is in the past it is set to `incomplete`, otherwise `complete`
+- `created_at` - set to `leaving_induction_record.created_at`
+- `school_urn` - set to `induction_record.induction_programme.school_cohort.school.urn`
+- `provider` - set to `induction_record.induction_programme.partnership.lead_provider.name`
+- `date` - set to `end_date` for leaving and `start_date` for joining induction record.
+
+## Types of Transfers
+
+### `new_school`
+
+Participant changes to a new school but stays with the same lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_school",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `new_provider`
+
+Participant changes to a new school with a different lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `unknown`
+
+Participant is leaving.
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "unknown",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer States
path: documentation/service-rules/ecf1/transfers.md
user: login: cwrw
body: maybe we can include this table mapping as well for clarity? 
<img width="1058" alt="Screenshot 2025-05-19 at 14 37 34" src="https://github.com/user-attachments/assets/b33395ea-55ad-41cf-9894-dea0c1bb34fa" />

created_at: 2025-05-19T13:38:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,232 @@
+---
+title: Transfers
+---
+
+# Transfers
+
+A transfer represents participant changing school or lead provider. Transfer can be a switch to a new school with same lead provider, switch to new school with different lead provider or a partial transfer where only leave is reported.
+
+## API Endpoints
+
+### `GET /api/v3/participants/ecf/transfers`
+
+This endpoint allows you to retrieve list of all ECF participant transfers.
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                                                                                                    |
+| --------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------- |
+| filter    | object | No       | Refine participant transfers to return. This consumes a `ListFilter` schema.                                   |
+| page      | object | No       | Pagination options to navigate through the list of participant transfers. This consumes a `Pagination` schema. |
+
+#### Filter parameters (`ListFilter`)
+
+| Name          | Type   | Required | Description                                                                                |
+| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
+| updated_since | string | No       | Return only records that have been updated since this date and time (ISO 8601 date format) |
+
+#### Pagination parameters (`Pagination`)
+
+| Name     | Type    | Required | Description                |
+| -------- | ------- | -------- | -------------------------- |
+| page     | integer | No       | Page number to return      |
+| per_page | integer | No       | Number of records per page |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": [
+    {
+      "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+      "type": "participant-transfer",
+      "attributes": {
+        "updated_at": "2021-05-31T02:22:32.000Z",
+        "transfers": {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2021-05-31"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2021-06-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      }
+    }
+  ]
+}
+```
+
+### GET /api/v3/participants/ecf/{id}/transfers
+
+This endpoint allows you to retrieve a single participant’s transfers
+
+#### Request parameters
+
+| Parameter | Type   | Required | Description                    |
+| --------- | ------ | -------- | ------------------------------ |
+| id        | string | Yes      | The ID of the ECF participant. |
+
+#### Response (200 OK)
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": null,
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer Fields
+
+The following describe how the transfer results are generated:
+
+- `id` - is set to `user.id`
+- `updated_at` - most recent `updated_at` from leaving or joining induction record, fallback to `user.updated_at`
+- `training_record_id` - is set to `participant_profile.id`
+- `transfer_type` - `induction_record.induction_programme.partnership.lead_provider` is used to calculate this value
+- `status` - if leaving end date or joining start date is in the past it is set to `incomplete`, otherwise `complete`
+- `created_at` - set to `leaving_induction_record.created_at`
+- `school_urn` - set to `induction_record.induction_programme.school_cohort.school.urn`
+- `provider` - set to `induction_record.induction_programme.partnership.lead_provider.name`
+- `date` - set to `end_date` for leaving and `start_date` for joining induction record.
+
+## Types of Transfers
+
+### `new_school`
+
+Participant changes to a new school but stays with the same lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_school",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `new_provider`
+
+Participant changes to a new school with a different lead provider
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "new_provider",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Old Institute",
+            "date": "2023-09-01"
+          },
+          "joining": {
+            "school_urn": "654321",
+            "provider": "New Institute",
+            "date": "2023-09-01"
+          },
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+### `unknown`
+
+Participant is leaving.
+
+```json
+{
+  "data": {
+    "id": "db3a7848-7308-4879-942a-c4a70ced400a",
+    "type": "participant-transfer",
+    "attributes": {
+      "updated_at": "2021-05-31T02:22:32.000Z",
+      "transfers": [
+        {
+          "training_record_id": "000a97ff-d2a9-4779-a397-9bfd9063072e",
+          "transfer_type": "unknown",
+          "status": "complete",
+          "leaving": {
+            "school_urn": "123456",
+            "provider": "Example Institute",
+            "date": "2023-09-01"
+          },
+          "joining": null,
+          "created_at": "2021-05-31T02:22:32.000Z"
+        }
+      ]
+    }
+  }
+}
+```
+
+## Transfer States
+
+- `incomplete` - both leaving end date and joining (if set) start date are in the future
+- `complete` - both leaving end date and joining (if set) start date are in the past
+
+## School Induction Tutor (SIT)
+
+Participant transfer is created when SIT report participants as leaving and the new school SIT reports participants as joining.
+
+## Admin User
+
+Admin user is able to see transfer entries in the participants audit log with `School transfer` set to `true`.
+
+## Data Impact and Schema
+
+Participant transfers is dynamically generated using the `Api::V3::ECF::BuildTransfers` service.
+
+Induction record with `induction_status` is set to `leaving` is used for leaving. The next induction record which does not have `induction_status` as `leaving` and has `school_transfer` set to `true` is used for joining.
path: documentation/service-rules/ecf1/transfers.md
user: login: cwrw
body: maybe worth including a caveat around old IRs might have incorrect formatting or sequence causing problems
created_at: 2025-05-19T13:39:38Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-15T17:13:59Z
body: Review app deployed to https://cpd-ec2-review-592-web.test.teacherservices.cloud
<!-- Sticky Pull Request Comment -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-05-20T14:58:20Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=DFE-Digital_register-early-career-teachers-public&pullRequest=592)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-22T09:38:32Z
body: Review app ECF2 deployed to <https://ec2-review-592-web.test.teacherservices.cloud> was deleted
<!-- Sticky Pull Request Commentaks -->
author_association: NONE