From 84e97817b0ab0a39616421d00c0f2ee0289e1f3c Mon Sep 17 00:00:00 2001 From: Arthur Campbell Date: Mon, 26 Jun 2023 17:35:35 +0100 Subject: [PATCH] refactor lettings log csv service and all associated tests remove methods on log models when we can call them directly on associated models update job to call the service directly with the collection of logs rather minor modifications to the sales log csv service update many test files to test the appropriate logic in the appropriate place --- app/jobs/email_csv_job.rb | 4 +- app/models/lettings_log.rb | 17 - app/models/log.rb | 6 +- app/services/csv/lettings_log_csv_service.rb | 194 +++--- app/services/csv/sales_log_csv_service.rb | 42 +- .../files/lettings_log_csv_export_codes.csv | 2 + .../files/lettings_log_csv_export_labels.csv | 2 + ...tings_log_csv_export_non_support_codes.csv | 2 + ...ings_log_csv_export_non_support_labels.csv | 2 + .../fixtures/files/lettings_logs_download.csv | 2 - .../lettings_logs_download_codes_only.csv | 2 - .../lettings_logs_download_non_support.csv | 2 - .../files/sales_logs_csv_export_codes.csv | 4 +- .../files/sales_logs_csv_export_labels.csv | 4 +- spec/jobs/email_csv_job_spec.rb | 349 +++++----- spec/models/lettings_log_spec.rb | 109 --- .../csv/lettings_log_csv_service_spec.rb | 619 ++++++------------ .../csv/sales_log_csv_service_spec.rb | 27 +- 18 files changed, 576 insertions(+), 813 deletions(-) create mode 100644 spec/fixtures/files/lettings_log_csv_export_codes.csv create mode 100644 spec/fixtures/files/lettings_log_csv_export_labels.csv create mode 100644 spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv create mode 100644 spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv delete mode 100644 spec/fixtures/files/lettings_logs_download.csv delete mode 100644 spec/fixtures/files/lettings_logs_download_codes_only.csv delete mode 100644 spec/fixtures/files/lettings_logs_download_non_support.csv diff --git a/app/jobs/email_csv_job.rb b/app/jobs/email_csv_job.rb index 426c3430e..31bb5e4b3 100644 --- a/app/jobs/email_csv_job.rb +++ b/app/jobs/email_csv_job.rb @@ -10,7 +10,9 @@ class EmailCsvJob < ApplicationJob when "lettings" unfiltered_logs = organisation.present? && user.support? ? LettingsLog.visible.where(owning_organisation_id: organisation.id) : user.lettings_logs.visible filtered_logs = FilterManager.filter_logs(unfiltered_logs, search_term, filters, all_orgs, user) - csv_string = filtered_logs.to_csv(user, codes_only_export:) + export_type = codes_only_export ? "codes" : "labels" + csv_string = Csv::LettingsLogCsvService.new(user:, export_type:).prepare_csv(filtered_logs) + # csv_string = filtered_logs.to_csv(user, codes_only_export:) when "sales" unfiltered_logs = organisation.present? && user.support? ? SalesLog.visible.where(owning_organisation_id: organisation.id) : user.sales_logs.visible filtered_logs = FilterManager.filter_logs(unfiltered_logs, search_term, filters, all_orgs, user) diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index b1de54bbf..b2f3023a5 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -411,23 +411,6 @@ class LettingsLog < Log managing_organisation&.name end - def created_by_name - created_by&.name - end - - def is_dpo - created_by&.is_dpo - end - - def scheme_code - scheme&.id ? "S#{scheme.id}" : nil - end - - def self.to_csv(user = nil, codes_only_export:) - export_type = codes_only_export ? "codes" : "labels" - Csv::LettingsLogCsvService.new(user, export_type:).to_csv - end - def beds_for_la_rent_range return 0 if is_supported_housing? diff --git a/app/models/log.rb b/app/models/log.rb index d394c0360..55290b3e9 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -172,7 +172,11 @@ class Log < ApplicationRecord end end - def creation_method + def creation_method_code + bulk_uploaded? ? 2 : 1 + end + + def creation_method_label bulk_uploaded? ? "bulk upload" : "single log" end diff --git a/app/services/csv/lettings_log_csv_service.rb b/app/services/csv/lettings_log_csv_service.rb index e8c2815f5..23afa2e5e 100644 --- a/app/services/csv/lettings_log_csv_service.rb +++ b/app/services/csv/lettings_log_csv_service.rb @@ -1,19 +1,30 @@ module Csv class LettingsLogCsvService - CSV_FIELDS_TO_OMIT = %w[hhmemb net_income_value_check first_time_property_let_as_social_housing renttype needstype postcode_known is_la_inferred totchild totelder totadult net_income_known is_carehome previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 rent_type_detail wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old vacdays la prevloc unresolved updated_by_id bulk_upload_id uprn_confirmed status_cache discarded_at].freeze + # CSV_FIELDS_TO_OMIT = %w[hhmemb net_income_value_check first_time_property_let_as_social_housing renttype needstype postcode_known is_la_inferred totchild totelder totadult net_income_known is_carehome previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 rent_type_detail wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old vacdays la prevloc unresolved updated_by_id bulk_upload_id uprn_confirmed status_cache discarded_at].freeze - def initialize(user, export_type:) + def initialize(user:, export_type:) @user = user @export_type = export_type - set_csv_attributes + # set_csv_attributes + @attributes = lettings_log_attributes + end + + def prepare_csv(logs) + CSV.generate(headers: true) do |csv| + csv << @attributes + + logs.find_each do |log| + csv << @attributes.map { |attribute| value(attribute, log) } + end + end end def to_csv CSV.generate(headers: true) do |csv| csv << @attributes - LettingsLog.all.find_each do |record| - csv << @attributes.map { |attribute| get_value(attribute, record) } + LettingsLog.all.find_each do |log| + csv << @attributes.map { |attribute| value(attribute, log) } end end end @@ -21,6 +32,14 @@ module Csv private ATTRIBUTES_OF_RELATED_OBJECTS = { + created_by: { + labels: %i[created_by email], + codes: %i[created_by email], + }, + updated_by: { + labels: %i[updated_by email], + codes: %i[updated_by email], + }, location_code: { labels: %i[location id], codes: %i[location id], @@ -61,7 +80,7 @@ module Csv labels: %i[scheme sensitive], codes: %i[scheme sensitive_before_type_cast], }, - scheme_type: { + SCHTYPE: { labels: %i[scheme scheme_type], codes: %i[scheme scheme_type_before_type_cast], }, @@ -97,37 +116,67 @@ module Csv labels: %i[scheme created_at], codes: %i[scheme created_at], }, + scheme_code: { + labels: %i[scheme id_to_display], + codes: %i[scheme id_to_display], + }, + creation_method: { + labels: %i[creation_method_label], + codes: %i[creation_method_code], + }, + is_dpo: { + labels: %i[created_by is_dpo?], + codes: %i[created_by is_dpo?], + }, }.freeze - def get_value(attribute, record) - attribute = "rent_type" if attribute == "rent_type_detail" # rent_type_detail is the requested column header for rent_type, so as not to confuse with renttype + FIELDS_ALWAYS_EXPORTED_AS_CODES = %w[ + la + prevloc + ].freeze + + FIELDS_ALWAYS_EXPORTED_AS_LABELS = { + "la_label" => "la", + "prevloc_label" => "prevloc", + }.freeze + + DATE_FIELDS = %w[ + mrcdate + startdate + voiddate + created_at + updated_at + ].freeze + + def value(attribute, log) + attribute = "rent_type" if attribute == "rent_type_detail" # rent_type_detail is the requested column header for rent_type, so as not to confuse with renttype. It can be exported as label or code. if ATTRIBUTES_OF_RELATED_OBJECTS.key? attribute.to_sym call_chain = ATTRIBUTES_OF_RELATED_OBJECTS[attribute.to_sym][@export_type.to_sym] - call_chain.reduce(record) { |object, next_call| object&.send(next_call) } - elsif %w[la prevloc].include? attribute # for all exports we output both the codes and labels for these location attributes - record.send(attribute) - elsif %w[la_label prevloc_label].include? attribute # as above - attribute = attribute.remove("_label") - field_value = record.send(attribute) - get_label(field_value, attribute, record) - elsif %w[mrcdate startdate voiddate].include? attribute - record.send(attribute)&.to_formatted_s(:govuk_date) + call_chain.reduce(log) { |object, next_call| object&.public_send(next_call) } + elsif FIELDS_ALWAYS_EXPORTED_AS_CODES.include? attribute + log.public_send(attribute) + elsif FIELDS_ALWAYS_EXPORTED_AS_LABELS.key? attribute + attribute = FIELDS_ALWAYS_EXPORTED_AS_LABELS[attribute] + value = log.public_send(attribute) + get_label(value, attribute, log) + elsif DATE_FIELDS.include? attribute + log.public_send(attribute)&.iso8601 else - field_value = record.send(attribute) + value = log.public_send(attribute) case @export_type when "codes" - field_value + value when "labels" - answer_label = get_label(field_value, attribute, record) - answer_label || label_if_boolean_value(field_value) || field_value + answer_label = get_label(value, attribute, log) + answer_label || label_if_boolean_value(value) || value end end end - def get_label(value, attribute, record) - record.form - .get_question(attribute, record) - &.label_from_value(value) + def get_label(value, attribute, log) + log.form + .get_question(attribute, log) + &.label_from_value(value) end def label_if_boolean_value(value) @@ -135,60 +184,53 @@ module Csv return "No" if value == false end - def set_csv_attributes - metadata_fields = %w[id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year] - metadata_id_fields = %w[managing_organisation_id owning_organisation_id created_by_id bulk_upload_id] - scheme_and_location_ids = %w[scheme_id location_id] - scheme_attributes = %w[scheme_code scheme_service_name scheme_sensitive scheme_type scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at] - location_attributes = %w[location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_admin_district location_startdate] - intersecting_attributes = ordered_form_questions & LettingsLog.attribute_names - scheme_and_location_ids - remaining_attributes = LettingsLog.attribute_names - intersecting_attributes - scheme_and_location_ids - - @attributes = (metadata_fields + intersecting_attributes + remaining_attributes - metadata_id_fields + %w[unittype_sh] + scheme_attributes + location_attributes).uniq - move_la_fields - rename_attributes - - @attributes -= CSV_FIELDS_TO_OMIT if @user.present? && !@user.support? - end - - def ordered_form_questions - downloaded_form_years = LettingsLog.all.map(&:collection_start_year).uniq.compact - - if downloaded_form_years.count == 1 && downloaded_form_years[0].present? - form_name = FormHandler.instance.form_name_from_start_year(downloaded_form_years[0], "lettings") - downloaded_form_fields = FormHandler.instance.get_form(form_name).questions - else - downloaded_form_fields = FormHandler.instance.current_lettings_form.questions - end - move_checkbox_answer_options(downloaded_form_fields) - end - - def move_checkbox_answer_options(form_questions) - checkboxes = form_questions.filter { |question| question.type == "checkbox" }.map { |question| { "#{question.id}": question.answer_options.keys } } - attributes = form_questions.map(&:id).uniq - - checkboxes.each do |checkbox_question| - checkbox_question.values[0].each do |answer_option| - attributes.insert(attributes.find_index(checkbox_question.keys[0].to_s), answer_option) - end - end - attributes - end + ATTRIBUTE_MAPPINGS = { + "owning_organisation_id" => %w[owning_organisation_name], + "managing_organisation_id" => %w[managing_organisation_name], + "created_by_id" => [], + "scheme_id" => [], + "location_id" => [], + "rent_type" => %w[renttype rent_type_detail], + "hb" => %w[hb has_benefits], + "age1" => %w[refused hhtype totchild totelder totadult age1], + "housingneeds_type" => %w[housingneeds_type housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h], + "net_income_known" => %w[net_income_known incref], + "irproduct_other" => %w[irproduct irproduct_other lar], + "la" => %w[is_la_inferred la_label la], + "prevloc" => %w[is_previous_la_inferred prevloc_label prevloc], + "needstype" => %w[needstype lettype], + "prevten" => %w[prevten new_old], + "voiddate" => %w[voiddate vacdays], + "rsnvac" => %w[rsnvac newprop], + "household_charge" => %w[household_charge nocharge], + "brent" => %w[brent wrent], + "scharge" => %w[scharge wscharge], + "pscharge" => %w[pscharge wpschrge], + "supcharg" => %w[supcharg wsupchrg], + "tcharge" => %w[tcharge wtcharge], + "chcharge" => %w[chcharge wchchrg], + "tshortfall" => %w[tshortfall wtshortfall], + }.freeze - def move_la_fields - { la: %w[is_la_inferred la_label], prevloc: %w[is_previous_la_inferred prevloc_label] }.each do |inferred_field, fields| - fields.each do |field| - @attributes.delete(field) - @attributes.insert(@attributes.find_index(inferred_field.to_s), field) + SUPPORT_ONLY_ATTRIBUTES = %w[hhmemb net_income_value_check first_time_property_let_as_social_housing renttype needstype postcode_known is_la_inferred totchild totelder totadult net_income_known is_carehome previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 rent_type_detail wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old vacdays la prevloc updated_by_id bulk_upload_id uprn_confirmed].freeze + + def lettings_log_attributes + ordered_questions = FormHandler.instance.ordered_lettings_questions_for_all_years + # ordered_questions.reject! { |q| q.id.match?(/(_known)|(_check)/) } + attributes = ordered_questions.flat_map do |question| + if question.type == "checkbox" + question.answer_options.keys.reject { |key| key == "divider" } + elsif ATTRIBUTE_MAPPINGS.key? question.id + ATTRIBUTE_MAPPINGS[question.id] + else + question.id end end - end - - def rename_attributes - { "rent_type" => "rent_type_detail" }.each do |original_field, new_field| - @attributes.insert(@attributes.find_index(original_field), new_field) - @attributes.delete(original_field) - end + non_question_fields = %w[id status created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year] + scheme_attributes = %w[scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at] + location_attributes = %w[location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_admin_district location_startdate] + final_attributes = non_question_fields + attributes + scheme_attributes + location_attributes + @user.support? ? final_attributes : final_attributes - SUPPORT_ONLY_ATTRIBUTES end end end diff --git a/app/services/csv/sales_log_csv_service.rb b/app/services/csv/sales_log_csv_service.rb index a9573df41..c8a029c7c 100644 --- a/app/services/csv/sales_log_csv_service.rb +++ b/app/services/csv/sales_log_csv_service.rb @@ -18,12 +18,34 @@ module Csv private ATTRIBUTES_OF_RELATED_OBJECTS = { - day: %i[saledate day], - month: %i[saledate month], - year: %i[saledate year], - is_dpo: %i[created_by is_dpo], - created_by_name: %i[created_by name], - owning_organisation_name: %i[owning_organisation name], + day: { + labels: %i[saledate day], + codes: %i[saledate day], + }, + month: { + labels: %i[saledate month], + codes: %i[saledate month], + }, + year: { + labels: %i[saledate year], + codes: %i[saledate year], + }, + is_dpo: { + labels: %i[created_by is_dpo], + codes: %i[created_by is_dpo], + }, + created_by: { + labels: %i[created_by email], + codes: %i[created_by email], + }, + owning_organisation_name: { + labels: %i[owning_organisation name], + codes: %i[owning_organisation name], + }, + creation_method: { + labels: %i[creation_method_label], + codes: %i[creation_method_code], + }, }.freeze FIELDS_ALWAYS_EXPORTED_AS_CODES = %w[ @@ -43,14 +65,14 @@ module Csv def value(attribute, log) if ATTRIBUTES_OF_RELATED_OBJECTS.key? attribute.to_sym - call_chain = ATTRIBUTES_OF_RELATED_OBJECTS[attribute.to_sym] + call_chain = ATTRIBUTES_OF_RELATED_OBJECTS[attribute.to_sym][@export_type.to_sym] call_chain.reduce(log) { |object, next_call| object&.public_send(next_call) } elsif FIELDS_ALWAYS_EXPORTED_AS_CODES.include? attribute log.send(attribute) elsif FIELDS_ALWAYS_EXPORTED_AS_LABELS.key? attribute attribute = FIELDS_ALWAYS_EXPORTED_AS_LABELS[attribute] - field_value = log.send(attribute) - get_label(field_value, attribute, log) + value = log.send(attribute) + get_label(value, attribute, log) elsif DATE_FIELDS.include? attribute log.send(attribute)&.iso8601 else @@ -84,7 +106,7 @@ module Csv "ppostcode_full" => %w[ppostc1 ppostc2], "la" => %w[la la_label], "prevloc" => %w[prevloc prevloc_label], - "created_by_id" => %w[created_by_name], + "created_by_id" => %w[created_by], "owning_organisation_id" => %w[owning_organisation_name], }.freeze diff --git a/spec/fixtures/files/lettings_log_csv_export_codes.csv b/spec/fixtures/files/lettings_log_csv_export_codes.csv new file mode 100644 index 000000000..6af97bfd6 --- /dev/null +++ b/spec/fixtures/files/lettings_log_csv_export_codes.csv @@ -0,0 +1,2 @@ +id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,rent_value_check,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,age1_known,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,ecstat1,details_known_2,relat2,age2_known,age2,sex2,ecstat2,details_known_3,relat3,age3_known,age3,sex3,ecstat3,details_known_4,relat4,age4_known,age4,sex4,ecstat4,details_known_5,relat5,age5_known,age5,sex5,ecstat5,details_known_6,relat6,age6_known,age6,sex6,ecstat6,details_known_7,relat7,age7_known,age7,sex7,ecstat7,details_known_8,relat8,age8_known,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_unknown,referral,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate +,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-06-26T00:00:00+01:00,2,1,,,,HIJKLMN,ABCDEFG,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,,0,2,6,2,2,7,1,1,3,,,,1,,,3,1,4,,2,,1,2,,0,0,4,0,0,2,35,,F,0,2,13,0,0,P,0,32,M,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,1,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,0,0,68,1,,6,1,1,,0,2,,,,,200.0,100.0,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels.csv b/spec/fixtures/files/lettings_log_csv_export_labels.csv new file mode 100644 index 000000000..f8c7c2a68 --- /dev/null +++ b/spec/fixtures/files/lettings_log_csv_export_labels.csv @@ -0,0 +1,2 @@ +id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,rent_value_check,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,age1_known,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,ecstat1,details_known_2,relat2,age2_known,age2,sex2,ecstat2,details_known_3,relat3,age3_known,age3,sex3,ecstat3,details_known_4,relat4,age4_known,age4,sex4,ecstat4,details_known_5,relat5,age5_known,age5,sex5,ecstat5,details_known_6,relat6,age6_known,age6,sex6,ecstat6,details_known_7,relat7,age7_known,age7,sex7,ecstat7,details_known_8,relat8,age8_known,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_unknown,referral,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate +,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,7,No,2023-06-26T00:00:00+01:00,2,Affordable Rent,,,,HIJKLMN,ABCDEFG,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,,No,Affordable rent basis,Tenant abandoned property,2,2,House,Purpose built,Yes,3,,,,Yes,,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,1,2,,Yes,0,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,Other,Yes,Partner,Yes,32,Male,Not seeking work,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,1,0,0,0,0,0,No,Yes,0,0,1,0,0,0,0,0,0,0,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,0,1,0,0,0,0,0,1,,Tenant applied directly (no referral or nomination),Yes,0,68,Weekly,,Universal Credit housing element,1,All,,0,Every 2 weeks,,,,,200.0,100.0,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv b/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv new file mode 100644 index 000000000..fe74f7793 --- /dev/null +++ b/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv @@ -0,0 +1,2 @@ +id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,collection_start_year,owning_organisation_name,managing_organisation_name,lettype,renewal,startdate,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,address_line1,address_line2,town_or_city,county,postcode_full,la_label,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,refused,age1,sex1,ethnic_group,ethnic,national,ecstat1,relat2,age2,sex2,ecstat2,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,relat7,age7,sex7,ecstat7,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,homeless,ppcodenk,ppostcode_full,prevloc_label,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,referral,incref,earnings,incfreq,hb,has_benefits,benefits,household_charge,nocharge,period,chcharge,wchchrg,carehome_charges_value_check,brent,scharge,pscharge,supcharg,tcharge,hbrentshortfall,tshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate +,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,2023,DLUHC,DLUHC,7,0,2023-06-26T00:00:00+01:00,,,,HIJKLMN,ABCDEFG,0,,fake address,,London,,NW9 5LL,Barnet,2,6,2,2,7,1,1,3,,,1,,,3,1,4,,2,,1,0,35,F,0,2,13,0,P,32,M,6,,,,,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,1,1,TN23 6LZ,Ashford,1,0,1,0,0,0,0,0,1,2,0,68,1,6,1,1,,0,2,,,,200.0,50.0,40.0,35.0,325.0,1,12.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv b/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv new file mode 100644 index 000000000..e3f12834c --- /dev/null +++ b/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv @@ -0,0 +1,2 @@ +id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,collection_start_year,owning_organisation_name,managing_organisation_name,lettype,renewal,startdate,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,address_line1,address_line2,town_or_city,county,postcode_full,la_label,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,refused,age1,sex1,ethnic_group,ethnic,national,ecstat1,relat2,age2,sex2,ecstat2,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,relat7,age7,sex7,ecstat7,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,homeless,ppcodenk,ppostcode_full,prevloc_label,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,referral,incref,earnings,incfreq,hb,has_benefits,benefits,household_charge,nocharge,period,chcharge,wchchrg,carehome_charges_value_check,brent,scharge,pscharge,supcharg,tcharge,hbrentshortfall,tshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate +,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,2023,DLUHC,DLUHC,7,No,2023-06-26T00:00:00+01:00,,,,HIJKLMN,ABCDEFG,No,,fake address,,London,,NW9 5LL,Barnet,Affordable rent basis,Tenant abandoned property,2,2,House,Purpose built,Yes,3,,,Yes,,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,1,0,35,Female,White,Irish,Tenant prefers not to say,Other,Partner,32,Male,Not seeking work,,,,,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,1,0,0,0,0,0,No,Yes,0,0,1,0,0,0,0,0,0,0,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,No,Yes,TN23 6LZ,Ashford,Yes,0,1,0,0,0,0,0,1,Tenant applied directly (no referral or nomination),0,68,Weekly,Universal Credit housing element,1,All,,0,Every 2 weeks,,,,200.0,50.0,40.0,35.0,325.0,Yes,12.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_logs_download.csv b/spec/fixtures/files/lettings_logs_download.csv deleted file mode 100644 index 24568524b..000000000 --- a/spec/fixtures/files/lettings_logs_download.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,uprn,uprn_known,uprn_confirmed,address_line1,address_line2,town_or_city,county,carehome_charges_value_check,status_cache,discarded_at,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate -{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,Supported housing,,2 October 2021,London Affordable Rent,,,,,,,,,,,,,,,,,,,,No,,,,,No,Westminster,E09000033,,SE1 1TE,,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,,,,,,,,,not_started,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate} diff --git a/spec/fixtures/files/lettings_logs_download_codes_only.csv b/spec/fixtures/files/lettings_logs_download_codes_only.csv deleted file mode 100644 index 15d671976..000000000 --- a/spec/fixtures/files/lettings_logs_download_codes_only.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,uprn,uprn_known,uprn_confirmed,address_line1,address_line2,town_or_city,county,carehome_charges_value_check,status_cache,discarded_at,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate -{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,false,DLUHC,DLUHC,2021,2,,2 October 2021,2,,,,,,,,,,,,,,,,,,,,false,,,,,false,Westminster,E09000033,,SE1 1TE,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,,,,,,,,,not_started,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},0,1,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,6,A,Westminster,{location_startdate} diff --git a/spec/fixtures/files/lettings_logs_download_non_support.csv b/spec/fixtures/files/lettings_logs_download_non_support.csv deleted file mode 100644 index c82dfa589..000000000 --- a/spec/fixtures/files/lettings_logs_download_non_support.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,renewal,startdate,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,relat2,age2,sex2,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,prevloc_label,illness_type_1,illness_type_2,la_label,postcode_full,wchair,preg_occ,cbl,earnings,incfreq,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,unitletas,builtype,voiddate,lettype,nocharge,household_charge,referral,tshortfall,chcharge,ppcodenk,ethnic_group,has_benefits,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,uprn,uprn_known,address_line1,address_line2,town_or_city,county,carehome_charges_value_check,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate -{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,,2 October 2021,,,,,,,,,,,,,,,,,,,,,Westminster,SE1 1TE,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,0,,,,,,,0,0,,,,,,,,,,,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate} diff --git a/spec/fixtures/files/sales_logs_csv_export_codes.csv b/spec/fixtures/files/sales_logs_csv_export_codes.csv index 31d964afe..3467917d6 100644 --- a/spec/fixtures/files/sales_logs_csv_export_codes.csv +++ b/spec/fixtures/files/sales_logs_csv_export_codes.csv @@ -1,2 +1,2 @@ -id,status,created_at,updated_at,old_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,created_by_name,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,2023-02-08T00:00:00+00:00,2023-02-08T00:00:00+00:00,,2022,single log,false,DLUHC,Danny Rojas,8,2,2023,,2,8,,,,1,1,2,1,1,0,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,18,1,1,P,35,X,17,,13,1,1,6,C,14,X,9,X,18,X,3,R,40,X,2,R,40,X,1,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 +id,status,created_at,updated_at,old_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,2023-02-08T00:00:00+00:00,2023-02-08T00:00:00+00:00,,2022,1,false,DLUHC,billyboy@eyeklaud.com,8,2,2023,,2,8,,,,1,1,2,1,1,0,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,18,1,1,P,35,X,17,,13,1,1,6,C,14,X,9,X,18,X,3,R,40,X,2,R,40,X,1,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 diff --git a/spec/fixtures/files/sales_logs_csv_export_labels.csv b/spec/fixtures/files/sales_logs_csv_export_labels.csv index aeda373f3..dc0acf9d2 100644 --- a/spec/fixtures/files/sales_logs_csv_export_labels.csv +++ b/spec/fixtures/files/sales_logs_csv_export_labels.csv @@ -1,2 +1,2 @@ -id,status,created_at,updated_at,old_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,created_by_name,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,2023-02-08T00:00:00+00:00,2023-02-08T00:00:00+00:00,,2022,single log,false,DLUHC,Danny Rojas,8,2,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,Yes,,,Address line 1,,Town or city,,SW1A,1AA,Yes,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer 1 prefers not to say,17,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,17,,13,Full-time - 30 hours or more,Yes,6,Child,14,Non-binary,Child under 16,Other,18,Non-binary,"In government training into work, such as New Deal",Person prefers not to say,40,Non-binary,Part-time - Less than 30 hours,Person prefers not to say,40,Non-binary,Full-time - 30 hours or more,Local authority tenant,No,,,No,,,1,1,1,1,,3,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,Don’t know ,No,,Yes,2,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 +id,status,created_at,updated_at,old_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,2023-02-08T00:00:00+00:00,2023-02-08T00:00:00+00:00,,2022,single log,false,DLUHC,billyboy@eyeklaud.com,8,2,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,Yes,,,Address line 1,,Town or city,,SW1A,1AA,Yes,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer 1 prefers not to say,17,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,17,,13,Full-time - 30 hours or more,Yes,6,Child,14,Non-binary,Child under 16,Other,18,Non-binary,"In government training into work, such as New Deal",Person prefers not to say,40,Non-binary,Part-time - Less than 30 hours,Person prefers not to say,40,Non-binary,Full-time - 30 hours or more,Local authority tenant,No,,,No,,,1,1,1,1,,3,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,2,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 diff --git a/spec/jobs/email_csv_job_spec.rb b/spec/jobs/email_csv_job_spec.rb index 40f13e022..28ff97916 100644 --- a/spec/jobs/email_csv_job_spec.rb +++ b/spec/jobs/email_csv_job_spec.rb @@ -7,186 +7,209 @@ describe EmailCsvJob do let(:job) { described_class.new } let(:user) { FactoryBot.create(:user) } - let(:organisation) { user.organisation } - let(:other_organisation) { FactoryBot.create(:organisation) } - let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") } + let(:storage_service) { instance_double(Storage::S3Service) } + let(:mailer) { instance_double(CsvDownloadMailer) } + let(:sales_log_csv_service) { instance_double(Csv::SalesLogCsvService) } + let(:lettings_log_csv_service) { instance_double(Csv::LettingsLogCsvService) } + let(:search_term) { "meaning" } + let(:filters) { { "user" => "yours", "status" => %w[in_progress] } } + let(:all_orgs) { false } + let(:organisation) { build(:organisation) } + let(:codes_only_export) { true } + let(:lettings_logs) { build_list(:lettings_log, 5) } + let(:sales_logs) { build_list(:sales_log, 5) } before do - allow(FormHandler.instance).to receive(:current_lettings_form).and_return(fake_2021_2022_form) + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:write_file) + allow(storage_service).to receive(:get_presigned_url).and_return(test_url) + + allow(Csv::SalesLogCsvService).to receive(:new).and_return(sales_log_csv_service) + allow(sales_log_csv_service).to receive(:prepare_csv).and_return("") + + allow(Csv::LettingsLogCsvService).to receive(:new).and_return(lettings_log_csv_service) + allow(lettings_log_csv_service).to receive(:prepare_csv).and_return("") + + allow(CsvDownloadMailer).to receive(:new).and_return(mailer) + allow(mailer).to receive(:send_csv_download_mail) end - context "when a log exists" do - let!(:lettings_log) do - FactoryBot.create( - :lettings_log, - created_by: user, - ecstat1: 1, - ) + context "when exporting lettings logs" do + before do + allow(FilterManager).to receive(:filter_logs).and_return(lettings_logs) + end + + it "uses an appropriate filename in S3" do + expect(storage_service).to receive(:write_file).with(/lettings-logs-.*\.csv/, anything) + job.perform(user) + end + + it "includes the organisation name in the filename when one is provided" do + expect(storage_service).to receive(:write_file).with(/lettings-logs-#{organisation.name}-.*\.csv/, anything) + job.perform(user, nil, {}, nil, organisation) + end + + it "calls the filter manager with the arguments provided" do + expect(FilterManager).to receive(:filter_logs).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user) + job.perform(user, search_term, filters, all_orgs, organisation, codes_only_export) + end + + it "creates a LettingsLogCsvService with the correct export type" do + expect(Csv::LettingsLogCsvService).to receive(:new).with(user:, export_type: "labels") + codes_only = false + job.perform(user, nil, {}, nil, nil, codes_only, "lettings") + expect(Csv::LettingsLogCsvService).to receive(:new).with(user:, export_type: "codes") + codes_only = true + job.perform(user, nil, {}, nil, nil, codes_only, "lettings") end - let(:storage_service) { instance_double(Storage::S3Service) } - let(:mailer) { instance_double(CsvDownloadMailer) } - let(:sales_log_csv_service) { instance_double(Csv::SalesLogCsvService) } + it "passes the logs returned by the filter manager to the csv service" do + expect(lettings_log_csv_service).to receive(:prepare_csv).with(lettings_logs) + job.perform(user, nil, {}, nil, nil, codes_only_export) + end + end + context "when exporting sales logs" do before do - FactoryBot.create(:lettings_log, - :completed, - created_by: user, - startdate: Time.zone.local(2022, 5, 1), - voiddate: Time.zone.local(2022, 5, 1), - mrcdate: Time.zone.local(2022, 5, 1)) - - allow(Storage::S3Service).to receive(:new).and_return(storage_service) - allow(storage_service).to receive(:write_file) - allow(storage_service).to receive(:get_presigned_url).and_return(test_url) - - allow(Csv::SalesLogCsvService).to receive(:new).and_return(sales_log_csv_service) - allow(sales_log_csv_service).to receive(:prepare_csv).and_return("") - - allow(CsvDownloadMailer).to receive(:new).and_return(mailer) - allow(mailer).to receive(:send_csv_download_mail) + allow(FilterManager).to receive(:filter_logs).and_return(sales_logs) end - context "when exporting lettings logs" do - it "uses an appropriate filename in S3" do - expect(storage_service).to receive(:write_file).with(/lettings-logs-.*\.csv/, anything) - job.perform(user) - end + it "uses an appropriate filename in S3" do + expect(storage_service).to receive(:write_file).with(/sales-logs-.*\.csv/, anything) + job.perform(user, nil, {}, nil, nil, nil, "sales") + end - it "includes the organisation name in the filename when one is provided" do - expect(storage_service).to receive(:write_file).with(/lettings-logs-#{organisation.name}-.*\.csv/, anything) - job.perform(user, nil, {}, nil, organisation) - end + it "includes the organisation name in the filename when one is provided" do + expect(storage_service).to receive(:write_file).with(/sales-logs-#{organisation.name}-.*\.csv/, anything) + job.perform(user, nil, {}, nil, organisation, nil, "sales") end - context "when exporting sales logs" do - it "uses an appropriate filename in S3" do - expect(storage_service).to receive(:write_file).with(/sales-logs-.*\.csv/, anything) - job.perform(user, nil, {}, nil, nil, nil, "sales") - end - - it "includes the organisation name in the filename when one is provided" do - expect(storage_service).to receive(:write_file).with(/sales-logs-#{organisation.name}-.*\.csv/, anything) - job.perform(user, nil, {}, nil, organisation, nil, "sales") - end - - it "creates a SalesLogCsvService with the correct export type" do - expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "labels") - codes_only = false - job.perform(user, nil, {}, nil, nil, codes_only, "sales") - expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "codes") - codes_only = true - job.perform(user, nil, {}, nil, nil, codes_only, "sales") - end + it "calls the filter manager with the arguments provided" do + expect(FilterManager).to receive(:filter_logs).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user) + job.perform(user, search_term, filters, all_orgs, organisation, codes_only_export, "sales") end - it "sends an E-mail with the presigned URL and duration" do - expect(mailer).to receive(:send_csv_download_mail).with(user, test_url, instance_of(Integer)) - job.perform(user) + it "creates a SalesLogCsvService with the correct export type" do + expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "labels") + codes_only = false + job.perform(user, nil, {}, nil, nil, codes_only, "sales") + expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "codes") + codes_only = true + job.perform(user, nil, {}, nil, nil, codes_only, "sales") end - context "when writing to S3" do - before do - FactoryBot.create_list(:lettings_log, 4, owning_organisation: other_organisation) - FactoryBot.create(:lettings_log, owning_organisation: other_organisation, status: "pending", skip_update_status: true) - end - - def expect_csv - expect(storage_service).to receive(:write_file) do |_filename, data| - # Ignore byte order marker - csv = CSV.parse(data[1..]) - yield(csv) - end - end - - it "writes CSV data with headers" do - expect_csv do |csv| - expect(csv.first.first).to eq("id") - expect(csv.second.first).to eq(lettings_log.id.to_s) - end - - job.perform(user) - end - - context "when there is no organisation provided" do - it "only writes logs from the user's organisation" do - expect_csv do |csv| - # Headings + 2 rows - expect(csv.count).to eq(3) - end - - job.perform(user) - end - end - - context "when the user is support and an organisation is provided" do - let(:user) { FactoryBot.create(:user, :support) } - - it "only writes logs from that organisation" do - expect_csv do |csv| - # other organisation => Headings + 4 rows - expect(csv.count).to eq(5) - end - - job.perform(user, nil, {}, nil, other_organisation) - end - end - - it "writes answer labels rather than values" do - expect_csv do |csv| - expect(csv.second[19]).to eq("Full-time – 30 hours or more") - end - - job.perform(user) - end - - it "writes filtered logs" do - expect_csv do |csv| - expect(csv.count).to eq(2) - end - - job.perform(user, nil, { status: "completed" }) - end - - it "writes searched logs" do - expect_csv do |csv| - expect(csv.count).to eq(LettingsLog.search_by(lettings_log.id.to_s).count + 1) - end - - job.perform(user, lettings_log.id.to_s) - end - - context "when both filter and search applied" do - let(:postcode) { "XX1 1TG" } - - before do - FactoryBot.create(:lettings_log, :in_progress, postcode_full: postcode, owning_organisation: organisation, created_by: user) - FactoryBot.create(:lettings_log, :completed, postcode_full: postcode, owning_organisation: organisation, created_by: user) - end - - it "downloads logs matching both csv and filter logs" do - expect_csv do |csv| - expect(csv.count).to eq(2) - end - - job.perform(user, postcode, { status: "completed" }) - end - end - - context "when there are more than 20 logs" do - before do - FactoryBot.create_list(:lettings_log, 26, owning_organisation: organisation) - end - - it "does not paginate, it downloads all the user's logs" do - expect_csv do |csv| - # Heading + 2 + 26 - expect(csv.count).to eq(29) - end - - job.perform(user) - end - end + it "passes the logs returned by the filter manager to the csv service" do + expect(sales_log_csv_service).to receive(:prepare_csv).with(sales_logs) + job.perform(user, nil, {}, nil, nil, codes_only_export, "sales") end end + + it "sends an E-mail with the presigned URL and duration" do + expect(mailer).to receive(:send_csv_download_mail).with(user, test_url, instance_of(Integer)) + job.perform(user) + end + + # context "when writing to S3" do + # before do + # FactoryBot.create_list(:lettings_log, 4, owning_organisation: other_organisation) + # FactoryBot.create(:lettings_log, owning_organisation: other_organisation, status: "pending", skip_update_status: true) + # end + + # def expect_csv + # expect(storage_service).to receive(:write_file) do |_filename, data| + # # Ignore byte order marker + # csv = CSV.parse(data[1..]) + # yield(csv) + # end + # end + + # it "writes CSV data with headers" do + # expect_csv do |csv| + # expect(csv.first.first).to eq("id") + # expect(csv.second.first).to eq(lettings_log.id.to_s) + # end + + # job.perform(user) + # end + + # context "when there is no organisation provided" do + # it "only writes logs from the user's organisation" do + # expect_csv do |csv| + # # Headings + 2 rows + # expect(csv.count).to eq(3) + # end + + # job.perform(user) + # end + # end + + # context "when the user is support and an organisation is provided" do + # let(:user) { FactoryBot.create(:user, :support) } + + # it "only writes logs from that organisation" do + # expect_csv do |csv| + # # other organisation => Headings + 4 rows + # expect(csv.count).to eq(5) + # end + + # job.perform(user, nil, {}, nil, other_organisation) + # end + # end + + # it "writes answer labels rather than values" do + # expect_csv do |csv| + # expect(csv.second[19]).to eq("Full-time – 30 hours or more") + # end + + # job.perform(user) + # end + + # it "writes filtered logs" do + # expect_csv do |csv| + # expect(csv.count).to eq(2) + # end + + # job.perform(user, nil, { status: "completed" }) + # end + + # it "writes searched logs" do + # expect_csv do |csv| + # expect(csv.count).to eq(LettingsLog.search_by(lettings_log.id.to_s).count + 1) + # end + + # job.perform(user, lettings_log.id.to_s) + # end + + # context "when both filter and search applied" do + # let(:postcode) { "XX1 1TG" } + + # before do + # FactoryBot.create(:lettings_log, :in_progress, postcode_full: postcode, owning_organisation: organisation, created_by: user) + # FactoryBot.create(:lettings_log, :completed, postcode_full: postcode, owning_organisation: organisation, created_by: user) + # end + + # it "downloads logs matching both csv and filter logs" do + # expect_csv do |csv| + # expect(csv.count).to eq(2) + # end + + # job.perform(user, postcode, { status: "completed" }) + # end + # end + + # context "when there are more than 20 logs" do + # before do + # FactoryBot.create_list(:lettings_log, 26, owning_organisation: organisation) + # end + + # it "does not paginate, it downloads all the user's logs" do + # expect_csv do |csv| + # # Heading + 2 + 26 + # expect(csv.count).to eq(29) + # end + + # job.perform(user) + # end + # end + # end end diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index 74abfd3c2..0365ee04f 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -2857,115 +2857,6 @@ RSpec.describe LettingsLog do end end - describe "csv download" do - let(:scheme) { create(:scheme) } - let(:location) do - create( - :location, - :export, - scheme:, - type_of_unit: 6, - postcode: "SE11TE", - startdate: Time.zone.local(2021, 10, 1), - ) - end - let(:user) { create(:user, organisation: location.scheme.owning_organisation) } - let(:expected_content) { csv_export_file.read } - - after do - Timecop.unfreeze - end - - context "with values represented as human readable labels" do - before do - Timecop.freeze(Time.utc(2022, 6, 5)) - lettings_log = FactoryBot.create( - :lettings_log, - needstype: 2, - scheme:, - location:, - owning_organisation: scheme.owning_organisation, - created_by: user, - rent_type: 2, - startdate: Time.zone.local(2021, 10, 2), - created_at: Time.zone.local(2022, 2, 8, 16, 52, 15), - updated_at: Time.zone.local(2022, 2, 8, 16, 52, 15), - ) - expected_content.sub!(/\{id\}/, lettings_log["id"].to_s) - expected_content.sub!(/\{scheme_code\}/, "S#{scheme['id']}") - expected_content.sub!(/\{scheme_service_name\}/, scheme["service_name"].to_s) - expected_content.sub!(/\{scheme_sensitive\}/, scheme["sensitive"].to_s) - expected_content.sub!(/\{scheme_primary_client_group\}/, scheme["primary_client_group"].to_s) - expected_content.sub!(/\{scheme_secondary_client_group\}/, scheme["secondary_client_group"].to_s) - expected_content.sub!(/\{scheme_support_type\}/, scheme["support_type"].to_s) - expected_content.sub!(/\{scheme_intended_stay\}/, scheme["intended_stay"].to_s) - expected_content.sub!(/\{location_code\}/, location["id"].to_s) - expected_content.sub!(/\{location_startdate\}/, location["startdate"].to_s) - expected_content.sub!(/\{scheme_id\}/, scheme["service_name"].to_s) - expected_content.sub!(/\{location_id\}/, location["id"].to_s) - end - - around do |example| - Timecop.freeze(Time.zone.local(2022, 6, 5)) do - Singleton.__init__(FormHandler) - example.run - end - Timecop.return - Singleton.__init__(FormHandler) - end - - context "with a support user" do - let(:csv_export_file) { File.open("spec/fixtures/files/lettings_logs_download.csv", "r:UTF-8") } - - it "generates a correct csv from a lettings log" do - expect(described_class.to_csv(codes_only_export: false)).to eq(expected_content) - end - end - - context "with a non support user" do - let(:csv_export_file) { File.open("spec/fixtures/files/lettings_logs_download_non_support.csv", "r:UTF-8") } - - it "generates a correct csv from a lettings log" do - expect(described_class.to_csv(user, codes_only_export: false)).to eq(expected_content) - end - end - end - - context "with values represented as codes" do - before do - Timecop.freeze(Time.utc(2022, 6, 5)) - lettings_log = FactoryBot.create(:lettings_log, needstype: 2, scheme:, location:, owning_organisation: scheme.owning_organisation, created_by: user, rent_type: 2, startdate: Time.zone.local(2021, 10, 2), created_at: Time.zone.local(2022, 2, 8, 16, 52, 15), updated_at: Time.zone.local(2022, 2, 8, 16, 52, 15)) - expected_content.sub!(/\{id\}/, lettings_log["id"].to_s) - expected_content.sub!(/\{scheme_code\}/, "S#{scheme.id}") - expected_content.sub!(/\{scheme_service_name\}/, scheme.service_name.to_s) - expected_content.sub!(/\{scheme_sensitive\}/, scheme.sensitive_before_type_cast.to_s) - expected_content.sub!(/\{scheme_primary_client_group\}/, scheme.primary_client_group_before_type_cast.to_s) - expected_content.sub!(/\{scheme_secondary_client_group\}/, scheme.secondary_client_group_before_type_cast.to_s) - expected_content.sub!(/\{scheme_support_type\}/, scheme.support_type_before_type_cast.to_s) - expected_content.sub!(/\{scheme_intended_stay\}/, scheme.intended_stay_before_type_cast.to_s) - expected_content.sub!(/\{location_code\}/, location.id.to_s) - expected_content.sub!(/\{location_startdate\}/, location.startdate.to_s) - expected_content.sub!(/\{scheme_id\}/, scheme.service_name.to_s) - expected_content.sub!(/\{location_id\}/, location.id.to_s) - end - - let(:csv_export_file) { File.open("spec/fixtures/files/lettings_logs_download_codes_only.csv", "r:UTF-8") } - - around do |example| - Timecop.freeze(Time.zone.local(2022, 6, 5)) do - Singleton.__init__(FormHandler) - example.run - end - Timecop.return - Singleton.__init__(FormHandler) - end - - it "generates a correct csv from a lettings log" do - expect(described_class.to_csv(codes_only_export: true)).to eq(expected_content) - end - end - end - describe "#blank_invalid_non_setup_fields!" do context "when a setup field is invalid" do subject(:model) { described_class.new(needstype: 404) } diff --git a/spec/services/csv/lettings_log_csv_service_spec.rb b/spec/services/csv/lettings_log_csv_service_spec.rb index 04d52065d..9379a9f43 100644 --- a/spec/services/csv/lettings_log_csv_service_spec.rb +++ b/spec/services/csv/lettings_log_csv_service_spec.rb @@ -1,430 +1,221 @@ require "rails_helper" RSpec.describe Csv::LettingsLogCsvService do - context "when the user is support" do - let(:user) { create(:user, :support) } - let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") } + let(:form_handler_mock) { instance_double(FormHandler) } + let(:organisation) { create(:organisation) } + let(:log) do + create( + :lettings_log, + :completed, + propcode: "ABCDEFG", + tenancycode: "HIJKLMN", + postcode_full: "NW9 5LL", + ppostcode_full: "TN23 6LZ", + created_by: user, + managing_organisation: organisation, + ) + end + let(:user) { create(:user, :support, email: "s.port@jeemayle.com") } + let(:service) { described_class.new(user:, export_type:) } + let(:export_type) { "labels" } + let(:csv) { CSV.parse(service.prepare_csv(LettingsLog.where(id: logs.map(&:id)))) } + let(:logs) { [log] } + let(:headers) { csv.first } + + it "calls the form handler to get all questions in order when initialized" do + allow(FormHandler).to receive(:instance).and_return(form_handler_mock) + allow(form_handler_mock).to receive(:ordered_lettings_questions_for_all_years).and_return([]) + service + expect(form_handler_mock).to have_received(:ordered_lettings_questions_for_all_years) + end + + it "returns a string" do + result = service.prepare_csv(LettingsLog.all) + expect(result).to be_a String + end + + it "returns a csv with headers" do + expect(csv.first.first).to eq "id" + end + + context "when stubbing :ordered_lettings_questions_for_all_years" do + let(:lettings_form) do + FormFactory.new(year: 2050, type: "lettings") + .with_sections([build(:section, :with_questions, question_ids:, questions:)]) + .build + end + let(:question_ids) { nil } + let(:questions) { nil } before do - LettingsLog.create!(startdate: Time.zone.today, created_at: Time.utc(2022, 2, 8, 16, 52, 15)) - allow(FormHandler.instance).to receive(:get_form).and_return(real_2021_2022_form) + allow(FormHandler).to receive(:instance).and_return(form_handler_mock) + allow(form_handler_mock).to receive(:form_name_from_start_year) + allow(form_handler_mock).to receive(:get_form).and_return(lettings_form) + allow(form_handler_mock).to receive(:ordered_lettings_questions_for_all_years).and_return(lettings_form.questions) + allow(form_handler_mock).to receive(:lettings_in_crossover_period?).and_return false + end + + context "when it returns questions with particular ids" do + let(:question_ids) { %w[prevten startdate brent rent_type] } + + it "includes log attributes related to questions to the headers" do + expect(headers).to include(*question_ids.first(3)) + end + + it "removes some log attributes related to questions from the headers and replaces them with their derived values in the correct order" do + expect(headers).not_to include "rent_type" + expect(headers).to include(*%w[wrent renttype rent_type_detail]) + end end - it "sets csv attributes in correct order" do - expected_csv_attributes = %w[ - id - status - created_at - updated_at - created_by_name - is_dpo - owning_organisation_name - managing_organisation_name - collection_start_year - needstype - renewal - startdate - rent_type_detail - irproduct_other - tenancycode - propcode - postcode_known - postcode_full - is_la_inferred - la_label - la - first_time_property_let_as_social_housing - unitletas - rsnvac - offered - unittype_gn - builtype - wchair - beds - voiddate - void_date_value_check - majorrepairs - mrcdate - major_repairs_date_value_check - startertenancy - tenancy - tenancyother - tenancylength - sheltered - declaration - hhmemb - pregnancy_value_check - age1_known - age1 - sex1 - ethnic_group - ethnic - national - ecstat1 - retirement_value_check - details_known_2 - relat2 - age2_known - age2 - sex2 - ecstat2 - details_known_3 - relat3 - age3_known - age3 - sex3 - ecstat3 - details_known_4 - relat4 - age4_known - age4 - sex4 - ecstat4 - details_known_5 - relat5 - age5_known - age5 - sex5 - ecstat5 - details_known_6 - relat6 - age6_known - age6 - sex6 - ecstat6 - details_known_7 - relat7 - age7_known - age7 - sex7 - ecstat7 - details_known_8 - relat8 - age8_known - age8 - sex8 - ecstat8 - armedforces - leftreg - reservist - preg_occ - housingneeds - housingneeds_type - housingneeds_other - illness - illness_type_4 - illness_type_5 - illness_type_2 - illness_type_6 - illness_type_7 - illness_type_3 - illness_type_9 - illness_type_8 - illness_type_1 - illness_type_10 - layear - waityear - reason - reasonother - prevten - underoccupation_benefitcap - homeless - ppcodenk - ppostcode_full - previous_la_known - is_previous_la_inferred - prevloc_label - prevloc - reasonpref - rp_homeless - rp_insan_unsat - rp_medwel - rp_hardship - rp_dontknow - cbl - cap - chr - letting_allocation_unknown - referral - net_income_known - earnings - incfreq - net_income_value_check - hb - benefits - household_charge - period - is_carehome - chcharge - carehome_charges_value_check - brent - scharge - pscharge - supcharg - tcharge - rent_value_check - hbrentshortfall - tshortfall_known - tshortfall - housingneeds_a - housingneeds_b - housingneeds_c - housingneeds_f - housingneeds_g - housingneeds_h - property_owner_organisation - property_manager_organisation - purchaser_code - property_relet - incref - renttype - lettype - totchild - totelder - totadult - nocharge - has_benefits - wrent - wscharge - wpschrge - wsupchrg - wtcharge - wtshortfall - refused - wchchrg - newprop - old_form_id - lar - irproduct - old_id - joint - hhtype - new_old - vacdays - unresolved - updated_by_id - uprn - uprn_known - uprn_confirmed - address_line1 - address_line2 - town_or_city - county - status_cache - discarded_at - unittype_sh - scheme_code - scheme_service_name - scheme_sensitive - scheme_type - scheme_registered_under_care_act - scheme_owning_organisation_name - scheme_primary_client_group - scheme_has_other_client_group - scheme_secondary_client_group - scheme_support_type - scheme_intended_stay - scheme_created_at - location_code - location_postcode - location_name - location_units - location_type_of_unit - location_mobility_type - location_admin_district - location_startdate - ] - - csv = CSV.parse(described_class.new(user, export_type: "labels").to_csv) - - expect(csv.first).to eq(expected_csv_attributes) + context "when it returns checkbox questions" do + let(:questions) do + [ + build(:question, id: "condition_effects", type: "checkbox", answer_options: { "illness_type_1" => {}, "illness_type_2" => {}, "illness_type_3" => {} }), + build(:question, id: "letting_allocation", type: "checkbox", answer_options: { "cbl" => {}, "cap" => {}, "chr" => {} }), + ] + end + + it "does not add the id of the checkbox question to the headers" do + question_ids = questions.map(&:id) + expect(headers).not_to include(*question_ids) + end + + it "adds the related log attributes from the answer options to the headers" do + log_attributes = questions.flat_map { |q| q.answer_options.keys } + expect(headers).to include(*log_attributes) + end end end - context "when the user is not support" do - let(:user) { FactoryBot.create(:user) } - let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") } + it "adds log attributes not related to questions to the headers" do + expect(headers.first(5)).to eq %w[id status created_by is_dpo created_at] + end - before do - LettingsLog.create!(startdate: Time.zone.today, created_at: Time.utc(2022, 2, 8, 16, 52, 15)) - allow(FormHandler.instance).to receive(:get_form).and_return(real_2021_2022_form) + it "adds attributes related to associated schemes and locations to the headers" do + expect(headers).to include(*%w[scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act]) + expect(headers.last(5)).to eq %w[location_units location_type_of_unit location_mobility_type location_admin_district location_startdate] + end + + context "when there are many logs" do + let(:logs) { create_list(:lettings_log, log_count) } + let(:log_count) { 30 } + + it "creates a CSV with the correct number of logs" do + expected_row_count_with_headers = log_count + 1 + expect(csv.size).to be expected_row_count_with_headers + end + end + + context "when exporting with human readable labels" do + let(:export_type) { "labels" } + + it "gives answer to radio questions as labels" do + relat2_column_index = csv.first.index("relat2") + relat2_value = csv.second[relat2_column_index] + expect(relat2_value).to eq "Partner" + end + + it "gives answers to free input questions as the user input" do + age1_column_index = csv.first.index("age1") + age1_value = csv.second[age1_column_index] + expect(age1_value).to eq 35.to_s end - it "sets csv attributes in correct order and without omitted values" do - expected_csv_attributes = %w[ - id - status - created_at - updated_at - created_by_name - is_dpo - owning_organisation_name - managing_organisation_name - collection_start_year - renewal - startdate - irproduct_other - tenancycode - propcode - postcode_full - la_label - unitletas - rsnvac - offered - unittype_gn - builtype - wchair - beds - voiddate - void_date_value_check - majorrepairs - mrcdate - major_repairs_date_value_check - startertenancy - tenancy - tenancyother - tenancylength - sheltered - declaration - age1 - sex1 - ethnic_group - ethnic - national - ecstat1 - relat2 - age2 - sex2 - ecstat2 - relat3 - age3 - sex3 - ecstat3 - relat4 - age4 - sex4 - ecstat4 - relat5 - age5 - sex5 - ecstat5 - relat6 - age6 - sex6 - ecstat6 - relat7 - age7 - sex7 - ecstat7 - relat8 - age8 - sex8 - ecstat8 - armedforces - leftreg - reservist - preg_occ - housingneeds - housingneeds_type - housingneeds_other - illness - illness_type_4 - illness_type_5 - illness_type_2 - illness_type_6 - illness_type_7 - illness_type_3 - illness_type_9 - illness_type_8 - illness_type_1 - illness_type_10 - layear - waityear - reason - reasonother - prevten - underoccupation_benefitcap - homeless - ppcodenk - ppostcode_full - prevloc_label - reasonpref - rp_homeless - rp_insan_unsat - rp_medwel - rp_hardship - rp_dontknow - cbl - cap - chr - referral - earnings - incfreq - hb - benefits - household_charge - period - chcharge - carehome_charges_value_check - brent - scharge - pscharge - supcharg - tcharge - hbrentshortfall - tshortfall - housingneeds_a - housingneeds_b - housingneeds_c - housingneeds_f - housingneeds_g - housingneeds_h - property_owner_organisation - property_manager_organisation - purchaser_code - property_relet - incref - lettype - nocharge - has_benefits - refused - wchchrg - newprop - lar - irproduct - joint - uprn - uprn_known - address_line1 - address_line2 - town_or_city - county - unittype_sh - scheme_code - scheme_service_name - scheme_sensitive - scheme_type - scheme_registered_under_care_act - scheme_owning_organisation_name - scheme_primary_client_group - scheme_has_other_client_group - scheme_secondary_client_group - scheme_support_type - scheme_intended_stay - scheme_created_at - location_code - location_postcode - location_name - location_units - location_type_of_unit - location_mobility_type - location_admin_district - location_startdate - ] - - csv = CSV.parse(described_class.new(user, export_type: "labels").to_csv) - - expect(csv.first).to eq(expected_csv_attributes) + it "exports the code for the local authority under the heading 'la'" do + la_column_index = csv.first.index("la") + la_value = csv.second[la_column_index] + expect(la_value).to eq "E09000003" + end + + it "exports the label for the local authority under the heading 'la_label'" do + la_label_column_index = csv.first.index("la_label") + la_label_value = csv.second[la_label_column_index] + expect(la_label_value).to eq "Barnet" + end + + it "exports the CSV with all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_labels.csv") + values_to_delete = %w[id mrcdate voiddate vacdays] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end + end + + context "when exporting as codes" do + let(:export_type) { "codes" } + + it "gives answer to radio questions as labels" do + relat2_column_index = csv.first.index("relat2") + relat2_value = csv.second[relat2_column_index] + expect(relat2_value).to eq "P" + end + + it "gives answers to free input questions as the user input" do + age1_column_index = csv.first.index("age1") + age1_value = csv.second[age1_column_index] + expect(age1_value).to eq 35.to_s + end + + it "exports the code for the local authority under the heading 'la'" do + la_column_index = csv.first.index("la") + la_value = csv.second[la_column_index] + expect(la_value).to eq "E09000003" + end + + it "exports the label for the local authority under the heading 'la_label'" do + la_label_column_index = csv.first.index("la_label") + la_label_value = csv.second[la_label_column_index] + expect(la_label_value).to eq "Barnet" + end + + it "exports the CSV with all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_codes.csv") + values_to_delete = %w[id mrcdate voiddate vacdays] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end + end + + context "when the user is not a support user" do + let(:user) { create(:user, email: "choreographer@owtluk.com") } + + it "does not include certain attributes in the headers" do + expect(headers).not_to include(*%w[rent_type_detail wrent wscharge wpschrge wsupchrg wtcharge]) + end + + context "and exporting with labels" do + let(:export_type) { "labels" } + + it "exports the CSV with all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv") + values_to_delete = %w[id mrcdate voiddate] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end + end + + context "and exporting values as codes" do + let(:export_type) { "codes" } + + it "exports the CSV with all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv") + values_to_delete = %w[id mrcdate voiddate] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end end end end diff --git a/spec/services/csv/sales_log_csv_service_spec.rb b/spec/services/csv/sales_log_csv_service_spec.rb index 2c24bf7b1..d1a10db86 100644 --- a/spec/services/csv/sales_log_csv_service_spec.rb +++ b/spec/services/csv/sales_log_csv_service_spec.rb @@ -3,23 +3,27 @@ require "rails_helper" RSpec.describe Csv::SalesLogCsvService do let(:form_handler_mock) { instance_double(FormHandler) } let(:organisation) { create(:organisation) } - let!(:log) { create(:sales_log, :completed, owning_organisation: organisation, purchid: nil) } + let(:fixed_time) { Time.zone.local(2023, 2, 8) } + let(:user) { create(:user, email: "billyboy@eyeKLAUD.com") } + let!(:log) do + create( + :sales_log, + :completed, + created_by: user, + saledate: fixed_time, + created_at: fixed_time, + updated_at: fixed_time, + owning_organisation: organisation, + purchid: nil + ) + end let(:service) { described_class.new(export_type: "labels") } let(:csv) { CSV.parse(service.prepare_csv(SalesLog.all)) } - around do |example| - Timecop.freeze(Time.utc(2023, 2, 8)) do - Singleton.__init__(FormHandler) - example.run - end - Timecop.return - Singleton.__init__(FormHandler) - end - it "calls the form handler to get all questions in order when initialized" do allow(FormHandler).to receive(:instance).and_return(form_handler_mock) allow(form_handler_mock).to receive(:ordered_sales_questions_for_all_years).and_return([]) - described_class.new(export_type: "codes") + service expect(form_handler_mock).to have_received(:ordered_sales_questions_for_all_years) end @@ -30,7 +34,6 @@ RSpec.describe Csv::SalesLogCsvService do it "returns a csv with headers" do expect(csv.first.first).to eq "id" - expect(csv.second.first).not_to be log.id.to_s end context "when stubbing :ordered_sales_questions_for_all_years" do