Browse Source

Merge branch 'v8-4454-fix_after_tests_3' into release/2.3.beta

Olivier Massot 2 years ago
parent
commit
9278f268a4

+ 4 - 0
components/Layout/Header/UniversalCreation/CreateButton.vue

@@ -92,4 +92,8 @@
 :deep(.v-btn .v-icon) {
 :deep(.v-btn .v-icon) {
   font-size: 16px !important;
   font-size: 16px !important;
 }
 }
+:deep(.v-btn) {
+  text-transform: none !important;
+  font-weight: 600;
+}
 </style>
 </style>

+ 24 - 3
components/Layout/Header/UniversalCreation/GenerateCardsSteps.vue

@@ -130,6 +130,15 @@
         />
         />
       </v-col>
       </v-col>
 
 
+      <v-col cols="6" v-if="hasOnlineRegistrationModule">
+        <LayoutHeaderUniversalCreationTypeCard
+            title="online_registration"
+            text-content="online_registration_text_creation_card"
+            icon="fa fa-list-alt"
+            :link="makeAdminUrl('/online/registration/new_registration')"
+        />
+      </v-col>
+
       <v-col cols="6">
       <v-col cols="6">
         <LayoutHeaderUniversalCreationTypeCard
         <LayoutHeaderUniversalCreationTypeCard
             title="another_type_of_contact"
             title="another_type_of_contact"
@@ -141,12 +150,13 @@
     </v-row>
     </v-row>
 
 
     <v-row v-if="type === 'event'">
     <v-row v-if="type === 'event'">
+      <!-- /?start=2023-06-12T08:00:00%2B0200&end=2023-06-12T09:00:00%2B0200 -->
       <v-col cols="6" v-if="ability.can('display', 'course_page')">
       <v-col cols="6" v-if="ability.can('display', 'course_page')">
         <LayoutHeaderUniversalCreationTypeCard
         <LayoutHeaderUniversalCreationTypeCard
             title="course"
             title="course"
             text-content="course_text_creation_card"
             text-content="course_text_creation_card"
             icon="fa fa-users"
             icon="fa fa-users"
-            :link="makeAdminUrl('/calendar/create/courses')"
+            :link="makeAdminUrl('/calendar/create/courses', {'start': eventDefaultStart, 'end': eventDefaultEnd})"
         />
         />
       </v-col>
       </v-col>
 
 
@@ -215,6 +225,7 @@
   import {useAbility} from "@casl/vue";
   import {useAbility} from "@casl/vue";
   import {ComputedRef} from "vue";
   import {ComputedRef} from "vue";
   import UrlUtils from "~/services/utils/urlUtils";
   import UrlUtils from "~/services/utils/urlUtils";
