Merge branch '292-signature-form-workflow' into 'signature-app-master'

Modify workflow form to indicate if signatures are wanted

See merge request Chill-Projet/chill-bundles!713
This commit is contained in:
Julien Fastré 2024-07-24 11:09:07 +00:00
commit b19dd4fc11
7 changed files with 192 additions and 58 deletions

View File

@ -193,11 +193,6 @@ class ChillMainExtension extends Extension implements
[]
);
$container->setParameter(
'chill_main.id_document_kinds',
$config['id_document_kinds']
);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml');
$loader->load('services/doctrine.yaml');

View File

@ -85,6 +85,29 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->end() // end of notifications
->arrayNode('workflow_signature')
->children()
->arrayNode('base_signer')
->children()
->arrayNode('document_kinds')
->arrayPrototype()
->children()
->scalarNode('key')->cannotBeEmpty()->end()
->arrayNode('labels')
->arrayPrototype()
->children()
->scalarNode('lang')->cannotBeEmpty()->end()
->scalarNode('label')->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end() // end of workflow signature document types
->arrayNode('phone_helper')
->canBeUnset()
->children()
@ -151,28 +174,6 @@ class Configuration implements ConfigurationInterface
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->arrayNode('id_document_kinds')->defaultValue([])
->arrayPrototype()
->children()
->scalarNode('key')->isRequired()->cannotBeEmpty()
->info('the key stored in database')
->example('id_card')
->end()
->arrayNode('labels')->isRequired()->requiresAtLeastOneElement()
->arrayPrototype()
->children()
->scalarNode('lang')->isRequired()->cannotBeEmpty()
->example('fr')
->end()
->scalarNode('label')->isRequired()->cannotBeEmpty()
->example('Carte de séjour')
->end()
->end()
->end()
->end()
->end()
->end()
->end() // end of document types
->arrayNode('cruds')
->defaultValue([])
->arrayPrototype()

View File

@ -25,7 +25,7 @@ class WorkflowSignatureMetadataType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$documentTypeChoices = $this->parameterBag->get('chill_main.id_document_kinds');
$documentTypeChoices = $this->parameterBag->get('chill_main')['workflow_signature']['base_signer']['document_kinds'];
$choices = [];

View File

