Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Migration DGFIP #675

Merged
merged 40 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3fec9f2
AuthorizationRequest::APIImpotParticulier does not need presence vali…
skelz0r Jan 7, 2025
716fba7
Authorization.validated relies on revoked boolean
skelz0r Jan 22, 2025
807475e
Harden revoked trait
skelz0r Feb 4, 2025
671b325
Migration: old unused exclude reopenings
skelz0r Jan 29, 2025
dc82136
Migration: Enhance Import::AuthorizationRequests classes methods
skelz0r Jan 7, 2025
0006e7b
Migration: enhance debugging by putting enrollment status
skelz0r Jan 7, 2025
a2b380a
Migration: Introduce Import::AuthorizationRequests::APIImpotParticuli…
skelz0r Jan 7, 2025
97ac460
Migration: wip main scripts
skelz0r Jan 7, 2025
a22cc57
Migration: Introduce Import::AuthorizationRequests::APIImpotParticuli…
skelz0r Jan 8, 2025
697f838
Migration: print skipped while loading
skelz0r Jan 15, 2025
ab7c887
Migration: Harden Import::AuthorizationRequests classes
skelz0r Jan 15, 2025
2486f85
Migration: Introduce Import::AuthorizationRequests::FranceConnectAttr…
skelz0r Jan 15, 2025
cc12619
Migration: FC no eidas => eidas 1
skelz0r Jan 21, 2025
dad4a0a
Migration: Harden Import::AuthorizationRequests organization build
skelz0r Jan 21, 2025
000f375
Migration: add disclaimer on reopening authorizations for invalid req…
skelz0r Jan 21, 2025
e79ff0c
Migration: harden imports on rows warn/skip
skelz0r Jan 22, 2025
b5d45e4
Migration: enhance imports for specific authorizations
skelz0r Jan 22, 2025
043a335
Migration: can skip validation on skipped rows and save anyway
skelz0r Jan 22, 2025
576e4b3
Migration: Harden Import::AuthorizationRequestEvents#find_closest_aut…
skelz0r Jan 22, 2025
b6b66a9
Migration: harden FC linked
skelz0r Jan 22, 2025
390f98a
Migration: clean
skelz0r Jan 22, 2025
840efe3
Migration: create approve events with authorizations within authoriza…
skelz0r Jan 22, 2025
0f8b982
Migration: wip main script
skelz0r Jan 21, 2025
8c5e45c
Migration: can load extra sql
skelz0r Jan 21, 2025
b9630ba
Migration: wip main scripts
skelz0r Jan 29, 2025
fabfc68
Migration: APIRialSandbox
skelz0r Jan 29, 2025
bef5da9
Migration: API CPR Adelie
skelz0r Jan 29, 2025
7445503
Migration: API Rial
skelz0r Jan 29, 2025
00c5d5e
Migration: APIEContacts
skelz0r Jan 29, 2025
ee55587
Migration: APIEPro
skelz0r Jan 29, 2025
4ae7ef1
Migration: APIENSUDocuments
skelz0r Jan 29, 2025
ff509eb
Migration: do not import validated production with more recent validated
skelz0r Jan 29, 2025
db19f73
Migration: API Hermes
skelz0r Jan 29, 2025
9e9cf9b
Migration: APIImprimfip
skelz0r Jan 29, 2025
0fbe701
Migration: API Mire / AI Ofci
skelz0r Jan 29, 2025
88b693a
Migration: API Opale
skelz0r Jan 29, 2025
245dce1
Migration: API Robf
skelz0r Jan 29, 2025
a9cd161
Migration: API Satelit
skelz0r Jan 29, 2025
f77bc60
Migration: WIP
skelz0r Jan 29, 2025
fa28a63
Update brakeman
skelz0r Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions app/migration/import/authorization_request_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Import::AuthorizationRequestEvents < Import::Base
include UserLegacyUtils

def extract(event_row)
authorization_request = AuthorizationRequest.find(event_row['enrollment_id'])
authorization_request = options[:authorization_request] || AuthorizationRequest.find(event_row['enrollment_id'])