+  import {add, formatISO, startOfHour} from "date-fns";
 
 
   const props = defineProps({
   const props = defineProps({
     step: {
     step: {
@@ -231,6 +242,11 @@
   const organizationProfile = useOrganizationProfileStore()
   const organizationProfile = useOrganizationProfileStore()
   const runtimeConfig = useRuntimeConfig()
   const runtimeConfig = useRuntimeConfig()
 
 
+  // Get the start of the next hour as a default event start
+  const now: Date = new Date()
+  const eventDefaultStart: string = formatISO(startOfHour(add(now, { 'hours': 1 })))
+  const eventDefaultEnd: string = formatISO(startOfHour(add(now, { 'hours': 2 })))
+
   const onTypeClick = (step: Number, Cardtype: String) => {
   const onTypeClick = (step: Number, Cardtype: String) => {
     type.value = Cardtype;
     type.value = Cardtype;
     emit('updateStep', { stepChoice: step, typeChoice: Cardtype });
     emit('updateStep', { stepChoice: step, typeChoice: Cardtype });
@@ -238,8 +254,13 @@
 
 
   const adminLegacy: Ref<string> = ref(runtimeConfig.baseUrlAdminLegacy)
   const adminLegacy: Ref<string> = ref(runtimeConfig.baseUrlAdminLegacy)
   const isLaw1901: ComputedRef<boolean> = organizationProfile.isAssociation
   const isLaw1901: ComputedRef<boolean> = organizationProfile.isAssociation
+  const hasOnlineRegistrationModule: ComputedRef<boolean> = computed(
+      () => organizationProfile.hasModule('IEL')
+  )
 
 
-  const makeAdminUrl = (tail: string) => {
-    return UrlUtils.join(runtimeConfig.baseUrlAdminLegacy, '#', tail)
+  const makeAdminUrl = (tail: string, query: Record<string, string> = {}) => {
+    let url = UrlUtils.join(runtimeConfig.baseUrlAdminLegacy, '#', tail)
+    url = UrlUtils.addQuery(url, query)
+    return url
   }
   }
 </script>
 </script>

+ 2 - 2
components/Layout/MainMenu.vue

@@ -57,7 +57,7 @@ Prend en paramètre une liste de ItemMenu et les met en forme
             :href="!isInternalLink(child) ? child.to : undefined"
             :href="!isInternalLink(child) ? child.to : undefined"
             :to="isInternalLink(child) ? child.to : undefined"
             :to="isInternalLink(child) ? child.to : undefined"
             exact
             exact
-            height="48px"
+            height="38px"
             class="theme-secondary-alt"
             class="theme-secondary-alt"
           />
           />
         </v-list-group>
         </v-list-group>
@@ -154,7 +154,7 @@ onUnmounted(() => {
   .v-list-group--no-action > .v-list-group__header,
   .v-list-group--no-action > .v-list-group__header,
   .v-list-item
   .v-list-item
   {
   {
-    border-left:3px solid rgb(var(--v-theme-secondary));
+    border-left: 3px solid rgb(var(--v-theme-secondary));
     height: 48px;
     height: 48px;
   }
   }
 
 

+ 6 - 0
config/abilities/pages/parameters.yaml

@@ -86,6 +86,12 @@
       - {function: organizationHasAnyModule, parameters: ['BillingAdministration']}
       - {function: organizationHasAnyModule, parameters: ['BillingAdministration']}
       - {function: accessHasAnyRoleAbility, parameters: [{action: 'read', subject: 'billings-administration'}]}
       - {function: accessHasAnyRoleAbility, parameters: [{action: 'read', subject: 'billings-administration'}]}
 
 
+  billing_schedules_settings_page:
+    action: 'display'
+    conditions:
+      - {function: organizationHasAnyModule, parameters: ['BillingAdministration']}
+      - {function: accessHasAnyRoleAbility, parameters: [{action: 'read', subject: 'billings-administration'}]}
+
   online_registration_settings_page:
   online_registration_settings_page:
     action: 'display'
     action: 'display'
     conditions:
     conditions:

+ 5 - 3
lang/fr.json

@@ -428,7 +428,7 @@
   "stats": "Statistiques",
   "stats": "Statistiques",
   "report_activity": "Rapport d'activité",
   "report_activity": "Rapport d'activité",
   "educations_quotas_by_education": "Quotas par enseignement",
   "educations_quotas_by_education": "Quotas par enseignement",
-  "accesses_quotas_courses_hebdos": "Quotas hebdomadaires",
+  "accesses_quotas_courses_hebdos": "Quotas par professeur pour la semaine",
   "fede_stats": "Fédérations",
   "fede_stats": "Fédérations",
   "structure_stats": "Structures",
   "structure_stats": "Structures",
   "rate_cotisation": "Saisie du tarif",
   "rate_cotisation": "Saisie du tarif",
@@ -483,7 +483,7 @@
   "activities": "Sections",
   "activities": "Sections",
   "billing_settings": "Facturation",
   "billing_settings": "Facturation",
   "online_registration_settings": "Pré-inscription(s) en ligne",
   "online_registration_settings": "Pré-inscription(s) en ligne",
-  "transition_next_year": "Passage à l'année suivante",
+  "billing_schedules": "Échéanciers de facturation",
   "course_duplication": "Dupliquer les cours hebdomadaires",
   "course_duplication": "Dupliquer les cours hebdomadaires",
   "import": "Importer",
   "import": "Importer",
   "schooling_year": "Année scolaire",
   "schooling_year": "Année scolaire",
@@ -575,5 +575,7 @@
   "ERROR": "Erreur",
   "ERROR": "Erreur",
   "select": "Sélectionner",
   "select": "Sélectionner",
   "Internal Server Error": "Erreur de serveur interne",
   "Internal Server Error": "Erreur de serveur interne",
-  "cmf_licence_breadcrumbs": "Licence CMF"
+  "cmf_licence_breadcrumbs": "Licence CMF",
+  "online_registration": "Inscription en ligne",
+  "online_registration_text_creation_card": "Ajouter une nouvelle inscription"
 }
 }

+ 0 - 4
services/layout/menuBuilder/accountMenuBuilder.ts

@@ -39,10 +39,6 @@ export default class AccountMenuBuilder extends AbstractMenuBuilder {
       children.push(this.createItem('my_students_education_students', undefined, '/my_students_education_students/list/', MENU_LINK_TYPE.V1))
       children.push(this.createItem('my_students_education_students', undefined, '/my_students_education_students/list/', MENU_LINK_TYPE.V1))
     }
     }
 
 
-    if (this.ability.can('display', 'criteria_notations_page') || this.ability.can('display', 'criteria_notations_page_from_account_menu')) {
-      children.push(this.createItem('criteria_notations', undefined, '/criteria_notations/list/', MENU_LINK_TYPE.V1))
-    }
-
     if (this.ability.can('display', 'my_education_students_page')) {
     if (this.ability.can('display', 'my_education_students_page')) {
       children.push(this.createItem('my_education_students', undefined, `/main/my_profile/${this.accessProfile.id}/dashboard/my_education_students/list/`, MENU_LINK_TYPE.V1))
       children.push(this.createItem('my_education_students', undefined, `/main/my_profile/${this.accessProfile.id}/dashboard/my_education_students/list/`, MENU_LINK_TYPE.V1))
     }
     }

+ 10 - 4
services/layout/menuBuilder/configurationMenuBuilder.ts

@@ -71,6 +71,16 @@ export default class ConfigurationMenuBuilder extends AbstractMenuBuilder {
       )
       )
     }
     }
 
 
+    if (this.ability.can('display', 'billing_schedules_settings_page')) {
+      children.push(
+          this.createItem(
+              'billing_schedules',
+              undefined,
+              '/bill_schedules/list/',
+              MENU_LINK_TYPE.V1)
+      )
+    }
+
     if (this.ability.can('display', 'online_registration_settings_page')) {
     if (this.ability.can('display', 'online_registration_settings_page')) {
       children.push(
       children.push(
           this.createItem(
           this.createItem(
@@ -82,10 +92,6 @@ export default class ConfigurationMenuBuilder extends AbstractMenuBuilder {
       )
       )
     }
     }
 
 
-    if (this.ability.can('display', 'transition_next_year_page')) {
-      children.push(this.createItem('transition_next_year', undefined, '/transition_next_year', MENU_LINK_TYPE.V1))
-    }
-
     if (this.ability.can('display', 'course_duplication_page')) {
     if (this.ability.can('display', 'course_duplication_page')) {
       children.push(this.createItem('course_duplication', undefined, '/duplicate_courses', MENU_LINK_TYPE.V1))
       children.push(this.createItem('course_duplication', undefined, '/duplicate_courses', MENU_LINK_TYPE.V1))
     }
     }

+ 37 - 0
services/utils/urlUtils.ts

@@ -1,3 +1,5 @@
+import _ from "lodash";
+
 /**
 /**
  * Classe permettant de construire une URL pour l'interrogation d'une API externe
  * Classe permettant de construire une URL pour l'interrogation d'une API externe
  */
  */
@@ -90,6 +92,41 @@ class UrlUtils {
   public static split(uri: string) {
   public static split(uri: string) {
     return uri.split('/').filter((s) => s.length > 0)
     return uri.split('/').filter((s) => s.length > 0)
   }
   }
+
+  /**
+   * Format and add a query to an url
+   * If the url already has a query, append the new parameters to it.
+   * If the query is an empty object, does nothing.
+   *
+   * Ex:
+   *     addQuery('foo/bar', {})  =>  'foo/bar'
+   *     addQuery('foo/bar', {'a': 1})  =>  'foo/bar?a=1'
+   *     addQuery('foo/bar?a=1', {'b': 2})  =>  'foo/bar?a=1&b=2'
+   *
+   * @param url
+   * @param query
+   */
+  public static addQuery(url: string | URL, query: object): string {
+
+    let urlObj = new URL(url, 'https://temporary-dommain.inexistent') as URL
+
+    if (!_.isEmpty(query)) {
+      urlObj = new URL(
+          `${urlObj.origin}${urlObj.pathname}${urlObj.hash}?${new URLSearchParams([
+            ...Array.from(urlObj.searchParams.entries()),
+            ...Object.entries(query),
+          ])}`
+      )
+    }
+
+    let result = urlObj.toString()
+
+    if (urlObj.host === 'temporary-dommain.inexistent') {
+      result = result.replace('https://temporary-dommain.inexistent', '')
+    }
+
+    return result
+  }
 }
 }
 
 
 export default UrlUtils
 export default UrlUtils

+ 3 - 3
stores/accessProfile.ts

@@ -98,7 +98,7 @@ export const useAccessProfileStore = defineStore('accessProfile', () => {
   }
   }
 
 
   const setProfile = (profile: any) => {
   const setProfile = (profile: any) => {
-    const profileRoles: Array<string> = Object.values(profile.roles)
+    const profileRoles: Array<string> = Array.from(Object.values(profile.roles))
 
 
     name.value = profile.name
     name.value = profile.name
     givenName.value = profile.givenName
     givenName.value = profile.givenName
@@ -138,10 +138,10 @@ export const useAccessProfileStore = defineStore('accessProfile', () => {
     }
     }
 
 
     // Set multi-accesses
     // Set multi-accesses
-    setMultiAccesses(profile.multiAccesses)
+    setMultiAccesses(Array.from(profile.multiAccesses))
 
 
     // Set family-accesses
     // Set family-accesses
-    setFamilyAccesses(profile.familyAccesses)
+    setFamilyAccesses(Array.from(profile.familyAccesses))
 
 
     // Set organization profile
     // Set organization profile
     // TODO: à voir si c'est bien d'appeler un autre store d'ici où s'il vaudrait mieux le faire dans la couche supérieure
     // TODO: à voir si c'est bien d'appeler un autre store d'ici où s'il vaudrait mieux le faire dans la couche supérieure

+ 2 - 2
stores/organizationProfile.ts

@@ -154,11 +154,11 @@ export const useOrganizationProfileStore = defineStore('organizationProfile', ()
     product.value = profile.product
     product.value = profile.product
     currentActivityYear.value = profile.currentYear
     currentActivityYear.value = profile.currentYear
     website.value = profile.website
     website.value = profile.website
-    modules.value = profile.modules
+    modules.value = Array.from(profile.modules)
     hasChildren.value = profile.hasChildren
     hasChildren.value = profile.hasChildren
     legalStatus.value = profile.legalStatus
     legalStatus.value = profile.legalStatus
     showAdherentList.value = profile.showAdherentList
     showAdherentList.value = profile.showAdherentList
-    networks.value = profile.networks
+    networks.value = Array.from(profile.networks)
 
 
     _.each(profile.parents, (parent) => {
     _.each(profile.parents, (parent) => {
       parents.value.push({
       parents.value.push({

+ 1 - 1
tests/units/services/layout/menuBuilder/accountMenuBuilder.test.ts

@@ -43,7 +43,7 @@ describe('build', () => {
         expect(result.label).toEqual('my_account')
         expect(result.label).toEqual('my_account')
 
 
         // @ts-ignore
         // @ts-ignore
-        expect(result.children.length).toEqual(15)
+        expect(result.children.length).toEqual(14)
         // @ts-ignore
         // @ts-ignore
         expect(result.actions.length).toEqual(1)
         expect(result.actions.length).toEqual(1)
 
 

+ 0 - 8
tests/units/services/layout/menuBuilder/configurationMenuBuilder.test.ts

@@ -99,14 +99,6 @@ describe('build', () => {
         )
         )
     })
     })
 
 
-    test('has only rights for menu transition_next_year', () => {
-        ability.can = vi.fn((action: string, subject: string) => action === 'display' && subject === 'transition_next_year_page')
-
-        expect(menuBuilder.build()).toEqual(
-            {label: 'transition_next_year', icon: undefined, to: 'https://mydomain.com/#/transition_next_year', type: MENU_LINK_TYPE.V1, active: false}
-        )
-    })
-
     test('has only rights for menu course_duplication', () => {
     test('has only rights for menu course_duplication', () => {
         ability.can = vi.fn((action: string, subject: string) => action === 'display' && subject === 'course_duplication_page')
         ability.can = vi.fn((action: string, subject: string) => action === 'display' && subject === 'course_duplication_page')
 
 

+ 27 - 0
tests/units/services/utils/urlUtils.test.ts

@@ -91,3 +91,30 @@ describe('split', () => {
         expect(UrlUtils.split('')).toEqual([])
         expect(UrlUtils.split('')).toEqual([])
     })
     })
 })
 })
+
+describe('addQuery', () => {
+    test('with empty query', () => {
+        expect(UrlUtils.addQuery('foo/bar', {})).toEqual('/foo/bar')
+    })
+    test('with simple query', () => {
+        expect(UrlUtils.addQuery('foo/bar', {'a': 1})).toEqual('/foo/bar?a=1')
+    })
+    test('with longer query', () => {
+        expect(UrlUtils.addQuery('foo/bar', {'a': 1, 'b': 2})).toEqual('/foo/bar?a=1&b=2')
+    })
+    test('with existing query', () => {
+        expect(UrlUtils.addQuery('foo/bar?a=1', {'b': 2})).toEqual('/foo/bar?a=1&b=2')
+    })
+    test('with empty url', () => {
+        expect(UrlUtils.addQuery('', {'a': 1})).toEqual('/?a=1')
+    })
+    test('with empty url and empty query', () => {
+        expect(UrlUtils.addQuery('', {})).toEqual('/')
+    })
+    test('with absolute url', () => {
+        expect(UrlUtils.addQuery('https://foo.com/bar/', {'a': 1})).toEqual('https://foo.com/bar/?a=1')
+    })
+    test('with number sign in path name', () => {
+        expect(UrlUtils.addQuery('https://foo.com/#/bar/', {'a': 1})).toEqual('https://foo.com/#/bar/?a=1')
+    })
+})