Explorar el Código

pages parametres

Vincent GUFFON hace 3 años
padre
commit
cc5ea70d22

+ 2 - 1
config/nuxtConfig/env.js

@@ -8,7 +8,8 @@ export default {
     manager_product: 'manager',
     cmf_network: 'CMF',
     ffec_network: 'FFEC',
-    OPENTALENT_MANAGER_ID: 93931
+    OPENTALENT_MANAGER_ID: 93931,
+    CMF_ID: 12097
   },
   publicRuntimeConfig: {
     http: {

+ 9 - 0
lang/enum/fr-FR.js

@@ -1,5 +1,14 @@
 export default (context, locale) => {
   return ({
+    GUARDIANS: 'Tuteurs uniquement',
+    STUDENTS: 'Élèves uniquement',
+    STUDENTS_AND_THEIR_GUARDIANS: 'Élèves et leurs tuteurs',
+    ANNUAL: 'Annuel',
+    HALF: 'Semestriel',
+    QUARTERLY: 'Trimestriel',
+    MONTHLY: 'Mensuel',
+    BY_EDUCATION: 'Par enseignement',
+    BY_TEACHER: 'Par professeur',
     CATEGORY_ORCHESTRE: 'Orchestre',
     CATEGORY_AMBULATORY: 'Musique ambulatoire',
     CATEGORY_OTHER: 'Autres activités',

+ 40 - 0
lang/field/fr-FR.js

@@ -1,5 +1,45 @@
 export default (context, locale) => {
   return ({
+    desactivateOpentalentSiteWeb: 'Désactiver le site opentalent',
+    passwordSMS: 'Mot de passe SMS',
+    usernameSMS: 'Nom d\'utilisateur SMS',
+    smsSenderName: 'Personnaliser le nom de l\'expéditeur SMS',
+    attendance: 'Abscences',
+    sendAttendanceEmail: 'Prévenir automatiquement la famille par mail en cas d\'absence non justifiée',
+    sendAttendanceSms: 'Prévenir automatiquement la famille par sms en cas d\'absence non justifiée',
+    bulletinReceiver: 'Adresser le bulletin à',
+    bulletinEditWithoutEvaluation: 'Editer également les bulletins ne contenant aucune évaluation',
+    bulletinShowAverages: 'Afficher les moyennes',
+    bulletinShowAbsences: 'Afficher les absences',
+    bulletinViewTestResults: 'Afficher les résultats des examens',
+    bulletinShowEducationWithoutEvaluation: 'Afficher les enseignements ne contenant aucune évaluation',
+    bulletinDisplayLevelAcquired: 'Affichage niveau acquis',
+    bulletinSignatureDirector: 'Un cadre « Tampon / Signature » pour l\'administration',
+    bulletinPrintAddress: 'L\'adresse postale de l\'élève ou son tuteur',
+    bulletinWithTeacher: 'Le nom du professeur',
+    bulletin_parameters: 'Bulletins',
+    sms: 'Sms',
+    web_parameters: 'Site internet',
+    averageMax: 'Note maximale pour les notes du suivi pédagogique (entre 1 et 100)',
+    educational_follow_up: 'Suivi pédagogique',
+    advancedEducationNotationType: 'Type de grilles d\'évaluation',
+    educationPeriodicity: 'Périodicité des évaluations',
+    editCriteriaNotationByAdminOnly: 'Autoriser uniquement l\'administration à modifier les critères d\'évaluation',
+    trackingValidation: 'Contrôle et validation du suivi pédagogique par l\'administration',
+    publicationDirectors: 'Directeur(s) de publication',
+    website: 'Autre site web',
+    newSubDomain: 'Nouveau sous domaine',
+    subDomainHistorical: 'Historique de vos sous domaine(s)',
+    otherWebsite: 'Votre site Opentalent est',
+    timezone: 'Fuseau horaire',
+    qrCode: 'QrCode pour la licence',
+    studentsAreAdherents: 'Les élèves sont adhérents également de l\'association',
+    showAdherentList: 'Afficher la liste des adhérents et leurs coordonnées',
+    endCourseDate: 'Date de fin des cours ',
+    startCourseDate: 'Date de début des cours ',
+    generalParams: 'Paramètres généraux',
+    financialDate: 'Début de la saison financière',
+    musicalDate: 'Début de la saison d\'activité',
     title: 'Titre',
     link: 'Lien',
     organizationArticle: 'Coups de projecteur',

+ 2 - 0
lang/help/fr-FR.js

@@ -7,6 +7,8 @@
  */
 export default (context, locale) => {
   return ({
+    bulletinEditWithoutEvaluationHelp:'Dans le cas ou la case n\'est pas cochée, si aucune évaluation dans le bulletin alors le bulletin n\'est pas exporté',
+    bulletinShowEducationWithoutEvaluationHelp: 'Dans le cas ou la case est cochée, alors pour chaque enseignement, on affiche le texte \"Aucune évaluation\" si aucune évaluation',
     type_of_practices_autocomplete: 'Sélectionnez parmi la liste des types de pratiques, une ou plusieurs pratiques correspondant aux activités de votre structure',
     logo_upload: '<div>Le logo est utilisée: </div>' +
       `\n<ul>` +

+ 2 - 0
lang/rulesAndErrors/fr-FR.js

@@ -1,5 +1,7 @@
 export default (context, locale) => {
   return ({
+    smsSenderName_error: 'Seuls les caractères alphanumériques sont permis, sans espaces, sans accent et sans caractères spéciaux',
+    value_need_to_be_beetween_0_100: 'La valeur doit être comprise entre 0 et 100',
     invalide_form: 'Formulaire invalide',
     required: 'Ce champs est obligatoire',
     name_length_rule: 'La taille du nom doit être de moins de 128 caractères',

+ 97 - 1
models/Organization/Parameters.ts

@@ -1,4 +1,4 @@
-import {Str, Model, Uid} from '@vuex-orm/core'
+import {Str, Model, Uid, Bool, Num, Attr} from '@vuex-orm/core'
 
 export class Parameters extends Model {
   static entity = 'parameters'
@@ -17,4 +17,100 @@ export class Parameters extends Model {
 
   @Str(null, { nullable: true })
   endCourseDate!: string|null
+
+  @Bool(false, { nullable: false })
+  trackingValidation!: boolean
+
+  @Num(20, { nullable: true })
+  average!: number
+
+  @Bool(true, { nullable: false })
+  editCriteriaNotationByAdminOnly!: boolean
+
+  @Str(null, { nullable: true })
+  smsSenderName!: string|null
+
+  @Bool(true, { nullable: false })
+  logoDonorsMove!: boolean
+
+  @Str(null, { nullable: true })
+  subDomain!: string|null
+
+  @Str(null, { nullable: true })
+  website!: string|null
+
+  @Str(null, { nullable: true })
+  otherWebsite!: string|null
+
+  @Bool(false, { nullable: false })
+  desactivateOpentalentSiteWeb!: boolean
+
+  @Attr([])
+  publicationDirectors!: []
+
+  @Str(null, { nullable: true })
+  bulletinPeriod!: string|null
+
+  @Bool(false, { nullable: false })
+  bulletinWithTeacher!: boolean
+
+  @Bool(false, { nullable: false })
+  bulletinPrintAddress!: boolean
+
+  @Bool(true, { nullable: false })
+  bulletinSignatureDirector!: boolean
+
+  @Bool(true, { nullable: false })
+  bulletinDisplayLevelAcquired!: boolean
+
+  @Bool(false, { nullable: false })
+  bulletinShowEducationWithoutEvaluation!: boolean
+
+  @Bool(false, { nullable: false })
+  bulletinViewTestResults!: boolean
+
+  @Bool(false, { nullable: false })
+  bulletinShowAbsences!: boolean
+
+  @Bool(true, { nullable: false })
+  bulletinShowAverages!: boolean
+
+  @Str(null, { nullable: true })
+  bulletinOutput!: string|null
+
+  @Bool(true, { nullable: false })
+  bulletinEditWithoutEvaluation!: boolean
+
+  @Str('STUDENTS_AND_THEIR_GUARDIANS', { nullable: true })
+  bulletinReceiver!: string|null
+
+  @Str(null, { nullable: true })
+  usernameSMS!: string|null
+
+  @Str(null, { nullable: true })
+  passwordSMS!: string|null
+
+  @Bool(true, { nullable: false })
+  showAdherentList!: boolean
+
+  @Bool(false, { nullable: false })
+  studentsAreAdherents!: boolean
+
+  @Str(null, { nullable: true })
+  qrCode!: string|null
+
+  @Str('Europe/Paris', { nullable: true })
+  timezone!: string|null
+
+  @Str('ANNUAL', { nullable: true })
+  educationPeriodicity!: string|null
+
+  @Str('BY_EDUCATION', { nullable: true })
+  advancedEducationNotationType!: string|null
+
+  @Bool(false, { nullable: false })
+  sendAttendanceEmail!: boolean
+
+  @Bool(false, { nullable: false })
+  sendAttendanceSms!: boolean
 }

+ 6 - 0
pages/parameters.vue

@@ -18,15 +18,21 @@
 import { defineComponent } from '@nuxtjs/composition-api'
 import { repositoryHelper } from '~/services/store/repository'
 import {Parameters} from "~/models/Organization/Parameters";
+import {Organization} from "~/models/Organization/Organization";
 
 export default defineComponent({
   name: 'parameters',
   layout: 'parameters',
+  middleware({ $ability, redirect }) {
+    if(!$ability.can('display', 'parameters_page'))
+      return redirect('/error')
+  },
   setup () {
     return {}
   },
   beforeDestroy() {
     repositoryHelper.cleanRepository(Parameters)
+    repositoryHelper.cleanRepository(Organization)
   },
 })
 

+ 72 - 19
pages/parameters/communication.vue

@@ -2,36 +2,74 @@
   <LayoutContainer v-if="!fetchState.pending">
     <UiForm :id="id" :model="model" :query="query()">
       <template #form.input="{entry, updateRepository}">
-        <v-expansion-panels  focusable multiple :value="[0,1]">
-          <!-- Description -->
-          <UiExpansionPanel id="description" icon="fa-info">
+        <v-expansion-panels  focusable multiple :value="[0, 1]">
+          <!-- Site internet -->
+          <UiExpansionPanel id="web_parameters" icon="fa-desktop">
             <v-container fluid class="container">
               <v-row>
                 <v-col cols="12" sm="6">
-                  <UiInputText field="financialDate" :data="entry['financialDate']" @update="updateRepository" />
+                  <div>
+                    <span>{{ $t('otherWebsite') }} : </span>
+                    <span>{{ entry['otherWebsite'] }}</span>
+                  </div>
                 </v-col>
+
+                <v-col cols="12" sm="6">
+                  <div>
+                    <span>{{ $t('subDomainHistorical') }} : </span>
+                  </div>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="newSubDomain" :data="entry['newSubDomain']" />
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="!organizationProfile.isCmf()">
+                  <UiInputCheckbox field="desactivateOpentalentSiteWeb" :data="entry['desactivateOpentalentSiteWeb']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText field="website" :data="entry['website']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputAutocompleteWithAPI
+                    field="publicationDirectors"
+                    label="publicationDirectors"
+                    :multiple="true"
+                    chips
+                    :remote-uri="entry['publicationDirectors']"
+                    remote-url="api/access_people"
+                    :item-text="['person.givenName', 'person.name']"
+                    :searchFunction="accessSearch"
+                    @update="updateRepository($event.map((id) => `/api/accesses/${id}`), 'publicationDirectors')"
+                  />
+                </v-col>
+
               </v-row>
             </v-container>
           </UiExpansionPanel>
 
-          <UiExpansionPanel id="salary" icon="fa-users">
-            <v-container class="container">
+          <!-- Sms -->
+          <UiExpansionPanel id="sms" icon="fa-mobile" v-if="organizationProfile.hasModule(['Sms'])">
+            <v-container fluid class="container">
               <v-row>
+
                 <v-col cols="12" sm="6">
-                  <UiInputText field="musicalDate" :data="entry['musicalDate']" @update="updateRepository" />
+                  <UiInputText field="smsSenderName" :data="entry['smsSenderName']" @update="updateRepository" :rules="rules().smsSenderNameRules"  />
                 </v-col>
 
                 <v-col cols="12" sm="6">
-                  <UiInputText field="startCourseDate" :data="entry['startCourseDate']" @update="updateRepository" />
+                  <UiInputText field="usernameSMS" :data="entry['usernameSMS']" @update="updateRepository" />
                 </v-col>
 
                 <v-col cols="12" sm="6">
-                  <UiInputText field="endCourseDate" :data="entry['endCourseDate']" @update="updateRepository" />
+                  <UiInputText field="passwordSMS" :data="entry['passwordSMS']" @update="updateRepository" type="password" />
                 </v-col>
-
               </v-row>
             </v-container>
           </UiExpansionPanel>
+
         </v-expansion-panels>
       </template>
     </UiForm>
@@ -39,18 +77,25 @@
 </template>
 
 <script lang="ts">
-import {computed, ComputedRef, defineComponent, useContext} from '@nuxtjs/composition-api'
+import {computed, ComputedRef, defineComponent, reactive, ref, useContext} from '@nuxtjs/composition-api'
 import { Organization } from '@/models/Organization/Organization'
 import { repositoryHelper } from '~/services/store/repository'
 import {useDataUtils} from "~/composables/data/useDataUtils";
 import {Parameters} from "~/models/Organization/Parameters";
 import {Query} from "@vuex-orm/core";
+import {$organizationProfile} from "~/services/profile/organizationProfile";
+import ModelsUtils from "~/services/utils/modelsUtils";
+import {useAccessesProvider} from "~/composables/data/useAccessesProvider";
 
 export default defineComponent({
   name: 'parameters',
   setup () {
-    const {store, $dataProvider} = useContext()
+    const {store, $dataProvider, app: {i18n}} = useContext()
     const {getItemToEdit} = useDataUtils($dataProvider)
+    const {getPhysicalByFullName: accessSearch} = useAccessesProvider($dataProvider)
+
+    const organizationProfile = reactive($organizationProfile(store))
+
     const id = store.state.profile.organization.parametersId
     const {fetchState} = getItemToEdit(id, Parameters)
 
@@ -58,17 +103,25 @@ export default defineComponent({
     const query: ComputedRef<Query> = computed(() => repository.query())
 
     return {
-      query: () => query,
+      query: () => query.value,
+      rules: () => getRules(i18n),
+      organizationProfile,
       id,
       fetchState,
-      model: Organization
+      accessSearch,
+      model: Parameters
     }
   }
 })
-</script>
 
-<style scoped>
-.v-icon.v-icon {
-  font-size: 14px;
+function getRules (i18n: any) {
+  return {
+    smsSenderNameRules: [
+      (smsSenderNameValue: string) => {
+        const pattern = /^[a-zA-z\d]+$/
+        return pattern.test(smsSenderNameValue) || i18n.t('smsSenderName_error')
+      }
+    ]
+  }
 }
-</style>
+</script>

+ 51 - 25
pages/parameters/index.vue

@@ -2,36 +2,57 @@
       <LayoutContainer v-if="!fetchState.pending">
         <UiForm :id="id" :model="model" :query="query()">
           <template #form.input="{entry, updateRepository}">
-            <v-expansion-panels  focusable multiple :value="[0,1]">
+            <v-expansion-panels  focusable multiple :value="[0]">
               <!-- Description -->
-              <UiExpansionPanel id="description" icon="fa-info">
+              <UiExpansionPanel id="generalParams" icon="fa-info">
                 <v-container fluid class="container">
                   <v-row>
-                    <v-col cols="12" sm="6">
-                      <UiInputText field="financialDate" :data="entry['financialDate']" @update="updateRepository" />
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isSchool()">
+                      <UiInputDatePicker field="financialDate" :data="entry['financialDate']" format="DD MMMM" @update="updateRepository" />
                     </v-col>
-                  </v-row>
-                </v-container>
-              </UiExpansionPanel>
 
-              <UiExpansionPanel id="salary" icon="fa-users">
-                <v-container class="container">
-                  <v-row>
                     <v-col cols="12" sm="6">
-                      <UiInputText field="musicalDate" :data="entry['musicalDate']" @update="updateRepository" />
+                      <UiInputDatePicker field="musicalDate" :data="entry['musicalDate']" format="DD MMMM" @update="updateRepository" />
+                    </v-col>
+
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isSchool()">
+                      <UiInputDatePicker field="startCourseDate" :data="entry['startCourseDate']" @update="updateRepository" />
+                    </v-col>
+
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isSchool()">
+                      <UiInputDatePicker field="endCourseDate" :data="entry['endCourseDate']" @update="updateRepository" />
                     </v-col>
 
                     <v-col cols="12" sm="6">
-                      <UiInputText field="startCourseDate" :data="entry['startCourseDate']" @update="updateRepository" />
+                      <UiInputCheckbox field="showAdherentList" :data="entry['showAdherentList']" @update="updateRepository" />
+                    </v-col>
+
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isSchool() && organization.legalStatus === 'ASSOCIATION_LAW_1901'">
+                      <UiInputCheckbox field="studentsAreAdherents" :data="entry['studentsAreAdherents']" @update="updateRepository" />
+                    </v-col>
+
+                    <v-col cols="12" sm="6" v-if="organizationProfile.isCMFCentralService()">
+                      <div>
+                        <span>{{ $t('qrCode') }}</span>
+                      </div>
+                      <UiImage
+                        :id="getIdFromUri(entry['qrCode'])"
+                        :upload="true"
+                        :width="100"
+                        field="qrCode"
+                        :ownerId="id"
+                        @update="updateRepository"
+                      ></UiImage>
                     </v-col>
 
                     <v-col cols="12" sm="6">
-                      <UiInputText field="endCourseDate" :data="entry['endCourseDate']" @update="updateRepository" />
+                      <UiInputEnum field="timezone" :data="entry['timezone']" enum-type="timezone" @update="updateRepository" />
                     </v-col>
 
                   </v-row>
                 </v-container>
               </UiExpansionPanel>
+
             </v-expansion-panels>
           </template>
         </UiForm>
@@ -39,36 +60,41 @@
 </template>
 
 <script lang="ts">
-import {computed, ComputedRef, defineComponent, useContext} from '@nuxtjs/composition-api'
+import {computed, ComputedRef, defineComponent, reactive, useContext} from '@nuxtjs/composition-api'
 import { Organization } from '@/models/Organization/Organization'
 import { repositoryHelper } from '~/services/store/repository'
 import {useDataUtils} from "~/composables/data/useDataUtils";
 import {Parameters} from "~/models/Organization/Parameters";
-import {Query} from "@vuex-orm/core";
+import {Model, Query, Item} from "@vuex-orm/core";
+import {$organizationProfile} from "~/services/profile/organizationProfile";
+import {Repository as VuexRepository} from "@vuex-orm/core/dist/src/repository/Repository";
+import ModelsUtils from "~/services/utils/modelsUtils";
 
 export default defineComponent({
   name: 'parameters',
   setup () {
     const {store, $dataProvider} = useContext()
+    const organizationProfile = reactive($organizationProfile(store))
     const {getItemToEdit} = useDataUtils($dataProvider)
     const id = store.state.profile.organization.parametersId
     const {fetchState} = getItemToEdit(id, Parameters)
+    const repositoryParameters: VuexRepository<Model> = repositoryHelper.getRepository(Parameters)
+    const query: ComputedRef<Query> = computed(() => repositoryParameters.query())
 
-    const repository = repositoryHelper.getRepository(Parameters)
-    const query: ComputedRef<Query> = computed(() => repository.query())
+    getItemToEdit(store.state.profile.organization.id, Organization)
+    const organization:ComputedRef<Item> = computed(() => repositoryHelper.findItemFromModel(Organization, store.state.profile.organization.id))
+
+    const getIdFromUri = (uri: string) => ModelsUtils.extractIdFromUri(uri)
 
     return {
-      query: () => query,
+      query: () => query.value,
       id,
       fetchState,
-      model: Organization
+      model: Parameters,
+      organizationProfile,
+      organization,
+      getIdFromUri
     }
   }
 })
 </script>
-
-<style scoped>
-.v-icon.v-icon {
-  font-size: 14px;
-}
-</style>

+ 111 - 22
pages/parameters/student.vue

@@ -2,36 +2,117 @@
   <LayoutContainer v-if="!fetchState.pending">
     <UiForm :id="id" :model="model" :query="query()">
       <template #form.input="{entry, updateRepository}">
-        <v-expansion-panels  focusable multiple :value="[0,1]">
-          <!-- Description -->
-          <UiExpansionPanel id="description" icon="fa-info">
+        <v-expansion-panels  focusable multiple :value="[0,1,2]">
+          <!-- Suivi pédagogique -->
+          <UiExpansionPanel id="educational_follow_up" icon="fa-graduation-cap">
             <v-container fluid class="container">
               <v-row>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="trackingValidation" :data="entry['trackingValidation']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="editCriteriaNotationByAdminOnly" :data="entry['editCriteriaNotationByAdminOnly']" @update="updateRepository" />
+                </v-col>
+
                 <v-col cols="12" sm="6">
-                  <UiInputText field="financialDate" :data="entry['financialDate']" @update="updateRepository" />
+                  <UiInputEnum field="educationPeriodicity" :data="entry['educationPeriodicity']" enum-type="education_periodicity" @update="updateRepository" />
                 </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.hasModule(['AdvancedEducationNotation'])">
+                  <UiInputEnum field="advancedEducationNotationType" :data="entry['advancedEducationNotationType']" enum-type="advanced_education_notation" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputText
+                    label="averageMax"
+                    field="average"
+                    type="number"
+                    :data="entry['average']"
+                    @update="updateRepository"
+                    :rules="rules().averageRules"
+                  />
+                </v-col>
+
               </v-row>
             </v-container>
           </UiExpansionPanel>
 
-          <UiExpansionPanel id="salary" icon="fa-users">
-            <v-container class="container">
+          <!-- Bulletins -->
+          <UiExpansionPanel id="bulletin_parameters" icon="fa-file-alt">
+            <v-container fluid class="container">
               <v-row>
+
                 <v-col cols="12" sm="6">
-                  <UiInputText field="musicalDate" :data="entry['musicalDate']" @update="updateRepository" />
+                  <UiInputCheckbox field="bulletinWithTeacher" :data="entry['bulletinWithTeacher']" @update="updateRepository" />
                 </v-col>
 
                 <v-col cols="12" sm="6">
-                  <UiInputText field="startCourseDate" :data="entry['startCourseDate']" @update="updateRepository" />
+                  <UiInputCheckbox field="bulletinPrintAddress" :data="entry['bulletinPrintAddress']" @update="updateRepository" />
                 </v-col>
 
                 <v-col cols="12" sm="6">
-                  <UiInputText field="endCourseDate" :data="entry['endCourseDate']" @update="updateRepository" />
+                  <UiInputCheckbox field="bulletinSignatureDirector" :data="entry['bulletinSignatureDirector']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="bulletinDisplayLevelAcquired" :data="entry['bulletinDisplayLevelAcquired']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <div class="d-flex flex-row">
+                    <UiInputCheckbox field="bulletinShowEducationWithoutEvaluation" :data="entry['bulletinShowEducationWithoutEvaluation']" @update="updateRepository" />
+                    <UiHelp>
+                      <p v-html="$t('bulletinShowEducationWithoutEvaluationHelp')" />
+                    </UiHelp>
+                  </div>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="bulletinViewTestResults" :data="entry['bulletinViewTestResults']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="bulletinShowAbsences" :data="entry['bulletinShowAbsences']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="bulletinShowAverages" :data="entry['bulletinShowAverages']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <div class="d-flex flex-row">
+                    <UiInputCheckbox field="bulletinEditWithoutEvaluation" :data="entry['bulletinEditWithoutEvaluation']" @update="updateRepository" />
+                    <UiHelp>
+                      <p v-html="$t('bulletinEditWithoutEvaluationHelp')" />
+                    </UiHelp>
+                  </div>
+                </v-col>
+
+                <v-col cols="12" sm="6">
+                  <UiInputEnum field="bulletinReceiver" :data="entry['bulletinReceiver']" enum-type="organization_bulletin_send_to" @update="updateRepository" />
                 </v-col>
 
               </v-row>
             </v-container>
           </UiExpansionPanel>
+
+          <!-- Abscences -->
+          <UiExpansionPanel id="attendance" icon="fa-check">
+            <v-container fluid class="container">
+              <v-row>
+                <v-col cols="12" sm="6">
+                  <UiInputCheckbox field="sendAttendanceEmail" :data="entry['sendAttendanceEmail']" @update="updateRepository" />
+                </v-col>
+
+                <v-col cols="12" sm="6" v-if="organizationProfile.hasModule(['Sms'])">
+                  <UiInputCheckbox field="sendAttendanceSms" :data="entry['sendAttendanceSms']" @update="updateRepository" />
+                </v-col>
+              </v-row>
+            </v-container>
+          </UiExpansionPanel>
+
         </v-expansion-panels>
       </template>
     </UiForm>
@@ -39,36 +120,44 @@
 </template>
 
 <script lang="ts">
-import {computed, ComputedRef, defineComponent, useContext} from '@nuxtjs/composition-api'
+import {computed, ComputedRef, defineComponent, reactive, useContext} from '@nuxtjs/composition-api'
 import { Organization } from '@/models/Organization/Organization'
 import { repositoryHelper } from '~/services/store/repository'
 import {useDataUtils} from "~/composables/data/useDataUtils";
 import {Parameters} from "~/models/Organization/Parameters";
-import {Query} from "@vuex-orm/core";
+import {Model, Query, Item} from "@vuex-orm/core";
+import {$organizationProfile} from "~/services/profile/organizationProfile";
+import {Repository as VuexRepository} from "@vuex-orm/core/dist/src/repository/Repository";
+import ModelsUtils from "~/services/utils/modelsUtils";
+import i18n from "~/config/nuxtConfig/i18n";
 
 export default defineComponent({
   name: 'parameters',
   setup () {
-    const {store, $dataProvider} = useContext()
+    const {store, $dataProvider, app: {i18n}} = useContext()
+    const organizationProfile = reactive($organizationProfile(store))
     const {getItemToEdit} = useDataUtils($dataProvider)
     const id = store.state.profile.organization.parametersId
     const {fetchState} = getItemToEdit(id, Parameters)
-
-    const repository = repositoryHelper.getRepository(Parameters)
-    const query: ComputedRef<Query> = computed(() => repository.query())
+    const repositoryParameters: VuexRepository<Model> = repositoryHelper.getRepository(Parameters)
+    const query: ComputedRef<Query> = computed(() => repositoryParameters.query())
 
     return {
-      query: () => query,
+      query: () => query.value,
+      rules: () => getRules(i18n),
       id,
       fetchState,
-      model: Organization
+      model: Parameters,
+      organizationProfile,
     }
   }
 })
-</script>
 
-<style scoped>
-.v-icon.v-icon {
-  font-size: 14px;
+function getRules (i18n: any) {
+  return {
+    averageRules: [
+      (averageValue: number) => (averageValue >= 1 && averageValue <= 100) || i18n.t('value_need_to_be_beetween_0_100')
+    ]
+  }
 }
-</style>
+</script>

+ 12 - 1
services/profile/organizationProfile.ts

@@ -136,6 +136,17 @@ class OrganizationProfile {
     return this.organizationProfile.showAdherentList;
   }
 
+  /**
+   * L'organization est-elle la CMF ?
+   *
+   * @return {boolean}
+   */
+  isCMFCentralService(): boolean {
+    if(process.env.CMF_ID)
+      return this.organizationProfile.id == parseInt(process.env.CMF_ID)
+    return false
+  }
+
   /**
    * Factory
    *
@@ -149,7 +160,7 @@ class OrganizationProfile {
       isManagerProduct: this.isManagerProduct.bind(this),
       isOrganizationWithChildren: this.hasChildren.bind(this),
       isShowAdherentList: this.isShowAdherentList.bind(this),
-      isCmf: this.isCmf.bind(this)
+      isCmf: this.isCmf.bind(this),
     }
   }
 }

+ 2 - 1
services/store/form.ts

@@ -1,6 +1,7 @@
 import {Store} from "vuex";
 import {FORM_STATUS} from "~/types/enums";
 import {Route} from "vue-router";
+import {AnyJson} from "~/types/interfaces";
 
 export default class FormStorage {
   private store:Store<any>
@@ -27,7 +28,7 @@ export default class FormStorage {
    * Ajout des violations dans le store
    * @param invalidFields
    */
-  addViolations(invalidFields: Array<any>){
+  addViolations(invalidFields: AnyJson){
     this.store.commit('form/setViolations', invalidFields)
   }
 }