Check the answers you gave for <%= subsection.humanize(capitalize: false) %>
- <%= display_answered_questions_summary(subsection, case_log, form) %>
+ <%= display_answered_questions_summary(subsection, @case_log, form) %>
<% form.pages_for_subsection(subsection).each do |page, page_info| %>
<% page_info["questions"].each do |question_title, question_info| %>
- <% if total_questions(subsection, case_log, form).include?(question_title) %>
- <%= render partial: 'form/check_answers_table', locals: { question_title: question_title, question_info: question_info, case_log: case_log, page: page } %>
+ <% if total_questions(subsection, @case_log, form).include?(question_title) %>
+ <%= render partial: 'form/check_answers_table', locals: { question_title: question_title, question_info: question_info, case_log: @case_log, page: page } %>
<%end %>
<%end %>
<% end %>
diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json
index 8bed823cf..47378e9f0 100644
--- a/config/forms/2021_2022.json
+++ b/config/forms/2021_2022.json
@@ -31,7 +31,7 @@
"hint_text": "",
"type": "numeric",
"min": 0,
- "max": 150,
+ "max": 120,
"step": 1
}
}
diff --git a/db/migrate/20211014154616_add_discarded_at_to_case_logs.rb b/db/migrate/20211014154616_add_discarded_at_to_case_logs.rb
new file mode 100644
index 000000000..429640759
--- /dev/null
+++ b/db/migrate/20211014154616_add_discarded_at_to_case_logs.rb
@@ -0,0 +1,6 @@
+class AddDiscardedAtToCaseLogs < ActiveRecord::Migration[6.1]
+ def change
+ add_column :case_logs, :discarded_at, :datetime
+ add_index :case_logs, :discarded_at
+ end
+end
diff --git a/db/migrate/20211015090040_update_property_number_of_times_relet_type.rb b/db/migrate/20211015090040_update_property_number_of_times_relet_type.rb
new file mode 100644
index 000000000..5fa030571
--- /dev/null
+++ b/db/migrate/20211015090040_update_property_number_of_times_relet_type.rb
@@ -0,0 +1,9 @@
+class UpdatePropertyNumberOfTimesReletType < ActiveRecord::Migration[6.1]
+ def up
+ change_column :case_logs, :property_number_of_times_relet, "integer USING CAST(property_number_of_times_relet AS integer)"
+ end
+
+ def down
+ change_column :case_logs, :property_number_of_times_relet, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 3e73a03e0..03a612ecd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2021_10_13_113607) do
+ActiveRecord::Schema.define(version: 2021_10_15_090040) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -84,7 +84,6 @@ ActiveRecord::Schema.define(version: 2021_10_13_113607) do
t.string "property_void_date"
t.string "property_major_repairs"
t.string "property_major_repairs_date"
- t.string "property_number_of_times_relet"
t.string "property_wheelchair_accessible"
t.string "net_income"
t.string "net_income_frequency"
@@ -131,6 +130,9 @@ ActiveRecord::Schema.define(version: 2021_10_13_113607) do
t.boolean "reasonable_preference_reason_medical_grounds"
t.boolean "reasonable_preference_reason_avoid_hardship"
t.boolean "reasonable_preference_reason_do_not_know"
+ t.datetime "discarded_at"
+ t.integer "property_number_of_times_relet"
+ t.index ["discarded_at"], name: "index_case_logs_on_discarded_at"
end
end
diff --git a/doc/adr/adr-001-initial-architecture-decisions.md b/docs/adr/adr-001-initial-architecture-decisions.md
similarity index 100%
rename from doc/adr/adr-001-initial-architecture-decisions.md
rename to docs/adr/adr-001-initial-architecture-decisions.md
diff --git a/doc/adr/adr-002-repositories.md b/docs/adr/adr-002-repositories.md
similarity index 100%
rename from doc/adr/adr-002-repositories.md
rename to docs/adr/adr-002-repositories.md
diff --git a/doc/adr/adr-003-form-submission-flow.md b/docs/adr/adr-003-form-submission-flow.md
similarity index 100%
rename from doc/adr/adr-003-form-submission-flow.md
rename to docs/adr/adr-003-form-submission-flow.md
diff --git a/doc/adr/adr-004-gov-paas.md b/docs/adr/adr-004-gov-paas.md
similarity index 100%
rename from doc/adr/adr-004-gov-paas.md
rename to docs/adr/adr-004-gov-paas.md
diff --git a/doc/adr/adr-005-form-definition.md b/docs/adr/adr-005-form-definition.md
similarity index 100%
rename from doc/adr/adr-005-form-definition.md
rename to docs/adr/adr-005-form-definition.md
diff --git a/doc/adr/adr-006-saving-values.md b/docs/adr/adr-006-saving-values.md
similarity index 100%
rename from doc/adr/adr-006-saving-values.md
rename to docs/adr/adr-006-saving-values.md
diff --git a/doc/adr/adr-007-data-validations.md b/docs/adr/adr-007-data-validations.md
similarity index 69%
rename from doc/adr/adr-007-data-validations.md
rename to docs/adr/adr-007-data-validations.md
index 24b8f539c..1241314f9 100644
--- a/doc/adr/adr-007-data-validations.md
+++ b/docs/adr/adr-007-data-validations.md
@@ -9,7 +9,7 @@ These are handled slightly differently:
##### Validity checks
-These run for all submitted data. Every time a form page (in the UI is submitted), the fields related to that form page will be checked to ensure that any responses given are valid. If they are not, an error message will be shown on screen, and it will not be possible to "Save and continue" until the response is fixed or removed.
+These run for all submitted data. Every time a form page (in the UI) is submitted, the fields related to that form page will be checked to ensure that any responses given are valid. If they are not, an error message will be shown on screen, and it will not be possible to "Save and continue" until the response is fixed or removed.
Similarly if an API request is made to create a case log with data that contains _invalid_ fields, that data will be rejected, and an error message will be returned.
@@ -18,10 +18,10 @@ Similarly if an API request is made to create a case log with data that contains
These are not strictly error checks since it's possible to submit partial data. In the form UI it is possible to click "Save and continue" and move past questions that you might not know right now, and leave them to come back to later. We shouldn't prevent this workflow.
-Similar the API client (3rd party software system) may not have all the required data and may only be submitting a partial log. This is still a valid use case so we should not be enforcing presence checks and returning errors based on them for either submission type.
+Similarly the API client (3rd party software system) may not have all the required data and may only be submitting a partial log. This is still a valid use case so we should not be enforcing presence checks and returning errors based on them for either submission type.
Instead we determine the _status_ of the case log based the presence checks. Every time data is submitted (via a form page, bulk upload or API), before saving the data, the system will check whether all fields have been completed *and* pass validity checks. If so, the case log will be marked as *completed*, if not it will be marked as *in progress*.
By default all fields that a Case Log has will be assumed to be required unless explicitly marked as not required (for example as a result of other answers rendering a question inapplicable).
-On the form UI this will work by by not allowing you to "submit" the form, until all presence checks have been satisfied, but all other navigation is allowed. On the API this will work by returning a Case Log that is "in progress" if you've submitted a partial log, or "completed" if you've submitted a full log, or "Errors" if you've submitted an invalid log.
+On the form UI this will work by not allowing you to "submit" the form, until all presence checks have been satisfied, but all other navigation is allowed. On the API this will work by returning a Case Log that is "in progress" if you've submitted a partial log, or "completed" if you've submitted a full log, or "Errors" if you've submitted an invalid log.
diff --git a/docs/api/DLUHC-CORE-Data.v1.json b/docs/api/DLUHC-CORE-Data.v1.json
new file mode 100644
index 000000000..8a2b02fc7
--- /dev/null
+++ b/docs/api/DLUHC-CORE-Data.v1.json
@@ -0,0 +1,1154 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "DLUHC CORE Data",
+ "version": "1.0",
+ "description": "Submit or Update CORE Case Log Data on Lettings and Sales of Social Housing in England"
+ },
+ "servers": [
+ {
+ "url": "https://dluhc-core.london.cloudapps.digital",
+ "description": "Sandbox"
+ }
+ ],
+ "paths": {
+ "/case_logs/:id": {
+ "parameters": [],
+ "get": {
+ "summary": "Get Case Log Info by Case Log ID",
+ "tags": [],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Case-Log"
+ },
+ "examples": {}
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ },
+ "examples": {
+ "Not found": {
+ "value": {
+ "error": "Case Log 67 not found"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "get-case_logs-case_logs-:id",
+ "description": "Retrieve data for a specific case log",
+ "parameters": [
+ {
+ "schema": {
+ "type": "string",
+ "enum": [
+ "application/json"
+ ]
+ },
+ "in": "header",
+ "name": "Accept",
+ "required": true
+ }
+ ]
+ },
+ "patch": {
+ "summary": "Update Case Log Information",
+ "operationId": "patch-case_logs-case_logs-:id",
+ "responses": {
+ "200": {
+ "description": "Case Log Updated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Case-Log"
+ },
+ "examples": {}
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ },
+ "examples": {
+ "Not found": {
+ "value": {
+ "error": "Case Log 67 not found"
+ }
+ }
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Unprocessable Entity ",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ },
+ "examples": {
+ "Invalid Age": {
+ "value": {
+ "errors": [
+ "Tenant age must be between 0 and 120"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "description": "Update the information of an existing case log",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Case-Log"
+ },
+ "examples": {}
+ }
+ },
+ "description": "Patch case log properties to update."
+ },
+ "parameters": [
+ {
+ "schema": {
+ "type": "string",
+ "enum": [
+ "application/json"
+ ]
+ },
+ "in": "header",
+ "name": "Accept",
+ "required": true
+ }
+ ]
+ },
+ "delete": {
+ "summary": "Delete a Case Log by Case Log ID",
+ "operationId": "delete-case_logs-:id",
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ },
+ "examples": {
+ "Not found": {
+ "value": {
+ "error": "Case Log 67 not found"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "description": "Delete a case log",
+ "parameters": [
+ {
+ "schema": {
+ "type": "string",
+ "enum": [
+ "application/json"
+ ]
+ },
+ "in": "header",
+ "name": "Accept",
+ "required": true
+ }
+ ]
+ }
+ },
+ "/case_logs": {
+ "post": {
+ "summary": "Create New Case Log",
+ "operationId": "post-caselog",
+ "responses": {
+ "200": {
+ "description": "Case Log Created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Case-Log"
+ },
+ "examples": {}
+ }
+ }
+ },
+ "422": {
+ "description": "Unprocessable Entity ",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {}
+ },
+ "examples": {
+ "Invalid Age": {
+ "value": {
+ "errors": [
+ "Tenant age must be between 0 and 120"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Case-Log"
+ },
+ "examples": {}
+ }
+ },
+ "description": "Post the necessary fields for the API to create a new case log."
+ },
+ "description": "Create a new case log.",
+ "parameters": [
+ {
+ "schema": {
+ "type": "string",
+ "pattern": "application/json",
+ "enum": [
+ "application/json"
+ ]
+ },
+ "in": "header",
+ "name": "Accept",
+ "required": true
+ }
+ ]
+ },
+ "parameters": []
+ }
+ },
+ "components": {
+ "schemas": {
+ "Case-Log": {
+ "description": "",
+ "type": "object",
+ "x-examples": {
+ "example-1": {
+ "tenant_code": "T657",
+ "tenant_age": 35,
+ "tenant_gender": "Female",
+ "tenant_ethnic_group": "White: English/Scottish/Welsh/Northern Irish/British",
+ "tenant_nationality": "UK national resident in UK",
+ "previous_housing_situation": "Private sector tenancy",
+ "armed_forces": "Yes - a regular",
+ "tenant_economic_status": "Full-time - 30 hours or more",
+ "household_number_of_other_members": 7,
+ "person_2_relationship": "Partner",
+ "person_2_age": 32,
+ "person_2_gender": "Male",
+ "person_2_economic_status": "Not seeking work",
+ "person_3_relationship": "Child - includes young adult and grown-up",
+ "person_3_age": 12,
+ "person_3_gender": "Male",
+ "person_3_economic_status": "Child under 16",
+ "person_4_relationship": "Child - includes young adult and grown-up",
+ "person_4_age": 12,
+ "person_4_gender": "Female",
+ "person_4_economic_status": "Child under 16",
+ "person_5_relationship": "Child - includes young adult and grown-up",
+ "person_5_age": 10,
+ "person_5_gender": "Non-binary",
+ "person_5_economic_status": "Child under 16",
+ "person_6_relationship": "Child - includes young adult and grown-up",
+ "person_6_age": 5,
+ "person_6_gender": "Prefer not to say",
+ "person_6_economic_status": "Child under 16",
+ "person_7_relationship": "Child - includes young adult and grown-up",
+ "person_7_age": 5,
+ "person_7_gender": "Prefer not to say",
+ "person_7_economic_status": "Child under 16",
+ "person_8_relationship": "Child - includes young adult and grown-up",
+ "person_8_age": 2,
+ "person_8_gender": "Prefer not to say",
+ "person_8_economic_status": "Child under 16",
+ "homelessness": "No",
+ "reason_for_leaving_last_settled_home": "Other problems with neighbours",
+ "benefit_cap_spare_room_subsidy": "No",
+ "armed_forces_active": "No",
+ "armed_forces_injured": "No",
+ "armed_forces_partner": "No",
+ "medical_conditions": "Yes",
+ "pregnancy": "No",
+ "accessibility_requirements": "No",
+ "condition_effects": "dummy",
+ "tenancy_code": "BZ757",
+ "tenancy_start_date": "12/03/2019",
+ "starter_tenancy": "No",
+ "fixed_term_tenancy": "No",
+ "tenancy_type": "Fixed term – Secure",
+ "letting_type": "Affordable Rent - General Needs",
+ "letting_provider": "This landlord",
+ "property_location": "Barnet",
+ "previous_postcode": "NW1 5TY",
+ "property_relet": "No",
+ "property_vacancy_reason": "Relet - tenant abandoned property",
+ "property_reference": "P9876",
+ "property_unit_type": "House",
+ "property_building_type": "dummy",
+ "property_number_of_bedrooms": 3,
+ "property_void_date": "03/11/2019",
+ "property_major_repairs": "Yes",
+ "property_major_repairs_date": "05/05/2020",
+ "property_number_of_times_relet": 2,
+ "property_wheelchair_accessible": true,
+ "net_income": 1000,
+ "net_income_frequency": "Monthly",
+ "net_income_uc_proportion": "Some",
+ "housing_benefit": "Universal Credit with housing element, but not Housing Benefit",
+ "rent_frequency": "Weekly",
+ "basic_rent": 200,
+ "service_charge": 50,
+ "personal_service_charge": 40,
+ "support_charge": 35,
+ "total_charge": 325,
+ "outstanding_amount": "Yes",
+ "time_lived_in_la": "1 to 2 years",
+ "time_on_la_waiting_list": "Less than 1 year",
+ "previous_la": "Ashford",
+ "property_postcode": "SE2 6RT",
+ "reasonable_preference": "Yes",
+ "reasonable_preference_reason": "dummy",
+ "cbl_letting": true,
+ "chr_letting": false,
+ "cap_letting": false,
+ "outstanding_rent_or_charges": 25,
+ "other_reason_for_leaving_last_settled_home": "Other reason",
+ "accessibility_requirements_fully_wheelchair_accessible_housing": true,
+ "accessibility_requirements_wheelchair_access_to_essential_rooms": false,
+ "accessibility_requirements_level_access_housing": false,
+ "accessibility_requirements_other_disability_requirements": false,
+ "accessibility_requirements_no_disability_requirements": false,
+ "accessibility_requirements_do_not_know": false,
+ "accessibility_requirements_prefer_not_to_say": false,
+ "condition_effects_vision": false,
+ "condition_effects_hearing": true,
+ "condition_effects_mobility": false,
+ "condition_effects_dexterity": false,
+ "condition_effects_stamina": false,
+ "condition_effects_learning": false,
+ "condition_effects_memory": false,
+ "condition_effects_mental_health": false,
+ "condition_effects_social_or_behavioral": false,
+ "condition_effects_other": false,
+ "condition_effects_prefer_not_to_say": false,
+ "reasonable_preference_reason_homeless": false,
+ "reasonable_preference_reason_unsatisfactory_housing": false,
+ "reasonable_preference_reason_medical_grounds": false,
+ "reasonable_preference_reason_avoid_hardship": false,
+ "reasonable_preference_reason_do_not_know": true
+ }
+ },
+ "title": "Case Log",
+ "x-internal": false,
+ "properties": {
+ "tenant_code": {
+ "type": "string",
+ "minLength": 1
+ },
+ "tenant_age": {
+ "type": "number",
+ "description": "The age of the lead tenant",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "tenant_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "tenant_ethnic_group": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "White: English/Scottish/Welsh/Northern Irish/British",
+ "White: Irish",
+ "White: Gypsy/Irish Traveller",
+ "White: Other",
+ "Mixed: White & Black Caribbean",
+ "Mixed: White & Black African",
+ "Mixed: White & Asian",
+ "Mixed: Other",
+ "Asian or Asian British: Indian",
+ "Asian or Asian British: Pakistani",
+ "Asian or Asian British: Bangladeshi",
+ "Asian or Asian British: Chinese",
+ "Asian or Asian British: Other",
+ "Black: Caribbean",
+ "Black: African",
+ "Black: Other",
+ "Other Ethnic Group: Arab",
+ "Other Ethnic Group: Other",
+ "Prefer not to say"
+ ]
+ },
+ "tenant_nationality": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "UK national resident in UK",
+ "A current or former reserve in the UK Armed Forces (exc. National Service)",
+ "UK national returning from residence overseas",
+ "Czech Republic",
+ "Estonia",
+ "Hungary",
+ "Latvia",
+ "Lithuania",
+ "Poland",
+ "Slovakia",
+ "Bulgaria",
+ "Romania",
+ "Ireland",
+ "Other EU Economic Area (EEA country)",
+ "Any other country",
+ "Prefer not to say"
+ ]
+ },
+ "previous_housing_situation": {
+ "type": "string",
+ "minLength": 1
+ },
+ "armed_forces": {
+ "type": "string",
+ "minLength": 1
+ },
+ "tenant_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "household_number_of_other_members": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 7
+ },
+ "person_2_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_2_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_2_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_2_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_3_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_3_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_3_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_3_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_4_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_4_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_4_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_4_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_5_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_5_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_5_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_5_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_6_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_6_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_6_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_6_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_7_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_7_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_7_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_7_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_8_relationship": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Partner",
+ "Child - includes young adult and grown-up",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "person_8_age": {
+ "type": "number",
+ "maximum": 120,
+ "minimum": 0
+ },
+ "person_8_gender": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Female",
+ "Male",
+ "Non-binary",
+ "Prefer not to say"
+ ]
+ },
+ "person_8_economic_status": {
+ "type": "string",
+ "minLength": 1,
+ "enum": [
+ "Part-time - Less than 30 hours",
+ "Full-time - 30 hours or more",
+ "In government training into work, such as New Deal",
+ "Jobseeker",
+ "Retired",
+ "Not seeking work",
+ "Full-time student",
+ "Unable to work because of long term sick or disability",
+ "Child under 16",
+ "Other",
+ "Prefer not to say"
+ ]
+ },
+ "homelessness": {
+ "type": "string",
+ "minLength": 1
+ },
+ "reason_for_leaving_last_settled_home": {
+ "type": "string",
+ "minLength": 1
+ },
+ "benefit_cap_spare_room_subsidy": {
+ "type": "string",
+ "minLength": 1
+ },
+ "armed_forces_active": {
+ "type": "string",
+ "minLength": 1
+ },
+ "armed_forces_injured": {
+ "type": "string",
+ "minLength": 1
+ },
+ "armed_forces_partner": {
+ "type": "string",
+ "minLength": 1
+ },
+ "medical_conditions": {
+ "type": "string",
+ "minLength": 1
+ },
+ "pregnancy": {
+ "type": "string",
+ "minLength": 1
+ },
+ "accessibility_requirements": {
+ "type": "string",
+ "minLength": 1
+ },
+ "condition_effects": {
+ "type": "string",
+ "minLength": 1
+ },
+ "tenancy_code": {
+ "type": "string",
+ "minLength": 1
+ },
+ "tenancy_start_date": {
+ "type": "string",
+ "minLength": 1
+ },
+ "starter_tenancy": {
+ "type": "string",
+ "minLength": 1
+ },
+ "fixed_term_tenancy": {
+ "type": "string",
+ "minLength": 1
+ },
+ "tenancy_type": {
+ "type": "string",
+ "minLength": 1
+ },
+ "letting_type": {
+ "type": "string",
+ "minLength": 1
+ },
+ "letting_provider": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_location": {
+ "type": "string",
+ "minLength": 1
+ },
+ "previous_postcode": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_relet": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_vacancy_reason": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_reference": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_unit_type": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_building_type": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_number_of_bedrooms": {
+ "type": "number"
+ },
+ "property_void_date": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_major_repairs": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_major_repairs_date": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_number_of_times_relet": {
+ "type": "number"
+ },
+ "property_wheelchair_accessible": {
+ "type": "boolean"
+ },
+ "net_income": {
+ "type": "number"
+ },
+ "net_income_frequency": {
+ "type": "string",
+ "minLength": 1
+ },
+ "net_income_uc_proportion": {
+ "type": "string",
+ "minLength": 1
+ },
+ "housing_benefit": {
+ "type": "string",
+ "minLength": 1
+ },
+ "rent_frequency": {
+ "type": "string",
+ "minLength": 1
+ },
+ "basic_rent": {
+ "type": "number"
+ },
+ "service_charge": {
+ "type": "number"
+ },
+ "personal_service_charge": {
+ "type": "number"
+ },
+ "support_charge": {
+ "type": "number"
+ },
+ "total_charge": {
+ "type": "number"
+ },
+ "outstanding_amount": {
+ "type": "string",
+ "minLength": 1
+ },
+ "time_lived_in_la": {
+ "type": "string",
+ "minLength": 1
+ },
+ "time_on_la_waiting_list": {
+ "type": "string",
+ "minLength": 1
+ },
+ "previous_la": {
+ "type": "string",
+ "minLength": 1
+ },
+ "property_postcode": {
+ "type": "string",
+ "minLength": 1
+ },
+ "reasonable_preference": {
+ "type": "string",
+ "minLength": 1
+ },
+ "reasonable_preference_reason": {
+ "type": "string",
+ "minLength": 1
+ },
+ "cbl_letting": {
+ "type": "boolean"
+ },
+ "chr_letting": {
+ "type": "boolean"
+ },
+ "cap_letting": {
+ "type": "boolean"
+ },
+ "outstanding_rent_or_charges": {
+ "type": "number"
+ },
+ "other_reason_for_leaving_last_settled_home": {
+ "type": "string",
+ "minLength": 1
+ },
+ "accessibility_requirements_fully_wheelchair_accessible_housing": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_wheelchair_access_to_essential_rooms": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_level_access_housing": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_other_disability_requirements": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_no_disability_requirements": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_do_not_know": {
+ "type": "boolean"
+ },
+ "accessibility_requirements_prefer_not_to_say": {
+ "type": "boolean"
+ },
+ "condition_effects_vision": {
+ "type": "boolean"
+ },
+ "condition_effects_hearing": {
+ "type": "boolean"
+ },
+ "condition_effects_mobility": {
+ "type": "boolean"
+ },
+ "condition_effects_dexterity": {
+ "type": "boolean"
+ },
+ "condition_effects_stamina": {
+ "type": "boolean"
+ },
+ "condition_effects_learning": {
+ "type": "boolean"
+ },
+ "condition_effects_memory": {
+ "type": "boolean"
+ },
+ "condition_effects_mental_health": {
+ "type": "boolean"
+ },
+ "condition_effects_social_or_behavioral": {
+ "type": "boolean"
+ },
+ "condition_effects_other": {
+ "type": "boolean"
+ },
+ "condition_effects_prefer_not_to_say": {
+ "type": "boolean"
+ },
+ "reasonable_preference_reason_homeless": {
+ "type": "boolean"
+ },
+ "reasonable_preference_reason_unsatisfactory_housing": {
+ "type": "boolean"
+ },
+ "reasonable_preference_reason_medical_grounds": {
+ "type": "boolean"
+ },
+ "reasonable_preference_reason_avoid_hardship": {
+ "type": "boolean"
+ },
+ "reasonable_preference_reason_do_not_know": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "tenant_code",
+ "tenant_age",
+ "tenant_gender",
+ "tenant_ethnic_group",
+ "tenant_nationality",
+ "previous_housing_situation",
+ "armed_forces",
+ "tenant_economic_status",
+ "household_number_of_other_members",
+ "person_2_relationship",
+ "person_2_age",
+ "person_2_gender",
+ "person_2_economic_status",
+ "person_3_relationship",
+ "person_3_age",
+ "person_3_gender",
+ "person_3_economic_status",
+ "person_4_relationship",
+ "person_4_age",
+ "person_4_gender",
+ "person_4_economic_status",
+ "person_5_relationship",
+ "person_5_age",
+ "person_5_gender",
+ "person_5_economic_status",
+ "person_6_relationship",
+ "person_6_age",
+ "person_6_gender",
+ "person_6_economic_status",
+ "person_7_relationship",
+ "person_7_age",
+ "person_7_gender",
+ "person_7_economic_status",
+ "person_8_relationship",
+ "person_8_age",
+ "person_8_gender",
+ "person_8_economic_status",
+ "homelessness",
+ "reason_for_leaving_last_settled_home",
+ "benefit_cap_spare_room_subsidy",
+ "armed_forces_active",
+ "armed_forces_injured",
+ "armed_forces_partner",
+ "medical_conditions",
+ "pregnancy",
+ "accessibility_requirements",
+ "condition_effects",
+ "tenancy_code",
+ "tenancy_start_date",
+ "starter_tenancy",
+ "fixed_term_tenancy",
+ "tenancy_type",
+ "letting_type",
+ "letting_provider",
+ "property_location",
+ "previous_postcode",
+ "property_relet",
+ "property_vacancy_reason",
+ "property_reference",
+ "property_unit_type",
+ "property_building_type",
+ "property_number_of_bedrooms",
+ "property_void_date",
+ "property_major_repairs",
+ "property_major_repairs_date",
+ "property_number_of_times_relet",
+ "property_wheelchair_accessible",
+ "net_income",
+ "net_income_frequency",
+ "net_income_uc_proportion",
+ "housing_benefit",
+ "rent_frequency",
+ "basic_rent",
+ "service_charge",
+ "personal_service_charge",
+ "support_charge",
+ "total_charge",
+ "outstanding_amount",
+ "time_lived_in_la",
+ "time_on_la_waiting_list",
+ "previous_la",
+ "property_postcode",
+ "reasonable_preference",
+ "reasonable_preference_reason",
+ "cbl_letting",
+ "chr_letting",
+ "cap_letting",
+ "outstanding_rent_or_charges",
+ "other_reason_for_leaving_last_settled_home",
+ "accessibility_requirements_fully_wheelchair_accessible_housing",
+ "accessibility_requirements_wheelchair_access_to_essential_rooms",
+ "accessibility_requirements_level_access_housing",
+ "accessibility_requirements_other_disability_requirements",
+ "accessibility_requirements_no_disability_requirements",
+ "accessibility_requirements_do_not_know",
+ "accessibility_requirements_prefer_not_to_say",
+ "condition_effects_vision",
+ "condition_effects_hearing",
+ "condition_effects_mobility",
+ "condition_effects_dexterity",
+ "condition_effects_stamina",
+ "condition_effects_learning",
+ "condition_effects_memory",
+ "condition_effects_mental_health",
+ "condition_effects_social_or_behavioral",
+ "condition_effects_other",
+ "condition_effects_prefer_not_to_say",
+ "reasonable_preference_reason_homeless",
+ "reasonable_preference_reason_unsatisfactory_housing",
+ "reasonable_preference_reason_medical_grounds",
+ "reasonable_preference_reason_avoid_hardship",
+ "reasonable_preference_reason_do_not_know"
+ ]
+ }
+ },
+ "securitySchemes": {}
+ }
+}
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 000000000..1f0ae16fa
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+OpenAPI DLUHC CORE Data Collection
+
+
+
diff --git a/spec/factories/case_log.rb b/spec/factories/case_log.rb
index a9aa4ab56..044a4cbac 100644
--- a/spec/factories/case_log.rb
+++ b/spec/factories/case_log.rb
@@ -2,14 +2,14 @@ FactoryBot.define do
factory :case_log do
sequence(:id) { |i| i }
trait :in_progress do
- status { 0 }
+ status { 1 }
tenant_code { "TH356" }
property_postcode { "SW2 6HI" }
previous_postcode { "P0 5ST" }
tenant_age { "12" }
end
- trait :submitted do
- status { 1 }
+ trait :completed do
+ status { 2 }
tenant_code { "BZ737" }
property_postcode { "NW1 7TY" }
end
diff --git a/spec/fixtures/complete_case_log.json b/spec/fixtures/complete_case_log.json
index 11f073714..195de85f5 100644
--- a/spec/fixtures/complete_case_log.json
+++ b/spec/fixtures/complete_case_log.json
@@ -38,7 +38,7 @@
"person_8_age": 2,
"person_8_gender": "Prefer not to say",
"person_8_economic_status": "Child under 16",
- "homelessness": "No",
+ "homelessness": "Yes - other homelessness",
"reason_for_leaving_last_settled_home": "Other problems with neighbours",
"benefit_cap_spare_room_subsidy": "No",
"armed_forces_active": "No",
@@ -68,8 +68,8 @@
"property_major_repairs_date": "05/05/2020",
"property_number_of_times_relet": 2,
"property_wheelchair_accessible": true,
- "net_income": 1000,
- "net_income_frequency": "Monthly",
+ "net_income": 0,
+ "net_income_frequency": null,
"net_income_uc_proportion": "Some",
"housing_benefit": "Universal Credit with housing element, but not Housing Benefit",
"rent_frequency": "Weekly",
@@ -89,7 +89,7 @@
"chr_letting": false,
"cap_letting": false,
"outstanding_rent_or_charges": 25,
- "other_reason_for_leaving_last_settled_home": "Other reason",
+ "other_reason_for_leaving_last_settled_home": null,
"accessibility_requirements_fully_wheelchair_accessible_housing": true,
"accessibility_requirements_wheelchair_access_to_essential_rooms": false,
"accessibility_requirements_level_access_housing": false,
@@ -107,7 +107,7 @@
"condition_effects_mental_health": false,
"condition_effects_social_or_behavioral": false,
"condition_effects_other": false,
- "condition_effects_prefer_not_to_say": false,
+ "condition_effects_prefer_not_to_say": true,
"reasonable_preference_reason_homeless": false,
"reasonable_preference_reason_unsatisfactory_housing": false,
"reasonable_preference_reason_medical_grounds": false,
diff --git a/spec/helpers/tasklist_helper_spec.rb b/spec/helpers/tasklist_helper_spec.rb
index 1252f1b66..2d821e3f3 100644
--- a/spec/helpers/tasklist_helper_spec.rb
+++ b/spec/helpers/tasklist_helper_spec.rb
@@ -1,8 +1,9 @@
require "rails_helper"
RSpec.describe TasklistHelper do
- let!(:empty_case_log) { FactoryBot.create(:case_log) }
- let!(:case_log) { FactoryBot.create(:case_log, :in_progress) }
+ let(:empty_case_log) { FactoryBot.build(:case_log) }
+ let(:case_log) { FactoryBot.build(:case_log, :in_progress) }
+ let(:completed_case_log) { FactoryBot.build(:case_log, :completed) }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
@@ -35,7 +36,6 @@ RSpec.describe TasklistHelper do
end
it "returns not started if the subsection is declaration and all the questions are completed" do
- completed_case_log = CaseLog.new(case_log.attributes.map { |key, value| Hash[key, value || "value"] }.reduce(:merge))
status = get_subsection_status("declaration", completed_case_log, declaration_questions)
expect(status).to eq(:not_started)
end
diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb
index 86f4e9d9b..6b1124241 100644
--- a/spec/models/case_log_spec.rb
+++ b/spec/models/case_log_spec.rb
@@ -13,5 +13,82 @@ RSpec.describe Form, type: :model do
it "validates age is over 0" do
expect { CaseLog.create!(tenant_age: 0) }.to raise_error(ActiveRecord::RecordInvalid)
end
+
+ it "validates number of relets is a number" do
+ expect { CaseLog.create!(property_number_of_times_relet: "random") }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "validates number of relets is under 20" do
+ expect { CaseLog.create!(property_number_of_times_relet: 21) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "validates number of relets is over 0" do
+ expect { CaseLog.create!(property_number_of_times_relet: 0) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ describe "reasonable preference validation" do
+ it "if given reasonable preference is yes a reason must be selected" do
+ expect {
+ CaseLog.create!(reasonable_preference: "Yes",
+ reasonable_preference_reason_homeless: nil,
+ reasonable_preference_reason_unsatisfactory_housing: nil,
+ reasonable_preference_reason_medical_grounds: nil,
+ reasonable_preference_reason_avoid_hardship: nil,
+ reasonable_preference_reason_do_not_know: nil
+ )
+ }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "if not previously homeless reasonable preference should not be selected" do
+ expect {
+ CaseLog.create!(
+ homelessness: "No",
+ reasonable_preference: "Yes"
+ )
+ }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "if not given reasonable preference a reason should not be selected" do
+ expect {
+ CaseLog.create!(
+ homelessness: "Yes",
+ reasonable_preference: "No",
+ reasonable_preference_reason_homeless: true
+ )
+ }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+ end
+ context "other reason for leaving last settled home validation" do
+ it "must be provided if main reason for leaving last settled home was given as other" do
+ expect {
+ CaseLog.create!(reason_for_leaving_last_settled_home: "Other",
+ other_reason_for_leaving_last_settled_home: nil)
+ }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "must not be provided if the main reason for leaving settled home is not other" do
+ expect {
+ CaseLog.create!(reason_for_leaving_last_settled_home: "Repossession",
+ other_reason_for_leaving_last_settled_home: "the other reason provided")
+ }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+ end
+ end
+
+ describe "status" do
+ let!(:empty_case_log) { FactoryBot.create(:case_log) }
+ let!(:in_progress_case_log) { FactoryBot.create(:case_log, :in_progress) }
+
+ it "is set to not started for an empty case log" do
+ expect(empty_case_log.not_started?).to be(true)
+ expect(empty_case_log.in_progress?).to be(false)
+ expect(empty_case_log.completed?).to be(false)
+ end
+
+ it "is set to not started for an empty case log" do
+ expect(in_progress_case_log.in_progress?).to be(true)
+ expect(in_progress_case_log.not_started?).to be(false)
+ expect(in_progress_case_log.completed?).to be(false)
+ end
end
end
diff --git a/spec/requests/case_log_controller_spec.rb b/spec/requests/case_log_controller_spec.rb
index cf874bb86..dc67b76e1 100644
--- a/spec/requests/case_log_controller_spec.rb
+++ b/spec/requests/case_log_controller_spec.rb
@@ -1,39 +1,45 @@
require "rails_helper"
RSpec.describe CaseLogsController, type: :request do
+ let(:api_username) { "test_user" }
+ let(:api_password) { "test_password" }
+ let(:basic_credentials) do
+ ActionController::HttpAuthentication::Basic
+ .encode_credentials(api_username, api_password)
+ end
+
+ let(:headers) do
+ {
+ "Content-Type" => "application/json",
+ "Accept" => "application/json",
+ "Authorization" => basic_credentials,
+ }
+ end
+
+ before do
+ allow(ENV).to receive(:[])
+ allow(ENV).to receive(:[]).with("API_USER").and_return(api_username)
+ allow(ENV).to receive(:[]).with("API_KEY").and_return(api_password)
+ end
+
describe "POST #create" do
let(:tenant_code) { "T365" }
let(:tenant_age) { 35 }
+ let(:property_number_of_times_relet) { 12 }
let(:property_postcode) { "SE11 6TY" }
- let(:api_username) { "test_user" }
- let(:api_password) { "test_password" }
- let(:basic_credentials) do
- ActionController::HttpAuthentication::Basic
- .encode_credentials(api_username, api_password)
- end
- let(:in_progress) { "in progress" }
- let(:submitted) { "submitted" }
-
- let(:headers) do
- {
- "Content-Type" => "application/json",
- "Accept" => "application/json",
- "Authorization" => basic_credentials,
- }
- end
+ let(:in_progress) { "in_progress" }
+ let(:completed) { "completed" }
let(:params) do
{
"tenant_code": tenant_code,
"tenant_age": tenant_age,
"property_postcode": property_postcode,
+ "property_number_of_times_relet": property_number_of_times_relet,
}
end
before do
- allow(ENV).to receive(:[])
- allow(ENV).to receive(:[]).with("API_USER").and_return(api_username)
- allow(ENV).to receive(:[]).with("API_KEY").and_return(api_password)
post "/case_logs", headers: headers, params: params.to_json
end
@@ -55,11 +61,12 @@ RSpec.describe CaseLogsController, type: :request do
context "invalid json params" do
let(:tenant_age) { 2000 }
+ let(:property_number_of_times_relet) { 21 }
it "validates case log parameters" do
json_response = JSON.parse(response.body)
expect(response).to have_http_status(:unprocessable_entity)
- expect(json_response["errors"]).to eq(["Tenant age must be between 0 and 120"])
+ expect(json_response["errors"]).to match_array(["Tenant age must be between 0 and 120", "Property number of times relet must be between 0 and 20"])
end
end
@@ -75,9 +82,165 @@ RSpec.describe CaseLogsController, type: :request do
JSON.parse(File.open("spec/fixtures/complete_case_log.json").read)
end
- it "marks the record as submitted" do
+ it "marks the record as completed" do
+ json_response = JSON.parse(response.body)
+ expect(json_response["status"]).to eq(completed)
+ end
+ end
+
+ context "request with invalid credentials" do
+ let(:basic_credentials) do
+ ActionController::HttpAuthentication::Basic.encode_credentials(api_username, "Oops")
+ end
+
+ it "returns 401" do
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+ end
+
+ describe "GET" do
+ let(:case_log) { FactoryBot.create(:case_log, :completed) }
+ let(:id) { case_log.id }
+
+ before do
+ get "/case_logs/#{id}", headers: headers
+ end
+
+ it "returns http success" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns a serialized Case Log" do
+ json_response = JSON.parse(response.body)
+ expect(json_response["status"]).to eq(case_log.status)
+ end
+ end
+
+ describe "PATCH" do
+ let(:case_log) do
+ FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "Old Value")
+ end
+ let(:params) do
+ { tenant_code: "New Value" }
+ end
+ let(:id) { case_log.id }
+
+ before do
+ patch "/case_logs/#{id}", headers: headers, params: params.to_json
+ end
+
+ it "returns http success" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "updates the case log with the given fields and keeps original values where none are passed" do
+ case_log.reload
+ expect(case_log.tenant_code).to eq("New Value")
+ expect(case_log.property_postcode).to eq("Old Value")
+ end
+
+ context "invalid case log id" do
+ let(:id) { (CaseLog.order(:id).last&.id || 0) + 1 }
+
+ it "returns 404" do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context "invalid case log params" do
+ let(:params) { { tenant_age: 200 } }
+
+ it "returns 422" do
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+
+ it "returns an error message" do
json_response = JSON.parse(response.body)
- expect(json_response["status"]).to eq(submitted)
+ expect(json_response["errors"]).to eq(["Tenant age must be between 0 and 120"])
+ end
+ end
+
+ context "request with invalid credentials" do
+ let(:basic_credentials) do
+ ActionController::HttpAuthentication::Basic.encode_credentials(api_username, "Oops")
+ end
+
+ it "returns 401" do
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+ end
+
+ # We don't really have any meaningful distinction between PUT and PATCH here since you can update some or all
+ # fields in both cases, and both route to #Update. Rails generally recommends PATCH as it more closely matches
+ # what actually happens to an ActiveRecord object and what we're doing here, but either is allowed.
+ describe "PUT" do
+ let(:case_log) do
+ FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "Old Value")
+ end
+ let(:params) do
+ { tenant_code: "New Value" }
+ end
+ let(:id) { case_log.id }
+
+ before do
+ put "/case_logs/#{id}", headers: headers, params: params.to_json
+ end
+
+ it "returns http success" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "updates the case log with the given fields and keeps original values where none are passed" do
+ case_log.reload
+ expect(case_log.tenant_code).to eq("New Value")
+ expect(case_log.property_postcode).to eq("Old Value")
+ end
+
+ context "invalid case log id" do
+ let(:id) { (CaseLog.order(:id).last&.id || 0) + 1 }
+
+ it "returns 404" do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context "request with invalid credentials" do
+ let(:basic_credentials) do
+ ActionController::HttpAuthentication::Basic.encode_credentials(api_username, "Oops")
+ end
+
+ it "returns 401" do
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+ end
+
+ describe "DELETE" do
+ let!(:case_log) do
+ FactoryBot.create(:case_log, :in_progress)
+ end
+ let(:id) { case_log.id }
+
+ before do
+ delete "/case_logs/#{id}", headers: headers
+ end
+
+ it "returns http success" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "soft deletes the case log" do
+ expect { CaseLog.find(id) }.to raise_error(ActiveRecord::RecordNotFound)
+ expect(CaseLog.with_discarded.find(id)).to be_a(CaseLog)
+ end
+
+ context "invalid case log id" do
+ let(:id) { (CaseLog.order(:id).last&.id || 0) + 1 }
+
+ it "returns 404" do
+ expect(response).to have_http_status(:not_found)
end
end
diff --git a/spec/views/case_log_index_view_spec.rb b/spec/views/case_log_index_view_spec.rb
index b97347cb6..cc826e3c8 100644
--- a/spec/views/case_log_index_view_spec.rb
+++ b/spec/views/case_log_index_view_spec.rb
@@ -1,12 +1,12 @@
require "rails_helper"
RSpec.describe "case_logs/index" do
let(:in_progress_log) { FactoryBot.build(:case_log, :in_progress) }
- let(:submitted_log) { FactoryBot.build(:case_log, :submitted) }
+ let(:completed_log) { FactoryBot.build(:case_log, :completed) }
context "given an in progress log list" do
it "renders a table for in progress logs only" do
assign(:in_progress_case_logs, [in_progress_log])
- assign(:submitted_case_logs, [])
+ assign(:completed_case_logs, [])
render
expect(rendered).to match(/
/)
expect(rendered).to match(/Logs you need to complete/)
@@ -16,23 +16,23 @@ RSpec.describe "case_logs/index" do
end
end
- context "given a submitted log list" do
+ context "given a completed log list" do
it "renders a table for in progress logs only" do
assign(:in_progress_case_logs, [])
- assign(:submitted_case_logs, [submitted_log])
+ assign(:completed_case_logs, [completed_log])
render
expect(rendered).to match(/
/)
expect(rendered).to match(/Logs you've submitted/)
expect(rendered).not_to match(/Logs you need to complete/)
- expect(rendered).to match(submitted_log.tenant_code)
- expect(rendered).to match(submitted_log.property_postcode)
+ expect(rendered).to match(completed_log.tenant_code)
+ expect(rendered).to match(completed_log.property_postcode)
end
end
- context "given a submitted log list and an in_progress log list" do
+ context "given a completed log list and an in_progress log list" do
it "renders two tables, one for each status" do
assign(:in_progress_case_logs, [in_progress_log])
- assign(:submitted_case_logs, [submitted_log])
+ assign(:completed_case_logs, [completed_log])
render
expect(rendered).to match(/