case event_row['name']
when 'create'
Expand Down Expand Up @@ -50,6 +50,8 @@ def extract(event_row)
authorization_request.update!(last_submitted_at: event_created_at)
end
when 'approve', 'validate'
return if options[:create_from_authorization_request_import].blank? && authorization_request.type == 'AuthorizationRequest::FranceConnect'

authorization_request.update(
last_validated_at: event_row['created_at'],
)
Expand Down Expand Up @@ -156,8 +158,11 @@ def create_authorization(event_row, authorization_request)
end

def find_closest_authorization(event_row, authorization_request)
event_created_at_as_datetime = DateTime.parse(event_row['created_at'])

Authorization.where(
request_id: authorization_request.id
request_id: authorization_request.id,
created_at: (event_created_at_as_datetime-10.seconds..event_created_at_as_datetime+10.seconds),
).order(created_at: :desc).first
end

Expand Down
125 changes: 101 additions & 24 deletions app/migration/import/authorization_requests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ def extract(enrollment_row)
authorization_request.applicant = user
authorization_request.organization_id = fetch_organization(user, enrollment_row).try(:id)

authorization_request.form_uid = fetch_form(authorization_request).id
authorization_request.form_uid ||= fetch_form(authorization_request).try(:id)
authorization_request.state = enrollment_row['status']
authorization_request.external_provider_id = enrollment_row['external_provider_id']
authorization_request.copied_from_request = AuthorizationRequest.find(enrollment_row['copied_from_enrollment_id']) if enrollment_row['copied_from_enrollment_id'] && AuthorizationRequest.exists?(enrollment_row['copied_from_enrollment_id'])
authorization_request.last_validated_at = enrollment_row['last_validated_at']
# FIXME to delete, will use raw data anyway
# authorization_request.copied_from_request = AuthorizationRequest.find(enrollment_row['copied_from_enrollment_id']) if enrollment_row['copied_from_enrollment_id'] && AuthorizationRequest.exists?(enrollment_row['copied_from_enrollment_id'])

if authorization_request.state != 'draft'
authorization_request.assign_attributes(
Expand All @@ -28,23 +30,35 @@ def extract(enrollment_row)
)
end

handle_authorization_request_type_specific_fields(authorization_request, enrollment_row)
authorization_request = handle_authorization_request_type_specific_fields(authorization_request, enrollment_row)

begin
authorization_request.save!
after_save_authorization_request(authorization_request, enrollment_row)
@models << authorization_request
rescue ActiveRecord::RecordInvalid => e
log("DataPass: https://datapass.api.gouv.fr/#{enrollment_row['target_api'].gsub('_', '-')}/#{enrollment_row['id']}")
log("DataPass: https://datapass.api.gouv.fr/#{enrollment_row['target_api'].gsub('_', '-')}/#{enrollment_row['id']} (status: #{enrollment_row['status']})")
log("Errors: #{authorization_request.errors.full_messages.join("\n")}")

byebug
rescue ActiveStorage::IntegrityError => e
byebug
ensure
($dummy_files || {}).each do |key, value|
value.close
end
$dummy_files = nil
end
end

private

def after_save_authorization_request(authorization_request, enrollment_row)
return unless @authorization_request_type_specific_field_builder.respond_to?(:after_save)

@authorization_request_type_specific_field_builder.after_save(authorization_request, enrollment_row)
end

def sql_tables_to_save
super.concat(
%w[
Expand Down Expand Up @@ -86,21 +100,37 @@ def fetch_organization(user, enrollment_row)
end

new_potential_siret = {
# PM => DINUM
'11000101300017' => '13002526500013',
# Agence de la recherche fermée
'13000250400020' => '13000250400038',
# DRJSCS => DREETS
'13001252900017' => '13002921800018',
# Recia
'18450311800020' => '12002503600035',
# Port de strasbourg
'77564141800014' => '77564141800089',
# # PM => DINUM
# '11000101300017' => '13002526500013',
# # Agence de la recherche fermée
# '13000250400020' => '13000250400038',
# # DRJSCS => DREETS
# '13001252900017' => '13002921800018',
# # Recia
# '18450311800020' => '12002503600035',
# # Port de strasbourg
# '77564141800014' => '77564141800089',
}[enrollment_row['siret']]

return if new_potential_siret.blank?
if new_potential_siret.present?
user.organizations.find_by(siret: new_potential_siret)
else
organization = build_organization(enrollment_row['siret'])

begin
organization.save!
rescue ActiveRecord::RecordInvalid => e
if e.record.errors.include?(:siret)
raise Import::AuthorizationRequests::Base::SkipRow.new(:invalid_siret_for_unknown_user_and_organization, id: enrollment_row['id'], target_api: enrollment_row['target_api'], authorization_request: e.record)
else
raise
end
end

user.organizations << organization

user.organizations.find_by(siret: new_potential_siret)
organization
end
end

def authorization_ids_where_user_belongs_to_organization
Expand Down Expand Up @@ -138,16 +168,13 @@ def try_to_create_user!(enrollment_row, demandeur)
)
)