@ -17,6 +17,7 @@ use Chill\MainBundle\Form\Type\ChillTextareaType;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
@ -102,6 +103,7 @@ class WorkflowStepType extends AbstractType
'choice_attr' => static function (Transition $transition) use ($workflow) {
$toFinal = true;
$isForward = 'neutral';
$isSignature = [];
$metadata = $workflow->getMetadataStore()->getTransitionMetadata($transition);
@ -121,18 +123,43 @@ class WorkflowStepType extends AbstractType
) {
$toFinal = false;
}
if (\array_key_exists('isSignature', $meta)) {
$isSignature = $meta['isSignature'];
}
}
return [
'data-is-transition' => 'data-is-transition',
'data-to-final' => $toFinal ? '1' : '0',
'data-is-forward' => $isForward,
'data-is-signature' => json_encode($isSignature),
];
},
])
->add('isPersonOrUserSignature', ChoiceType::class, [
'mapped' => false,
'multiple' => false,
'expanded' => true,
'label' => 'workflow.signature_zone.type of signature',
'choices' => [
'workflow.signature_zone.persons' => 'person',
'workflow.signature_zone.user' => 'user',
],
])
->add('futurePersonSignatures', PickPersonDynamicType::class, [
'label' => 'workflow.signature_zone.person signatures',
'multiple' => true,
'empty_data' => '[]',
])
->add('futureUserSignature', PickUserDynamicType::class, [
'label' => 'workflow.signature_zone.user signature',
'multiple' => false,
])
->add('futureDestUsers', PickUserDynamicType::class, [
'label' => 'workflow.dest for next steps',
'multiple' => true,
'empty_data' => '[]',
'suggested' => $options['suggested_users'],
])
->add('futureCcUsers', PickUserDynamicType::class, [
@ -140,6 +167,8 @@ class WorkflowStepType extends AbstractType
'multiple' => true,
'required' => false,
'suggested' => $options['suggested_users'],
'empty_data' => '[]',
'attr' => ['class' => 'future-cc-users'],
])
->add('futureDestEmails', ChillCollectionType::class, [
'label' => 'workflow.dest by email',

View File

@ -4,38 +4,124 @@ window.addEventListener('DOMContentLoaded', function() {
let
divTransitions = document.querySelector('#transitions'),
futureDestUsersContainer = document.querySelector('#futureDests')
;
if (null !== divTransitions) {
new ShowHide({
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function(divs, arg2, arg3) {
for (let div of divs) {
for (let input of div.querySelectorAll('input')) {
if (input.checked) {
if (input.dataset.toFinal === "1") {
return false;
} else {
return true;
}
}
}
}
return true;
},
});
}
personSignatureField = document.querySelector('#person-signature-field');
userSignatureField = document.querySelector('#user-signature-field');
signatureTypeChoices = document.querySelector('#signature-type-choice');
personChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_0');
userChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_1');
signatureZone = document.querySelector('#signature-zone');
;
let
transitionFilterContainer = document.querySelector('#transitionFilter'),
transitions = document.querySelector('#transitions')
transitionFilterContainer = document.querySelector('#transitionFilter'),
transitionsContainer = document.querySelector('#transitions')
;
// ShowHide instance for signatureTypeChoices. This should always be present in the DOM and we toggle visibility.
// The field is not mapped and so not submitted with the form. Without it's presence upon DOM loading other show hides do not function well.
signatureTypeChoices.style.display = 'none';
// ShowHide instance for future dest users
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function(froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
if (input.checked) {
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
signatureTypeChoices.style.display = '';
return false;
} else {
personChoice.checked = false
userChoice.checked = false
signatureTypeChoices.style.display = 'none';
return true;
}
}
}
}
return false;
}
});
// ShowHide signature zone
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [signatureZone],
test: function(froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
if (input.checked) {
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
signatureTypeChoices.style.display = '';
return true;
}
}
}
}
return false;
}
});
// ShowHides for personSignatureField or userSignatureField within signature zone
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [personSignatureField],
test: function(froms, event) {
for (let container of froms) {
return personChoice.checked;
}
return false;
},
});
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [userSignatureField],
test: function(froms, event) {
for (let container of froms) {
return userChoice.checked;
}
return false;
},
});
if (null !== divTransitions) {
new ShowHide({
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function(divs, arg2, arg3) {
for (let div of divs) {
for (let input of div.querySelectorAll('input')) {
if (input.checked) {
if (input.dataset.toFinal === "1") {
return false;
} else {
return true;
}
}
}
}
return true;
},
});
}
if (null !== transitionFilterContainer) {
transitions.querySelectorAll('.form-check').forEach(function(row) {
transitionsContainer.querySelectorAll('.form-check').forEach(function(row) {
const isForward = row.querySelector('input').dataset.isForward;
@ -66,5 +152,4 @@ window.addEventListener('DOMContentLoaded', function() {
});
});
}
});

View File

@ -58,15 +58,34 @@
{{ form_row(transition_form.transition) }}
</div>
<div id="signature-zone">
<div id="signature-type-choice">
{{ form_row(transition_form.isPersonOrUserSignature) }}
{{ form_errors(transition_form.isPersonOrUserSignature) }}
</div>
<div id="user-signature-field">
{{ form_row(transition_form.futureUserSignature) }}
{{ form_errors(transition_form.futureUserSignature) }}
</div>
<div id="person-signature-field">
{{ form_row(transition_form.futurePersonSignatures) }}
{{ form_errors(transition_form.futurePersonSignatures) }}
</div>
</div>
<div id="futureDests">
<div id="future-dest-users">
{{ form_row(transition_form.futureDestUsers) }}
{{ form_errors(transition_form.futureDestUsers) }}
</div>
<div id="future-cc-users">
{{ form_row(transition_form.futureCcUsers) }}
{{ form_errors(transition_form.futureCcUsers) }}
</div>
<div id="future-dest-emails">
{{ form_row(transition_form.futureDestEmails) }}
{{ form_errors(transition_form.futureDestEmails) }}
</div>
</div>
<p>{{ form_label(transition_form.comment) }}</p>

View File

@ -536,6 +536,11 @@ workflow:
docType: Type de document
docNumber: Numéro de document
docExpiration: Date d'expiration
type of signature: Type de signature
person signatures: Selectionner usagers pour signer
user signature: Selectionner utilisateur pour signer
persons: Usagers
user: Utilisateur
Subscribe final: Recevoir une notification à l'étape finale