From 50f791995340261a97206b3c406e36b011687315 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:29:30 +0300 Subject: [PATCH 01/16] UHF-10537: Update document dl function --- .../src/ApplicationGetterService.php | 161 +++++++++--------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index c7b397538..e13b58476 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -16,9 +16,13 @@ use Drupal\grants_profile\GrantsProfileService; use Drupal\helfi_atv\AtvDocument; use Drupal\helfi_atv\AtvDocumentNotFoundException; +use Drupal\helfi_atv\AtvFailedToConnectException; use Drupal\helfi_atv\AtvService; use Drupal\helfi_helsinki_profiili\HelsinkiProfiiliUserData; +use Drupal\helfi_helsinki_profiili\TokenExpiredException; +use Drupal\webform\Entity\Webform; use Drupal\webform\Entity\WebformSubmission; +use GuzzleHttp\Exception\GuzzleException; /** * Class to get things related to applications. @@ -32,13 +36,6 @@ final class ApplicationGetterService { */ protected GrantsProfileService $grantsProfileService; - /** - * Atv document holding this application. - * - * @var \Drupal\helfi_atv\AtvDocument - */ - protected AtvDocument $atvDocument; - /** * Log errors. * @@ -53,6 +50,8 @@ final class ApplicationGetterService { */ protected EntityStorageInterface $storage; + protected array $submissions = []; + /** * Constructs an ApplicationGetterService object. */ @@ -68,7 +67,7 @@ public function __construct( try { $this->storage = $entityTypeManager->getStorage('webform_submission'); } - catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { + catch (InvalidPluginDefinitionException|PluginNotFoundException $e) { } } @@ -90,26 +89,27 @@ public function setGrantsProfileService(GrantsProfileService $grantsProfileServi * @param bool $refetch * Force atv document fetch. * - * @return \Drupal\helfi_atv\AtvDocument + * @return \Drupal\helfi_atv\AtvDocument|null * FEtched document. * - * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException - * @throws \Drupal\helfi_atv\AtvFailedToConnectException - * @throws \GuzzleHttp\Exception\GuzzleException */ - public function getAtvDocument(string $transactionId, bool $refetch = FALSE): AtvDocument { - - if (!isset($this->atvDocument) || $refetch === TRUE) { - $sParams = [ - 'transaction_id' => $transactionId, - 'lookfor' => 'appenv:' . Helpers::getAppEnv(), - ]; + public function getAtvDocument(string $transactionId, bool $refetch = FALSE): ?AtvDocument { + $sParams = [ + 'transaction_id' => $transactionId, + 'lookfor' => 'appenv:' . Helpers::getAppEnv(), + ]; - $res = $this->helfiAtvAtvService->searchDocuments($sParams); - $this->atvDocument = reset($res); + try { + $result = $this->helfiAtvAtvService->searchDocuments($sParams, $refetch); } - - return $this->atvDocument; + catch (AtvDocumentNotFoundException|AtvFailedToConnectException|TokenExpiredException|GuzzleException $e) { + $this->logger->error( + 'Failed to get document from ATV. Error: @error', + ['@error' => $e->getMessage()] + ); + return NULL; + } + return reset($result); } /** @@ -141,7 +141,6 @@ public function getCompanyApplications( bool $sortByStatus = FALSE, string $themeHook = '', ): array { - $userData = $this->helfiHelsinkiProfiiliUserdata->getUserData(); $applications = []; @@ -164,7 +163,7 @@ public function getCompanyApplications( 'service' => 'AvustushakemusIntegraatio', 'user_id' => $userData['sub'], 'lookfor' => $lookForAppEnv . ',applicant_type:' . $selectedRoleData['type'] . - ',applicant_id:' . $selectedRoleData['identifier'], + ',applicant_id:' . $selectedRoleData['identifier'], ]; } else { @@ -195,7 +194,6 @@ public function getCompanyApplications( if (array_key_exists($document->getType(), Helpers::getApplicationTypes())) { try { - // Convert the data. $dataDefinition = ApplicationHelpers::getDataDefinition($document->getType()); $submissionData = DocumentContentMapper::documentContentToTypedData( @@ -226,7 +224,7 @@ public function getCompanyApplications( 'Failed to get submission object from application number. Submission skipped in application listing. ID: @id Error: @error', [ '@error' => $e->getMessage(), - '@id' => $document->getTransactionId(), + '@id' => $document->getTransactionId(), ] ); continue; @@ -303,15 +301,9 @@ public function getCompanyApplications( * @return \Drupal\webform\Entity\WebformSubmission|null * Webform submission. * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Core\Entity\EntityStorageException - * @throws \Drupal\Core\TempStore\TempStoreException * @throws \Drupal\grants_mandate\CompanySelectException - * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException - * @throws \Drupal\helfi_atv\AtvFailedToConnectException - * @throws \GuzzleHttp\Exception\GuzzleException - * @throws \Drupal\helfi_helsinki_profiili\TokenExpiredException + * @throws \Exception */ public function submissionObjectFromApplicationNumber( string $applicationNumber, @@ -320,23 +312,10 @@ public function submissionObjectFromApplicationNumber( bool $skipAccessCheck = FALSE, ): ?WebformSubmission { - $submissionSerial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); - $webform = ApplicationHelpers::getWebformFromApplicationNumber($applicationNumber, TRUE); - - if (!$webform) { - return NULL; + if (isset($this->submissions[$applicationNumber])) { + return $this->submissions[$applicationNumber]; } - $webformIds = array_map(function ($element) { - return $element->id(); - }, $webform); - - $result = $this->storage - ->loadByProperties([ - 'serial' => $submissionSerial, - 'webform_id' => $webformIds, - ]); - $selectedCompany = $this->grantsProfileService->getSelectedRoleData(); // If no company selected, no mandates no access. @@ -344,53 +323,55 @@ public function submissionObjectFromApplicationNumber( throw new CompanySelectException('User not authorised'); } + // We need the ATV document to get the form uuid. if ($document == NULL) { - $sParams = [ - 'transaction_id' => $applicationNumber, - 'lookfor' => 'appenv:' . Helpers::getAppEnv(), - ]; + $document = $this->getAtvDocument($applicationNumber, $refetch); + } - $document = $this->helfiAtvAtvService->searchDocuments( - $sParams, - $refetch - ); - if (empty($document)) { - throw new AtvDocumentNotFoundException('Document not found'); - } - $document = reset($document); + // Get webform via uuid that is saved to document metadata. + $webform = ApplicationHelpers::getWebformByUuid($document->getMetadata()['form_uuid'], $applicationNumber); + + // Should we throw an error here? + if (!$webform) { + throw new \Exception('Webform not found'); } + // Get serial from application number. + $submissionSerial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); + + + $result = $this->storage + ->loadByProperties([ + 'serial' => $submissionSerial, + 'webform_id' => $webform->id(), + ]); $submissionObject = NULL; // If there's no local submission with given serial // we can actually create that object on the fly and use that for editing. if (empty($result)) { - $webform = ApplicationHelpers::getWebformFromApplicationNumber($applicationNumber); - if ($webform) { - /** @var \Drupal\webform\Entity\WebformSubmission $submissionObject */ - $submissionObject = WebformSubmission::create(['webform_id' => $webform->id()]); - $submissionObject->set('serial', $submissionSerial); - - // Lets mark that we don't want to generate new application - // number, as we just assigned the serial from ATV application id. - // check GrantsHandler@preSave. - WebformSubmissionNotesHelper::setValue( - $submissionObject, - 'skip_available_number_check', - TRUE - ); - if ($document->getStatus() == 'DRAFT') { - $submissionObject->set('in_draft', TRUE); - } - $submissionObject->save(); + /** @var \Drupal\webform\Entity\WebformSubmission $submissionObject */ + $submissionObject = WebformSubmission::create(['webform_id' => $webform->id()]); + $submissionObject->set('serial', $submissionSerial); + + // Lets mark that we don't want to generate new application + // number, as we just assigned the serial from ATV application id. + // check GrantsHandler@preSave. + WebformSubmissionNotesHelper::setValue( + $submissionObject, + 'skip_available_number_check', + TRUE + ); + if ($document->getStatus() == 'DRAFT') { + $submissionObject->set('in_draft', TRUE); } + $submissionObject->save(); } else { /** @var \Drupal\webform\Entity\WebformSubmission $submissionObject */ $submissionObject = reset($result); } if ($submissionObject) { - $dataDefinition = ApplicationHelpers::getDataDefinition($document->getType()); $sData = DocumentContentMapper::documentContentToTypedData( @@ -404,9 +385,29 @@ public function submissionObjectFromApplicationNumber( // Set submission data from parsed mapper. $submissionObject->setData($sData); + $this->submissions[$applicationNumber] = $submissionObject; + return $submissionObject; } return NULL; } + /** + * Extract webform id from application number string. + * + * @param string $applicationNumber + * Application number. + * + * @return \Drupal\webform\Entity\Webform Webform object. + * Webform object. + */ + public function getWebformFromApplicationNumber(string $applicationNumber): Webform { + // We need the ATV document to get the form uuid. + $document = $this->getAtvDocument($applicationNumber); + + // Get webform via uuid that is saved to document metadata. + $webform = ApplicationHelpers::getWebformByUuid($document->getMetadata()['form_uuid'], $applicationNumber); + return $webform; + } + } From 1f1593d054c2c83fcac433edeb9e7363004748ff Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:30:39 +0300 Subject: [PATCH 02/16] UHF-10537: Set processed file types to static --- .../src/DocumentContentMapper.php | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php index 79089613e..b9f6b8d42 100644 --- a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php +++ b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php @@ -13,6 +13,15 @@ */ class DocumentContentMapper { + /** + * Attachment file types. + * + * Saved statically to prevent too many queries. + * + * @var array + */ + private static array $attachmentFileTypes = []; + /** * Map document structure to typed data object. * @@ -120,7 +129,19 @@ private static function processStatusUpdates(array &$typedDataValues): void { */ private static function processAttachments(array &$typedDataValues): void { $other_attachments = []; - $attachmentFileTypes = AttachmentHandler::getAttachmentFieldNames($typedDataValues["application_number"], TRUE); + + $applicationNumber = $typedDataValues["application_number"]; + + // Check if the static variable is already populated for the given application number + if (!isset(self::$attachmentFileTypes[$applicationNumber])) { + self::$attachmentFileTypes[$applicationNumber] = + AttachmentHandler::getAttachmentFieldNames( + $applicationNumber, + TRUE + ); + } + + $attachmentFileTypes = self::$attachmentFileTypes[$applicationNumber]; if (!isset($typedDataValues["attachments"])) { $typedDataValues["attachments"] = []; @@ -185,7 +206,12 @@ private static function updateIssuerNameCase(array &$typedDataValues, string $ke */ private static function processCommunityAddress(array &$typedDataValues): void { $community_address = []; - foreach (['community_street', 'community_city', 'community_post_code', 'community_country'] as $field) { + foreach ([ + 'community_street', + 'community_city', + 'community_post_code', + 'community_country', + ] as $field) { if (isset($typedDataValues[$field])) { $community_address[$field] = $typedDataValues[$field]; unset($typedDataValues[$field]); From 4d4bbc4d2e197b46e9317b2957940669aac2e1e0 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:31:47 +0300 Subject: [PATCH 03/16] UHF-10537: Load application types via webform. --- .../custom/grants_handler/grants_handler.module | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/public/modules/custom/grants_handler/grants_handler.module b/public/modules/custom/grants_handler/grants_handler.module index 9ba74435c..5cd1a0180 100644 --- a/public/modules/custom/grants_handler/grants_handler.module +++ b/public/modules/custom/grants_handler/grants_handler.module @@ -1361,7 +1361,6 @@ function grants_handler_preprocess_application_list(&$variables) { * Implements hook_preprocess_HOOK(). */ function grants_handler_preprocess_application_list_item(&$variables): void { - $language = \Drupal::languageManager()->getCurrentLanguage()->getId(); $tOpts = ['context' => 'grants_handler']; // Get status service and get listed statuses. @@ -1377,9 +1376,12 @@ function grants_handler_preprocess_application_list_item(&$variables): void { return; } - $applicationTypes = Helpers::getApplicationTypes(); - - $variables['applicationFormName'] = $applicationTypes[$submissionData["application_type"]][$language]; + // Get webform by saved form uuid + $webform = ApplicationHelpers::getWebformByUuid( + $submissionData["metadata"]["form_uuid"], + $submissionData['application_number']); + // Set webform title + $variables['applicationFormName'] = $webform->label(); $variables['applicationNumber'] = $submissionData["application_number"]; From 49a7f975b563c6944c03663f71d2f12ae2e429f5 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:32:06 +0300 Subject: [PATCH 04/16] UHF-10537: Add new example applications. --- conf/examples/esimerkki_70_KUVAERILLIS.json | 118 ++++--- .../Definition/KuvaErillisDefinition.php | 306 ++++++------------ 2 files changed, 156 insertions(+), 268 deletions(-) diff --git a/conf/examples/esimerkki_70_KUVAERILLIS.json b/conf/examples/esimerkki_70_KUVAERILLIS.json index 6bee156f4..bbd0d2a5a 100644 --- a/conf/examples/esimerkki_70_KUVAERILLIS.json +++ b/conf/examples/esimerkki_70_KUVAERILLIS.json @@ -208,62 +208,62 @@ ] ] }, - "customQuestionsInfo": { - "customQuestionsArray": [ - { - "ID": "a", - "label": "Label a", - "value": "Value a", - "valueType": "string" - }, - { - "ID": "b", - "label": "LABEL B", - "value": "Value B", - "valueType": "string" - } - ] - }, - "budgetInfo": { - "incomeGroupsArrayStatic": [ - { - "incomeGroupName": "general", - "otherIncomeRowsArrayStatic": [ - { - "ID": "a", - "label": "Kioskimyynti", - "value": "300.00", - "valueType": "double" - }, - { - "ID": "b", - "label": "Parkkitulot", - "value": "50.00", - "valueType": "double" - } - ] - } - ], - "costGroupsArrayStatic": [ - { - "costGroupName": "general", - "otherCostRowsArrayStatic": [ - { - "ID": "a", - "label": "Kioskiostot", - "value": "100.00", - "valueType": "double" - }, - { - "ID": "b", - "label": "Jätemaksut", - "value": "50.00", - "valueType": "double" - } - ] - } - ] - }, + "customQuestionsInfo": { + "customQuestionsArray": [ + { + "ID": "a", + "label": "Label a", + "value": "Value a", + "valueType": "string" + }, + { + "ID": "b", + "label": "LABEL B", + "value": "Value B", + "valueType": "string" + } + ] + }, + "budgetInfo": { + "incomeGroupsArrayStatic": [ + { + "incomeGroupName": "general", + "otherIncomeRowsArrayStatic": [ + { + "ID": "a", + "label": "Kioskimyynti", + "value": "300.00", + "valueType": "double" + }, + { + "ID": "b", + "label": "Parkkitulot", + "value": "50.00", + "valueType": "double" + } + ] + } + ], + "costGroupsArrayStatic": [ + { + "costGroupName": "general", + "otherCostRowsArrayStatic": [ + { + "ID": "a", + "label": "Kioskiostot", + "value": "100.00", + "valueType": "double" + }, + { + "ID": "b", + "label": "Jätemaksut", + "value": "50.00", + "valueType": "double" + } + ] + } + ] + }, "otherCompensationsInfo": { "otherCompensationsArray": [ [ @@ -299,7 +299,7 @@ } ] ], - "otherAppliedCompensationsArray": [ + "otherAppliedCompensationsArray": [ [ { "ID": "issuer", @@ -368,8 +368,6 @@ } ] }, - - "attachmentsInfo": { "attachmentsArray": [ [ @@ -405,4 +403,4 @@ ] }, "formUpdate": false -} \ No newline at end of file +} diff --git a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php index 8ce6ad5ff..bfe928baf 100644 --- a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php +++ b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php @@ -34,216 +34,67 @@ public function getPropertyDefinitions() { 'purpose', ]); - $info['hankesuunnitelma_jatkohakemus'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankesuunnitelma_jatkohakemus', - ]); - - $info['hankkeen_tarkoitus_tavoitteet'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_tarkoitus_tavoitteet', - ]); - - $info['hankkeen_toimenpiteet_aikataulu'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_toimenpiteet_aikataulu', - ]); - - $info['hankkeen_toimenpiteet_alkupvm'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_toimenpiteet_alkupvm', - ]) - ->setSetting('typeOverride', [ - 'dataType' => 'string', - 'jsonType' => 'datetime', - ]) - ->setSetting('valueCallback', [ - 'service' => 'grants_metadata.converter', - 'method' => 'convertDates', - 'arguments' => [ - 'dateFormat' => 'c', + $customQuestions = [ + 'hankesuunnitelma_jatkohakemus' => [], + 'hankkeen_tarkoitus_tavoitteet' => [], + 'hankkeen_toimenpiteet_aikataulu' => [], + 'hankkeen_toimenpiteet_alkupvm' => [ + 'defaultValue' => '', + 'typeOverride' => [ + 'dataType' => 'string', + 'jsonType' => 'datetime', ], - ]); - - $info['hankkeen_toimenpiteet_loppupvm'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_toimenpiteet_loppupvm', - ]) - ->setSetting('typeOverride', [ - 'dataType' => 'string', - 'jsonType' => 'datetime', - ]) - ->setSetting('valueCallback', [ - 'service' => 'grants_metadata.converter', - 'method' => 'convertDates', - 'arguments' => [ - 'dateFormat' => 'c', + 'valueCallback' => [ + 'service' => 'grants_metadata.converter', + 'method' => 'convertDates', + 'arguments' => [ + 'dateFormat' => 'c', + ], ], - ]); - - $info['hankkeen_keskeisimmat_kumppanit'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_keskeisimmat_kumppanit', - ]); - - $info['haun_painopisteet_liikkumis_kehitys'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'haun_painopisteet_liikkumis_kehitys', - ]); - - $info['haun_painopisteet_digi_kehitys'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'haun_painopisteet_digi_kehitys', - ]); - - $info['haun_painopisteet_vertais_kehitys'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'haun_painopisteet_vertais_kehitys', - ]); - - $info['haun_painopisteet_kulttuuri_kehitys'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'haun_painopisteet_kulttuuri_kehitys', - ]); - - $info['hankkeen_kohderyhmat_kenelle'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_kenelle', - ]); - - $info['hankkeen_kohderyhmat_erityisryhmat'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_erityisryhmat', - ]); - - $info['hankkeen_kohderyhmat_tavoitus'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_tavoitus', - ]); - - $info['hankkeen_kohderyhmat_konkretia'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_konkretia', - ]); - - $info['hankkeen_kohderyhmat_osallisuus'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_osallisuus', - ]); - - $info['hankkeen_kohderyhmat_osaaminen'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_osaaminen', - ]); - - $info['hankkeen_kohderyhmat_postinrot'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_postinrot', - ]); - - $info['hankkeen_kohderyhmat_miksi_alue'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_kohderyhmat_miksi_alue', - ]); - - $info['hankkeen_riskit_keskeisimmat'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_riskit_keskeisimmat', - ]); - - $info['hankkeen_riskit_seuranta'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_riskit_seuranta', - ]); - - $info['hankkeen_riskit_vakiinnuttaminen'] = DataDefinition::create('string') - ->setSetting('defaultValue', '') - ->setSetting('jsonPath', [ - 'compensation', - 'customQuestionsInfo', - 'customQuestionsArray', - 'hankkeen_riskit_vakiinnuttaminen', - ]); + ], + 'hankkeen_toimenpiteet_loppupvm' => [ + 'defaultValue' => '', + 'typeOverride' => [ + 'dataType' => 'string', + 'jsonType' => 'datetime', + ], + 'valueCallback' => [ + 'service' => 'grants_metadata.converter', + 'method' => 'convertDates', + 'arguments' => [ + 'dateFormat' => 'c', + ], + ], + ], + 'hankkeen_keskeisimmat_kumppanit' => [], + 'haun_painopisteet_liikkumis_kehitys' => [], + 'haun_painopisteet_digi_kehitys' => [], + 'haun_painopisteet_vertais_kehitys' => [], + 'haun_painopisteet_kulttuuri_kehitys' => [], + 'hankkeen_kohderyhmat_kenelle' => [], + 'hankkeen_kohderyhmat_erityisryhmat' => [], + 'hankkeen_kohderyhmat_tavoitus' => [], + 'hankkeen_kohderyhmat_konkretia' => [], + 'hankkeen_kohderyhmat_osallisuus' => [], + 'hankkeen_kohderyhmat_osaaminen' => [], + 'hankkeen_kohderyhmat_postinrot' => [], + 'hankkeen_kohderyhmat_miksi_alue' => [], + 'hankkeen_riskit_keskeisimmat' => [], + 'hankkeen_riskit_seuranta' => [], + 'hankkeen_riskit_vakiinnuttaminen' => [], + // example forms + 'puuttuva_kentta_1' => [], + 'puuttuva_kentta_2' => [], + 'vaikka_sahkoposti' => [], + 'checkboksiki_onnistuu' => [], + 'tekstialue' => [], + 'tekstikentta' => [], + 'paivamaara' => [], + ]; + + foreach ($customQuestions as $key => $value) { + $this->createCustomQuestionDefinitions($key, $value,$info); + } $info['budgetInfo'] = GrantsBudgetInfoDefinition::create('grants_budget_info') ->setSetting('propertyStructureCallback', [ @@ -280,4 +131,43 @@ public function getPropertyDefinitions() { return $this->propertyDefinitions; } + /** + * Helper function generate repetitive definition. + * + * @param string $key + * Webform element key. + * @param array $value + * Additional settings for given field. + * @param array $info + * Data definitions. + */ + private function createCustomQuestionDefinitions(string $key, array $value, array &$info): void { + // Create initial definition with position in JSON. + $info[$key] = DataDefinition::create('string') + ->setSetting('jsonPath', [ + 'compensation', + 'customQuestionsInfo', + 'customQuestionsArray', + $key, + ]); + // Add type override if set. + if(isset($value['typeOverride'])) { + $info[$key]->setSetting('typeOverride', $value['typeOverride']); + } + // Add value callback if set. + if(isset($value['valueCallback'])) { + $info[$key]->setSetting('valueCallback', $value['valueCallback']); + } + // Add default value if set or empty value. + if (isset($value['defaultValue'])) { + $info[$key]->setSetting('defaultValue', $value['defaultValue']); + } + // DO not add defaultValue if not set, this makes all fields inserted into + // data, this is not an issue, but if there's lot of fields data may get confusing. + + // The negative is that if field is not set required in form, it will not + // be added to data. If an empty field & value is wanted, the defaultValue + // can be added to specific field in array above. + } + } From b7b43e4559467580c75b78d5ca0e76e1c7da88a4 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:45:07 +0300 Subject: [PATCH 05/16] UHF-10537: New configs --- .../webform.webform.kuvaerillis_esimerkki.yml | 1137 ++++++++++++++++ ...webform.webform.kuvaerillis_esimerkki2.yml | 1138 +++++++++++++++++ 2 files changed, 2275 insertions(+) create mode 100644 conf/cmi/webform.webform.kuvaerillis_esimerkki.yml create mode 100644 conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml diff --git a/conf/cmi/webform.webform.kuvaerillis_esimerkki.yml b/conf/cmi/webform.webform.kuvaerillis_esimerkki.yml new file mode 100644 index 000000000..19231ccad --- /dev/null +++ b/conf/cmi/webform.webform.kuvaerillis_esimerkki.yml @@ -0,0 +1,1137 @@ +uuid: 7240b5ab-9408-4934-97c9-022e1ed589c9 +langcode: en +status: open +dependencies: + module: + - grants_handler + - grants_metadata +third_party_settings: + grants_metadata: + applicationTypeSelect: '70' + applicationType: KUVAERILLIS + applicationTypeID: '70' + applicationIndustry: KUVA + applicantTypes: + registered_community: registered_community + unregistered_community: unregistered_community + private_person: private_person + applicationTypeTerms: + 71: '71' + 53: '53' + 46: '46' + applicationTargetGroup: '22' + applicationOpen: null + applicationClose: null + applicationActingYearsType: fixed + applicationActingYears: + 2024: '2024' + 2025: '2025' + 2026: '2026' + applicationActingYearsNextCount: '' + applicationContinuous: 1 + disableCopying: 0 + status: development + parent: '' + avus2BreakingChange: 0 +weight: 0 +open: null +close: null +uid: 1 +template: false +archive: false +id: kuvaerillis_esimerkki +title: 'Kuva: Erillishakemus esimerkki' +description: '

Kulttuurin ja vapaa-ajan erillisavustushakemus: Ikääntyneiden liikkumisen ja kulttuuritoiminnan avustus

' +categories: + - Kehityksessä +elements: |- + avustukset_summa: + '#type': grants_webform_summation_field + '#title': 'Avustukset summa' + '#title_display': none + '#collect_field': + subventions%%amount: subventions%%amount + applicant_type: 0 + application_number: 0 + status: 0 + hakijan_tiedot: 0 + email: 0 + contact_person: 0 + contact_person_phone_number: 0 + community_address: 0 + bank_account: 0 + community_officials: 0 + acting_year: 0 + subventions%%subventionTypeTitle: 0 + subventions%%subventionType: 0 + ensisijainen_taiteen_ala: 0 + hankkeen_nimi: 0 + kyseessa_on_festivaali_tai_tapahtuma: 0 + hankkeen_tai_toiminnan_lyhyt_esittelyteksti: 0 + olemme_saaneet_muita_avustuksia: 0 + myonnetty_avustus: 0 + members_applicant_person_global: 0 + members_applicant_person_local: 0 + members_applicant_community_global: 0 + members_applicant_community_local: 0 + kokoaikainen_henkilosto: 0 + kokoaikainen_henkilotyovuosia: 0 + osa_aikainen_henkilosto: 0 + osa_aikainen_henkilotyovuosia: 0 + vapaaehtoinen_henkilosto: 0 + tapahtuma_tai_esityspaivien_maara_helsingissa: 0 + esitykset_maara_helsingissa: 0 + nayttelyt_maara_helsingissa: 0 + tyopaja_maara_helsingissa: 0 + esitykset_maara_kaikkiaan: 0 + nayttelyt_maara_kaikkiaan: 0 + tyopaja_maara_kaikkiaan: 0 + esitykset_kavijamaara_helsingissa: 0 + nayttelyt_kavijamaara_helsingissa: 0 + tyopaja_kavijamaara_helsingissa: 0 + esitykset_kavijamaara_kaikkiaan: 0 + nayttelyt_kavijamaara_kaikkiaan: 0 + tyopaja_kavijamaara_kaikkiaan: 0 + kantaesitysten_maara: 0 + ensi_iltojen_maara_helsingissa: 0 + ensimmainen_yleisolle_avoimen_tilaisuuden_paikka_helsingissa: 0 + postinumero: 0 + kyseessa_on_kaupungin_omistama_tila: 0 + tila: 0 + ensimmaisen_yleisolle_avoimen_tilaisuuden_paivamaara: 0 + festivaalin_tai_tapahtuman_kohdalla_tapahtuman_paivamaarat: 0 + hanke_alkaa: 0 + hanke_loppuu: 0 + laajempi_hankekuvaus: 0 + toiminta_taiteelliset_lahtokohdat: 0 + toiminta_tasa_arvo: 0 + toiminta_saavutettavuus: 0 + toiminta_yhteisollisyys: 0 + toiminta_kohderyhmat: 0 + toiminta_ammattimaisuus: 0 + toiminta_ekologisuus: 0 + toiminta_yhteistyokumppanit: 0 + organisaatio_kuuluu_valtionosuusjarjestelmaan_vos_: 0 + budget_static_income: 0 + budget_static_cost: 0 + budget_other_cost: 0 + muu_huomioitava_panostus: 0 + additional_information: 0 + extra_info: 0 + muu_liite: 0 + '#data_type': euro + '#form_item': hidden + applicant_type: + '#type': hidden + '#title': 'Hakijan tyyppi' + 1_hakijan_tiedot: + '#type': webform_wizard_page + '#title': '1. Hakijan tiedot' + '#prev_button_label': Edellinen + '#next_button_label': Seuraava + application_number: + '#type': hidden + '#title': Hakemusnumero + '#disabled': true + status: + '#type': hidden + '#title': 'Hakemuksen tila' + '#readonly': true + hakemusprofiili: + '#type': webform_section + '#title': 'Haetut tiedot' + '#attributes': + class: + - grants-profile--imported-section + prh_markup: + '#type': webform_markup + '#markup': 'Tiedot on haettu hakuprofiilistasi.' + hakijan_tiedot: + '#type': applicant_info + '#title': Hakija + contact_person_email_section: + '#type': webform_section + '#title': Sähköposti + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + contact_markup: + '#type': webform_markup + '#markup': 'Ilmoita tässä sellainen yhteisön sähköpostiosoite, jota luetaan aktiivisesti. Sähköpostiin lähetetään avustushakemukseen liittyviä yhteydenottoja esim. lisäselvitys- ja täydennyspyyntöjä.' + email: + '#type': email + '#title': Sähköpostiosoite + '#help': 'Ilmoita sähköpostiosoite, johon tähän hakemukseen liittyvät viestit sekä herätteet osoitetaan ja jota luetaan aktiivisesti' + '#size': 63 + '#autocomplete': 'off' + '#pattern': '(?:[a-zA-Z0-9!#$%&''*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])' + '#states': + required: + ':input[name="applicant_type"]': + value: registered_community + contact_person_section: + '#type': webform_section + '#title': 'Hakemuksen yhteyshenkilö' + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + contact_person: + '#type': textfield + '#title': Yhteyshenkilö + '#autocomplete': 'off' + '#required': true + '#attributes': + class: + - webform--large + '#size': 63 + contact_person_phone_number: + '#type': textfield + '#title': Puhelinnumero + '#required': true + '#autocomplete': 'off' + '#attributes': + class: + - webform--medium + '#size': 32 + osoite: + '#type': webform_section + '#title': Osoite + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + community_address: + '#type': community_address_composite + '#title': 'Yhteisön osoite' + '#help': 'Jos haluat lisätä, poistaa tai muuttaa osoitetietoa tallenna hakemus luonnokseksi ja siirry ylläpitämään osoitetietoa omiin tietoihin.' + '#attributes': + class: + - webform--large + '#required': true + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + tilinumero: + '#type': webform_section + '#title': Tilinumero + bank_account: + '#type': bank_account_composite + '#title': Tilinumero + '#help': 'Jos haluat lisätä, poistaa tai muuttaa tilinumerotietoa tallenna hakemus luonnokseksi ja siirry ylläpitämään tilinumerotietoa omiin tietoihin.' + '#attributes': + class: + - webform--medium + '#required': true + toiminnasta_vastaavat_henkilot: + '#type': webform_section + '#title': 'Toiminnasta vastaavat henkilöt' + '#states': + visible: + ':input[name="applicant_type"]': + '!value': private_person + community_officials: + '#type': community_officials_composite + '#help': 'Jos haluat lisätä, poistaa tai muuttaa henkilöitä tallenna hakemus luonnokseksi ja siirry ylläpitämään henkilöiden tietoja omiin tietoihin.' + '#title': 'Valitse toiminnasta vastaavat henkilöt' + '#multiple': true + '#multiple__item_label': henkilö + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää henkilö' + '#wrapper_attributes': + class: + - community_officials_wrapper + '#attributes': + class: + - webform--large + 2_avustustiedot: + '#type': webform_wizard_page + '#title': '2. Avustustiedot' + avustuksen_tiedot: + '#type': webform_section + '#title': 'Avustuksen tiedot' + acting_year: + '#type': select + '#title': 'Vuosi, jolle haen avustusta' + '#options': + 2024: '2024' + 2025: '2025' + 2026: '2026' + '#required': true + avustuslajit: + '#type': webform_section + '#title': Avustuslajit + subventions: + '#type': grants_compensations + '#title': Avustukset + '#multiple': true + '#subventionType': + 40: '40' + 41: '41' + 42: '42' + '#requiredSubventionType': '40' + '#onlyOneSubventionPerApplication': 1 + '#required': true + '#multiple__header': true + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__remove': false + '#multiple__add_more': false + '#attributes': + class: + - subventions + '#subvention_type': + 1: '1' + 6: '6' + '#subvention_type_id__access': false + '#subvention_type__title': Avustuslaji + '#subvention_amount__title': 'Avustuksen summa' + grants_compensations_information: + '#type': webform_markup + '#markup': '

Hae yhdellä hakemuksella aina vain yhtä avustuslajia kerrallaan.

' + kayttotarkoitus: + '#type': webform_section + '#title': Käyttötarkoitus + compensation_purpose: + '#type': textarea + '#title': 'Lyhyt kuvaus haettavan / haettavien avustusten käyttötarkoituksista' + '#maxlength': 5000 + '#required': true + '#counter_type': character + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + other_grants_for_same_purpose: + '#type': webform_section + '#title': 'Muut samaan tarkoitukseen myönnetyt avustukset' + info_muut_samaan_tarkoitukseen_myonnetty: + '#type': webform_markup + '#markup': | + Ilmoita tähän ainoastaan avustukset, jotka on myönnetty muualta kuin Helsingin kaupungilta kuluvana tai kahtena edellisenä verovuotena. +
+
+
+ + Myöntävä vastaus avaa lisäkysymyksen +
+
+
+ olemme_saaneet_muita_avustuksia: + '#type': radios + '#title': 'Olemme saaneet muita avustuksia' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + myonnetty_avustus: + '#type': webform_custom_composite + '#title': 'Myönnetty avustus' + '#title_display': before + '#states': + visible: + ':input[name="olemme_saaneet_muita_avustuksia"]': + value: '1' + required: + ':input[name="olemme_saaneet_muita_avustuksia"]': + value: '1' + '#multiple__header': false + '#multiple__item_label': 'myönnetty avustus' + '#multiple__no_items_message': 'Ei syötettyjä arvoja. Lisää uusi myönnetty avustus alta.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi myönnetty avustus' + '#element': + issuer: + '#type': select + '#options': + 1: Valtio + 3: EU + 4: Muu + 5: Säätiö + 6: STEA + '#required': true + '#title': 'Avustuksen myöntäjä' + issuer_name: + '#type': textfield + '#required': true + '#title': 'Myöntäjän nimi' + '#attributes': + class: + - webform--large + '#help': 'Mikä taho avustusta on myöntänyt (esim. ministeriön nimi)' + year: + '#type': textfield + '#required': true + '#title': Vuosi + '#attributes': + class: + - webform--small + '#maxlength': 4 + '#pattern': ^(19\d\d|20\d\d|2100)$ + '#pattern_error': 'Syötä vuosiluku väliltä 1900 - 2100' + amount: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': 'Myönnetyn avustuksen summa' + '#input_mask': "'alias': 'currency', 'prefix': '', 'suffix': '€','groupSeparator': ' ','radixPoint':','" + purpose: + '#type': textarea + '#title': 'Kuvaus käyttötarkoituksesta' + '#help': 'Anna lyhyt kuvaus, mihin tarkoitukseen avustus on myönnetty?' + '#maxlength': 1000 + '#counter_type': character + '#attributes': + class: + - webform--large + '#counter_maximum': 1000 + '#counter_maximum_message': '%d/1000 merkkiä jäljellä' + muut_samaan_tarkoitukseen_haetut_avustukset: + '#type': webform_section + '#title': 'Muut samaan tarkoitukseen haetut avustukset' + info_muut_samaan_tarkoitukseen_haettu: + '#type': webform_markup + '#markup': | + Ilmoita tähän ainoastaan avustukset, jotka on haettu muualta kuin Helsingin kaupungilta, eikä päätöstä ole vielä tehty. +
+
+
+ + Myöntävä vastaus avaa lisäkysymyksen +
+
+
+ olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta: + '#type': radios + '#title': 'Olemme hakeneet avustuksia muualta kuin Helsingin kaupungilta' + '#options': + 1: Kyllä + 0: Ei + haettu_avustus_tieto: + '#type': webform_custom_composite + '#title': 'Lisää uusi haettu avustus' + '#title_display': before + '#states': + visible: + ':input[name="olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta"]': + value: '1' + required: + ':input[name="olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta"]': + value: '1' + '#multiple__header': false + '#multiple__item_label': 'haettu avustus' + '#multiple__no_items_message': 'Ei syötettyjä arvoja. Lisää uusi haettu avustus alta.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi haettu avustus' + '#element': + issuer: + '#type': select + '#options': + 1: Valtio + 3: EU + 4: Muu + 5: Säätiö + 6: STEA + '#required': true + '#title': 'Avustuksen myöntäjä' + issuer_name: + '#type': textfield + '#required': true + '#title': 'Myöntäjän nimi' + '#attributes': + class: + - webform--large + '#help': 'Mikä taho avustusta on myöntänyt (esim. ministeriön nimi)' + year: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': Vuosi + '#maxlength': 4 + '#pattern': ^(19\d\d|20\d\d|2100)$ + '#pattern_error': 'Syötä vuosiluku väliltä 1900 - 2100' + amount: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': 'Haetun avustuksen summa' + '#input_mask': "'alias': 'currency', 'prefix': '', 'suffix': '€','groupSeparator': ' ','radixPoint':','" + purpose: + '#type': textarea + '#title': 'Kuvaus käyttötarkoituksesta' + '#help': 'Anna lyhyt kuvaus, mihin tarkoitukseen avustus on myönnetty?' + '#maxlength': 1000 + '#counter_type': character + '#attributes': + class: + - webform--large + '#counter_maximum': 1000 + '#counter_maximum_message': '%d/1000 merkkiä jäljellä' + 3_tarkemmat_tiedot: + '#type': webform_wizard_page + '#title': '3. Tarkemmat tiedot' + tarkemmat_tiedot_section: + '#type': webform_section + '#title': '3.0 Tarkemmat tiedot' + hankesuunnitelma_radios: + '#type': radios + '#title': 'Haetaanko nyt vuonna 2024 myönnetyn kaksivuotisen avustuksen 2. osaa?' + '#help': 'Vastaa tähän kysymykseen "kyllä" vain siinä tapauksessa, jos yhteisölläsi on jo käynnissä oleva, samasta avustuksesta rahoitettu hanke ja haet sille jatkorahoitusta.' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + '#default_value': '0' + hankesuunnitelma_section: + '#type': webform_section + '#title': '3.1 Hankesuunnitelma' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + hankesuunnitelma_jatkohakemus: + '#type': radios + '#title': 'Onko haettava avustus käynnissä olevan hankkeen jatkohakemus?' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + '#default_value': '0' + hankkeen_tarkoitus_tavoitteet: + '#type': textarea + '#title': 'Hankkeen tarkoitus ja tavoitteet' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/2500 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_aikataulu: + '#type': textarea + '#title': 'Mitkä ovat hankkeen konkreettiset toimenpiteet ja niiden toteutusaikataulu?' + '#maxlength': 4000 + '#required': true + '#counter_type': character + '#counter_maximum': 4000 + '#counter_maximum_message': '%d/4000 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_toteutus: + '#type': fieldset + '#title': 'Hankkeen konkreettiset toimenpiteet on tarkoitus toteuttaa välillä' + '#attributes': + class: + - grants-fieldset + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_alkupvm: + '#type': date + '#title': Alkupäivämäärä + '#required': true + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_loppupvm: + '#type': date + '#title': Loppupäivämäärä + '#required': true + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_keskeisimmat_kumppanit: + '#type': textarea + '#title': 'Nimeä hankkeen keskeisimmät yhteistyökumppanit ja heidän roolinsa hankkeessa' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/2500 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_section: + '#type': webform_section + '#title': '3.2 Haun painopisteet' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_ohje: + '#type': webform_markup + '#markup': 'Hankkeessa tulee toteuttaa yhtä tai useampaa painopistettä. HUOM! Valitse vain ne painopisteet, joita edistätte hankkeessa konkreettisella tavalla. Jos hanke ei toteuta jotakin painopistettä, jätä tekstikenttä tyhjäksi.' + haun_painopisteet_liikkumis_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa liikkumismahdollisuuksia tai taide- ja kulttuuritoimintaa lähiympäristössä / alueellisesti? Miten?' + '#maxlength': 1250 + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + '#required': true + haun_painopisteet_digi_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa digitaalisesti / etänä toteutettavia kulttuuritoimintoja tai liikkumiseen aktivoivaa toimintaa? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_vertais_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa vapaaehtois- / vertaistoimintaa? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_kulttuuri_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa taide- ja kulttuuritoimijoiden osaamista tai luodaanko uusia työtapoja / rakenteita? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_section: + '#type': webform_section + '#title': '3.3 Hankkeen kohderyhmät' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_kenelle: + '#type': textarea + '#title': 'Kenelle hankkeen toiminta on pääasiallisesti suunnattu?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_erityisryhmat: + '#type': textarea + '#title': 'Kohdennetaanko hankkeessa toimintaa jollekin erityisryhmälle?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_tavoitus: + '#type': textarea + '#title': 'Kuinka hankkeen kohderyhmät aiotaan tavoittaa?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_konkretia: + '#type': textarea + '#title': 'Miten hankkeessa edistetään konkreettisin toimenpitein valitun kohderyhmän toimintakykyä ja hyvinvointia?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_osallisuus: + '#type': textarea + '#title': 'Millä tavoin hankkeessa edistetään osallisuutta? Mikä ikäihmisten rooli hankkeessa on?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_osaaminen: + '#type': textarea + '#title': 'Millaista osaamista kyseisen kohderyhmän/-ryhmien kanssa työskentelystä hanketoimijoilla on ennestään?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_postinrot: + '#type': textfield + '#title': 'Millä postinumeroalueella tai -alueilla Helsingissä hanke toteutetaan?' + '#required': true + '#autocomplete': 'off' + '#attributes': + class: + - webform--medium + '#size': 32 + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_miksi_alue: + '#type': textarea + '#title': 'Miksi juuri kyseinen alue / alueet on valittu?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_section: + '#type': webform_section + '#title': '3.4 Riskit & analyysi' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_keskeisimmat: + '#type': textarea + '#title': 'Mitkä ovat hankkeen toteuttamisen näkökulmasta keskeisimmät riskit?' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_seuranta: + '#type': textarea + '#title': 'Miten hankkeessa aiotaan toteuttaa seurantaa ja arviointia?' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_vakiinnuttaminen: + '#type': textarea + '#title': 'Onko hankkeen suunniteltu toiminta aikomus vakiinnuttaa osaksi hakijan/jonkun muun toimijan perustoimintaa hankkeen jälkeen?' + '#help': 'Jos kyllä, niin kuvaa tekstikenttään kuinka vakiinnuttaminen aiotaan tehdä, muuten jätä tyhjäksi.' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + unknown_for_now: + '#type': webform_section + '#title': '3.5 puuttuva määritys' + puuttuva_kentta_1: + '#type': textarea + '#title': 'Puuttuva kenttä 1' + puuttuva_kentta_2: + '#type': textfield + '#title': 'Puuttuva kenttä 2' + vaikka_sahkoposti: + '#type': email + '#title': 'Vaikka sähköposti' + checkboksiki_onnistuu: + '#type': checkbox + '#title': 'Checkboksiki onnistuu' + 4_talousarvio: + '#type': webform_wizard_page + '#title': '4. Talousarvio' + tulot_section: + '#type': webform_section + '#title': '4.1 Tulot' + tulot: + '#type': grants_budget_income_static + '#title': Tulot + '#multiple': false + '#incomeGroup': general + '#plannedStateOperativeSubvention__access': false + '#otherCompensationFromCity__access': false + '#stateOperativeSubvention__access': false + '#plannedOtherCompensations__access': false + '#sponsorships__access': false + '#entryFees__access': false + '#sales__access': false + '#financialFundingAndInterests__access': false + '#customerFees__access': false + '#donations__access': false + '#compensationFromCulturalAffairs__access': false + '#otherCompensationType__access': false + '#incomeWithoutCompensations__access': false + '#ownFunding__access': false + '#plannedTotalIncome__access': false + '#otherCompensations__access': false + '#plannedTotalIncomeWithoutSubventions__access': false + '#plannedShareOfIncomeWithoutSubventions__access': false + '#shareOfIncomeWithoutSubventions__access': false + '#totalIncomeWithoutSubventions__access': false + '#totalIncome__access': false + '#incomeGroupName__access': false + talous_tulon_tyyppi: + '#type': grants_budget_other_income + '#title': 'Tulon tyyppi' + '#multiple': true + '#incomeGroup': general + '#help': 'Kerro tässä minkälainen tulo on kyseessä. Toiminnan tuloja voivat olla esimerkiksi muut avustukset ja pääsy- tai osallistumismaksut. Kirjaa tähän kohtaan myös omarahoitusosuus, jos hankkeen alijäämä kuitataan muusta taloudestanne.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi tulo' + '#multiple__item_label': tulo + menot_section: + '#type': webform_section + '#title': '4.2 Menot' + talous_menon_tyyppi: + '#type': grants_budget_other_cost + '#title': Meno + '#multiple': true + '#incomeGroup': general + '#help': 'Kerro tässä minkälainen meno on kyseessä. Toiminnan menoja voivat olla esimerkiksi tilavuokrat ja henkilöstökulut.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi meno' + '#multiple__item_label': meno + lisatiedot_ja_liitteet: + '#type': webform_wizard_page + '#title': '5. Lisätiedot ja liitteet' + lisatietoja_hakemukseen_liittyen: + '#type': webform_section + '#title': 'Lisätietoja hakemukseen liittyen' + additional_information: + '#type': textarea + '#title': Lisätiedot + '#attributes': + class: + - webform--large + '#help': 'Tähän voit tarvittaessa kirjoittaa lisätietoja tai muita perusteluja hakemukseen liittyen tai ilmoittaa perustietoihin tulleista muutoksista ' + '#counter_type': character + '#maxlength': 5000 + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + '#cols': 63 + liitteet: + '#type': webform_section + '#title': Liitteet + attachments_info: + '#type': webform_markup + '#markup': '

Avustushakemuksen käsittelyä varten tulee toimittaa kaikki hakuilmoituksessa luetellut liitteet. Avustushakemus voidaan hylätä, jos liitteitä ei ole toimitettu. Mikäli joku liitteistä puuttuu kerro siitä hakemuksen Lisäselvitys liitteistä -kohdassa.

Helsingin kaupungille aiemmin toimitetut liitteet

Jos vaaditut liitteet on jo toimitettu toisen Helsingin kaupungille osoitetun avustushakemuksen liitteenä, samoja liitteitä ei tarvitse toimittaa uudelleen. Yhteisön vahvistettu tilinpäätös, toimintakertomus, toimintasuunnitelma ja talousarvio eivät voi olla erilaisia eri hakemusten liitteenä. Merkitse tällöin toimitettujen liitteiden kohdalla ”Liite on toimitettu yhtenä tiedostona tai toisen hakemuksen yhteydessä”.

' + notification_attachments: + '#type': webform_markup + '#markup': | +
+
+
Liitteiden sisältöä ei voi tarkastella jälkikäteen
+ +

Huomioithan, että et pysty avaamaan liitteitä sen jälkeen, kun olet liittänyt ne lomakkeelle. Näet liitteestä ainoastaan sen tiedostonimen.

+

Vaikka et voi tarkastella liitteiden sisältä jälkikäteen, lomakkeelle liitetyt liitteet lähtevät lomakkeen muiden tietojen mukana avustushakemuksen käsittelijälle.

+
+
+ '#format': full_html + extra_info: + '#type': textarea + '#title': 'Lisäselvitys liitteistä' + '#maxlength': 5000 + '#counter_type': character + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + '#attributes': + class: + - webform--large + '#cols': 63 + muu_liite: + '#type': grants_attachments + '#title': 'Muu liite' + '#multiple': 10 + '#filetype': '0' + '#title_display': before + '#multiple__item_label': liite + '#multiple__sorting': false + '#multiple__add': false + '#multiple__remove': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää liite' + '#isDeliveredLater__access': false + '#isIncludedInOtherFile__access': false + actions: + '#type': webform_actions + '#title': 'Submit button(s)' + '#submit__label': Lähetä + '#draft__label': 'Tallenna keskeneräisenä' + '#wizard_prev__label': Edellinen + '#wizard_next__label': Seuraava + '#preview_prev__label': Edellinen + '#preview_next__label': Esikatseluun + '#delete_hide': false + '#delete__label': 'Poista keskeneräinen' + '#delete__attributes': + class: + - hds-button + - hds-button--primary + '#delete__dialog': true +css: '' +javascript: '' +settings: + ajax: false + ajax_scroll_top: form + ajax_progress_type: '' + ajax_effect: '' + ajax_speed: null + page: true + page_submit_path: '' + page_confirm_path: '' + page_theme_name: '' + form_title: source_entity_webform + form_submit_once: false + form_open_message: '' + form_close_message: '' + form_exception_message: '' + form_previous_submissions: false + form_confidential: false + form_confidential_message: '' + form_disable_remote_addr: false + form_convert_anonymous: false + form_prepopulate: false + form_prepopulate_source_entity: false + form_prepopulate_source_entity_required: false + form_prepopulate_source_entity_type: '' + form_unsaved: true + form_disable_back: false + form_submit_back: true + form_disable_autocomplete: false + form_novalidate: false + form_disable_inline_errors: false + form_required: false + form_autofocus: false + form_details_toggle: false + form_reset: false + form_access_denied: default + form_access_denied_title: '' + form_access_denied_message: '' + form_access_denied_attributes: { } + form_file_limit: '' + form_attributes: { } + form_method: '' + form_action: '' + share: false + share_node: false + share_theme_name: '' + share_title: true + share_page_body_attributes: { } + submission_label: '' + submission_exception_message: '' + submission_locked_message: '' + submission_log: false + submission_excluded_elements: { } + submission_exclude_empty: false + submission_exclude_empty_checkbox: false + submission_views: { } + submission_views_replace: { } + submission_user_columns: { } + submission_user_duplicate: false + submission_access_denied: default + submission_access_denied_title: '' + submission_access_denied_message: '' + submission_access_denied_attributes: { } + previous_submission_message: '' + previous_submissions_message: '' + autofill: false + autofill_message: '' + autofill_excluded_elements: { } + wizard_progress_bar: true + wizard_progress_pages: false + wizard_progress_percentage: false + wizard_progress_link: true + wizard_progress_states: false + wizard_start_label: '' + wizard_preview_link: false + wizard_confirmation: true + wizard_confirmation_label: '7. Valmis' + wizard_auto_forward: true + wizard_auto_forward_hide_next_button: false + wizard_keyboard: true + wizard_track: '' + wizard_prev_button_label: Edellinen + wizard_next_button_label: Seuraava + wizard_toggle: true + wizard_toggle_show_label: '' + wizard_toggle_hide_label: '' + wizard_page_type: container + wizard_page_title_tag: h2 + preview: 2 + preview_label: '6. Vahvista, esikatsele ja lähetä' + preview_title: 'Vahvista, esikatsele ja lähetä' + preview_message: '' + preview_attributes: { } + preview_excluded_elements: { } + preview_exclude_empty: false + preview_exclude_empty_checkbox: false + draft: all + draft_multiple: false + draft_auto_save: false + draft_saved_message: '' + draft_loaded_message: '' + draft_pending_single_message: '' + draft_pending_multiple_message: '' + confirmation_type: none + confirmation_url: '' + confirmation_title: '' + confirmation_message: '' + confirmation_attributes: { } + confirmation_back: true + confirmation_back_label: '' + confirmation_back_attributes: { } + confirmation_exclude_query: true + confirmation_exclude_token: true + confirmation_update: false + limit_total: null + limit_total_interval: null + limit_total_message: '' + limit_total_unique: false + limit_user: null + limit_user_interval: null + limit_user_message: '' + limit_user_unique: false + entity_limit_total: null + entity_limit_total_interval: null + entity_limit_user: null + entity_limit_user_interval: null + purge: draft + purge_days: 365 + results_disabled: false + results_disabled_ignore: false + results_customize: false + token_view: false + token_update: false + token_delete: false + serial_disabled: false +access: + create: + roles: + - anonymous + - authenticated + users: { } + permissions: { } + view_any: + roles: { } + users: { } + permissions: { } + update_any: + roles: { } + users: { } + permissions: { } + delete_any: + roles: { } + users: { } + permissions: { } + purge_any: + roles: { } + users: { } + permissions: { } + view_own: + roles: { } + users: { } + permissions: { } + update_own: + roles: { } + users: { } + permissions: { } + delete_own: + roles: { } + users: { } + permissions: { } + administer: + roles: { } + users: { } + permissions: { } + test: + roles: { } + users: { } + permissions: { } + configuration: + roles: { } + users: { } + permissions: { } +handlers: + grants_handler: + id: grants_handler + handler_id: grants_handler + label: 'Grants Handler' + notes: '' + status: true + conditions: { } + weight: 0 + settings: + debug: false +variants: { } diff --git a/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml b/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml new file mode 100644 index 000000000..78aa03ad4 --- /dev/null +++ b/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml @@ -0,0 +1,1138 @@ +uuid: 86c3417f-0dfd-4516-9744-d86cd3cdbe48 +langcode: en +status: open +dependencies: + module: + - grants_handler + - grants_metadata +third_party_settings: + grants_metadata: + applicationTypeSelect: '70' + applicationType: KUVAERILLIS + applicationTypeID: '70' + applicationIndustry: KUVA + applicantTypes: + registered_community: registered_community + applicationTypeTerms: + 62: '62' + applicationTargetGroup: '22' + applicationOpen: null + applicationClose: null + applicationActingYearsType: fixed + applicationActingYears: + 2024: '2024' + 2025: '2025' + 2026: '2026' + applicationActingYearsNextCount: '' + applicationContinuous: 1 + disableCopying: 0 + status: development + parent: '' + avus2BreakingChange: 0 +weight: 0 +open: null +close: null +uid: 1 +template: false +archive: false +id: kuvaerillis_esimerkki2 +title: 'Kuva: ESIMERKKI 2' +description: '

Kulttuurin ja vapaa-ajan erillisavustushakemus: Ikääntyneiden liikkumisen ja kulttuuritoiminnan avustus

' +categories: + - Kehityksessä +elements: |- + avustukset_summa: + '#type': grants_webform_summation_field + '#title': 'Avustukset summa' + '#title_display': none + '#collect_field': + subventions%%amount: subventions%%amount + applicant_type: 0 + application_number: 0 + status: 0 + hakijan_tiedot: 0 + email: 0 + contact_person: 0 + contact_person_phone_number: 0 + community_address: 0 + bank_account: 0 + community_officials: 0 + acting_year: 0 + subventions%%subventionTypeTitle: 0 + subventions%%subventionType: 0 + ensisijainen_taiteen_ala: 0 + hankkeen_nimi: 0 + kyseessa_on_festivaali_tai_tapahtuma: 0 + hankkeen_tai_toiminnan_lyhyt_esittelyteksti: 0 + olemme_saaneet_muita_avustuksia: 0 + myonnetty_avustus: 0 + members_applicant_person_global: 0 + members_applicant_person_local: 0 + members_applicant_community_global: 0 + members_applicant_community_local: 0 + kokoaikainen_henkilosto: 0 + kokoaikainen_henkilotyovuosia: 0 + osa_aikainen_henkilosto: 0 + osa_aikainen_henkilotyovuosia: 0 + vapaaehtoinen_henkilosto: 0 + tapahtuma_tai_esityspaivien_maara_helsingissa: 0 + esitykset_maara_helsingissa: 0 + nayttelyt_maara_helsingissa: 0 + tyopaja_maara_helsingissa: 0 + esitykset_maara_kaikkiaan: 0 + nayttelyt_maara_kaikkiaan: 0 + tyopaja_maara_kaikkiaan: 0 + esitykset_kavijamaara_helsingissa: 0 + nayttelyt_kavijamaara_helsingissa: 0 + tyopaja_kavijamaara_helsingissa: 0 + esitykset_kavijamaara_kaikkiaan: 0 + nayttelyt_kavijamaara_kaikkiaan: 0 + tyopaja_kavijamaara_kaikkiaan: 0 + kantaesitysten_maara: 0 + ensi_iltojen_maara_helsingissa: 0 + ensimmainen_yleisolle_avoimen_tilaisuuden_paikka_helsingissa: 0 + postinumero: 0 + kyseessa_on_kaupungin_omistama_tila: 0 + tila: 0 + ensimmaisen_yleisolle_avoimen_tilaisuuden_paivamaara: 0 + festivaalin_tai_tapahtuman_kohdalla_tapahtuman_paivamaarat: 0 + hanke_alkaa: 0 + hanke_loppuu: 0 + laajempi_hankekuvaus: 0 + toiminta_taiteelliset_lahtokohdat: 0 + toiminta_tasa_arvo: 0 + toiminta_saavutettavuus: 0 + toiminta_yhteisollisyys: 0 + toiminta_kohderyhmat: 0 + toiminta_ammattimaisuus: 0 + toiminta_ekologisuus: 0 + toiminta_yhteistyokumppanit: 0 + organisaatio_kuuluu_valtionosuusjarjestelmaan_vos_: 0 + budget_static_income: 0 + budget_static_cost: 0 + budget_other_cost: 0 + muu_huomioitava_panostus: 0 + additional_information: 0 + extra_info: 0 + muu_liite: 0 + '#data_type': euro + '#form_item': hidden + applicant_type: + '#type': hidden + '#title': 'Hakijan tyyppi' + 1_hakijan_tiedot: + '#type': webform_wizard_page + '#title': '1. Hakijan tiedot' + '#prev_button_label': Edellinen + '#next_button_label': Seuraava + application_number: + '#type': hidden + '#title': Hakemusnumero + '#disabled': true + status: + '#type': hidden + '#title': 'Hakemuksen tila' + '#readonly': true + hakemusprofiili: + '#type': webform_section + '#title': 'Haetut tiedot' + '#attributes': + class: + - grants-profile--imported-section + prh_markup: + '#type': webform_markup + '#markup': 'Tiedot on haettu hakuprofiilistasi.' + hakijan_tiedot: + '#type': applicant_info + '#title': Hakija + contact_person_email_section: + '#type': webform_section + '#title': Sähköposti + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + contact_markup: + '#type': webform_markup + '#markup': 'Ilmoita tässä sellainen yhteisön sähköpostiosoite, jota luetaan aktiivisesti. Sähköpostiin lähetetään avustushakemukseen liittyviä yhteydenottoja esim. lisäselvitys- ja täydennyspyyntöjä.' + email: + '#type': email + '#title': Sähköpostiosoite + '#help': 'Ilmoita sähköpostiosoite, johon tähän hakemukseen liittyvät viestit sekä herätteet osoitetaan ja jota luetaan aktiivisesti' + '#size': 63 + '#autocomplete': 'off' + '#pattern': '(?:[a-zA-Z0-9!#$%&''*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])' + '#states': + required: + ':input[name="applicant_type"]': + value: registered_community + contact_person_section: + '#type': webform_section + '#title': 'Hakemuksen yhteyshenkilö' + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + contact_person: + '#type': textfield + '#title': Yhteyshenkilö + '#autocomplete': 'off' + '#required': true + '#attributes': + class: + - webform--large + '#size': 63 + contact_person_phone_number: + '#type': textfield + '#title': Puhelinnumero + '#required': true + '#autocomplete': 'off' + '#attributes': + class: + - webform--medium + '#size': 32 + osoite: + '#type': webform_section + '#title': Osoite + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + community_address: + '#type': community_address_composite + '#title': 'Yhteisön osoite' + '#help': 'Jos haluat lisätä, poistaa tai muuttaa osoitetietoa tallenna hakemus luonnokseksi ja siirry ylläpitämään osoitetietoa omiin tietoihin.' + '#attributes': + class: + - webform--large + '#required': true + '#states': + visible: + ':input[name="applicant_type"]': + value: registered_community + tilinumero: + '#type': webform_section + '#title': Tilinumero + bank_account: + '#type': bank_account_composite + '#title': Tilinumero + '#help': 'Jos haluat lisätä, poistaa tai muuttaa tilinumerotietoa tallenna hakemus luonnokseksi ja siirry ylläpitämään tilinumerotietoa omiin tietoihin.' + '#attributes': + class: + - webform--medium + '#required': true + toiminnasta_vastaavat_henkilot: + '#type': webform_section + '#title': 'Toiminnasta vastaavat henkilöt' + '#states': + visible: + ':input[name="applicant_type"]': + '!value': private_person + community_officials: + '#type': community_officials_composite + '#help': 'Jos haluat lisätä, poistaa tai muuttaa henkilöitä tallenna hakemus luonnokseksi ja siirry ylläpitämään henkilöiden tietoja omiin tietoihin.' + '#title': 'Valitse toiminnasta vastaavat henkilöt' + '#multiple': true + '#multiple__item_label': henkilö + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää henkilö' + '#wrapper_attributes': + class: + - community_officials_wrapper + '#attributes': + class: + - webform--large + 2_avustustiedot: + '#type': webform_wizard_page + '#title': '2. Avustustiedot' + avustuksen_tiedot: + '#type': webform_section + '#title': 'Avustuksen tiedot' + acting_year: + '#type': select + '#title': 'Vuosi, jolle haen avustusta' + '#options': + 2024: '2024' + 2025: '2025' + 2026: '2026' + '#required': true + avustuslajit: + '#type': webform_section + '#title': Avustuslajit + subventions: + '#type': grants_compensations + '#title': Avustukset + '#multiple': true + '#subventionType': + 47: '47' + 51: '51' + '#onlyOneSubventionPerApplication': 1 + '#required': true + '#multiple__header': true + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__remove': false + '#multiple__add_more': false + '#attributes': + class: + - subventions + '#subvention_type': + 1: '1' + 6: '6' + '#subvention_type_id__access': false + '#subvention_type__title': Avustuslaji + '#subvention_amount__title': 'Avustuksen summa' + grants_compensations_information: + '#type': webform_markup + '#markup': '

Hae yhdellä hakemuksella aina vain yhtä avustuslajia kerrallaan.

' + kayttotarkoitus: + '#type': webform_section + '#title': Käyttötarkoitus + compensation_purpose: + '#type': textarea + '#title': 'Lyhyt kuvaus haettavan / haettavien avustusten käyttötarkoituksista' + '#maxlength': 5000 + '#required': true + '#counter_type': character + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + other_grants_for_same_purpose: + '#type': webform_section + '#title': 'Muut samaan tarkoitukseen myönnetyt avustukset' + info_muut_samaan_tarkoitukseen_myonnetty: + '#type': webform_markup + '#markup': | + Ilmoita tähän ainoastaan avustukset, jotka on myönnetty muualta kuin Helsingin kaupungilta kuluvana tai kahtena edellisenä verovuotena. +
+
+
+ + Myöntävä vastaus avaa lisäkysymyksen +
+
+
+ olemme_saaneet_muita_avustuksia: + '#type': radios + '#title': 'Olemme saaneet muita avustuksia' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + myonnetty_avustus: + '#type': webform_custom_composite + '#title': 'Myönnetty avustus' + '#title_display': before + '#states': + visible: + ':input[name="olemme_saaneet_muita_avustuksia"]': + value: '1' + required: + ':input[name="olemme_saaneet_muita_avustuksia"]': + value: '1' + '#multiple__header': false + '#multiple__item_label': 'myönnetty avustus' + '#multiple__no_items_message': 'Ei syötettyjä arvoja. Lisää uusi myönnetty avustus alta.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi myönnetty avustus' + '#element': + issuer: + '#type': select + '#options': + 1: Valtio + 3: EU + 4: Muu + 5: Säätiö + 6: STEA + '#required': true + '#title': 'Avustuksen myöntäjä' + issuer_name: + '#type': textfield + '#required': true + '#title': 'Myöntäjän nimi' + '#attributes': + class: + - webform--large + '#help': 'Mikä taho avustusta on myöntänyt (esim. ministeriön nimi)' + year: + '#type': textfield + '#required': true + '#title': Vuosi + '#attributes': + class: + - webform--small + '#maxlength': 4 + '#pattern': ^(19\d\d|20\d\d|2100)$ + '#pattern_error': 'Syötä vuosiluku väliltä 1900 - 2100' + amount: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': 'Myönnetyn avustuksen summa' + '#input_mask': "'alias': 'currency', 'prefix': '', 'suffix': '€','groupSeparator': ' ','radixPoint':','" + purpose: + '#type': textarea + '#title': 'Kuvaus käyttötarkoituksesta' + '#help': 'Anna lyhyt kuvaus, mihin tarkoitukseen avustus on myönnetty?' + '#maxlength': 1000 + '#counter_type': character + '#attributes': + class: + - webform--large + '#counter_maximum': 1000 + '#counter_maximum_message': '%d/1000 merkkiä jäljellä' + muut_samaan_tarkoitukseen_haetut_avustukset: + '#type': webform_section + '#title': 'Muut samaan tarkoitukseen haetut avustukset' + info_muut_samaan_tarkoitukseen_haettu: + '#type': webform_markup + '#markup': | + Ilmoita tähän ainoastaan avustukset, jotka on haettu muualta kuin Helsingin kaupungilta, eikä päätöstä ole vielä tehty. +
+
+
+ + Myöntävä vastaus avaa lisäkysymyksen +
+
+
+ olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta: + '#type': radios + '#title': 'Olemme hakeneet avustuksia muualta kuin Helsingin kaupungilta' + '#options': + 1: Kyllä + 0: Ei + haettu_avustus_tieto: + '#type': webform_custom_composite + '#title': 'Lisää uusi haettu avustus' + '#title_display': before + '#states': + visible: + ':input[name="olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta"]': + value: '1' + required: + ':input[name="olemme_hakeneet_avustuksia_muualta_kuin_helsingin_kaupungilta"]': + value: '1' + '#multiple__header': false + '#multiple__item_label': 'haettu avustus' + '#multiple__no_items_message': 'Ei syötettyjä arvoja. Lisää uusi haettu avustus alta.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__sorting': false + '#multiple__add': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi haettu avustus' + '#element': + issuer: + '#type': select + '#options': + 1: Valtio + 3: EU + 4: Muu + 5: Säätiö + 6: STEA + '#required': true + '#title': 'Avustuksen myöntäjä' + issuer_name: + '#type': textfield + '#required': true + '#title': 'Myöntäjän nimi' + '#attributes': + class: + - webform--large + '#help': 'Mikä taho avustusta on myöntänyt (esim. ministeriön nimi)' + year: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': Vuosi + '#maxlength': 4 + '#pattern': ^(19\d\d|20\d\d|2100)$ + '#pattern_error': 'Syötä vuosiluku väliltä 1900 - 2100' + amount: + '#type': textfield + '#required': true + '#attributes': + class: + - webform--small + '#title': 'Haetun avustuksen summa' + '#input_mask': "'alias': 'currency', 'prefix': '', 'suffix': '€','groupSeparator': ' ','radixPoint':','" + purpose: + '#type': textarea + '#title': 'Kuvaus käyttötarkoituksesta' + '#help': 'Anna lyhyt kuvaus, mihin tarkoitukseen avustus on myönnetty?' + '#maxlength': 1000 + '#counter_type': character + '#attributes': + class: + - webform--large + '#counter_maximum': 1000 + '#counter_maximum_message': '%d/1000 merkkiä jäljellä' + 3_tarkemmat_tiedot: + '#type': webform_wizard_page + '#title': '3. Tarkemmat tiedot' + tarkemmat_tiedot_section: + '#type': webform_section + '#title': '3.0 Tarkemmat tiedot' + hankesuunnitelma_radios: + '#type': radios + '#title': 'Haetaanko nyt vuonna 2024 myönnetyn kaksivuotisen avustuksen 2. osaa?' + '#help': 'Vastaa tähän kysymykseen "kyllä" vain siinä tapauksessa, jos yhteisölläsi on jo käynnissä oleva, samasta avustuksesta rahoitettu hanke ja haet sille jatkorahoitusta.' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + '#default_value': '0' + hankesuunnitelma_section: + '#type': webform_section + '#title': '3.1 Hankesuunnitelma' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + hankesuunnitelma_jatkohakemus: + '#type': radios + '#title': 'Onko haettava avustus käynnissä olevan hankkeen jatkohakemus?' + '#description_display': before + '#options': + 1: Kyllä + 0: Ei + '#default_value': '0' + hankkeen_tarkoitus_tavoitteet: + '#type': textarea + '#title': 'Hankkeen tarkoitus ja tavoitteet' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/2500 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_aikataulu: + '#type': textarea + '#title': 'Mitkä ovat hankkeen konkreettiset toimenpiteet ja niiden toteutusaikataulu?' + '#maxlength': 4000 + '#required': true + '#counter_type': character + '#counter_maximum': 4000 + '#counter_maximum_message': '%d/4000 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_toteutus: + '#type': fieldset + '#title': 'Hankkeen konkreettiset toimenpiteet on tarkoitus toteuttaa välillä' + '#attributes': + class: + - grants-fieldset + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_alkupvm: + '#type': date + '#title': Alkupäivämäärä + '#required': true + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_toimenpiteet_loppupvm: + '#type': date + '#title': Loppupäivämäärä + '#required': true + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_keskeisimmat_kumppanit: + '#type': textarea + '#title': 'Nimeä hankkeen keskeisimmät yhteistyökumppanit ja heidän roolinsa hankkeessa' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/2500 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_section: + '#type': webform_section + '#title': '3.2 Haun painopisteet' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_ohje: + '#type': webform_markup + '#markup': 'Hankkeessa tulee toteuttaa yhtä tai useampaa painopistettä. HUOM! Valitse vain ne painopisteet, joita edistätte hankkeessa konkreettisella tavalla. Jos hanke ei toteuta jotakin painopistettä, jätä tekstikenttä tyhjäksi.' + haun_painopisteet_liikkumis_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa liikkumismahdollisuuksia tai taide- ja kulttuuritoimintaa lähiympäristössä / alueellisesti? Miten?' + '#maxlength': 1250 + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + '#required': true + haun_painopisteet_digi_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa digitaalisesti / etänä toteutettavia kulttuuritoimintoja tai liikkumiseen aktivoivaa toimintaa? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_vertais_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa vapaaehtois- / vertaistoimintaa? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + haun_painopisteet_kulttuuri_kehitys: + '#type': textarea + '#title': 'Kehitetäänkö hankkeessa taide- ja kulttuuritoimijoiden osaamista tai luodaanko uusia työtapoja / rakenteita? Miten?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_section: + '#type': webform_section + '#title': '3.3 Hankkeen kohderyhmät' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_kenelle: + '#type': textarea + '#title': 'Kenelle hankkeen toiminta on pääasiallisesti suunnattu?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_erityisryhmat: + '#type': textarea + '#title': 'Kohdennetaanko hankkeessa toimintaa jollekin erityisryhmälle?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_tavoitus: + '#type': textarea + '#title': 'Kuinka hankkeen kohderyhmät aiotaan tavoittaa?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_konkretia: + '#type': textarea + '#title': 'Miten hankkeessa edistetään konkreettisin toimenpitein valitun kohderyhmän toimintakykyä ja hyvinvointia?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_osallisuus: + '#type': textarea + '#title': 'Millä tavoin hankkeessa edistetään osallisuutta? Mikä ikäihmisten rooli hankkeessa on?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_osaaminen: + '#type': textarea + '#title': 'Millaista osaamista kyseisen kohderyhmän/-ryhmien kanssa työskentelystä hanketoimijoilla on ennestään?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_postinrot: + '#type': textfield + '#title': 'Millä postinumeroalueella tai -alueilla Helsingissä hanke toteutetaan?' + '#required': true + '#autocomplete': 'off' + '#attributes': + class: + - webform--medium + '#size': 32 + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_kohderyhmat_miksi_alue: + '#type': textarea + '#title': 'Miksi juuri kyseinen alue / alueet on valittu?' + '#maxlength': 1250 + '#required': true + '#counter_type': character + '#counter_maximum': 1250 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_section: + '#type': webform_section + '#title': '3.4 Riskit & analyysi' + '#states': + visible: + ':input[name="hankesuunnitelma_radios"]': + value: '0' + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_keskeisimmat: + '#type': textarea + '#title': 'Mitkä ovat hankkeen toteuttamisen näkökulmasta keskeisimmät riskit?' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_seuranta: + '#type': textarea + '#title': 'Miten hankkeessa aiotaan toteuttaa seurantaa ja arviointia?' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + hankkeen_riskit_vakiinnuttaminen: + '#type': textarea + '#title': 'Onko hankkeen suunniteltu toiminta aikomus vakiinnuttaa osaksi hakijan/jonkun muun toimijan perustoimintaa hankkeen jälkeen?' + '#help': 'Jos kyllä, niin kuvaa tekstikenttään kuinka vakiinnuttaminen aiotaan tehdä, muuten jätä tyhjäksi.' + '#maxlength': 2500 + '#required': true + '#counter_type': character + '#counter_maximum': 2500 + '#counter_maximum_message': '%d/1250 merkkiä jäljellä' + '#states': + visible: + ':input[name="hankesuunnitelma_jatkohakemus"]': + value: '0' + unknown_for_now: + '#type': webform_section + '#title': '3.5 puuttuva määritys' + tekstialue: + '#type': textarea + '#title': 'Tekstialue ' + '#description': '

asdf asdfasdf

' + '#help_title': asdf + '#help': '

asdf asdfasdf

' + tekstikentta: + '#type': textfield + '#title': tekstikenttä + '#description': '

asdf asdf sdf asdfa sdf

' + '#help': '

asdf asdf sdfasdf

' + '#more_title': sadf + '#more': '

asdf

' + paivamaara: + '#type': date + '#title': päivämäärä + '#description': '

dfgsdfgs sdfg f

' + '#help_title': sdfg + '#help': '

sgdfgdfg

' + 4_talousarvio: + '#type': webform_wizard_page + '#title': '4. Talousarvio' + tulot_section: + '#type': webform_section + '#title': '4.1 Tulot' + tulot: + '#type': grants_budget_income_static + '#title': Tulot + '#multiple': false + '#incomeGroup': general + '#plannedStateOperativeSubvention__access': false + '#otherCompensationFromCity__access': false + '#stateOperativeSubvention__access': false + '#plannedOtherCompensations__access': false + '#sponsorships__access': false + '#entryFees__access': false + '#sales__access': false + '#financialFundingAndInterests__access': false + '#customerFees__access': false + '#donations__access': false + '#compensationFromCulturalAffairs__access': false + '#otherCompensationType__access': false + '#incomeWithoutCompensations__access': false + '#ownFunding__access': false + '#plannedTotalIncome__access': false + '#otherCompensations__access': false + '#plannedTotalIncomeWithoutSubventions__access': false + '#plannedShareOfIncomeWithoutSubventions__access': false + '#shareOfIncomeWithoutSubventions__access': false + '#totalIncomeWithoutSubventions__access': false + '#totalIncome__access': false + '#incomeGroupName__access': false + talous_tulon_tyyppi: + '#type': grants_budget_other_income + '#title': 'Tulon tyyppi' + '#multiple': true + '#incomeGroup': general + '#help': 'Kerro tässä minkälainen tulo on kyseessä. Toiminnan tuloja voivat olla esimerkiksi muut avustukset ja pääsy- tai osallistumismaksut. Kirjaa tähän kohtaan myös omarahoitusosuus, jos hankkeen alijäämä kuitataan muusta taloudestanne.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi tulo' + '#multiple__item_label': tulo + menot_section: + '#type': webform_section + '#title': '4.2 Menot' + talous_menon_tyyppi: + '#type': grants_budget_other_cost + '#title': Meno + '#multiple': true + '#incomeGroup': general + '#help': 'Kerro tässä minkälainen meno on kyseessä. Toiminnan menoja voivat olla esimerkiksi tilavuokrat ja henkilöstökulut.' + '#multiple__min_items': 1 + '#multiple__empty_items': 0 + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää uusi meno' + '#multiple__item_label': meno + lisatiedot_ja_liitteet: + '#type': webform_wizard_page + '#title': '5. Lisätiedot ja liitteet' + lisatietoja_hakemukseen_liittyen: + '#type': webform_section + '#title': 'Lisätietoja hakemukseen liittyen' + additional_information: + '#type': textarea + '#title': Lisätiedot + '#attributes': + class: + - webform--large + '#help': 'Tähän voit tarvittaessa kirjoittaa lisätietoja tai muita perusteluja hakemukseen liittyen tai ilmoittaa perustietoihin tulleista muutoksista ' + '#counter_type': character + '#maxlength': 5000 + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + '#cols': 63 + liitteet: + '#type': webform_section + '#title': Liitteet + attachments_info: + '#type': webform_markup + '#markup': '

Avustushakemuksen käsittelyä varten tulee toimittaa kaikki hakuilmoituksessa luetellut liitteet. Avustushakemus voidaan hylätä, jos liitteitä ei ole toimitettu. Mikäli joku liitteistä puuttuu kerro siitä hakemuksen Lisäselvitys liitteistä -kohdassa.

Helsingin kaupungille aiemmin toimitetut liitteet

Jos vaaditut liitteet on jo toimitettu toisen Helsingin kaupungille osoitetun avustushakemuksen liitteenä, samoja liitteitä ei tarvitse toimittaa uudelleen. Yhteisön vahvistettu tilinpäätös, toimintakertomus, toimintasuunnitelma ja talousarvio eivät voi olla erilaisia eri hakemusten liitteenä. Merkitse tällöin toimitettujen liitteiden kohdalla ”Liite on toimitettu yhtenä tiedostona tai toisen hakemuksen yhteydessä”.

' + notification_attachments: + '#type': webform_markup + '#markup': | +
+
+
Liitteiden sisältöä ei voi tarkastella jälkikäteen
+ +

Huomioithan, että et pysty avaamaan liitteitä sen jälkeen, kun olet liittänyt ne lomakkeelle. Näet liitteestä ainoastaan sen tiedostonimen.

+

Vaikka et voi tarkastella liitteiden sisältä jälkikäteen, lomakkeelle liitetyt liitteet lähtevät lomakkeen muiden tietojen mukana avustushakemuksen käsittelijälle.

+
+
+ '#format': full_html + extra_info: + '#type': textarea + '#title': 'Lisäselvitys liitteistä' + '#maxlength': 5000 + '#counter_type': character + '#counter_maximum': 5000 + '#counter_maximum_message': '%d/5000 merkkiä jäljellä' + '#attributes': + class: + - webform--large + '#cols': 63 + muu_liite: + '#type': grants_attachments + '#title': 'Muu liite' + '#multiple': 10 + '#filetype': '0' + '#title_display': before + '#multiple__item_label': liite + '#multiple__sorting': false + '#multiple__add': false + '#multiple__remove': false + '#multiple__add_more_input': false + '#multiple__add_more_button_label': 'Lisää liite' + '#isDeliveredLater__access': false + '#isIncludedInOtherFile__access': false + actions: + '#type': webform_actions + '#title': 'Submit button(s)' + '#submit__label': Lähetä + '#draft__label': 'Tallenna keskeneräisenä' + '#wizard_prev__label': Edellinen + '#wizard_next__label': Seuraava + '#preview_prev__label': Edellinen + '#preview_next__label': Esikatseluun + '#delete_hide': false + '#delete__label': 'Poista keskeneräinen' + '#delete__attributes': + class: + - hds-button + - hds-button--primary + '#delete__dialog': true +css: '' +javascript: '' +settings: + ajax: false + ajax_scroll_top: form + ajax_progress_type: '' + ajax_effect: '' + ajax_speed: null + page: true + page_submit_path: '' + page_confirm_path: '' + page_theme_name: '' + form_title: source_entity_webform + form_submit_once: false + form_open_message: '' + form_close_message: '' + form_exception_message: '' + form_previous_submissions: false + form_confidential: false + form_confidential_message: '' + form_disable_remote_addr: false + form_convert_anonymous: false + form_prepopulate: false + form_prepopulate_source_entity: false + form_prepopulate_source_entity_required: false + form_prepopulate_source_entity_type: '' + form_unsaved: true + form_disable_back: false + form_submit_back: true + form_disable_autocomplete: false + form_novalidate: false + form_disable_inline_errors: false + form_required: false + form_autofocus: false + form_details_toggle: false + form_reset: false + form_access_denied: default + form_access_denied_title: '' + form_access_denied_message: '' + form_access_denied_attributes: { } + form_file_limit: '' + form_attributes: { } + form_method: '' + form_action: '' + share: false + share_node: false + share_theme_name: '' + share_title: true + share_page_body_attributes: { } + submission_label: '' + submission_exception_message: '' + submission_locked_message: '' + submission_log: false + submission_excluded_elements: { } + submission_exclude_empty: false + submission_exclude_empty_checkbox: false + submission_views: { } + submission_views_replace: { } + submission_user_columns: { } + submission_user_duplicate: false + submission_access_denied: default + submission_access_denied_title: '' + submission_access_denied_message: '' + submission_access_denied_attributes: { } + previous_submission_message: '' + previous_submissions_message: '' + autofill: false + autofill_message: '' + autofill_excluded_elements: { } + wizard_progress_bar: true + wizard_progress_pages: false + wizard_progress_percentage: false + wizard_progress_link: true + wizard_progress_states: false + wizard_start_label: '' + wizard_preview_link: false + wizard_confirmation: true + wizard_confirmation_label: '7. Valmis' + wizard_auto_forward: true + wizard_auto_forward_hide_next_button: false + wizard_keyboard: true + wizard_track: '' + wizard_prev_button_label: Edellinen + wizard_next_button_label: Seuraava + wizard_toggle: true + wizard_toggle_show_label: '' + wizard_toggle_hide_label: '' + wizard_page_type: container + wizard_page_title_tag: h2 + preview: 2 + preview_label: '6. Vahvista, esikatsele ja lähetä' + preview_title: 'Vahvista, esikatsele ja lähetä' + preview_message: '' + preview_attributes: { } + preview_excluded_elements: { } + preview_exclude_empty: false + preview_exclude_empty_checkbox: false + draft: all + draft_multiple: false + draft_auto_save: false + draft_saved_message: '' + draft_loaded_message: '' + draft_pending_single_message: '' + draft_pending_multiple_message: '' + confirmation_type: none + confirmation_url: '' + confirmation_title: '' + confirmation_message: '' + confirmation_attributes: { } + confirmation_back: true + confirmation_back_label: '' + confirmation_back_attributes: { } + confirmation_exclude_query: true + confirmation_exclude_token: true + confirmation_update: false + limit_total: null + limit_total_interval: null + limit_total_message: '' + limit_total_unique: false + limit_user: null + limit_user_interval: null + limit_user_message: '' + limit_user_unique: false + entity_limit_total: null + entity_limit_total_interval: null + entity_limit_user: null + entity_limit_user_interval: null + purge: draft + purge_days: 365 + results_disabled: false + results_disabled_ignore: false + results_customize: false + token_view: false + token_update: false + token_delete: false + serial_disabled: false +access: + create: + roles: + - anonymous + - authenticated + users: { } + permissions: { } + view_any: + roles: { } + users: { } + permissions: { } + update_any: + roles: { } + users: { } + permissions: { } + delete_any: + roles: { } + users: { } + permissions: { } + purge_any: + roles: { } + users: { } + permissions: { } + view_own: + roles: { } + users: { } + permissions: { } + update_own: + roles: { } + users: { } + permissions: { } + delete_own: + roles: { } + users: { } + permissions: { } + administer: + roles: { } + users: { } + permissions: { } + test: + roles: { } + users: { } + permissions: { } + configuration: + roles: { } + users: { } + permissions: { } +handlers: + grants_handler: + id: grants_handler + handler_id: grants_handler + label: 'Grants Handler' + notes: '' + status: true + conditions: { } + weight: 0 + settings: + debug: false +variants: { } From 1c52f585c445f7c7e3f4be9251174e5f2b5d49a6 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 11:45:17 +0300 Subject: [PATCH 06/16] UHF-10537: PHPCS --- .../custom/grants_handler/grants_handler.module | 4 ++-- .../src/ApplicationGetterService.php | 15 +++++++++------ .../grants_metadata/src/DocumentContentMapper.php | 3 ++- .../Definition/KuvaErillisDefinition.php | 14 +++++++------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/public/modules/custom/grants_handler/grants_handler.module b/public/modules/custom/grants_handler/grants_handler.module index 5cd1a0180..72ab2e1bf 100644 --- a/public/modules/custom/grants_handler/grants_handler.module +++ b/public/modules/custom/grants_handler/grants_handler.module @@ -1376,11 +1376,11 @@ function grants_handler_preprocess_application_list_item(&$variables): void { return; } - // Get webform by saved form uuid + // Get webform by saved form uuid. $webform = ApplicationHelpers::getWebformByUuid( $submissionData["metadata"]["form_uuid"], $submissionData['application_number']); - // Set webform title + // Set webform title. $variables['applicationFormName'] = $webform->label(); $variables['applicationNumber'] = $submissionData["application_number"]; diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index e13b58476..fe05e10f5 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -50,6 +50,11 @@ final class ApplicationGetterService { */ protected EntityStorageInterface $storage; + /** + * Loaded submissions in array to prevent multiple loads. + * + * @var array + */ protected array $submissions = []; /** @@ -67,7 +72,7 @@ public function __construct( try { $this->storage = $entityTypeManager->getStorage('webform_submission'); } - catch (InvalidPluginDefinitionException|PluginNotFoundException $e) { + catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { } } @@ -91,7 +96,6 @@ public function setGrantsProfileService(GrantsProfileService $grantsProfileServi * * @return \Drupal\helfi_atv\AtvDocument|null * FEtched document. - * */ public function getAtvDocument(string $transactionId, bool $refetch = FALSE): ?AtvDocument { $sParams = [ @@ -102,7 +106,7 @@ public function getAtvDocument(string $transactionId, bool $refetch = FALSE): ?A try { $result = $this->helfiAtvAtvService->searchDocuments($sParams, $refetch); } - catch (AtvDocumentNotFoundException|AtvFailedToConnectException|TokenExpiredException|GuzzleException $e) { + catch (AtvDocumentNotFoundException | AtvFailedToConnectException | TokenExpiredException | GuzzleException $e) { $this->logger->error( 'Failed to get document from ATV. Error: @error', ['@error' => $e->getMessage()] @@ -163,7 +167,7 @@ public function getCompanyApplications( 'service' => 'AvustushakemusIntegraatio', 'user_id' => $userData['sub'], 'lookfor' => $lookForAppEnv . ',applicant_type:' . $selectedRoleData['type'] . - ',applicant_id:' . $selectedRoleData['identifier'], + ',applicant_id:' . $selectedRoleData['identifier'], ]; } else { @@ -338,7 +342,6 @@ public function submissionObjectFromApplicationNumber( // Get serial from application number. $submissionSerial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); - $result = $this->storage ->loadByProperties([ 'serial' => $submissionSerial, @@ -398,7 +401,7 @@ public function submissionObjectFromApplicationNumber( * @param string $applicationNumber * Application number. * - * @return \Drupal\webform\Entity\Webform Webform object. + * @return \Drupal\webform\Entity\Webform * Webform object. */ public function getWebformFromApplicationNumber(string $applicationNumber): Webform { diff --git a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php index b9f6b8d42..5c149452e 100644 --- a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php +++ b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php @@ -132,7 +132,8 @@ private static function processAttachments(array &$typedDataValues): void { $applicationNumber = $typedDataValues["application_number"]; - // Check if the static variable is already populated for the given application number + // Check if the static variable is already populated + // for the given application number. if (!isset(self::$attachmentFileTypes[$applicationNumber])) { self::$attachmentFileTypes[$applicationNumber] = AttachmentHandler::getAttachmentFieldNames( diff --git a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php index bfe928baf..d1ebe48aa 100644 --- a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php +++ b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php @@ -82,7 +82,7 @@ public function getPropertyDefinitions() { 'hankkeen_riskit_keskeisimmat' => [], 'hankkeen_riskit_seuranta' => [], 'hankkeen_riskit_vakiinnuttaminen' => [], - // example forms + // Example forms. 'puuttuva_kentta_1' => [], 'puuttuva_kentta_2' => [], 'vaikka_sahkoposti' => [], @@ -93,7 +93,7 @@ public function getPropertyDefinitions() { ]; foreach ($customQuestions as $key => $value) { - $this->createCustomQuestionDefinitions($key, $value,$info); + $this->createCustomQuestionDefinitions($key, $value, $info); } $info['budgetInfo'] = GrantsBudgetInfoDefinition::create('grants_budget_info') @@ -137,7 +137,7 @@ public function getPropertyDefinitions() { * @param string $key * Webform element key. * @param array $value - * Additional settings for given field. + * Additional settings for given field. * @param array $info * Data definitions. */ @@ -151,11 +151,11 @@ private function createCustomQuestionDefinitions(string $key, array $value, arra $key, ]); // Add type override if set. - if(isset($value['typeOverride'])) { + if (isset($value['typeOverride'])) { $info[$key]->setSetting('typeOverride', $value['typeOverride']); } // Add value callback if set. - if(isset($value['valueCallback'])) { + if (isset($value['valueCallback'])) { $info[$key]->setSetting('valueCallback', $value['valueCallback']); } // Add default value if set or empty value. @@ -163,8 +163,8 @@ private function createCustomQuestionDefinitions(string $key, array $value, arra $info[$key]->setSetting('defaultValue', $value['defaultValue']); } // DO not add defaultValue if not set, this makes all fields inserted into - // data, this is not an issue, but if there's lot of fields data may get confusing. - + // data, this is not an issue, but if there's lot of fields + // data may get confusing. // The negative is that if field is not set required in form, it will not // be added to data. If an empty field & value is wanted, the defaultValue // can be added to specific field in array above. From 63d84be2f584b4cc5da75b53245fcc0a0f20b845 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Mon, 21 Oct 2024 12:50:18 +0300 Subject: [PATCH 07/16] UHF-10537: Add check for nonexistent UUID --- public/modules/custom/grants_handler/grants_handler.module | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/public/modules/custom/grants_handler/grants_handler.module b/public/modules/custom/grants_handler/grants_handler.module index 72ab2e1bf..ca9d877ba 100644 --- a/public/modules/custom/grants_handler/grants_handler.module +++ b/public/modules/custom/grants_handler/grants_handler.module @@ -1376,6 +1376,13 @@ function grants_handler_preprocess_application_list_item(&$variables): void { return; } + if (!isset($submissionData["metadata"]["form_uuid"])) { + \Drupal::logger('grants_handler') + ->error('No form uuid found for submission @submissionId', + ['@submissionId' => $submissionData["application_number"]]); + return; + } + // Get webform by saved form uuid. $webform = ApplicationHelpers::getWebformByUuid( $submissionData["metadata"]["form_uuid"], From 3cf9726fe6b2c4404885c2750facd8c66740083c Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 08:53:59 +0200 Subject: [PATCH 08/16] Comment out parent_loadData in storage controller --- .../src/AttachmentFixerService.php | 2 +- .../src/GrantsHandlerSubmissionStorage.php | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php index 87d506fe6..beb0e4172 100644 --- a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php +++ b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php @@ -44,7 +44,7 @@ public function fixAttachmentsOnApplication(AtvDocument $atvDoc): AtvDocument { // Loop attachments and if attachment is not ok, update the integration ID. foreach ($attachments as $attachment) { - if ($this->areAttachmentsOk($events, $attachment, $attachmentInfo, $appEnv)['form'] === FALSE) { + if ($attachmentInfo && $this->areAttachmentsOk($events, $attachment, $attachmentInfo, $appEnv)['form'] === FALSE) { $this->updateIntegrationIdForAttachment($attachment, $attachmentInfo, $appEnv); } } diff --git a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php index 8dc764114..41cbb10ae 100644 --- a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php +++ b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php @@ -212,7 +212,7 @@ public function setAtvDataToSubmission(AtvDocument $document, WebformSubmissionI * @throws \GuzzleHttp\Exception\GuzzleException */ protected function loadData(array &$webform_submissions): void { - parent::loadData($webform_submissions); +// parent::loadData($webform_submissions); $userRoles = $this->account->getRoles(); // Check that we have required role. @@ -242,18 +242,6 @@ protected function loadData(array &$webform_submissions): void { /** @var \Drupal\helfi_atv\AtvDocument $document */ $document = reset($results); - if (!$document) { - $applicationNumber = ApplicationHelpers::createApplicationNumber($submission, TRUE); - $results = $this->atvService->searchDocuments( - [ - 'transaction_id' => $applicationNumber, - 'lookfor' => 'appenv:' . Helpers::getAppEnv(), - ] - ); - /** @var \Drupal\helfi_atv\AtvDocument $document */ - $document = reset($results); - } - if (!$document) { throw new \Exception('Submission data load failed.'); } @@ -284,5 +272,4 @@ protected function loadData(array &$webform_submissions): void { } } - } From cfb3f0c17fd8bcaf0574bd3ac6ceba220d80ba2d Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 08:53:59 +0200 Subject: [PATCH 09/16] Comment out parent_loadData in storage controller --- .../src/AttachmentFixerService.php | 2 +- .../src/GrantsHandlerSubmissionStorage.php | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php index 87d506fe6..beb0e4172 100644 --- a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php +++ b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php @@ -44,7 +44,7 @@ public function fixAttachmentsOnApplication(AtvDocument $atvDoc): AtvDocument { // Loop attachments and if attachment is not ok, update the integration ID. foreach ($attachments as $attachment) { - if ($this->areAttachmentsOk($events, $attachment, $attachmentInfo, $appEnv)['form'] === FALSE) { + if ($attachmentInfo && $this->areAttachmentsOk($events, $attachment, $attachmentInfo, $appEnv)['form'] === FALSE) { $this->updateIntegrationIdForAttachment($attachment, $attachmentInfo, $appEnv); } } diff --git a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php index 8dc764114..41cbb10ae 100644 --- a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php +++ b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php @@ -212,7 +212,7 @@ public function setAtvDataToSubmission(AtvDocument $document, WebformSubmissionI * @throws \GuzzleHttp\Exception\GuzzleException */ protected function loadData(array &$webform_submissions): void { - parent::loadData($webform_submissions); +// parent::loadData($webform_submissions); $userRoles = $this->account->getRoles(); // Check that we have required role. @@ -242,18 +242,6 @@ protected function loadData(array &$webform_submissions): void { /** @var \Drupal\helfi_atv\AtvDocument $document */ $document = reset($results); - if (!$document) { - $applicationNumber = ApplicationHelpers::createApplicationNumber($submission, TRUE); - $results = $this->atvService->searchDocuments( - [ - 'transaction_id' => $applicationNumber, - 'lookfor' => 'appenv:' . Helpers::getAppEnv(), - ] - ); - /** @var \Drupal\helfi_atv\AtvDocument $document */ - $document = reset($results); - } - if (!$document) { throw new \Exception('Submission data load failed.'); } @@ -284,5 +272,4 @@ protected function loadData(array &$webform_submissions): void { } } - } From a17fbc31458aa3ab309a534f864266fc3e4087e3 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Tue, 29 Oct 2024 12:19:22 +0200 Subject: [PATCH 10/16] UHF-10877: Add rest queries for testing race condition things. Suggestion for fixing race conditions. --- .../src/ApplicationUploaderService.php | 19 ++++++- tools/http/ATV.http | 4 +- tools/http/Integraatio.http | 50 +++++++++++++++++++ tools/http/http-client.env.json | 8 +++ 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 tools/http/Integraatio.http create mode 100644 tools/http/http-client.env.json diff --git a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php index 38d88ae06..53c8c9fbc 100644 --- a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php +++ b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php @@ -191,8 +191,19 @@ public function handleApplicationUploadViaIntegration( * the most recent version available even if integration fails * for some reason. */ - $updatedDocumentFromAtv = $this->handleApplicationUploadToAtv($applicationData, $applicationNumber, $submittedFormData); - $myJSON = Json::encode($updatedDocumentFromAtv->getContent()); + $updatedDocumentFromAtv = $this->handleApplicationUploadToAtv($applicationData, $applicationNumber, $submittedFormData); + $myJSON = Json::encode($updatedDocumentFromAtv->getContent()); + + /* + * This is how we could send the data to the integration w/o saving it to ATV first. + */ +// $webform_submission = $this->applicationGetterService->submissionObjectFromApplicationNumber($applicationNumber); +// $appDocumentContent = +// $this->helfiAtvAtvSchema->typedDataToDocumentContent( +// $applicationData, +// $webform_submission, +// $submittedFormData); +// $myJSON = Json::encode($appDocumentContent); // No matter what the debug value is, we do NOT log json in PROD. if ($this->isDebug() && Helpers::getAppEnv() !== 'PROD') { @@ -213,6 +224,10 @@ public function handleApplicationUploadViaIntegration( try { $headers = []; + // Use service to get desired status if no ATV saving was done. + // $headers['X-Case-Status'] = $this->grantsHandlerApplicationStatusService->getNewStatusHeader(); + + // Get status from updated document. $headers['X-Case-Status'] = $updatedDocumentFromAtv->getStatus(); // We set the data source for integration to be used in controlling diff --git a/tools/http/ATV.http b/tools/http/ATV.http index be6ec438c..c3a407258 100644 --- a/tools/http/ATV.http +++ b/tools/http/ATV.http @@ -1,6 +1,6 @@ # Get single document by transaction_id GET {{atvUrl}}/v1/documents/? - transaction_id={{transaction_id}} + transaction_id={{transactionId}} Accept-Encoding: utf8 X-Api-Key: {{atvApiKey}} @@ -19,7 +19,7 @@ GET {{atvUrl}}/v1/documents/? user_id={{user_id}}& type={{type}}& service_name=AvustushakemusIntegraatio& - transaction_id={{transaction_id}} + transaction_id={{transactionId}} Accept-Encoding: utf8 X-Api-Key: {{atvApiKey}} diff --git a/tools/http/Integraatio.http b/tools/http/Integraatio.http new file mode 100644 index 000000000..fe97c5a54 --- /dev/null +++ b/tools/http/Integraatio.http @@ -0,0 +1,50 @@ +### Create Event via integration API +POST {{integraatioUrl}}/createEvent +Authorization: Basic {{integraatioBasicToken}} +Content-Type: application/json + +{ + "caseId": "{{transactionId}}", + "eventType": "EVENT_INFO", + "eventCode": 0, + "eventSource": "Avustusten kasittelyjarjestelma", + "eventDescription": "Puhakka Tero;09 310 36070;tero.puhakka@hel.fi", + "eventDescription_SV": null, + "eventDescription_EN": null, + "timeUpdated": null, + "timeCreated": "{{$isoTimestamp}}", + "eventTarget": null, + "eventID": "{{$random.uuid}}" +} + +### Create Status Update via integration API +POST {{integraatioUrl}}/updateCitizenCaseStatus +Authorization: Basic {{integraatioBasicToken}} +Content-Type: application/json + +{ + "caseId": "{{transactionId}}", + "citizenCaseStatus" : "PROCESSING", + "eventType" : "STATUS_UPDATE", + "eventCode" : 0, + "eventSource" : "Avustusten kasittelyjarjestelma", + "timeUpdated" : null, + "timeCreated": "{{$isoTimestamp}}" +} + +### Create Message via integration API +POST {{integraatioUrl}}/createConversationMessage +Authorization: Basic {{integraatioBasicToken}} +Content-Type: application/json + +{ +"caseId": "{{transactionId}}", +"messageId" : "{{$random.uuid}}", +"body" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit", +"sentBy" : "Avustusten kasittelyjarjestelma", +"sendDateTime" :"{{$isoTimestamp}}" +} + +### + + diff --git a/tools/http/http-client.env.json b/tools/http/http-client.env.json new file mode 100644 index 000000000..719f9b855 --- /dev/null +++ b/tools/http/http-client.env.json @@ -0,0 +1,8 @@ +{ + "dev": { + "atvUrl": "https://atv-api-hki-kanslia-atv-test.agw.arodevtest.hel.fi", + "transactionId": "LOCALYRTTI12-068-0000647", + "document_id": "28753685-24b8-4542-b1c1-cc70ff9f9fbc", + "integraatioUrl": "https://avustus-integration-test.agw.arodevtest.hel.fi" + } +} From 11879740245e52177e85da6030d62e7d11414996 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 13:29:32 +0200 Subject: [PATCH 11/16] UHF-10537: Refactor to support webform title usage. --- ...webform.webform.kuvaerillis_esimerkki2.yml | 2 - .../src/AttachmentFixerService.php | 2 +- .../grants_handler/grants_handler.module | 7 +- .../src/ApplicationGetterService.php | 40 +++++----- .../src/ApplicationUploaderService.php | 18 +---- .../src/Controller/ApplicationController.php | 78 +++++++++++-------- .../src/GrantsHandlerSubmissionStorage.php | 2 +- .../Block/ApplicationTimeoutMessageBlock.php | 2 +- .../Definition/KuvaErillisDefinition.php | 20 +++-- tools/http/http-client.env.json | 2 +- 10 files changed, 92 insertions(+), 81 deletions(-) diff --git a/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml b/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml index 78aa03ad4..58635ced8 100644 --- a/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml +++ b/conf/cmi/webform.webform.kuvaerillis_esimerkki2.yml @@ -494,7 +494,6 @@ elements: |- '#options': 1: Kyllä 0: Ei - '#default_value': '0' hankesuunnitelma_section: '#type': webform_section '#title': '3.1 Hankesuunnitelma' @@ -509,7 +508,6 @@ elements: |- '#options': 1: Kyllä 0: Ei - '#default_value': '0' hankkeen_tarkoitus_tavoitteet: '#type': textarea '#title': 'Hankkeen tarkoitus ja tavoitteet' diff --git a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php index beb0e4172..fd6f37976 100644 --- a/public/modules/custom/grants_attachments/src/AttachmentFixerService.php +++ b/public/modules/custom/grants_attachments/src/AttachmentFixerService.php @@ -40,7 +40,7 @@ public function fixAttachmentsOnApplication(AtvDocument $atvDoc): AtvDocument { // Get the events from the content. $events = $content['events']; // Get the attachment info from the content. - $attachmentInfo = $content['attachmentsInfo']['attachmentsArray']; + $attachmentInfo = $content['attachmentsInfo']['attachmentsArray'] ?? NULL; // Loop attachments and if attachment is not ok, update the integration ID. foreach ($attachments as $attachment) { diff --git a/public/modules/custom/grants_handler/grants_handler.module b/public/modules/custom/grants_handler/grants_handler.module index 8e4390fdc..94cc1aad4 100644 --- a/public/modules/custom/grants_handler/grants_handler.module +++ b/public/modules/custom/grants_handler/grants_handler.module @@ -938,7 +938,8 @@ function grants_handler_preprocess_webform_submission_data(&$variables) { /** * Implements hook_preprocess_HOOK(). */ -function grants_handler_preprocess_webform_submission(&$variables) { +function grants_handler_preprocess_webform_submission(&$variables): void { + // Get submission object. /** @var \Drupal\webform\Entity\WebformSubmission $submission */ $submission = $variables['webform_submission']; @@ -1512,8 +1513,8 @@ function grants_handler_preprocess_application_list_item(&$variables): void { $status = $applicationStatusService->getWebformStatus($webform); - $variables['openStartDate'] = strtotime($thirdPartySettings['applicationOpen']); - $variables['openEndDate'] = strtotime($thirdPartySettings['applicationClose']); + $variables['openStartDate'] = $thirdPartySettings['applicationOpen'] ? strtotime($thirdPartySettings['applicationOpen']) : ''; + $variables['openEndDate'] = $thirdPartySettings['applicationClose'] ? strtotime($thirdPartySettings['applicationClose']) : ''; $variables['isContinuous'] = $thirdPartySettings['applicationContinuous'] != 0; if (!$variables['isContinuous'] && ($variables['openStartDate'] > time() || $variables['openEndDate'] < time())) { $variables['errorType'] = 'NOT_OPEN'; diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index fe05e10f5..5013a60a6 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -22,6 +22,7 @@ use Drupal\helfi_helsinki_profiili\TokenExpiredException; use Drupal\webform\Entity\Webform; use Drupal\webform\Entity\WebformSubmission; +use Drupal\webform\WebformException; use GuzzleHttp\Exception\GuzzleException; /** @@ -136,7 +137,7 @@ public function getAtvDocument(string $transactionId, bool $refetch = FALSE): ?A * * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException * @throws \Drupal\helfi_atv\AtvFailedToConnectException - * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \GuzzleHttp\Exception\GuzzleException|\Drupal\helfi_helsinki_profiili\TokenExpiredException */ public function getCompanyApplications( array $selectedCompany, @@ -182,8 +183,6 @@ public function getCompanyApplications( /** * Create rows for table. - * - * @var \Drupal\helfi_atv\AtvDocument $document */ foreach ($applicationDocuments as $document) { // Make sure the type is acceptable one. @@ -315,7 +314,6 @@ public function submissionObjectFromApplicationNumber( bool $refetch = FALSE, bool $skipAccessCheck = FALSE, ): ?WebformSubmission { - if (isset($this->submissions[$applicationNumber])) { return $this->submissions[$applicationNumber]; } @@ -374,25 +372,31 @@ public function submissionObjectFromApplicationNumber( /** @var \Drupal\webform\Entity\WebformSubmission $submissionObject */ $submissionObject = reset($result); } - if ($submissionObject) { - $dataDefinition = ApplicationHelpers::getDataDefinition($document->getType()); - $sData = DocumentContentMapper::documentContentToTypedData( - $document->getContent(), - $dataDefinition, - $document->getMetadata() - ); + if (!$submissionObject) { + throw new WebformException('Failed to load submission object with ATV data'); + } - $sData['messages'] = $this->grantsHandlerMessageService->parseMessages($sData); + // Load definition. + $dataDefinition = ApplicationHelpers::getDataDefinition($document->getType()); - // Set submission data from parsed mapper. - $submissionObject->setData($sData); + // Build data. + $sData = DocumentContentMapper::documentContentToTypedData( + $document->getContent(), + $dataDefinition, + $document->getMetadata() + ); - $this->submissions[$applicationNumber] = $submissionObject; + // Parse messages separately. + $sData['messages'] = $this->grantsHandlerMessageService->parseMessages($sData); - return $submissionObject; - } - return NULL; + // Set submission data from parsed mapper. + $submissionObject->setData($sData); + + // Set caching, as we don't want to load this again. + $this->submissions[$applicationNumber] = $submissionObject; + + return $submissionObject; } /** diff --git a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php index 53c8c9fbc..66966a96e 100644 --- a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php +++ b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php @@ -191,19 +191,8 @@ public function handleApplicationUploadViaIntegration( * the most recent version available even if integration fails * for some reason. */ - $updatedDocumentFromAtv = $this->handleApplicationUploadToAtv($applicationData, $applicationNumber, $submittedFormData); - $myJSON = Json::encode($updatedDocumentFromAtv->getContent()); - - /* - * This is how we could send the data to the integration w/o saving it to ATV first. - */ -// $webform_submission = $this->applicationGetterService->submissionObjectFromApplicationNumber($applicationNumber); -// $appDocumentContent = -// $this->helfiAtvAtvSchema->typedDataToDocumentContent( -// $applicationData, -// $webform_submission, -// $submittedFormData); -// $myJSON = Json::encode($appDocumentContent); + $updatedDocumentFromAtv = $this->handleApplicationUploadToAtv($applicationData, $applicationNumber, $submittedFormData); + $myJSON = Json::encode($updatedDocumentFromAtv->getContent()); // No matter what the debug value is, we do NOT log json in PROD. if ($this->isDebug() && Helpers::getAppEnv() !== 'PROD') { @@ -224,9 +213,6 @@ public function handleApplicationUploadViaIntegration( try { $headers = []; - // Use service to get desired status if no ATV saving was done. - // $headers['X-Case-Status'] = $this->grantsHandlerApplicationStatusService->getNewStatusHeader(); - // Get status from updated document. $headers['X-Case-Status'] = $updatedDocumentFromAtv->getStatus(); diff --git a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php index 289fdb878..8d4ff0097 100644 --- a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php +++ b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php @@ -12,7 +12,6 @@ use Drupal\Core\Render\Markup; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\Core\TempStore\TempStoreException; use Drupal\grants_handler\ApplicationAccessHandler; use Drupal\grants_handler\ApplicationGetterService; use Drupal\grants_handler\ApplicationHelpers; @@ -25,8 +24,6 @@ use Drupal\grants_profile\Form\GrantsProfileFormRegisteredCommunity; use Drupal\grants_profile\GrantsProfileService; use Drupal\helfi_atv\AtvDocumentNotFoundException; -use Drupal\helfi_atv\AtvFailedToConnectException; -use Drupal\helfi_helsinki_profiili\TokenExpiredException; use Drupal\webform\Entity\Webform; use Drupal\webform\Entity\WebformSubmission; use Drupal\webform\WebformRequestInterface; @@ -42,11 +39,10 @@ class ApplicationController extends ControllerBase { const ISO8601 = "/^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])" . - "|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)" . - "|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])" . - "|(?:[2468][048]|[13579][26])00)-02-29)(T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d{1,9})" . - "?(?:Z|[+-][01]\d:[0-5]\d))?$/"; - + "|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)" . + "|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])" . + "|(?:[2468][048]|[13579][26])00)-02-29)(T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d{1,9})" . + "?(?:Z|[+-][01]\d:[0-5]\d))?$/"; use StringTranslationTrait; @@ -197,24 +193,15 @@ public function access(AccountInterface $account, string $webform, string $webfo * @return \Drupal\Core\Access\AccessResultInterface * The access result. * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException - * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException * @throws \GuzzleHttp\Exception\GuzzleException */ public function accessByApplicationNumber(AccountInterface $account, string $submission_id): AccessResultInterface { try { $webform_submission = $this->applicationGetterService->submissionObjectFromApplicationNumber($submission_id); } - catch (InvalidPluginDefinitionException | - PluginNotFoundException | + catch (\Exception | EntityStorageException | - TempStoreException | - CompanySelectException | - AtvDocumentNotFoundException | - AtvFailedToConnectException | - TokenExpiredException | - GuzzleException $e) { + CompanySelectException $e) { return AccessResult::forbidden('Submission gettting failed'); } @@ -261,12 +248,10 @@ public function showMessageForDataStatus(string $status): void { default: break; - } if ($message != NULL) { $this->messenger()->addWarning($message); } - } /** @@ -283,7 +268,6 @@ public function showMessageForDataStatus(string $status): void { * Build for the page. */ public function view(string $submission_id, string $view_mode = 'full', string $langcode = 'fi'): array { - $view_mode = 'default'; try { @@ -305,8 +289,6 @@ public function view(string $submission_id, string $view_mode = 'full', string $ '#theme' => 'webform_submission', '#view_mode' => $view_mode, '#webform_submission' => $webform_submission, - // '#editSubmissionLink' => - // Link::fromTextAndUrl(t('Edit application'), $url), ]; // Navigation. @@ -341,7 +323,6 @@ public function view(string $submission_id, string $view_mode = 'full', string $ else { throw new NotFoundHttpException('Application ' . $submission_id . ' not found.'); } - } catch (InvalidPluginDefinitionException | PluginNotFoundException | AtvDocumentNotFoundException | GuzzleException $e) { throw new NotFoundHttpException($e->getMessage()); @@ -366,13 +347,13 @@ public function view(string $submission_id, string $view_mode = 'full', string $ * @throws \GuzzleHttp\Exception\GuzzleException */ public function newApplication(string $webform_id): RedirectResponse { - $webform = Webform::load($webform_id); if (!$this->applicationStatusService->isApplicationOpen($webform)) { // Add message if application is not open. $tOpts = ['context' => 'grants_handler']; - $this->messenger()->addError($this->t('This application is not open', [], $tOpts), TRUE); + $this->messenger() + ->addError($this->t('This application is not open', [], $tOpts), TRUE); $node_storage = $this->entityTypeManager()->getStorage('node'); // @codingStandardsIgnoreStart // Get service page node. @@ -385,7 +366,8 @@ public function newApplication(string $webform_id): RedirectResponse { $res = $query->execute(); if (empty($res)) { // If we end up here, the real issue is with content input. - $this->messenger()->addError($this->t('Service page not found!', [], $tOpts), TRUE); + $this->messenger() + ->addError($this->t('Service page not found!', [], $tOpts), TRUE); return $this->redirect(''); } @@ -430,8 +412,19 @@ public function newApplication(string $webform_id): RedirectResponse { /** * Helper funtion to transform ATV data for print view. + * + * @param $field + * Field. + * @param $pages + * Form pages. + * @param $isSubventionType + * Is subvention type. + * @param $subventionType + * Subvention type. + * @param $langcode + * Language code. */ - private function transformField($field, &$pages, &$isSubventionType, &$subventionType, $langcode) { + private function transformField($field, &$pages, &$isSubventionType, &$subventionType, $langcode): void { if (isset($field['ID'])) { $labelData = json_decode($field['meta'], TRUE); if (!$labelData || $labelData['element']['hidden']) { @@ -489,7 +482,6 @@ private function transformField($field, &$pages, &$isSubventionType, &$subventio if ($field['ID'] === 'fileName') { $field['value'] = Markup::create($field['value'] . '

'); } - } // Handle subvention type composite field. @@ -663,17 +655,37 @@ public function printViewAtv(string $submission_id): array { /** * Returns a page title. + * + * This works better than getTitle, since we know the webform object and can + * get the title from it. + * + * @param \Drupal\webform\Entity\WebformSubmission $webform_submission + * Submission object. + * + * @return string + * Webform title. */ - public function getEditTitle($webform_submission): string { + public function getEditTitle(WebformSubmission $webform_submission): string { $webform = $webform_submission->getWebform(); return $webform->label(); } /** * Returns a page title. + * + * @param string $submission_id + * Application number of the submission. NOT THE OBJECT ID! + * + * @return string + * Webform title + * + * @throws \Drupal\Core\Entity\EntityStorageException + * @throws \Drupal\grants_mandate\CompanySelectException */ - public function getTitle($submission_id): string { - $webform = ApplicationHelpers::getWebformFromApplicationNumber($submission_id); + public function getTitle(string $submission_id): string { + $submission = $this->applicationGetterService->submissionObjectFromApplicationNumber($submission_id); + $webform = $submission->getWebform(); + return $webform->label(); } diff --git a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php index 41cbb10ae..00a21ae0c 100644 --- a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php +++ b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php @@ -212,7 +212,6 @@ public function setAtvDataToSubmission(AtvDocument $document, WebformSubmissionI * @throws \GuzzleHttp\Exception\GuzzleException */ protected function loadData(array &$webform_submissions): void { -// parent::loadData($webform_submissions); $userRoles = $this->account->getRoles(); // Check that we have required role. @@ -272,4 +271,5 @@ protected function loadData(array &$webform_submissions): void { } } + } diff --git a/public/modules/custom/grants_handler/src/Plugin/Block/ApplicationTimeoutMessageBlock.php b/public/modules/custom/grants_handler/src/Plugin/Block/ApplicationTimeoutMessageBlock.php index a53369b78..1b0b1c1c4 100644 --- a/public/modules/custom/grants_handler/src/Plugin/Block/ApplicationTimeoutMessageBlock.php +++ b/public/modules/custom/grants_handler/src/Plugin/Block/ApplicationTimeoutMessageBlock.php @@ -44,7 +44,7 @@ public function build(): array { } $applicationCloseTime = $webform->getThirdPartySetting('grants_metadata', 'applicationClose'); - $applicationCloseTimestamp = strtotime($applicationCloseTime); + $applicationCloseTimestamp = $applicationCloseTime ? strtotime($applicationCloseTime) : FALSE; $currentTimestamp = strtotime('now'); // Do not render this message if the form is already closed. diff --git a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php index d1ebe48aa..d625fab6c 100644 --- a/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php +++ b/public/modules/custom/grants_metadata/src/TypedData/Definition/KuvaErillisDefinition.php @@ -18,7 +18,6 @@ class KuvaErillisDefinition extends ComplexDataDefinitionBase { */ public function getPropertyDefinitions() { if (!isset($this->propertyDefinitions)) { - $info = &$this->propertyDefinitions; foreach ($this->getBaseProperties() as $key => $property) { @@ -35,11 +34,23 @@ public function getPropertyDefinitions() { ]); $customQuestions = [ - 'hankesuunnitelma_jatkohakemus' => [], + 'hankesuunnitelma_radios' => [ + 'type' => 'boolean', + 'typeOverride' => [ + 'dataType' => 'string', + 'jsonType' => 'bool', + ], + ], + 'hankesuunnitelma_jatkohakemus' => [ + 'type' => 'boolean', + 'typeOverride' => [ + 'dataType' => 'string', + 'jsonType' => 'bool', + ], + ], 'hankkeen_tarkoitus_tavoitteet' => [], 'hankkeen_toimenpiteet_aikataulu' => [], 'hankkeen_toimenpiteet_alkupvm' => [ - 'defaultValue' => '', 'typeOverride' => [ 'dataType' => 'string', 'jsonType' => 'datetime', @@ -53,7 +64,6 @@ public function getPropertyDefinitions() { ], ], 'hankkeen_toimenpiteet_loppupvm' => [ - 'defaultValue' => '', 'typeOverride' => [ 'dataType' => 'string', 'jsonType' => 'datetime', @@ -143,7 +153,7 @@ public function getPropertyDefinitions() { */ private function createCustomQuestionDefinitions(string $key, array $value, array &$info): void { // Create initial definition with position in JSON. - $info[$key] = DataDefinition::create('string') + $info[$key] = DataDefinition::create($value['type'] ?? 'string') ->setSetting('jsonPath', [ 'compensation', 'customQuestionsInfo', diff --git a/tools/http/http-client.env.json b/tools/http/http-client.env.json index 719f9b855..b2d490c53 100644 --- a/tools/http/http-client.env.json +++ b/tools/http/http-client.env.json @@ -1,7 +1,7 @@ { "dev": { "atvUrl": "https://atv-api-hki-kanslia-atv-test.agw.arodevtest.hel.fi", - "transactionId": "LOCALYRTTI12-068-0000647", + "transactionId": "LOCALYRTTI12-070-0000009", "document_id": "28753685-24b8-4542-b1c1-cc70ff9f9fbc", "integraatioUrl": "https://avustus-integration-test.agw.arodevtest.hel.fi" } From 1596852c96086fb0b133076c42c4629698b0c4b7 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 14:06:23 +0200 Subject: [PATCH 12/16] UHF-10817: PHPCS --- .../src/ApplicationGetterService.php | 2 +- .../src/Controller/ApplicationController.php | 22 +++++++++---------- .../src/GrantsHandlerSubmissionStorage.php | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index 5013a60a6..9166dd80d 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -181,7 +181,7 @@ public function getCompanyApplications( $applicationDocuments = $this->helfiAtvAtvService->searchDocuments($searchParams); - /** + /* * Create rows for table. */ foreach ($applicationDocuments as $document) { diff --git a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php index 8d4ff0097..6248cd44c 100644 --- a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php +++ b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php @@ -413,18 +413,18 @@ public function newApplication(string $webform_id): RedirectResponse { /** * Helper funtion to transform ATV data for print view. * - * @param $field - * Field. - * @param $pages - * Form pages. - * @param $isSubventionType - * Is subvention type. - * @param $subventionType - * Subvention type. - * @param $langcode - * Language code. + * @param array $field + * Field. + * @param array $pages + * Form pages. + * @param bool $isSubventionType + * Is subvention type. + * @param string $subventionType + * Subvention type. + * @param string $langcode + * Language code. */ - private function transformField($field, &$pages, &$isSubventionType, &$subventionType, $langcode): void { + private function transformField(array $field, array &$pages, bool &$isSubventionType, string &$subventionType, string $langcode): void { if (isset($field['ID'])) { $labelData = json_decode($field['meta'], TRUE); if (!$labelData || $labelData['element']['hidden']) { diff --git a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php index e6b51a948..00a21ae0c 100644 --- a/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php +++ b/public/modules/custom/grants_handler/src/GrantsHandlerSubmissionStorage.php @@ -271,4 +271,5 @@ protected function loadData(array &$webform_submissions): void { } } + } From 2c9f55ea491aacd699773bd3a50c9a14221fc4d6 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 15:09:37 +0200 Subject: [PATCH 13/16] UHF-10817: Refactor ApplicationController. --- .../grants_handler/grants_handler.routing.yml | 4 +- .../src/Controller/ApplicationController.php | 248 ----------- .../src/Controller/AtvPrintViewController.php | 395 ++++++++++++++++++ 3 files changed, 397 insertions(+), 250 deletions(-) create mode 100644 public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php diff --git a/public/modules/custom/grants_handler/grants_handler.routing.yml b/public/modules/custom/grants_handler/grants_handler.routing.yml index 70d03be36..837324868 100644 --- a/public/modules/custom/grants_handler/grants_handler.routing.yml +++ b/public/modules/custom/grants_handler/grants_handler.routing.yml @@ -61,10 +61,10 @@ grants_handler.copy_application_modal: requirements: _custom_access: '\Drupal\grants_handler\Controller\ApplicationController::accessByApplicationNumber' -grants_handler.print_application_atv: +grants_handler.atv_print_view: path: '/hakemus/{submission_id}/tulosta' defaults: _title_callback: '\Drupal\grants_handler\Controller\ApplicationController::getTitle' - _controller: '\Drupal\grants_handler\Controller\ApplicationController::printViewAtv' + _controller: '\Drupal\grants_handler\Controller\AtvPrintViewController' requirements: _custom_access: '\Drupal\grants_handler\Controller\ApplicationController::accessByApplicationNumber' diff --git a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php index 6248cd44c..c3f2ba13d 100644 --- a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php +++ b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php @@ -9,19 +9,14 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityStorageException; -use Drupal\Core\Render\Markup; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\grants_handler\ApplicationAccessHandler; use Drupal\grants_handler\ApplicationGetterService; -use Drupal\grants_handler\ApplicationHelpers; use Drupal\grants_handler\ApplicationInitService; use Drupal\grants_handler\ApplicationStatusService; -use Drupal\grants_handler\Plugin\WebformElement\CompensationsComposite; use Drupal\grants_mandate\CompanySelectException; use Drupal\grants_metadata\ApplicationDataService; -use Drupal\grants_metadata\InputmaskHandler; -use Drupal\grants_profile\Form\GrantsProfileFormRegisteredCommunity; use Drupal\grants_profile\GrantsProfileService; use Drupal\helfi_atv\AtvDocumentNotFoundException; use Drupal\webform\Entity\Webform; @@ -410,249 +405,6 @@ public function newApplication(string $webform_id): RedirectResponse { ); } - /** - * Helper funtion to transform ATV data for print view. - * - * @param array $field - * Field. - * @param array $pages - * Form pages. - * @param bool $isSubventionType - * Is subvention type. - * @param string $subventionType - * Subvention type. - * @param string $langcode - * Language code. - */ - private function transformField(array $field, array &$pages, bool &$isSubventionType, string &$subventionType, string $langcode): void { - if (isset($field['ID'])) { - $labelData = json_decode($field['meta'], TRUE); - if (!$labelData || $labelData['element']['hidden']) { - return; - } - // Handle application type field. - if ($field['ID'] === 'applicantType' && $field['value'] === 'registered_community') { - $field['value'] = '' . $this->t('Registered community', [], ['langcode' => $langcode]); - // Add other types here when needed. - } - // Handle dates. - if (preg_match(self::ISO8601, $field['value'])) { - $field['value'] = date_format(date_create($field['value']), 'd.m.Y'); - } - - // Handle input masks. - if (isset($labelData['element']['input_mask'])) { - $field['value'] = InputmaskHandler::convertPossibleInputmaskValue($field['value'], $labelData); - } - - // Handle application type field. - if ($field['ID'] === 'issuer') { - $issuerLanguageOptions = [ - 'context' => 'Grant Issuers', - 'langcode' => $langcode, - ]; - $issuerArray = [ - "1" => $this->t('State', [], $issuerLanguageOptions), - "3" => $this->t('EU', [], $issuerLanguageOptions), - "4" => $this->t('Other', [], $issuerLanguageOptions), - "5" => $this->t('Foundation', [], $issuerLanguageOptions), - "6" => $this->t("STEA", [], $issuerLanguageOptions), - ]; - $field['value'] = $issuerArray[$field['value']]; - } - if ($labelData['section']['id'] === 'application_number' || $labelData['section']['id'] === 'status') { - unset($field); - unset($labelData['section']); - return; - } - if ($labelData['section']['id'] === 'lisatiedot_ja_liitteet_section') { - if ($field['ID'] === 'integrationID' || $field['ID'] === 'isNewAttachment' || $field['ID'] === 'fileType') { - unset($field); - return; - } - if ($field['ID'] === 'isDeliveredLater' || $field['ID'] === 'isIncludedInOtherFile') { - if ($field['value'] === 'false') { - unset($field); - return; - } - else { - $field['value'] = Markup::create('
'); - } - } - if ($field['ID'] === 'fileName') { - $field['value'] = Markup::create($field['value'] . '

'); - } - } - - // Handle subvention type composite field. - if ($field['ID'] === 'subventionType') { - $typeNames = CompensationsComposite::getOptionsForTypes($langcode); - $subventionType = $typeNames[$field['value']]; - $isSubventionType = TRUE; - return; - } - elseif ($isSubventionType) { - $labelData['element']['label'] = $subventionType; - $isSubventionType = FALSE; - } - - if ($field['ID'] == 'role') { - $roles = GrantsProfileFormRegisteredCommunity::getOfficialRoles(); - $role = $roles[$field['value']]; - if ($role) { - $field['value'] = $role; - } - } - - if (isset($field) && array_key_exists('value', $field) && $field['value'] === 'true') { - $field['value'] = $this->t('Yes', [], [ - 'context' => 'grants_handler', - 'langcode' => $langcode, - ]); - } - - if (isset($field) && array_key_exists('value', $field) && $field['value'] === 'false') { - $field['value'] = $this->t('No', [], [ - 'context' => 'grants_handler', - 'langcode' => $langcode, - ]); - } - - if ($field['value'] === '') { - $field['value'] = '-'; - } - - $newField = [ - 'ID' => $field['ID'], - 'value' => $labelData['element']['valueTranslation'] ?? $field['value'], - 'valueType' => $field['valueType'], - 'label' => $labelData['element']['label'], - 'weight' => $labelData['element']['weight'], - ]; - $pageNumber = $labelData['page']['number']; - if (!isset($pages[$pageNumber])) { - $pages[$pageNumber] = [ - 'label' => $labelData['page']['label'], - 'id' => $labelData['page']['id'], - 'sections' => [], - ]; - } - $sectionId = $labelData['section']['id']; - if (!isset($pages[$pageNumber]['sections'][$sectionId])) { - $pages[$pageNumber]['sections'][$sectionId] = [ - 'label' => $labelData['section']['label'], - 'id' => $labelData['section']['id'], - 'weight' => $labelData['section']['weight'], - 'fields' => [], - ]; - } - $pages[$pageNumber]['sections'][$sectionId]['fields'][] = $newField; - return; - } - $isSubventionType = FALSE; - $subventionType = ''; - - if (is_array($field)) { - foreach ($field as $subField) { - $this->transformField($subField, $pages, $isSubventionType, $subventionType, $langcode); - } - } - } - - /** - * Print view for single application in ATV schema. - * - * @param string $submission_id - * Application number for submission. - * - * @return array - * Render array for the page. - */ - public function printViewAtv(string $submission_id): array { - $isSubventionType = FALSE; - $subventionType = ''; - try { - /** @var \Drupal\helfi_atv\AtvDocument $atv_document */ - $atv_document = ApplicationHelpers::atvDocumentFromApplicationNumber($submission_id); - } - catch (\Exception $e) { - throw new NotFoundHttpException('Application ' . $submission_id . ' not found.'); - } - $langcode = $atv_document->getMetadata()['language']; - - $newPages = []; - // Iterate over regular fields. - $compensation = $atv_document->jsonSerialize()['content']['compensation']; - - foreach ($compensation as $page) { - if (!is_array($page)) { - continue; - } - foreach ($page as $field) { - $this->transformField($field, $newPages, $isSubventionType, $subventionType, $langcode); - } - } - $attachments = $atv_document->jsonSerialize()['content']['attachmentsInfo']; - foreach ($attachments as $page) { - if (!is_array($page)) { - continue; - } - foreach ($page as $field) { - $this->transformField($field, $newPages, $isSubventionType, $subventionType, $langcode); - } - } - - // Sort the fields based on weight. - foreach ($newPages as $pageKey => $page) { - foreach ($page['sections'] as $sectionKey => $section) { - usort($newPages[$pageKey]['sections'][$sectionKey]['fields'], function ($fieldA, $fieldB) { - return $fieldA['weight'] - $fieldB['weight']; - }); - } - } - - if (isset($compensation['additionalInformation'])) { - $tOpts = [ - 'context' => 'grants_handler', - 'langcode' => $langcode, - ]; - $field = [ - 'ID' => 'additionalInformationField', - 'value' => $compensation['additionalInformation'], - 'valueType' => 'string', - 'label' => $this->t('Additional Information', [], $tOpts), - 'weight' => 1, - ]; - $sections = []; - $sections['section'] = [ - 'label' => $this->t('Additional information concerning the application', [], $tOpts), - 'id' => 'additionalInformationPageSection', - 'weight' => 1, - 'fields' => [$field], - ]; - $newPages['additionalInformation'] = [ - 'label' => $this->t('Additional Information', [], $tOpts), - 'id' => 'additionalInformationPage', - 'sections' => $sections, - ]; - } - - // Set correct template. - $build = [ - '#theme' => 'grants_handler_print_atv_document', - '#atv_document' => $atv_document->jsonSerialize(), - '#pages' => $newPages, - '#document_langcode' => $atv_document->getMetadata()['language'], - '#cache' => [ - 'contexts' => [ - 'url.path', - ], - ], - ]; - - return $build; - } - /** * Returns a page title. * diff --git a/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php b/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php new file mode 100644 index 000000000..2c1997069 --- /dev/null +++ b/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php @@ -0,0 +1,395 @@ +getMetadata()['language']; + + $newPages = []; + // Iterate over regular fields. + $compensation = $atv_document->jsonSerialize()['content']['compensation']; + + foreach ($compensation as $page) { + if (!is_array($page)) { + continue; + } + foreach ($page as $field) { + $this->transformField($field, $newPages, $isSubventionType, $subventionType, $langcode); + } + } + $attachments = $atv_document->jsonSerialize()['content']['attachmentsInfo']; + foreach ($attachments as $page) { + if (!is_array($page)) { + continue; + } + foreach ($page as $field) { + $this->transformField($field, $newPages, $isSubventionType, $subventionType, $langcode); + } + } + + // Sort the fields based on weight. + foreach ($newPages as $pageKey => $page) { + foreach ($page['sections'] as $sectionKey => $section) { + usort($newPages[$pageKey]['sections'][$sectionKey]['fields'], function ($fieldA, $fieldB) { + return $fieldA['weight'] - $fieldB['weight']; + }); + } + } + + if (isset($compensation['additionalInformation'])) { + $tOpts = [ + 'context' => 'grants_handler', + 'langcode' => $langcode, + ]; + $field = [ + 'ID' => 'additionalInformationField', + 'value' => $compensation['additionalInformation'], + 'valueType' => 'string', + 'label' => $this->t('Additional Information', [], $tOpts), + 'weight' => 1, + ]; + $sections = []; + $sections['section'] = [ + 'label' => $this->t('Additional information concerning the application', [], $tOpts), + 'id' => 'additionalInformationPageSection', + 'weight' => 1, + 'fields' => [$field], + ]; + $newPages['additionalInformation'] = [ + 'label' => $this->t('Additional Information', [], $tOpts), + 'id' => 'additionalInformationPage', + 'sections' => $sections, + ]; + } + + // Set correct template. + return [ + '#theme' => 'grants_handler_print_atv_document', + '#atv_document' => $atv_document->jsonSerialize(), + '#pages' => $newPages, + '#document_langcode' => $atv_document->getMetadata()['language'], + '#cache' => [ + 'contexts' => [ + 'url.path', + ], + ], + ]; + } + + /** + * Helper funtion to transform ATV data for print view. + * + * @param mixed $field + * Field. + * @param array $pages + * Form pages. + * @param bool $isSubventionType + * Is subvention type. + * @param string $subventionType + * Subvention type. + * @param string $langcode + * Language code. + */ + private function transformField(mixed $field, array &$pages, bool &$isSubventionType, string &$subventionType, string $langcode): void { + if (isset($field['ID'])) { + $labelData = json_decode($field['meta'], TRUE); + if (!$labelData || $labelData['element']['hidden']) { + return; + } + + $this->handleContent($field, $labelData, $langcode, $isSubventionType, $subventionType); + + if ($field['value'] === '') { + $field['value'] = '-'; + } + + $newField = [ + 'ID' => $field['ID'], + 'value' => $labelData['element']['valueTranslation'] ?? $field['value'], + 'valueType' => $field['valueType'], + 'label' => $labelData['element']['label'], + 'weight' => $labelData['element']['weight'], + ]; + $pageNumber = $labelData['page']['number']; + if (!isset($pages[$pageNumber])) { + $pages[$pageNumber] = [ + 'label' => $labelData['page']['label'], + 'id' => $labelData['page']['id'], + 'sections' => [], + ]; + } + $sectionId = $labelData['section']['id']; + if (!isset($pages[$pageNumber]['sections'][$sectionId])) { + $pages[$pageNumber]['sections'][$sectionId] = [ + 'label' => $labelData['section']['label'], + 'id' => $labelData['section']['id'], + 'weight' => $labelData['section']['weight'], + 'fields' => [], + ]; + } + $pages[$pageNumber]['sections'][$sectionId]['fields'][] = $newField; + return; + } + $isSubventionType = FALSE; + $subventionType = ''; + + if (is_array($field)) { + foreach ($field as $subField) { + $this->transformField($subField, $pages, $isSubventionType, $subventionType, $langcode); + } + } + } + + /** + * Handle application content fields. + * + * @param array $field + * Field. + * @param array $labelData + * Label data. + * @param string $langcode + * Language code. + * @param bool $isSubventionType + * Is subvention type. + * @param string $subventionType + * Subvention type. + */ + private function handleContent( + array &$field, + array $labelData, + string $langcode, + bool &$isSubventionType, + string &$subventionType, + ): void { + $this->handleApplicantType($field, $langcode); + $this->handleDates($field); + $this->handleInputMasks($field, $labelData); + $this->handleIssuer($field, $langcode); + $this->handleSection($field, $labelData); + $this->handleLiitteetSection($field); + $this->handleSubventionType($field, $labelData, $langcode, $isSubventionType, $subventionType); + $this->handleRole($field); + $this->handleBooleanValues($field, $langcode); + } + + /** + * Handle applicant type. + * + * @param array $field + * Field. + * @param string $langcode + * Language code. + */ + private function handleApplicantType(array &$field, string $langcode): void { + if ($field['ID'] === 'applicantType' && $field['value'] === 'registered_community') { + $field['value'] = '' . $this->t('Registered community', [], ['langcode' => $langcode]); + } + } + + /** + * Handle dates. + * + * @param array $field + * Field. + */ + private function handleDates(array &$field): void { + if (preg_match(self::ISO8601, $field['value'])) { + $field['value'] = date_format(date_create($field['value']), 'd.m.Y'); + } + } + + /** + * Handle input masks. + * + * @param array $field + * Field. + * @param array $labelData + * Label data. + */ + private function handleInputMasks(array &$field, array $labelData): void { + if (isset($labelData['element']['input_mask'])) { + $field['value'] = InputmaskHandler::convertPossibleInputmaskValue($field['value'], $labelData); + } + } + + /** + * Handle issuer. + * + * @param array $field + * Field. + * @param string $langcode + * Language code. + */ + private function handleIssuer(array &$field, string $langcode): void { + if ($field['ID'] === 'issuer') { + $issuerLanguageOptions = [ + 'context' => 'Grant Issuers', + 'langcode' => $langcode, + ]; + $issuerArray = [ + "1" => $this->t('State', [], $issuerLanguageOptions), + "3" => $this->t('EU', [], $issuerLanguageOptions), + "4" => $this->t('Other', [], $issuerLanguageOptions), + "5" => $this->t('Foundation', [], $issuerLanguageOptions), + "6" => $this->t("STEA", [], $issuerLanguageOptions), + ]; + $field['value'] = $issuerArray[$field['value']]; + } + } + + /** + * Handle section. + * + * @param array $field + * Field. + * @param array $labelData + * Label data. + */ + private function handleSection(array &$field, array &$labelData): void { + if ($labelData['section']['id'] === 'application_number' || $labelData['section']['id'] === 'status') { + unset($field); + unset($labelData['section']); + } + } + + /** + * Handle liitteet section. + * + * @param array $field + * Field. + */ + private function handleLiitteetSection(array &$field): void { + if ($field['ID'] === 'integrationID' || $field['ID'] === 'isNewAttachment' || $field['ID'] === 'fileType') { + unset($field); + return; + } + if ($field['ID'] === 'isDeliveredLater' || $field['ID'] === 'isIncludedInOtherFile') { + if ($field['value'] === 'false') { + unset($field); + return; + } + else { + $field['value'] = Markup::create('
'); + } + } + if ($field['ID'] === 'fileName') { + $field['value'] = Markup::create($field['value'] . '

'); + } + } + + /** + * Handle subventiontypes. + * + * @param array $field + * Field. + * @param array $labelData + * Label data. + * @param string $langcode + * Language code. + * @param bool $isSubventionType + * Is subvention type. + * @param string $subventionType + * Subvention type. + */ + private function handleSubventionType( + array &$field, + array &$labelData, + string $langcode, + bool &$isSubventionType, + string &$subventionType, + ): void { + if ($field['ID'] === 'subventionType') { + $typeNames = CompensationsComposite::getOptionsForTypes($langcode); + $subventionType = $typeNames[$field['value']]; + $isSubventionType = TRUE; + } + elseif ($isSubventionType) { + $labelData['element']['label'] = $subventionType; + $isSubventionType = FALSE; + } + } + + /** + * Handle role. + * + * @param array $field + * Field. + */ + private function handleRole(array &$field): void { + if ($field['ID'] == 'role') { + $roles = GrantsProfileFormRegisteredCommunity::getOfficialRoles(); + $role = $roles[$field['value']]; + if ($role) { + $field['value'] = $role; + } + } + } + + /** + * Handle boolean values. + * + * @param array $field + * Field. + * @param string $langcode + * Language code. + */ + private function handleBooleanValues(array &$field, string $langcode): void { + if (array_key_exists('value', $field)) { + if ($field['value'] === 'true') { + $field['value'] = $this->t('Yes', [], [ + 'context' => 'grants_handler', + 'langcode' => $langcode, + ]); + } + elseif ($field['value'] === 'false') { + $field['value'] = $this->t('No', [], [ + 'context' => 'grants_handler', + 'langcode' => $langcode, + ]); + } + } + } + +} From 660adf609838b6af3822522414545ea1da5039fb Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Thu, 31 Oct 2024 15:19:02 +0200 Subject: [PATCH 14/16] UHF-10817: Remove base Exception throwing. --- .../custom/grants_handler/src/ApplicationGetterService.php | 3 +-- .../grants_handler/src/Controller/ApplicationController.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index 9166dd80d..3204cc8e3 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -306,7 +306,6 @@ public function getCompanyApplications( * * @throws \Drupal\Core\Entity\EntityStorageException * @throws \Drupal\grants_mandate\CompanySelectException - * @throws \Exception */ public function submissionObjectFromApplicationNumber( string $applicationNumber, @@ -335,7 +334,7 @@ public function submissionObjectFromApplicationNumber( // Should we throw an error here? if (!$webform) { - throw new \Exception('Webform not found'); + throw new WebformException('Webform not found'); } // Get serial from application number. $submissionSerial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); diff --git a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php index c3f2ba13d..1d3d7bffc 100644 --- a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php +++ b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php @@ -194,7 +194,7 @@ public function accessByApplicationNumber(AccountInterface $account, string $sub try { $webform_submission = $this->applicationGetterService->submissionObjectFromApplicationNumber($submission_id); } - catch (\Exception | + catch ( EntityStorageException | CompanySelectException $e) { return AccessResult::forbidden('Submission gettting failed'); From 4bf644e97c695cb59df62b6ba8219e74cce5d422 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Fri, 1 Nov 2024 14:38:44 +0200 Subject: [PATCH 15/16] UHF-10817: A bit more refactoring to remove static methods & calls. --- .../src/AttachmentHandler.php | 1 + .../grants_handler/grants_handler.module | 9 +- .../grants_handler.services.yml | 9 +- .../src/ApplicationAccessHandler.php | 13 +- .../src/ApplicationGetterService.php | 99 +++--- .../grants_handler/src/ApplicationHelpers.php | 291 +----------------- .../src/ApplicationStatusService.php | 4 + .../src/ApplicationUploaderService.php | 69 ++++- .../src/Controller/ApplicationController.php | 128 ++------ .../src/Controller/AtvPrintViewController.php | 24 +- .../Plugin/WebformHandler/GrantsHandler.php | 2 +- .../grants_metadata.services.yml | 3 +- .../src/ApplicationDataService.php | 56 +++- .../src/DocumentContentMapper.php | 6 +- 14 files changed, 235 insertions(+), 479 deletions(-) diff --git a/public/modules/custom/grants_attachments/src/AttachmentHandler.php b/public/modules/custom/grants_attachments/src/AttachmentHandler.php index 5730e689e..94049cbcd 100644 --- a/public/modules/custom/grants_attachments/src/AttachmentHandler.php +++ b/public/modules/custom/grants_attachments/src/AttachmentHandler.php @@ -138,6 +138,7 @@ public static function getAttachmentFieldNames(string $applicationNumber, $preve // This could probably be done just by parsing the application number, // however this more futureproof. $webform = ApplicationHelpers::getWebformFromApplicationNumber($applicationNumber); + if (!$webform) { return []; } diff --git a/public/modules/custom/grants_handler/grants_handler.module b/public/modules/custom/grants_handler/grants_handler.module index 94cc1aad4..611e567b3 100644 --- a/public/modules/custom/grants_handler/grants_handler.module +++ b/public/modules/custom/grants_handler/grants_handler.module @@ -1384,10 +1384,11 @@ function grants_handler_preprocess_application_list_item(&$variables): void { return; } - // Get webform by saved form uuid. - $webform = ApplicationHelpers::getWebformByUuid( - $submissionData["metadata"]["form_uuid"], - $submissionData['application_number']); + /** @var \Drupal\grants_handler\ApplicationGetterService $applicationGetterService */ + $applicationGetterService = \Drupal::service('grants_handler.application_getter_service'); + + // Get webform. + $webform = $applicationGetterService->getWebformFromApplicationNumber($submissionData["application_number"]); // Set webform title. $variables['applicationFormName'] = $webform->label(); diff --git a/public/modules/custom/grants_handler/grants_handler.services.yml b/public/modules/custom/grants_handler/grants_handler.services.yml index c054cdd8b..12ba9cd06 100644 --- a/public/modules/custom/grants_handler/grants_handler.services.yml +++ b/public/modules/custom/grants_handler/grants_handler.services.yml @@ -155,9 +155,14 @@ services: '@messenger', '@grants_handler.application_getter_service', '@helfi_helsinki_profiili.userdata', - '@grants_attachments.attachment_fixer_service' + '@grants_attachments.attachment_fixer_service', + '@current_user', + '@database' ] grants_handler.application_access_handler: class: Drupal\grants_handler\ApplicationAccessHandler - arguments: ['@grants_profile.service'] + arguments: [ + '@grants_profile.service', + '@grants_handler.application_getter_service' + ] diff --git a/public/modules/custom/grants_handler/src/ApplicationAccessHandler.php b/public/modules/custom/grants_handler/src/ApplicationAccessHandler.php index 3919b5d13..c8181a755 100644 --- a/public/modules/custom/grants_handler/src/ApplicationAccessHandler.php +++ b/public/modules/custom/grants_handler/src/ApplicationAccessHandler.php @@ -6,7 +6,6 @@ use Drupal\grants_mandate\CompanySelectException; use Drupal\grants_profile\GrantsProfileService; -use Drupal\helfi_atv\AtvDocumentNotFoundException; use Drupal\webform\Entity\WebformSubmission; /** @@ -19,6 +18,7 @@ */ public function __construct( private GrantsProfileService $grantsProfileService, + private ApplicationGetterService $applicationGetterService, ) {} /** @@ -30,7 +30,8 @@ public function __construct( * @return bool * Access status * - * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Drupal\grants_profile\GrantsProfileException + * @throws \Drupal\grants_mandate\CompanySelectException */ public function singleSubmissionAccess(WebformSubmission $webform_submission): bool { @@ -51,12 +52,12 @@ public function singleSubmissionAccess(WebformSubmission $webform_submission): b return FALSE; } - try { - $atvDoc = ApplicationHelpers::atvDocumentFromApplicationNumber($webformData['application_number']); - } - catch (AtvDocumentNotFoundException $e) { + $atvDoc = $this->applicationGetterService->getAtvDocument($webformData['application_number']); + + if (!$atvDoc) { return FALSE; } + $atvMetadata = $atvDoc->getMetadata(); // Mismatch between profile and application applicant type. if ($companyType !== $webformData['hakijan_tiedot']['applicantType']) { diff --git a/public/modules/custom/grants_handler/src/ApplicationGetterService.php b/public/modules/custom/grants_handler/src/ApplicationGetterService.php index 3204cc8e3..8e04eb45e 100644 --- a/public/modules/custom/grants_handler/src/ApplicationGetterService.php +++ b/public/modules/custom/grants_handler/src/ApplicationGetterService.php @@ -6,12 +6,10 @@ use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Component\Plugin\Exception\PluginNotFoundException; -use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\grants_mandate\CompanySelectException; -use Drupal\grants_metadata\AtvSchema; use Drupal\grants_metadata\DocumentContentMapper; use Drupal\grants_profile\GrantsProfileService; use Drupal\helfi_atv\AtvDocument; @@ -44,13 +42,6 @@ final class ApplicationGetterService { */ protected LoggerChannelInterface $logger; - /** - * Webform submission storage. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected EntityStorageInterface $storage; - /** * Loaded submissions in array to prevent multiple loads. * @@ -70,11 +61,6 @@ public function __construct( private readonly EntityTypeManagerInterface $entityTypeManager, ) { $this->logger = $loggerChannelFactory->get('application_getter_service'); - try { - $this->storage = $entityTypeManager->getStorage('webform_submission'); - } - catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { - } } /** @@ -185,42 +171,12 @@ public function getCompanyApplications( * Create rows for table. */ foreach ($applicationDocuments as $document) { - // Make sure the type is acceptable one. - $docArray = $document->toArray(); - $id = AtvSchema::extractDataForWebForm( - $docArray['content'], ['applicationNumber'] - ); - if (empty($id['applicationNumber'])) { - continue; - } + $applicationNumber = $document->getTransactionId(); if (array_key_exists($document->getType(), Helpers::getApplicationTypes())) { try { - // Convert the data. - $dataDefinition = ApplicationHelpers::getDataDefinition($document->getType()); - $submissionData = DocumentContentMapper::documentContentToTypedData( - $document->getContent(), - $dataDefinition, - $document->getMetadata() - ); - - $metaData = $document->getMetadata(); - - // Load the webform submission ID. - $applicationNumber = $submissionData['application_number']; - $serial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); - - $webformUuidExists = isset($metaData['form_uuid']) && !empty($metaData['form_uuid']); - $webform = $webformUuidExists - ? ApplicationHelpers::getWebformByUuid($metaData['form_uuid'], $applicationNumber) - : ApplicationHelpers::getWebformFromApplicationNumber($applicationNumber); - - if (!$webform || !$serial) { - continue; - } - - $submissionId = ApplicationHelpers::getSubmissionIdWithSerialAndWebformId($serial, $webform->id(), $document); + $submission = $this->submissionObjectFromApplicationNumber($applicationNumber, $document, FALSE, TRUE); } catch (\Throwable $e) { $this->logger->error( @@ -233,17 +189,15 @@ public function getCompanyApplications( continue; } - if (!$submissionData || !$submissionId) { - continue; - } + $submissionData = $submission->getData(); $submissionData['messages'] = $this->grantsHandlerMessageService->parseMessages($submissionData); $submission = [ '#theme' => $themeHook, '#submission' => $submissionData, '#document' => $document, - '#webform' => $webform, - '#submission_id' => $submissionId, + '#webform' => $submission->getWebform(), + '#submission_id' => $submission->id(), ]; $ts = strtotime($submissionData['form_timestamp_created'] ?? ''); @@ -329,8 +283,8 @@ public function submissionObjectFromApplicationNumber( $document = $this->getAtvDocument($applicationNumber, $refetch); } - // Get webform via uuid that is saved to document metadata. - $webform = ApplicationHelpers::getWebformByUuid($document->getMetadata()['form_uuid'], $applicationNumber); + // Get WebFrom from application number. + $webform = $this->getWebformFromApplicationNumber($applicationNumber); // Should we throw an error here? if (!$webform) { @@ -339,11 +293,16 @@ public function submissionObjectFromApplicationNumber( // Get serial from application number. $submissionSerial = ApplicationHelpers::getSerialFromApplicationNumber($applicationNumber); - $result = $this->storage - ->loadByProperties([ - 'serial' => $submissionSerial, - 'webform_id' => $webform->id(), - ]); + try { + $result = $this->entityTypeManager->getStorage('webform_submission') + ->loadByProperties([ + 'serial' => $submissionSerial, + 'webform_id' => $webform->id(), + ]); + } + catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { + throw new WebformException('Failed to load submission object with ATV data'); + } $submissionObject = NULL; @@ -410,10 +369,28 @@ public function submissionObjectFromApplicationNumber( public function getWebformFromApplicationNumber(string $applicationNumber): Webform { // We need the ATV document to get the form uuid. $document = $this->getAtvDocument($applicationNumber); + $uuid = $document->getMetadata()['form_uuid']; - // Get webform via uuid that is saved to document metadata. - $webform = ApplicationHelpers::getWebformByUuid($document->getMetadata()['form_uuid'], $applicationNumber); - return $webform; + try { + // Try to load webform via UUID and return it. + $wids = $this->entityTypeManager->getStorage('webform') + ->getQuery() + ->condition('uuid', $uuid) + ->execute(); + return Webform::load(reset($wids)); + } + catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { + // Log failure. + $this->logger->error( + 'Failed to load webform with uuid: @uuid. Error: @error', + [ + '@uuid' => $uuid, + '@error' => $e->getMessage(), + ] + ); + } + // And return webform loaded the old way. + return ApplicationHelpers::getWebformFromApplicationNumber($applicationNumber); } } diff --git a/public/modules/custom/grants_handler/src/ApplicationHelpers.php b/public/modules/custom/grants_handler/src/ApplicationHelpers.php index e57a8d579..6bf421112 100644 --- a/public/modules/custom/grants_handler/src/ApplicationHelpers.php +++ b/public/modules/custom/grants_handler/src/ApplicationHelpers.php @@ -2,15 +2,8 @@ namespace Drupal\grants_handler; -use Drupal\Component\Datetime\Time; -use Drupal\Core\Database\Database; -use Drupal\grants_mandate\CompanySelectException; -use Drupal\helfi_atv\AtvDocument; -use Drupal\helfi_atv\AtvDocumentNotFoundException; use Drupal\webform\Entity\Webform; use Drupal\webform\Entity\WebformSubmission; -use Drupal\webform\WebformSubmissionInterface; -use Ramsey\Uuid\Uuid; /** * Handle all things related to applications & submission objects themselves. @@ -292,123 +285,6 @@ public static function getWebformFromApplicationNumber(string $applicationNumber return reset($webform); } - /** - * Get Webform object by UUID. - * - * @param string $uuid - * Uuid of the webform. - * @param string $application_number - * The application number. - * - * @return \Drupal\webform\Entity\Webform - * Webform object. - */ - public static function getWebformByUuid(string $uuid, string $application_number): Webform|bool|array { - - $wids = \Drupal::entityQuery('webform') - ->condition('uuid', $uuid) - ->execute(); - - // Fallback to original method, if webform for some reason is not found. - if (empty($wids)) { - return self::getWebformFromApplicationNumber($application_number); - } - - return Webform::load(reset($wids)); - } - - /** - * Extract serial numbor from application number string. - * - * @param string $applicationNumber - * Application number. - * @param bool $refetch - * Force refetch from ATV. - * - * @return array|\Drupal\helfi_atv\AtvDocument - * ATV Document - * - * @throws \Drupal\grants_mandate\CompanySelectException - * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException - */ - public static function atvDocumentFromApplicationNumber( - string $applicationNumber, - bool $refetch = FALSE, - ): array|AtvDocument { - - /** @var \Drupal\helfi_atv\AtvService $atvService */ - $atvService = \Drupal::service('helfi_atv.atv_service'); - - $grantsProfileService = \Drupal::service('grants_profile.service'); - $selectedCompany = $grantsProfileService->getSelectedRoleData(); - - // If no company selected, no mandates no access. - if ($selectedCompany == NULL) { - throw new CompanySelectException('User not authorised'); - } - try { - $sParams = [ - 'transaction_id' => $applicationNumber, - 'lookfor' => 'appenv:' . Helpers::getAppEnv(), - ]; - - /** @var \Drupal\helfi_atv\AtvDocument[] $document */ - $document = $atvService->searchDocuments( - $sParams, - $refetch - ); - } - catch (\Throwable $e) { - } - - if (empty($document)) { - throw new AtvDocumentNotFoundException('Document not found'); - } - $document = reset($document); - return $document; - } - - /** - * Set up sender details from helsinkiprofiili data. - * - * @return array - * Sender details. - * - * @throws \Drupal\helfi_helsinki_profiili\TokenExpiredException - * @throws \Drupal\grants_handler\ApplicationException - */ - public static function parseSenderDetails(): array { - - $helfiHelsinkiProfiiliUserdata = \Drupal::service('helfi_helsinki_profiili.userdata'); - - // Set sender information after save so no accidental saving of data. - $userProfileData = $helfiHelsinkiProfiiliUserdata->getUserProfileData(); - $userData = $helfiHelsinkiProfiiliUserdata->getUserData(); - - $senderDetails = []; - - if (isset($userProfileData["myProfile"])) { - $data = $userProfileData["myProfile"]; - } - else { - $data = $userProfileData; - } - - // If no userprofile data, we need to hardcode these values. - if ($userProfileData == NULL || $userData == NULL) { - throw new ApplicationException('No profile data found for user.'); - } - else { - $senderDetails['sender_firstname'] = $data["verifiedPersonalInformation"]["firstName"]; - $senderDetails['sender_lastname'] = $data["verifiedPersonalInformation"]["lastName"]; - $senderDetails['sender_person_id'] = $data["verifiedPersonalInformation"]["nationalIdentificationNumber"]; - $senderDetails['sender_user_id'] = $userData["sub"]; - $senderDetails['sender_email'] = $data["primaryEmail"]["email"]; - } - - return $senderDetails; - } - /** * Get data definition class from application type. * @@ -421,167 +297,6 @@ public static function getDataDefinition(string $type) { return $defClass::create($defId); } - /** - * The getSubmissionIdWithSerialAndWebformId method. - * - * This method queries the database in an attempt to - * find a webform submission ID with the help of a - * submission serial and a webform ID. If one is not - * found, then we create a submission. - * - * @param string $serial - * A webform submission serial. - * @param string $webformId - * A webform ID. - * @param \Drupal\helfi_atv\AtvDocument $document - * An ATV document. - * - * @return string - * A webform submission ID. - * - * @throws \Drupal\Core\Entity\EntityStorageException - * Exception on EntityStorageException. - */ - public static function getSubmissionIdWithSerialAndWebformId( - string $serial, - string $webformId, - AtvDocument $document, - ): string { - $database = Database::getConnection(); - $query = $database->select('webform_submission', 'ws') - ->fields('ws', ['sid']) - ->condition('ws.serial', $serial) - ->condition('ws.webform_id', $webformId); - $result = $query->execute(); - $sid = $result->fetchField(); - - // If a submission ID is found, return it. - if ($sid) { - return $sid; - } - - // If we can't find a submission, then create one. - $webformSubmission = self::createWebformSubmissionWithSerialAndWebformId($serial, $document); - return $webformSubmission->id(); - } - - /** - * The createWebformSubmissionWithSerialAndWebformId method. - * - * This method creates a webform submission and sets the - * webform ID, serial and draft state if needed. - * - * @param string $serial - * A webform submission serial. - * @param \Drupal\helfi_atv\AtvDocument $document - * An ATV document. - * - * @return \Drupal\webform\Entity\WebformSubmission - * A webform submission. - * - * @throws \Drupal\Core\Entity\EntityStorageException - * Exception on EntityStorageException. - */ - protected static function createWebformSubmissionWithSerialAndWebformId( - string $serial, - AtvDocument $document, - ): WebformSubmission { - - $metaData = $document->getMetadata(); - $webformUuidExists = isset($metaData['form_uuid']) && !empty($metaData['form_uuid']); - - $webform = $webformUuidExists - ? self::getWebformByUuid($metaData['form_uuid'], $document->getTransactionId()) - : self::getWebformFromApplicationNumber($document->getTransactionId()); - - $webformId = $webform->id(); - - $submissionObject = WebformSubmission::create(['webform_id' => $webformId]); - $submissionObject->set('serial', $serial); - - // Mark that we don't want to generate new application - // number, as we just assigned the serial from ATV application id. - // Check GrantsHandler@preSave. - WebformSubmissionNotesHelper::setValue( - $submissionObject, - 'skip_available_number_check', - TRUE - ); - if ($document->getStatus() == 'DRAFT') { - $submissionObject->set('in_draft', TRUE); - } - $submissionObject->save(); - return $submissionObject; - } - - /** - * Logs the current submission page. - * - * @param \Drupal\webform\WebformSubmissionInterface|null $webform_submission - * A webform submission entity. - * @param string $applicationNumber - * The page to log. - * @param array $userData - * User data. - * @param string $saveId - * Submission save id. - * - * @return string - * The save ID. - * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException - * @throws \Drupal\Core\Entity\EntityStorageException - * @throws \Drupal\Core\TempStore\TempStoreException - * @throws \Drupal\grants_mandate\CompanySelectException - * @throws \Drupal\helfi_atv\AtvDocumentNotFoundException - * @throws \Drupal\helfi_atv\AtvFailedToConnectException - * @throws \Drupal\helfi_helsinki_profiili\TokenExpiredException - * @throws \GuzzleHttp\Exception\GuzzleException - * @throws \Exception - */ - public static function logSubmissionSaveid( - ?WebformSubmissionInterface $webform_submission, - string $applicationNumber, - array $userData, - string $saveId = '', - ): string { - if (!$userData) { - throw new \Exception('User data is required'); - } - - if (empty($saveId)) { - $saveId = Uuid::uuid4()->toString(); - } - - if ($webform_submission == NULL) { - /** @var \Drupal\grants_handler\ApplicationGetterService $applicationGetterService */ - $applicationGetterService = \Drupal::service('grants_handler.application_getter_service'); - $webform_submission = $applicationGetterService->submissionObjectFromApplicationNumber($applicationNumber); - } - - $currentUser = \Drupal::currentUser(); - $database = \Drupal::database(); - - $fields = [ - 'webform_id' => ($webform_submission) ? $webform_submission->getWebform() - ->id() : '', - 'sid' => ($webform_submission) ? $webform_submission->id() : 0, - 'handler_id' => self::HANDLER_ID, - 'application_number' => $applicationNumber, - 'saveid' => $saveId, - 'uid' => $currentUser->id(), - 'user_uuid' => $userData['sub'] ?? '', - 'timestamp' => (string) (new Time)->getRequestTime(), - ]; - - $query = $database->insert(self::TABLE, $fields); - $query->fields($fields)->execute(); - - return $saveId; - - } - /** * Tries to find latest webform for given application ID. * @@ -617,6 +332,12 @@ public static function getLatestApplicationForm($id): Webform|NULL { * * @param string $id * Application ID. + * + * @return array + * Active webforms. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public static function getActiveApplicationWebforms(string $id): array { $webforms = \Drupal::entityTypeManager() diff --git a/public/modules/custom/grants_handler/src/ApplicationStatusService.php b/public/modules/custom/grants_handler/src/ApplicationStatusService.php index 7d078c6a3..be4a82503 100644 --- a/public/modules/custom/grants_handler/src/ApplicationStatusService.php +++ b/public/modules/custom/grants_handler/src/ApplicationStatusService.php @@ -160,6 +160,10 @@ public function isApplicationOpen(Webform $webform): bool { $thirdPartySettings = $webform->getThirdPartySettings('grants_metadata'); $applicationContinuous = $thirdPartySettings["applicationContinuous"] == 1; + if (!$thirdPartySettings["applicationOpen"] && !$thirdPartySettings["applicationClose"]) { + return $applicationContinuous; + } + try { $now = new \DateTime(); $from = new \DateTime($thirdPartySettings["applicationOpen"]); diff --git a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php index 66966a96e..9add608ed 100644 --- a/public/modules/custom/grants_handler/src/ApplicationUploaderService.php +++ b/public/modules/custom/grants_handler/src/ApplicationUploaderService.php @@ -4,11 +4,14 @@ namespace Drupal\grants_handler; +use Drupal\Component\Datetime\Time; use Drupal\Component\Serialization\Json; +use Drupal\Core\Database\Connection; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\grants_attachments\AttachmentFixerService; @@ -16,7 +19,9 @@ use Drupal\helfi_atv\AtvDocument; use Drupal\helfi_atv\AtvService; use Drupal\helfi_helsinki_profiili\HelsinkiProfiiliUserData; +use Drupal\webform\WebformSubmissionInterface; use GuzzleHttp\Client as HttpClient; +use Ramsey\Uuid\Uuid; /** * Class to handle application uploads. @@ -76,6 +81,8 @@ public function __construct( private readonly ApplicationGetterService $applicationGetterService, private readonly HelsinkiProfiiliUserData $helfiHelsinkiProfiiliUserdata, private readonly AttachmentFixerService $attachmentFixerService, + private readonly AccountInterface $currentUser, + private readonly Connection $database, ) { $this->logger = $this->loggerChannelFactory->get('application_uploader_service'); @@ -129,7 +136,7 @@ public function handleApplicationUploadToAtv( $atvDocument->addMetadata('language', $language); try { $userData = $this->helfiHelsinkiProfiiliUserdata->getUserData(); - $saveId = ApplicationHelpers::logSubmissionSaveid(NULL, $applicationNumber, $userData); + $saveId = $this->logSubmissionSaveid(NULL, $applicationNumber, $userData); $atvDocument->addMetadata('saveid', $saveId); } catch (\Exception $e) { @@ -226,7 +233,7 @@ public function handleApplicationUploadViaIntegration( $headers['X-hki-applicationNumber'] = $applicationNumber; // Set new saveid and save it to db. - $headers['X-hki-saveId'] = ApplicationHelpers::logSubmissionSaveid( + $headers['X-hki-saveId'] = $this->logSubmissionSaveid( NULL, $applicationNumber, $this->helfiHelsinkiProfiiliUserdata->getUserData() @@ -280,4 +287,62 @@ public function clearCache(string $applicationNumber): void { $this->helfiAtvAtvService->clearCache($applicationNumber); } + /** + * Logs the current submission page. + * + * @param \Drupal\webform\WebformSubmissionInterface|null $webform_submission + * A webform submission entity. + * @param string $applicationNumber + * The page to log. + * @param array $userData + * User data. + * @param string $saveId + * Submission save id. + * + * @return string + * The save ID. + * + * @throws \Drupal\Core\Entity\EntityStorageException + * @throws \Drupal\grants_mandate\CompanySelectException + * @throws \Exception + */ + public function logSubmissionSaveid( + ?WebformSubmissionInterface $webform_submission, + string $applicationNumber, + array $userData, + string $saveId = '', + ): string { + if (!$userData) { + throw new \Exception('User data is required'); + } + + if (empty($saveId)) { + $saveId = Uuid::uuid4()->toString(); + } + + if ($webform_submission == NULL) { + $webform_submission = + $this->applicationGetterService + ->submissionObjectFromApplicationNumber($applicationNumber); + } + + $fields = [ + 'webform_id' => ($webform_submission) ? $webform_submission->getWebform() + ->id() : '', + 'sid' => ($webform_submission) ? $webform_submission->id() : 0, + 'handler_id' => ApplicationHelpers::HANDLER_ID, + 'application_number' => $applicationNumber, + 'saveid' => $saveId, + 'uid' => $this->currentUser->id(), + 'user_uuid' => $userData['sub'] ?? '', + 'timestamp' => (string) (new Time)->getRequestTime(), + ]; + + $query = $this->database->insert(ApplicationHelpers::TABLE, $fields); + $query->fields($fields)->execute(); + + return $saveId; + + } + } diff --git a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php index 1d3d7bffc..272cb2d1f 100644 --- a/public/modules/custom/grants_handler/src/Controller/ApplicationController.php +++ b/public/modules/custom/grants_handler/src/Controller/ApplicationController.php @@ -9,6 +9,7 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\grants_handler\ApplicationAccessHandler; @@ -31,7 +32,7 @@ /** * Returns responses for Grants Handler routes. */ -class ApplicationController extends ControllerBase { +final class ApplicationController extends ControllerBase { const ISO8601 = "/^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])" . "|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)" . @@ -41,110 +42,35 @@ class ApplicationController extends ControllerBase { use StringTranslationTrait; - /** - * The current user. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $currentUser; - - /** - * The entity repository. - * - * @var \Drupal\Core\Entity\EntityRepositoryInterface - */ - protected EntityRepositoryInterface $entityRepository; - - /** - * The webform request handler. - * - * @var \Drupal\webform\WebformRequestInterface - */ - protected WebformRequestInterface $requestHandler; - - /** - * The entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - protected $entityTypeManager; - - /** - * The renderer service. - * - * @var \Drupal\Core\Render\RendererInterface - */ - protected $renderer; - - /** - * The request service. - * - * @var \Symfony\Component\HttpFoundation\RequestStack - */ - protected RequestStack $request; - - /** - * Access to grants profile. - * - * @var \Drupal\grants_profile\GrantsProfileService - */ - protected GrantsProfileService $grantsProfileService; - - /** - * Application data service. - * - * @var \Drupal\grants_metadata\ApplicationDataService - */ - protected ApplicationDataService $applicationDataService; - - /** - * Application status service. - * - * @var \Drupal\grants_handler\ApplicationStatusService - */ - protected ApplicationStatusService $applicationStatusService; - - /** - * Application init service. - * - * @var \Drupal\grants_handler\ApplicationInitService - */ - protected ApplicationInitService $applicationInitService; - - /** - * Access handler for applications. - * - * @var \Drupal\grants_handler\ApplicationAccessHandler - */ - protected ApplicationAccessHandler $applicationAccessHandler; - - /** - * Getter service for applications. - * - * @var \Drupal\grants_handler\ApplicationGetterService - */ - protected ApplicationGetterService $applicationGetterService; + public function __construct( + private readonly EntityRepositoryInterface $entityRepository, + private readonly WebformRequestInterface $requestHandler, + private readonly RendererInterface $renderer, + private readonly RequestStack $request, + private readonly GrantsProfileService $grantsProfileService, + private readonly ApplicationDataService $applicationDataService, + private readonly ApplicationStatusService $applicationStatusService, + private readonly ApplicationInitService $applicationInitService, + private readonly ApplicationAccessHandler $applicationAccessHandler, + private readonly ApplicationGetterService $applicationGetterService, + ) {} /** * {@inheritdoc} */ public static function create(ContainerInterface $container): ApplicationController { - $instance = parent::create($container); - $instance->currentUser = $container->get('current_user'); - - $instance->entityRepository = $container->get('entity.repository'); - $instance->requestHandler = $container->get('webform.request'); - $instance->entityTypeManager = $container->get('entity_type.manager'); - $instance->renderer = $container->get('renderer'); - $instance->request = $container->get('request_stack'); - $instance->grantsProfileService = $container->get('grants_profile.service'); - $instance->applicationDataService = $container->get('grants_metadata.application_data_service'); - $instance->applicationStatusService = $container->get('grants_handler.application_status_service'); - $instance->applicationInitService = $container->get('grants_handler.application_init_service'); - $instance->applicationAccessHandler = $container->get('grants_handler.application_access_handler'); - $instance->applicationGetterService = $container->get('grants_handler.application_getter_service'); - - return $instance; + return new self( + $container->get('entity.repository'), + $container->get('webform.request'), + $container->get('renderer'), + $container->get('request_stack'), + $container->get('grants_profile.service'), + $container->get('grants_metadata.application_data_service'), + $container->get('grants_handler.application_status_service'), + $container->get('grants_handler.application_init_service'), + $container->get('grants_handler.application_access_handler'), + $container->get('grants_handler.application_getter_service') + ); } /** @@ -299,7 +225,7 @@ public function view(string $submission_id, string $view_mode = 'full', string $ '#source_entity' => $webform_submission, ]; - $page = $this->entityTypeManager + $page = $this->entityTypeManager() ->getViewBuilder($webform_submission->getEntityTypeId()) ->view($webform_submission, $view_mode); diff --git a/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php b/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php index 2c1997069..be3b46fc3 100644 --- a/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php +++ b/public/modules/custom/grants_handler/src/Controller/AtvPrintViewController.php @@ -7,10 +7,11 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Render\Markup; use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\grants_handler\ApplicationHelpers; +use Drupal\grants_handler\ApplicationGetterService; use Drupal\grants_handler\Plugin\WebformElement\CompensationsComposite; use Drupal\grants_metadata\InputmaskHandler; use Drupal\grants_profile\Form\GrantsProfileFormRegisteredCommunity; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -26,6 +27,25 @@ final class AtvPrintViewController extends ControllerBase { use StringTranslationTrait; + /** + * Constructs a new AtvPrintViewController object. + * + * @param \Drupal\grants_handler\ApplicationGetterService $applicationGetterService + * Application getter. + */ + public function __construct( + private readonly ApplicationGetterService $applicationGetterService, + ) {} + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container): AtvPrintViewController { + return new self( + $container->get('grants_handler.application_getter_service') + ); + } + /** * Builds the response. * @@ -40,7 +60,7 @@ public function __invoke(string $submission_id): array { $subventionType = ''; try { /** @var \Drupal\helfi_atv\AtvDocument $atv_document */ - $atv_document = ApplicationHelpers::atvDocumentFromApplicationNumber($submission_id); + $atv_document = $this->applicationGetterService->getAtvDocument($submission_id); } catch (\Exception $e) { throw new NotFoundHttpException('Application ' . $submission_id . ' not found.'); diff --git a/public/modules/custom/grants_handler/src/Plugin/WebformHandler/GrantsHandler.php b/public/modules/custom/grants_handler/src/Plugin/WebformHandler/GrantsHandler.php index 35dfb6208..8440223c5 100644 --- a/public/modules/custom/grants_handler/src/Plugin/WebformHandler/GrantsHandler.php +++ b/public/modules/custom/grants_handler/src/Plugin/WebformHandler/GrantsHandler.php @@ -1191,7 +1191,7 @@ public function validateForm( try { $this->submittedFormData = array_merge( $this->submittedFormData, - ApplicationHelpers::parseSenderDetails()); + $this->applicationDataService->parseSenderDetails()); } catch (ApplicationException $e) { } diff --git a/public/modules/custom/grants_metadata/grants_metadata.services.yml b/public/modules/custom/grants_metadata/grants_metadata.services.yml index deeb66bcf..5fbb9c68d 100644 --- a/public/modules/custom/grants_metadata/grants_metadata.services.yml +++ b/public/modules/custom/grants_metadata/grants_metadata.services.yml @@ -14,7 +14,8 @@ services: class: Drupal\grants_metadata\ApplicationDataService arguments: [ '@logger.factory', - '@database' + '@database', + '@helfi_helsinki_profiili.userdata' ] calls: - [ setEventsService, [ '@?grants_events.events_service' ] ] diff --git a/public/modules/custom/grants_metadata/src/ApplicationDataService.php b/public/modules/custom/grants_metadata/src/ApplicationDataService.php index 2d2f18001..87f3547a9 100644 --- a/public/modules/custom/grants_metadata/src/ApplicationDataService.php +++ b/public/modules/custom/grants_metadata/src/ApplicationDataService.php @@ -8,8 +8,10 @@ use Drupal\Core\TypedData\TypedDataInterface; use Drupal\grants_attachments\AttachmentHandler; use Drupal\grants_events\EventsService; +use Drupal\grants_handler\ApplicationException; use Drupal\grants_handler\DebuggableTrait; use Drupal\grants_handler\Helpers; +use Drupal\helfi_helsinki_profiili\HelsinkiProfiiliUserData; /** * Application data service. @@ -30,13 +32,6 @@ final class ApplicationDataService { */ protected LoggerChannelInterface $logger; - /** - * The database service. - * - * @var \Drupal\Core\Database\Connection - */ - protected Connection $database; - /** * Events service. * @@ -49,15 +44,17 @@ final class ApplicationDataService { * * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactory * Logger channel factory. - * @param \Drupal\Core\Database\Connection $datababse + * @param \Drupal\Core\Database\Connection $database * Database connection. + * @param \Drupal\helfi_helsinki_profiili\HelsinkiProfiiliUserData $helsinkiProfiiliUserData + * Helsinki profiili user data. */ public function __construct( LoggerChannelFactoryInterface $loggerChannelFactory, - Connection $datababse, + private readonly Connection $database, + private readonly HelsinkiProfiiliUserData $helsinkiProfiiliUserData, ) { $this->logger = $loggerChannelFactory->get('grants_application_helpers'); - $this->database = $datababse; } /** @@ -70,6 +67,43 @@ public function setEventsService(EventsService $eventsService): void { $this->eventsService = $eventsService; } + /** + * Set up sender details from helsinkiprofiili data. + * + * @return array + * Sender details. + * + * @throws \Drupal\helfi_helsinki_profiili\TokenExpiredException + * @throws \Drupal\grants_handler\ApplicationException + */ + public function parseSenderDetails(): array { + // Set sender information after save so no accidental saving of data. + $userProfileData = $this->helsinkiProfiiliUserData->getUserProfileData(); + $userData = $this->helsinkiProfiiliUserData->getUserData(); + + // If no userprofile data, we cannot proceed. + if (!$userProfileData || !$userData) { + throw new ApplicationException('No profile data found for user.'); + } + + $senderDetails = []; + + if (isset($userProfileData["myProfile"])) { + $data = $userProfileData["myProfile"]; + } + else { + $data = $userProfileData; + } + + $senderDetails['sender_firstname'] = $data["verifiedPersonalInformation"]["firstName"]; + $senderDetails['sender_lastname'] = $data["verifiedPersonalInformation"]["lastName"]; + $senderDetails['sender_person_id'] = $data["verifiedPersonalInformation"]["nationalIdentificationNumber"]; + $senderDetails['sender_user_id'] = $userData["sub"]; + $senderDetails['sender_email'] = $data["primaryEmail"]["email"]; + + return $senderDetails; + } + /** * Validate submission data integrity. * @@ -167,7 +201,7 @@ private function shouldSkipIntegrityCheck(array $submissionData): bool { * * @throws \Exception */ - private function getLatestSaveid(string $applicationNumber): string { + protected function getLatestSaveid(string $applicationNumber): string { $query = $this->database->select(self::TABLE, 'l'); $query->condition('application_number', $applicationNumber); $query->fields('l', ['lid', 'saveid']); diff --git a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php index 5c149452e..e2521aeac 100644 --- a/public/modules/custom/grants_metadata/src/DocumentContentMapper.php +++ b/public/modules/custom/grants_metadata/src/DocumentContentMapper.php @@ -135,6 +135,7 @@ private static function processAttachments(array &$typedDataValues): void { // Check if the static variable is already populated // for the given application number. if (!isset(self::$attachmentFileTypes[$applicationNumber])) { + // If not, populate it. self::$attachmentFileTypes[$applicationNumber] = AttachmentHandler::getAttachmentFieldNames( $applicationNumber, @@ -142,15 +143,14 @@ private static function processAttachments(array &$typedDataValues): void { ); } - $attachmentFileTypes = self::$attachmentFileTypes[$applicationNumber]; - if (!isset($typedDataValues["attachments"])) { $typedDataValues["attachments"] = []; } foreach ($typedDataValues["attachments"] as $key => $attachment) { $fileType = $attachment["fileType"]; - $fieldName = array_search($fileType, $attachmentFileTypes); + // Get fieldname for the attachment. + $fieldName = array_search($fileType, self::$attachmentFileTypes[$applicationNumber]); $newValues = $attachment; if (!empty($attachment["fileName"])) { From 785c0207db514e91cc5c1692aee6e4b3516d0056 Mon Sep 17 00:00:00 2001 From: Janne Suominen Date: Tue, 5 Nov 2024 10:42:56 +0200 Subject: [PATCH 16/16] UHF-10817: Fix copy form button in admin UI. --- .../grants_handler/src/ApplicationHelpers.php | 41 ++++++++++++------- .../grants_metadata/grants_metadata.module | 3 +- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/public/modules/custom/grants_handler/src/ApplicationHelpers.php b/public/modules/custom/grants_handler/src/ApplicationHelpers.php index 6bf421112..ae7ca2219 100644 --- a/public/modules/custom/grants_handler/src/ApplicationHelpers.php +++ b/public/modules/custom/grants_handler/src/ApplicationHelpers.php @@ -46,7 +46,6 @@ public static function createApplicationNumber(WebformSubmission &$submission, $ } return self::getApplicationNumberInEnvFormat($appParam, $applicationTypeId, $serial); - } /** @@ -65,7 +64,6 @@ public static function createApplicationNumber(WebformSubmission &$submission, $ * @throws \Drupal\helfi_atv\AtvUnexpectedResponseException */ public static function getAvailableApplicationNumber(WebformSubmission &$submission): string { - $appParam = Helpers::getAppEnv(); $serial = $submission->serial(); $webform_id = $submission->getWebform()->id(); @@ -200,7 +198,6 @@ public static function hasBreakingChangesInNewerVersion(Webform $webform): bool $hasBreakingChanges = $latestApplicationForm->getThirdPartySetting('grants_metadata', 'avus2BreakingChange'); while (!empty($parent)) { - $map[$parent] = $hasBreakingChanges; $loaded_webform = \Drupal::entityTypeManager() @@ -220,7 +217,6 @@ public static function hasBreakingChangesInNewerVersion(Webform $webform): bool } return $map[$uuid] ?? FALSE; - } /** @@ -257,7 +253,6 @@ public static function getWebformFromApplicationNumber(string $applicationNumber // Look for for application type and return if found. $webform = array_filter($webforms, function ($wf) use ($webformTypeId, $applicationTypes, $fieldToCheck) { - $thirdPartySettings = $wf->getThirdPartySettings('grants_metadata'); $thisApplicationTypeConfig = array_filter($applicationTypes, function ($appType) use ($thirdPartySettings) { if (isset($thirdPartySettings["applicationTypeID"]) && @@ -309,8 +304,7 @@ public static function getDataDefinition(string $type) { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public static function getLatestApplicationForm($id): Webform|NULL { - + public static function getLatestApplicationForm($id): Webform|null { $webforms = \Drupal::entityTypeManager() ->getStorage('webform') ->loadByProperties([ @@ -330,8 +324,10 @@ public static function getLatestApplicationForm($id): Webform|NULL { /** * Get all Webform objects for given application id. * - * @param string $id + * @param string $applicationTypeId * Application ID. + * @param null $formId + * Webform ID. * * @return array * Active webforms. @@ -339,13 +335,23 @@ public static function getLatestApplicationForm($id): Webform|NULL { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public static function getActiveApplicationWebforms(string $id): array { + public static function getActiveApplicationWebforms(string $applicationTypeId, $formId = NULL): array { + $properties = [ + 'third_party_settings.grants_metadata.applicationType' => $applicationTypeId, + 'archive' => FALSE, + ]; + + // If we've given form id, we want to load only that form. + if ($formId) { + // Effectevely this limits results to single form. + // But since we now can have multiple forms with same application type, + // we need to check that the form id is correct. + $properties['id'] = $formId; + } + $webforms = \Drupal::entityTypeManager() ->getStorage('webform') - ->loadByProperties([ - 'third_party_settings.grants_metadata.applicationType' => $id, - 'archive' => FALSE, - ]); + ->loadByProperties($properties); $result = [ 'released' => [], @@ -371,12 +377,17 @@ public static function getActiveApplicationWebforms(string $id): array { * * @param string $id * Application ID. + * @param string|null $formId + * Webform ID. Or null if all is wanted. * * @return bool * Can the webform be duplicated. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public static function isApplicationWebformDuplicatable(string $id) { - $applicationForms = self::getActiveApplicationWebforms($id); + public static function isApplicationWebformDuplicatable(string $id, string $formId = NULL): bool { + $applicationForms = self::getActiveApplicationWebforms($id, $formId); return count($applicationForms['released']) <= 1 && count($applicationForms['development']) === 0; } diff --git a/public/modules/custom/grants_metadata/grants_metadata.module b/public/modules/custom/grants_metadata/grants_metadata.module index 408f22b6c..279ee8b1e 100644 --- a/public/modules/custom/grants_metadata/grants_metadata.module +++ b/public/modules/custom/grants_metadata/grants_metadata.module @@ -724,8 +724,9 @@ from being edited, even if normal rules would otherwise permit it. $bundle = $formObject->getEntity(); $applicationTypeId = $bundle->getThirdPartySetting('grants_metadata', 'applicationType'); $isDuplicatable = in_array($formStatus, ['', 'released']); + if ($applicationTypeId && $isDuplicatable) { - $isDuplicatable = ApplicationHelpers::isApplicationWebformDuplicatable($applicationTypeId); + $isDuplicatable = ApplicationHelpers::isApplicationWebformDuplicatable($applicationTypeId, $webform->id()); } $route_parameters = ['webform' => $webform->id()];