organization = Organization.find_or_initialize_by(siret: enrollment_row['siret'])
organization.assign_attributes(
mon_compte_pro_payload: { siret: enrollment_row['siret'], manual_creation: true },
last_mon_compte_pro_updated_at: DateTime.now,
)
organization = build_organization(enrollment_row['siret'])

begin
organization.save!
rescue ActiveRecord::RecordInvalid => e
if e.record.errors.include?(:siret)
raise Import::AuthorizationRequests::Base::SkipRow.new(:invalid_siret_for_unknown_user_and_organization, id: enrollment_row['id'], target_api: enrollment_row['target_api'])
raise Import::AuthorizationRequests::Base::SkipRow.new(:invalid_siret_for_unknown_user_and_organization, id: enrollment_row['id'], target_api: enrollment_row['target_api'], authorization_request: e.record)
else
raise
end
Expand All @@ -161,6 +188,19 @@ def try_to_create_user!(enrollment_row, demandeur)
user
end

def build_organization(siret)
organization = Organization.find_or_initialize_by(siret: siret)

return organization if organization.persisted?

organization.assign_attributes(
mon_compte_pro_payload: { siret:, manual_creation: true },
last_mon_compte_pro_updated_at: DateTime.now,
)

organization
end

def fetch_form(authorization_request)
if authorization_request.definition.available_forms.one?
authorization_request.definition.available_forms.first
Expand All @@ -172,32 +212,40 @@ def fetch_form(authorization_request)
end

def handle_authorization_request_type_specific_fields(authorization_request, enrollment_row)
Kernel.const_get(
@authorization_request_type_specific_field_builder = Kernel.const_get(
"Import::AuthorizationRequests::#{authorization_request.type.split('::')[-1]}Attributes"
).new(
authorization_request,
enrollment_row,
fetch_team_members(enrollment_row['id']),
options[:warned],
@models,
).perform
)
@authorization_request_type_specific_field_builder.perform
end

def import?(enrollment_row)
whitelisted_enrollment?(enrollment_row) ||
(
!old_unused?(enrollment_row) &&
!ignore?(enrollment_row['id']) &&
!more_recent_validated_production?(enrollment_row) &&
from_target_api_to_type(enrollment_row).present?
)
end

def more_recent_validated_production?(enrollment_row)
enrollment_row['target_api'] =~ /_production$/ &&
database.execute("select id from enrollments where status = 'validated' and copied_from_enrollment_id = ?", enrollment_row['id']).any?
end

def whitelisted_enrollment?(enrollment_row)
(options[:authorization_request_ids] || []).include?(enrollment_row['id'].to_i)
end

def old_unused?(enrollment_row)
%w[refused revoked changes_requested draft archived].include?(enrollment_row['status']) &&
enrollment_row['last_validated_at'].blank? &&
DateTime.parse(enrollment_row['created_at']) < DateTime.new(2022, 1, 1)
end

Expand Down Expand Up @@ -225,6 +273,35 @@ def from_target_api_to_type(enrollment)
'hubee_portail_dila' => 'hubee_dila',
'api_entreprise' => 'api_entreprise',
'api_particulier' => 'api_particulier',
'api_impot_particulier_sandbox' => 'api_impot_particulier_sandbox',
'api_impot_particulier_fc_sandbox' => 'api_impot_particulier_sandbox',
'api_impot_particulier_production' => 'api_impot_particulier',
'api_impot_particulier_fc_production' => 'api_impot_particulier',
'franceconnect' => 'france_connect',
'api_rial_sandbox' => 'api_rial_sandbox',
'api_rial_production' => 'api_rial',
'api_cpr_pro_sandbox' => 'api_cpr_pro_adelie_sandbox',
'api_cpr_pro_production' => 'api_cpr_pro_adelie',
'api_e_contacts_sandbox' => 'api_e_contacts_sandbox',
'api_e_contacts_production' => 'api_e_contacts',
'api_e_pro_sandbox' => 'api_e_pro_sandbox',
'api_e_pro_production' => 'api_e_pro',
'api_ensu_documents_sandbox' => 'api_ensu_documents_sandbox',
'api_ensu_documents_production' => 'api_ensu_documents',
'api_hermes_sandbox' => 'api_hermes_sandbox',
'api_hermes_production' => 'api_hermes',
'api_imprimfip_sandbox' => 'api_imprimfip_sandbox',
'api_imprimfip_production' => 'api_imprimfip',
'api_mire_sandbox' => 'api_mire_sandbox',
'api_mire_production' => 'api_mire',
'api_ocfi_sandbox' => 'api_ocfi_sandbox',
'api_ocfi_production' => 'api_ocfi',
'api_opale_sandbox' => 'api_opale_sandbox',
'api_opale_production' => 'api_opale',
'api_robf_sandbox' => 'api_robf_sandbox',
'api_robf_production' => 'api_robf',
'api_satelit_sandbox' => 'api_satelit_sandbox',
'api_satelit_production' => 'api_satelit',
}[enrollment['target_api']].try(:classify)
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APICprProAdelieAttributes < Import::AuthorizationRequests::APIRialAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APICprProAdelieSandboxAttributes < Import::AuthorizationRequests::APIRialSandboxAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIEContactsAttributes < Import::AuthorizationRequests::APIRialAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIEContactsSandboxAttributes < Import::AuthorizationRequests::APIRialSandboxAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Import::AuthorizationRequests::APIEProAttributes < Import::AuthorizationRequests::APIRialAttributes
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIEProSandboxAttributes < Import::AuthorizationRequests::APIRialSandboxAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIENSUDocumentsAttributes < Import::AuthorizationRequests::APIRialAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIENSUDocumentsSandboxAttributes < Import::AuthorizationRequests::APIRialSandboxAttributes
end
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@ def affect_potential_legal_document
end
end

def affect_form_uid
form_uid = demarche_to_form_uid

return if form_uid.blank?

authorization_request.form_uid = form_uid
end

def demarche_to_form_uid
case enrollment_row['demarche']
when 'marches_publics'
Expand Down Expand Up @@ -74,12 +66,6 @@ def affect_not_specified_to_duree_conservation
authorization_request.duree_conservation_donnees_caractere_personnel = 'Non renseigné'
end

def recent_validated_enrollment_exists?
bool = database.execute('select id from enrollments where copied_from_enrollment_id = ? and status = "validated" limit 1;', enrollment_row['id']).any?
database.close
bool
end

def attributes_mapping
{
"intitule" => "intitule",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIHermesAttributes < Import::AuthorizationRequests::APIRialAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Import::AuthorizationRequests::APIHermesSandboxAttributes < Import::AuthorizationRequests::APIRialSandboxAttributes
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class Import::AuthorizationRequests::APIImpotParticulierAttributes < Import::AuthorizationRequests::APIImpotParticulierSandboxAttributes
def affect_data
migrate_from_sandbox_to_production!

affect_form_uid

affect_operational_acceptance
affect_safety_certification
affect_volumetrie

handle_franceconnect

authorization_request.state = enrollment_row['status']

return if authorization_request.valid?

skip_row!(:invalid_cadre_juridique) if authorization_request.errors[:cadre_juridique_url].any?
end

private

def handle_franceconnect
return unless enrollment_row['target_api'] == 'api_impot_particulier_fc_production'

authorization_request.modalities ||= []
authorization_request.modalities = authorization_request.modalities.concat(['with_france_connect'])
authorization_request.modalities = authorization_request.modalities.uniq
end

# FIXME
def affect_form_uid
authorization_request.form_uid = authorization_request.definition.available_forms.first.id
end
end
Loading