• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inclusion-numerique / coop-mediation-numerique / 63ed3aef-04ec-416c-af7d-d56de15ebe3e

17 Mar 2026 03:48PM UTC coverage: 10.613% (-0.2%) from 10.79%
63ed3aef-04ec-416c-af7d-d56de15ebe3e

Pull #437

circleci

web-flow
Merge pull request #458 from inclusion-numerique/fix/admin-stats-min-date

fix(admin): allow filtering statistics from January 2020
Pull Request #437: release

685 of 10426 branches covered (6.57%)

Branch coverage included in aggregate %.

34 of 590 new or added lines in 86 files covered. (5.76%)

23 existing lines in 20 files now uncovered.

2130 of 16099 relevant lines covered (13.23%)

2.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/apps/web/src/server/rpc/structures/structuresRouter.ts
1
import { searchStructureEmployeuseCombined } from '@app/web/features/inscription/use-cases/renseigner-structure-employeuse/searchStructureEmployeuseCombined'
2
import { CreerStructureValidation } from '@app/web/features/structures/CreerStructureValidation'
3
import { searchStructuresEmployeuses } from '@app/web/features/structures/getStructuresEmployeusesOptions'
4
import { mergeStructure } from '@app/web/features/structures/use-cases/merge/mutations/mergeStructure'
5
import { mediateurCoordonnesIdsFor } from '@app/web/mediateurs/mediateurCoordonnesIdsFor'
6
import { prismaClient } from '@app/web/prismaClient'
7
import { protectedProcedure, router } from '@app/web/server/rpc/createRouter'
8
import { enforceIsAdmin } from '@app/web/server/rpc/enforceIsAdmin'
9
import { searchLieuActiviteCombined } from '@app/web/structure/searchLieuActiviteCombined'
10
import { searchStructure } from '@app/web/structure/searchStructure'
11
import { searchStructureCartographieNationale } from '@app/web/structure/searchStructureCartographieNationale'
12
import { fixTelephone } from '@app/web/utils/clean-operations'
13
import { onlyDefinedAndNotNull } from '@app/web/utils/onlyDefinedAndNotNull'
14
import { createStopwatch } from '@app/web/utils/stopwatch'
15
import { Itinerance, ModaliteAcces } from '@prisma/client'
16
import { v4 } from 'uuid'
17
import { z } from 'zod'
18

19
export const structuresRouter = router({
×
20
  search: protectedProcedure
21
    .input(z.object({ query: z.string() }))
22
    .query(({ input: { query } }) => searchStructure(query)),
×
23

24
  searchCombined: protectedProcedure
25
    .input(z.object({ query: z.string() }))
26
    .query(({ input: { query } }) => searchStructureEmployeuseCombined(query)),
×
27

28
  searchCartographieNationale: protectedProcedure
29
    .input(
30
      z.object({ query: z.string(), except: z.array(z.string()).nullish() }),
31
    )
32
    .query(({ input: { query, except } }) =>
33
      searchStructureCartographieNationale(query, {
×
34
        except: except ?? undefined,
×
35
      }),
36
    ),
37

38
  searchLieuActiviteCombined: protectedProcedure
39
    .input(
40
      z.object({ query: z.string(), except: z.array(z.string()).nullish() }),
41
    )
42
    .query(({ input: { query, except } }) =>
NEW
43
      searchLieuActiviteCombined(query, {
×
44
        except: except ?? undefined,
×
45
      }),
46
    ),
47

48
  searchStructuresEmployeuses: protectedProcedure
49
    .input(
50
      z.object({
51
        query: z.string(),
52
        excludeIds: z.array(z.string().uuid()).optional(),
53
      }),
54
    )
55
    .query(({ input: { query, excludeIds }, ctx: { user } }) => {
NEW
56
      const mediateurIds = [
×
57
        ...(user.mediateur?.id ? [user.mediateur.id] : []),
×
58
        ...mediateurCoordonnesIdsFor(user),
59
      ]
NEW
60
      return searchStructuresEmployeuses({ query, mediateurIds, excludeIds })
×
61
    }),
62

63
  create: protectedProcedure.input(CreerStructureValidation).mutation(
64
    async ({
65
      input: {
66
        lieuActiviteMediateurId,
67
        nom,
68
        typologies,
69
        adresseBan: {
70
          longitude,
71
          latitude,
72
          codeInsee,
73
          nom: adresse,
74
          commune,
75
          codePostal,
76
        },
77
        complementAdresse,
78
        siret,
79
        rna,
80
        visiblePourCartographieNationale,
81
        presentationResume,
82
        presentationDetail,
83
        siteWeb,
84
        ficheAccesLibre,
85
        horaires,
86
        priseEnChargeSpecifique,
87
        modalitesAcces,
88
        fraisACharge,
89
        lieuItinerant,
90
        publicsSpecifiquementAdresses,
91
        services,
92
        modalitesAccompagnement,
93
        priseRdv,
94
      },
95
      ctx: { user },
96
    }) => {
97
      const stopwatch = createStopwatch()
×
98

99
      const id = v4()
×
100

101
      const created = await prismaClient.structure.create({
×
102
        data: {
103
          id,
104
          nom,
105
          typologies: typologies ?? undefined,
×
106
          adresse,
107
          commune,
108
          codePostal,
109
          complementAdresse,
110
          siret,
111
          rna,
112
          longitude,
113
          latitude,
114
          codeInsee,
115
          visiblePourCartographieNationale:
116
            visiblePourCartographieNationale ?? false,
×
117
          presentationResume,
118
          presentationDetail,
119
          siteWeb,
120
          ficheAccesLibre,
121
          horaires,
122
          creationParId: user.id,
123
          mediateursEnActivite: lieuActiviteMediateurId
×
124
            ? {
125
                create: {
126
                  id: v4(),
127
                  mediateurId: lieuActiviteMediateurId,
128
                  debut: new Date(),
129
                  creationParId: user.id,
130
                },
131
              }
132
            : undefined,
133
          fraisACharge: fraisACharge ?? undefined,
×
134
          itinerance:
135
            typeof lieuItinerant === 'boolean'
×
136
              ? lieuItinerant
×
137
                ? [Itinerance.Itinerant]
138
                : [Itinerance.Fixe]
139
              : undefined,
140
          modalitesAcces: modalitesAcces
×
141
            ? [
142
                modalitesAcces.surPlace ? ModaliteAcces.SePresenter : undefined,
×
143
                modalitesAcces.parTelephone
×
144
                  ? ModaliteAcces.Telephoner
145
                  : undefined,
146
                modalitesAcces.parMail
×
147
                  ? ModaliteAcces.ContacterParMail
148
                  : undefined,
149
              ].filter(onlyDefinedAndNotNull)
150
            : undefined,
151
          telephone: modalitesAcces?.numeroTelephone
×
152
            ? fixTelephone(modalitesAcces.numeroTelephone)
153
            : undefined,
154
          courriels: modalitesAcces?.adresseMail
×
155
            ? [modalitesAcces.adresseMail]
156
            : undefined,
157
          modalitesAccompagnement: modalitesAccompagnement ?? undefined,
×
158
          priseEnChargeSpecifique: priseEnChargeSpecifique ?? undefined,
×
159
          publicsSpecifiquementAdresses:
160
            publicsSpecifiquementAdresses ?? undefined,
×
161
          services: services ?? undefined,
×
162
          priseRdv: priseRdv ?? undefined,
×
163
        },
164
      })
165

166
      await prismaClient.mutation.create({
×
167
        data: {
168
          nom: 'CreerStructure',
169
          userId: user.id,
170
          duration: stopwatch.stop().duration,
171
          data: {
172
            id,
173
            nom,
174
            typologies,
175
            siret,
176
            rna,
177
            codePostal,
178
          },
179
        },
180
      })
181

182
      return created
×
183
    },
184
  ),
185

186
  merge: protectedProcedure
187
    .input(
188
      z.object({
189
        sourceStructureId: z.string().uuid(),
190
        targetStructureId: z.string().uuid(),
191
      }),
192
    )
193
    .mutation(async ({ input, ctx: { user } }) => {
NEW
194
      enforceIsAdmin(user)
×
NEW
195
      return mergeStructure(input.sourceStructureId, input.targetStructureId)
×
196
    }),
197
})
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc