@studious-lms/server 1.23.0 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/.env.example +0 -1
  2. package/data/curriculum/nepal-cdc-g4-g5/README.md +90 -0
  3. package/data/curriculum/nepal-cdc-g4-g5/manifest.json +97 -0
  4. package/data/curriculum/nepal-cdc-g4-g5/proficiency-scale.json +76 -0
  5. package/data/curriculum/nepal-cdc-g4-g5/subjects/english.json +6936 -0
  6. package/data/curriculum/nepal-cdc-g4-g5/subjects/health-physical-creative-arts.json +3401 -0
  7. package/data/curriculum/nepal-cdc-g4-g5/subjects/mathematics.json +1511 -0
  8. package/data/curriculum/nepal-cdc-g4-g5/subjects/nepali.json +7928 -0
  9. package/data/curriculum/nepal-cdc-g4-g5/subjects/science-technology.json +2420 -0
  10. package/data/curriculum/nepal-cdc-g4-g5/subjects/social-studies.json +2177 -0
  11. package/dist/lib/assignmentTypeDefaults.d.ts +41 -0
  12. package/dist/lib/assignmentTypeDefaults.d.ts.map +1 -0
  13. package/dist/lib/assignmentTypeDefaults.js +167 -0
  14. package/dist/lib/assignmentTypeDefaults.js.map +1 -0
  15. package/dist/lib/config/env.d.ts +0 -8
  16. package/dist/lib/config/env.d.ts.map +1 -1
  17. package/dist/lib/config/env.js +2 -5
  18. package/dist/lib/config/env.js.map +1 -1
  19. package/dist/lib/feePdf.d.ts +19 -0
  20. package/dist/lib/feePdf.d.ts.map +1 -0
  21. package/dist/lib/feePdf.js +167 -0
  22. package/dist/lib/feePdf.js.map +1 -0
  23. package/dist/lib/feePdfFormat.d.ts +4 -0
  24. package/dist/lib/feePdfFormat.d.ts.map +1 -0
  25. package/dist/lib/feePdfFormat.js +16 -0
  26. package/dist/lib/feePdfFormat.js.map +1 -0
  27. package/dist/lib/idCardPdf.d.ts +26 -0
  28. package/dist/lib/idCardPdf.d.ts.map +1 -0
  29. package/dist/lib/idCardPdf.js +272 -0
  30. package/dist/lib/idCardPdf.js.map +1 -0
  31. package/dist/lib/pdfLetterhead.d.ts +41 -0
  32. package/dist/lib/pdfLetterhead.d.ts.map +1 -0
  33. package/dist/lib/pdfLetterhead.js +86 -0
  34. package/dist/lib/pdfLetterhead.js.map +1 -0
  35. package/dist/lib/transcriptPdf.d.ts +55 -0
  36. package/dist/lib/transcriptPdf.d.ts.map +1 -0
  37. package/dist/lib/transcriptPdf.js +303 -0
  38. package/dist/lib/transcriptPdf.js.map +1 -0
  39. package/dist/models/academicCalendar.d.ts +198 -0
  40. package/dist/models/academicCalendar.d.ts.map +1 -0
  41. package/dist/models/academicCalendar.js +106 -0
  42. package/dist/models/academicCalendar.js.map +1 -0
  43. package/dist/models/agenda.d.ts +8 -0
  44. package/dist/models/agenda.d.ts.map +1 -1
  45. package/dist/models/announcement.d.ts +2 -0
  46. package/dist/models/announcement.d.ts.map +1 -1
  47. package/dist/models/assignment.d.ts +66 -0
  48. package/dist/models/assignment.d.ts.map +1 -1
  49. package/dist/models/attendance.d.ts +659 -21
  50. package/dist/models/attendance.d.ts.map +1 -1
  51. package/dist/models/attendance.js +547 -75
  52. package/dist/models/attendance.js.map +1 -1
  53. package/dist/models/auth.d.ts +2 -0
  54. package/dist/models/auth.d.ts.map +1 -1
  55. package/dist/models/class.d.ts +12 -0
  56. package/dist/models/class.d.ts.map +1 -1
  57. package/dist/models/class.js +3 -2
  58. package/dist/models/class.js.map +1 -1
  59. package/dist/models/event.d.ts +16 -0
  60. package/dist/models/event.d.ts.map +1 -1
  61. package/dist/models/fees.d.ts +554 -0
  62. package/dist/models/fees.d.ts.map +1 -0
  63. package/dist/models/fees.js +278 -0
  64. package/dist/models/fees.js.map +1 -0
  65. package/dist/models/file.d.ts +29 -0
  66. package/dist/models/file.d.ts.map +1 -1
  67. package/dist/models/folder.d.ts +2 -0
  68. package/dist/models/folder.d.ts.map +1 -1
  69. package/dist/models/labChat.d.ts +2 -0
  70. package/dist/models/labChat.d.ts.map +1 -1
  71. package/dist/models/marketplace.d.ts +180 -0
  72. package/dist/models/marketplace.d.ts.map +1 -0
  73. package/dist/models/marketplace.js +116 -0
  74. package/dist/models/marketplace.js.map +1 -0
  75. package/dist/models/moduleItem.d.ts +308 -0
  76. package/dist/models/moduleItem.d.ts.map +1 -0
  77. package/dist/models/moduleItem.js +93 -0
  78. package/dist/models/moduleItem.js.map +1 -0
  79. package/dist/models/newtonChat.d.ts +1 -0
  80. package/dist/models/newtonChat.d.ts.map +1 -1
  81. package/dist/models/school.d.ts +18 -0
  82. package/dist/models/school.d.ts.map +1 -1
  83. package/dist/models/school.js +7 -2
  84. package/dist/models/school.js.map +1 -1
  85. package/dist/models/section.d.ts +4 -0
  86. package/dist/models/section.d.ts.map +1 -1
  87. package/dist/models/worksheet.d.ts +19 -0
  88. package/dist/models/worksheet.d.ts.map +1 -1
  89. package/dist/models/worksheet.js +2 -2
  90. package/dist/models/worksheet.js.map +1 -1
  91. package/dist/routers/_app.d.ts +12024 -7778
  92. package/dist/routers/_app.d.ts.map +1 -1
  93. package/dist/routers/_app.js +12 -2
  94. package/dist/routers/_app.js.map +1 -1
  95. package/dist/routers/academicCalendar.d.ts +229 -0
  96. package/dist/routers/academicCalendar.d.ts.map +1 -0
  97. package/dist/routers/academicCalendar.js +75 -0
  98. package/dist/routers/academicCalendar.js.map +1 -0
  99. package/dist/routers/admin.d.ts +2 -0
  100. package/dist/routers/admin.d.ts.map +1 -1
  101. package/dist/routers/agenda.d.ts +8 -0
  102. package/dist/routers/agenda.d.ts.map +1 -1
  103. package/dist/routers/assignment.d.ts +75 -0
  104. package/dist/routers/assignment.d.ts.map +1 -1
  105. package/dist/routers/assignment.js +10 -2
  106. package/dist/routers/assignment.js.map +1 -1
  107. package/dist/routers/attendance.d.ts +103 -0
  108. package/dist/routers/attendance.d.ts.map +1 -1
  109. package/dist/routers/attendance.js +8 -5
  110. package/dist/routers/attendance.js.map +1 -1
  111. package/dist/routers/class.d.ts +27 -0
  112. package/dist/routers/class.d.ts.map +1 -1
  113. package/dist/routers/class.js +6 -2
  114. package/dist/routers/class.js.map +1 -1
  115. package/dist/routers/event.d.ts +8 -0
  116. package/dist/routers/event.d.ts.map +1 -1
  117. package/dist/routers/fees.d.ts +513 -0
  118. package/dist/routers/fees.d.ts.map +1 -0
  119. package/dist/routers/fees.js +88 -0
  120. package/dist/routers/fees.js.map +1 -0
  121. package/dist/routers/file.d.ts +2 -0
  122. package/dist/routers/file.d.ts.map +1 -1
  123. package/dist/routers/gradebook.d.ts +4 -1
  124. package/dist/routers/gradebook.d.ts.map +1 -1
  125. package/dist/routers/marketplace.d.ts +371 -0
  126. package/dist/routers/marketplace.d.ts.map +1 -0
  127. package/dist/routers/marketplace.js +87 -0
  128. package/dist/routers/marketplace.js.map +1 -0
  129. package/dist/routers/moduleItem.d.ts +263 -0
  130. package/dist/routers/moduleItem.d.ts.map +1 -0
  131. package/dist/routers/moduleItem.js +61 -0
  132. package/dist/routers/moduleItem.js.map +1 -0
  133. package/dist/routers/parent.d.ts +170 -0
  134. package/dist/routers/parent.d.ts.map +1 -0
  135. package/dist/routers/parent.js +49 -0
  136. package/dist/routers/parent.js.map +1 -0
  137. package/dist/routers/school.d.ts +363 -7
  138. package/dist/routers/school.d.ts.map +1 -1
  139. package/dist/routers/school.js +110 -3
  140. package/dist/routers/school.js.map +1 -1
  141. package/dist/routers/worksheet.d.ts +27 -0
  142. package/dist/routers/worksheet.d.ts.map +1 -1
  143. package/dist/routers/worksheet.js +10 -3
  144. package/dist/routers/worksheet.js.map +1 -1
  145. package/dist/services/academicCalendar.d.ts +173 -0
  146. package/dist/services/academicCalendar.d.ts.map +1 -0
  147. package/dist/services/academicCalendar.js +242 -0
  148. package/dist/services/academicCalendar.js.map +1 -0
  149. package/dist/services/adminInstitution.d.ts +2 -0
  150. package/dist/services/adminInstitution.d.ts.map +1 -1
  151. package/dist/services/agenda.d.ts +8 -0
  152. package/dist/services/agenda.d.ts.map +1 -1
  153. package/dist/services/assignment.d.ts +75 -0
  154. package/dist/services/assignment.d.ts.map +1 -1
  155. package/dist/services/assignment.js +91 -12
  156. package/dist/services/assignment.js.map +1 -1
  157. package/dist/services/attendance.d.ts +327 -10
  158. package/dist/services/attendance.d.ts.map +1 -1
  159. package/dist/services/attendance.js +389 -25
  160. package/dist/services/attendance.js.map +1 -1
  161. package/dist/services/attendanceMerge.d.ts +53 -0
  162. package/dist/services/attendanceMerge.d.ts.map +1 -0
  163. package/dist/services/attendanceMerge.js +87 -0
  164. package/dist/services/attendanceMerge.js.map +1 -0
  165. package/dist/services/attendanceRate.d.ts +24 -0
  166. package/dist/services/attendanceRate.d.ts.map +1 -0
  167. package/dist/services/attendanceRate.js +31 -0
  168. package/dist/services/attendanceRate.js.map +1 -0
  169. package/dist/services/attendanceStats.d.ts +22 -0
  170. package/dist/services/attendanceStats.d.ts.map +1 -0
  171. package/dist/services/attendanceStats.js +45 -0
  172. package/dist/services/attendanceStats.js.map +1 -0
  173. package/dist/services/class.d.ts +34 -2
  174. package/dist/services/class.d.ts.map +1 -1
  175. package/dist/services/class.js +27 -4
  176. package/dist/services/class.js.map +1 -1
  177. package/dist/services/event.d.ts +8 -0
  178. package/dist/services/event.d.ts.map +1 -1
  179. package/dist/services/fees.d.ts +422 -0
  180. package/dist/services/fees.d.ts.map +1 -0
  181. package/dist/services/fees.js +330 -0
  182. package/dist/services/fees.js.map +1 -0
  183. package/dist/services/feesAuthz.d.ts +46 -0
  184. package/dist/services/feesAuthz.d.ts.map +1 -0
  185. package/dist/services/feesAuthz.js +49 -0
  186. package/dist/services/feesAuthz.js.map +1 -0
  187. package/dist/services/file.d.ts +4 -0
  188. package/dist/services/file.d.ts.map +1 -1
  189. package/dist/services/gradebook.d.ts +18 -1
  190. package/dist/services/gradebook.d.ts.map +1 -1
  191. package/dist/services/gradebook.js +57 -2
  192. package/dist/services/gradebook.js.map +1 -1
  193. package/dist/services/idCard.d.ts +11 -0
  194. package/dist/services/idCard.d.ts.map +1 -0
  195. package/dist/services/idCard.js +122 -0
  196. package/dist/services/idCard.js.map +1 -0
  197. package/dist/services/marketplace.d.ts +301 -0
  198. package/dist/services/marketplace.d.ts.map +1 -0
  199. package/dist/services/marketplace.js +631 -0
  200. package/dist/services/marketplace.js.map +1 -0
  201. package/dist/services/moduleItem.d.ts +196 -0
  202. package/dist/services/moduleItem.d.ts.map +1 -0
  203. package/dist/services/moduleItem.js +204 -0
  204. package/dist/services/moduleItem.js.map +1 -0
  205. package/dist/services/notification.d.ts +58 -0
  206. package/dist/services/notification.d.ts.map +1 -1
  207. package/dist/services/notification.js +30 -2
  208. package/dist/services/notification.js.map +1 -1
  209. package/dist/services/parentPortal.d.ts +131 -0
  210. package/dist/services/parentPortal.d.ts.map +1 -0
  211. package/dist/services/parentPortal.js +314 -0
  212. package/dist/services/parentPortal.js.map +1 -0
  213. package/dist/services/school.d.ts +28 -3
  214. package/dist/services/school.d.ts.map +1 -1
  215. package/dist/services/school.js +98 -54
  216. package/dist/services/school.js.map +1 -1
  217. package/dist/services/studentImport.d.ts +34 -0
  218. package/dist/services/studentImport.d.ts.map +1 -0
  219. package/dist/services/studentImport.js +249 -0
  220. package/dist/services/studentImport.js.map +1 -0
  221. package/dist/services/transcript.d.ts +60 -0
  222. package/dist/services/transcript.d.ts.map +1 -0
  223. package/dist/services/transcript.js +231 -0
  224. package/dist/services/transcript.js.map +1 -0
  225. package/dist/services/worksheet.d.ts +22 -0
  226. package/dist/services/worksheet.d.ts.map +1 -1
  227. package/dist/services/worksheet.js +94 -2
  228. package/dist/services/worksheet.js.map +1 -1
  229. package/dist/trpc.d.ts +1 -1
  230. package/dist/trpc.d.ts.map +1 -1
  231. package/dist/trpc.js +5 -5
  232. package/dist/trpc.js.map +1 -1
  233. package/dist/utils/adminPanelAccess.d.ts +4 -5
  234. package/dist/utils/adminPanelAccess.d.ts.map +1 -1
  235. package/dist/utils/adminPanelAccess.js +12 -34
  236. package/dist/utils/adminPanelAccess.js.map +1 -1
  237. package/package.json +2 -1
  238. package/prisma/migrations/20260804120000_add_attendance_records_and_excusals/migration.sql +114 -0
  239. package/prisma/migrations/20260804120100_add_fee_plans_invoices_payments/migration.sql +101 -0
  240. package/prisma/migrations/20260804120200_add_marketplace_listings/migration.sql +54 -0
  241. package/prisma/migrations/20260804120300_content_platform_b3_b9/migration.sql +63 -0
  242. package/prisma/migrations/20260804120400_c_academic_ops/migration.sql +77 -0
  243. package/prisma/schema.prisma +371 -11
  244. package/scripts/import-nepal-cdc-curriculum.ts +402 -0
  245. package/src/lib/assignmentTypeDefaults.ts +222 -0
  246. package/src/lib/config/env.ts +0 -3
  247. package/src/lib/feePdf.ts +199 -0
  248. package/src/lib/feePdfFormat.ts +14 -0
  249. package/src/lib/idCardPdf.ts +336 -0
  250. package/src/lib/pdfLetterhead.ts +124 -0
  251. package/src/lib/transcriptPdf.ts +502 -0
  252. package/src/models/academicCalendar.ts +139 -0
  253. package/src/models/attendance.ts +702 -73
  254. package/src/models/class.ts +1 -0
  255. package/src/models/fees.ts +349 -0
  256. package/src/models/marketplace.ts +161 -0
  257. package/src/models/moduleItem.ts +125 -0
  258. package/src/models/school.ts +6 -0
  259. package/src/models/worksheet.ts +2 -0
  260. package/src/routers/_app.ts +10 -0
  261. package/src/routers/academicCalendar.ts +103 -0
  262. package/src/routers/assignment.ts +8 -0
  263. package/src/routers/attendance.ts +7 -3
  264. package/src/routers/class.ts +4 -0
  265. package/src/routers/fees.ts +126 -0
  266. package/src/routers/marketplace.ts +134 -0
  267. package/src/routers/moduleItem.ts +91 -0
  268. package/src/routers/parent.ts +68 -0
  269. package/src/routers/school.ts +149 -1
  270. package/src/routers/worksheet.ts +11 -0
  271. package/src/services/academicCalendar.ts +327 -0
  272. package/src/services/assignment.ts +122 -12
  273. package/src/services/attendance.ts +552 -26
  274. package/src/services/attendanceMerge.ts +139 -0
  275. package/src/services/attendanceRate.ts +41 -0
  276. package/src/services/attendanceStats.ts +63 -0
  277. package/src/services/class.ts +26 -2
  278. package/src/services/fees.ts +447 -0
  279. package/src/services/feesAuthz.ts +73 -0
  280. package/src/services/gradebook.ts +70 -0
  281. package/src/services/idCard.ts +147 -0
  282. package/src/services/marketplace.ts +790 -0
  283. package/src/services/moduleItem.ts +298 -0
  284. package/src/services/notification.ts +43 -0
  285. package/src/services/parentPortal.ts +367 -0
  286. package/src/services/school.ts +100 -54
  287. package/src/services/studentImport.ts +285 -0
  288. package/src/services/transcript.ts +301 -0
  289. package/src/services/worksheet.ts +111 -0
  290. package/src/trpc.ts +3 -3
  291. package/src/utils/adminPanelAccess.ts +12 -35
  292. package/tests/unit/assignmentTypeDefaults.test.ts +52 -0
  293. package/tests/unit/lib/feePdf.test.ts +15 -0
  294. package/tests/unit/lib/idCardPdf.test.ts +40 -0
  295. package/tests/unit/lib/transcriptPdf.test.ts +111 -0
  296. package/tests/unit/services/attendanceMerge.test.ts +90 -0
  297. package/tests/unit/services/attendanceRate.test.ts +38 -0
  298. package/tests/unit/services/attendanceStats.test.ts +54 -0
@@ -29,6 +29,9 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
29
29
  logoId: string | null;
30
30
  logoPath: string | null;
31
31
  logoType: string | null;
32
+ letterheadFileId: string | null;
33
+ letterheadPath: string | null;
34
+ letterheadType: string | null;
32
35
  } | null;
33
36
  activeRole: import(".prisma/client").$Enums.SchoolMembershipRole | null;
34
37
  memberships: ({
@@ -39,12 +42,19 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
39
42
  name: string;
40
43
  description: string | null;
41
44
  logoId: string | null;
45
+ letterheadFileId: string | null;
42
46
  subdomain: string | null;
43
47
  logo: {
44
48
  path: string;
45
49
  type: string;
46
50
  id: string;
47
51
  } | null;
52
+ letterhead: {
53
+ path: string;
54
+ type: string;
55
+ id: string;
56
+ name: string;
57
+ } | null;
48
58
  };
49
59
  } & {
50
60
  status: import(".prisma/client").$Enums.SchoolMembershipStatus;
@@ -83,6 +93,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
83
93
  name: string;
84
94
  description: string | null;
85
95
  logoId: string | null;
96
+ letterheadFileId: string | null;
86
97
  subdomain: string | null;
87
98
  };
88
99
  };
@@ -94,6 +105,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
94
105
  name?: string | undefined;
95
106
  description?: string | null | undefined;
96
107
  logoId?: string | null | undefined;
108
+ letterheadFileId?: string | null | undefined;
97
109
  subdomain?: string | null | undefined;
98
110
  };
99
111
  output: {
@@ -102,6 +114,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
102
114
  name: string;
103
115
  description: string | null;
104
116
  logoId: string | null;
117
+ letterheadFileId: string | null;
105
118
  subdomain: string | null;
106
119
  };
107
120
  };
@@ -112,7 +125,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
112
125
  query: string;
113
126
  schoolId: string;
114
127
  limit?: number | undefined;
115
- role?: "ADMIN" | "TEACHER" | "STUDENT" | undefined;
128
+ role?: "ADMIN" | "TEACHER" | "STUDENT" | "ACCOUNTANT" | "PARENT" | undefined;
116
129
  };
117
130
  output: {
118
131
  id: string;
@@ -209,13 +222,17 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
209
222
  }[];
210
223
  attendance: {
211
224
  id: string;
225
+ recordId: string;
212
226
  date: Date;
213
227
  class: {
214
228
  id: string;
215
229
  name: string;
216
230
  color: string | null;
217
231
  };
218
- status: "PRESENT" | "LATE" | "ABSENT";
232
+ status: import(".prisma/client").$Enums.AttendanceStatus;
233
+ note: string | null;
234
+ lockedFromExcusal: boolean;
235
+ reason: string | null;
219
236
  }[];
220
237
  };
221
238
  meta: object;
@@ -276,13 +293,17 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
276
293
  }[];
277
294
  attendance: {
278
295
  id: string;
296
+ recordId: string;
279
297
  date: Date;
280
298
  class: {
281
299
  id: string;
282
300
  name: string;
283
301
  color: string | null;
284
302
  };
285
- status: "PRESENT" | "LATE" | "ABSENT";
303
+ status: import(".prisma/client").$Enums.AttendanceStatus;
304
+ note: string | null;
305
+ lockedFromExcusal: boolean;
306
+ reason: string | null;
286
307
  }[];
287
308
  classes?: undefined;
288
309
  } | {
@@ -335,6 +356,8 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
335
356
  ADMIN: number;
336
357
  TEACHER: number;
337
358
  STUDENT: number;
359
+ ACCOUNTANT: number;
360
+ PARENT: number;
338
361
  classes: number;
339
362
  members: number;
340
363
  pendingInvites: number;
@@ -378,6 +401,251 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
378
401
  };
379
402
  meta: object;
380
403
  }>;
404
+ /** School-admin: today's attendance rollup across classes. */
405
+ listTodayAttendanceSummary: import("@trpc/server").TRPCQueryProcedure<{
406
+ input: {
407
+ schoolId: string;
408
+ };
409
+ output: {
410
+ date: Date;
411
+ totalStudents: number;
412
+ totals: import("../services/attendanceStats.js").AttendanceStatusCount;
413
+ percentage: number | null;
414
+ sessions: {
415
+ attendanceId: string;
416
+ classId: string;
417
+ className: string;
418
+ section: string;
419
+ subject: string;
420
+ eventId: string | null;
421
+ eventName: string | null;
422
+ date: Date;
423
+ present: number;
424
+ late: number;
425
+ absent: number;
426
+ excused: number;
427
+ unmarked: number;
428
+ classStudentCount: number;
429
+ }[];
430
+ };
431
+ meta: object;
432
+ }>;
433
+ /** School-admin: per-student attendance counts + % (excused excluded from %). */
434
+ listStudentAttendanceStats: import("@trpc/server").TRPCQueryProcedure<{
435
+ input: {
436
+ schoolId: string;
437
+ studentId?: string | undefined;
438
+ from?: Date | undefined;
439
+ to?: Date | undefined;
440
+ };
441
+ output: {
442
+ studentId: string;
443
+ username: string;
444
+ displayName: string | null;
445
+ profilePicture: string | null;
446
+ profilePictureThumbnail: string | null;
447
+ classes: {
448
+ section: string;
449
+ id: string;
450
+ name: string;
451
+ subject: string;
452
+ }[];
453
+ present: number;
454
+ late: number;
455
+ absent: number;
456
+ excused: number;
457
+ attendancePercentage: number | null;
458
+ }[];
459
+ meta: object;
460
+ }>;
461
+ listExcusals: import("@trpc/server").TRPCQueryProcedure<{
462
+ input: {
463
+ schoolId: string;
464
+ studentId?: string | undefined;
465
+ includeRevoked?: boolean | undefined;
466
+ };
467
+ output: {
468
+ id: string;
469
+ schoolId: string;
470
+ startDate: Date;
471
+ endDate: Date;
472
+ reason: string;
473
+ note: string | null;
474
+ revokedAt: Date | null;
475
+ createdAt: Date;
476
+ updatedAt: Date;
477
+ status: "ACTIVE" | "REVOKED" | "EXPIRED" | "UPCOMING";
478
+ studentIds: string[];
479
+ students: {
480
+ id: string;
481
+ username: string;
482
+ displayName: string | null;
483
+ profilePicture: string | null;
484
+ profilePictureThumbnail: string | null;
485
+ }[];
486
+ createdBy: {
487
+ id: string;
488
+ username: string;
489
+ displayName: string | null;
490
+ };
491
+ revokedBy: {
492
+ id: string;
493
+ username: string;
494
+ displayName: string | null;
495
+ } | null;
496
+ }[];
497
+ meta: object;
498
+ }>;
499
+ createExcusal: import("@trpc/server").TRPCMutationProcedure<{
500
+ input: {
501
+ schoolId: string;
502
+ reason: string;
503
+ startDate: Date;
504
+ endDate: Date;
505
+ studentIds: string[];
506
+ note?: string | null | undefined;
507
+ };
508
+ output: {
509
+ students: {
510
+ student: {
511
+ id: string;
512
+ username: string;
513
+ profile: {
514
+ profilePicture: string | null;
515
+ displayName: string | null;
516
+ profilePictureThumbnail: string | null;
517
+ } | null;
518
+ };
519
+ studentId: string;
520
+ }[];
521
+ createdBy: {
522
+ id: string;
523
+ username: string;
524
+ profile: {
525
+ displayName: string | null;
526
+ } | null;
527
+ };
528
+ revokedBy: {
529
+ id: string;
530
+ username: string;
531
+ profile: {
532
+ displayName: string | null;
533
+ } | null;
534
+ } | null;
535
+ } & {
536
+ id: string;
537
+ createdAt: Date;
538
+ updatedAt: Date;
539
+ schoolId: string;
540
+ reason: string;
541
+ startDate: Date;
542
+ endDate: Date;
543
+ createdById: string;
544
+ revokedAt: Date | null;
545
+ note: string | null;
546
+ revokedById: string | null;
547
+ };
548
+ meta: object;
549
+ }>;
550
+ updateExcusal: import("@trpc/server").TRPCMutationProcedure<{
551
+ input: {
552
+ schoolId: string;
553
+ excusalId: string;
554
+ reason?: string | undefined;
555
+ startDate?: Date | undefined;
556
+ endDate?: Date | undefined;
557
+ studentIds?: string[] | undefined;
558
+ note?: string | null | undefined;
559
+ };
560
+ output: {
561
+ students: {
562
+ student: {
563
+ id: string;
564
+ username: string;
565
+ profile: {
566
+ profilePicture: string | null;
567
+ displayName: string | null;
568
+ profilePictureThumbnail: string | null;
569
+ } | null;
570
+ };
571
+ studentId: string;
572
+ }[];
573
+ createdBy: {
574
+ id: string;
575
+ username: string;
576
+ profile: {
577
+ displayName: string | null;
578
+ } | null;
579
+ };
580
+ revokedBy: {
581
+ id: string;
582
+ username: string;
583
+ profile: {
584
+ displayName: string | null;
585
+ } | null;
586
+ } | null;
587
+ } & {
588
+ id: string;
589
+ createdAt: Date;
590
+ updatedAt: Date;
591
+ schoolId: string;
592
+ reason: string;
593
+ startDate: Date;
594
+ endDate: Date;
595
+ createdById: string;
596
+ revokedAt: Date | null;
597
+ note: string | null;
598
+ revokedById: string | null;
599
+ };
600
+ meta: object;
601
+ }>;
602
+ revokeExcusal: import("@trpc/server").TRPCMutationProcedure<{
603
+ input: {
604
+ schoolId: string;
605
+ excusalId: string;
606
+ };
607
+ output: {
608
+ students: {
609
+ student: {
610
+ id: string;
611
+ username: string;
612
+ profile: {
613
+ profilePicture: string | null;
614
+ displayName: string | null;
615
+ profilePictureThumbnail: string | null;
616
+ } | null;
617
+ };
618
+ studentId: string;
619
+ }[];
620
+ createdBy: {
621
+ id: string;
622
+ username: string;
623
+ profile: {
624
+ displayName: string | null;
625
+ } | null;
626
+ };
627
+ revokedBy: {
628
+ id: string;
629
+ username: string;
630
+ profile: {
631
+ displayName: string | null;
632
+ } | null;
633
+ } | null;
634
+ } & {
635
+ id: string;
636
+ createdAt: Date;
637
+ updatedAt: Date;
638
+ schoolId: string;
639
+ reason: string;
640
+ startDate: Date;
641
+ endDate: Date;
642
+ createdById: string;
643
+ revokedAt: Date | null;
644
+ note: string | null;
645
+ revokedById: string | null;
646
+ };
647
+ meta: object;
648
+ }>;
381
649
  getAiUsage: import("@trpc/server").TRPCQueryProcedure<{
382
650
  input: {
383
651
  schoolId: string;
@@ -444,6 +712,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
444
712
  discussionsEnabled: boolean;
445
713
  studentsCanCreateDiscussions: boolean;
446
714
  studentsCanReply: boolean;
715
+ sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
447
716
  treatMissingAsZero: boolean;
448
717
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
449
718
  })[];
@@ -497,6 +766,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
497
766
  discussionsEnabled: boolean;
498
767
  studentsCanCreateDiscussions: boolean;
499
768
  studentsCanReply: boolean;
769
+ sidebarFeatures: import("@prisma/client/runtime/library.js").JsonValue | null;
500
770
  treatMissingAsZero: boolean;
501
771
  gradeRoundingMode: import(".prisma/client").$Enums.GradeRoundingMode;
502
772
  };
@@ -563,7 +833,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
563
833
  addMember: import("@trpc/server").TRPCMutationProcedure<{
564
834
  input: {
565
835
  schoolId: string;
566
- role: "ADMIN" | "TEACHER" | "STUDENT";
836
+ role: "ADMIN" | "TEACHER" | "STUDENT" | "ACCOUNTANT" | "PARENT";
567
837
  memberUserId: string;
568
838
  };
569
839
  output: {
@@ -582,7 +852,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
582
852
  updateMemberRole: import("@trpc/server").TRPCMutationProcedure<{
583
853
  input: {
584
854
  schoolId: string;
585
- role: "ADMIN" | "TEACHER" | "STUDENT";
855
+ role: "ADMIN" | "TEACHER" | "STUDENT" | "ACCOUNTANT" | "PARENT";
586
856
  memberUserId: string;
587
857
  };
588
858
  output: {
@@ -652,10 +922,65 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
652
922
  };
653
923
  meta: object;
654
924
  }>;
925
+ /**
926
+ * Generate a branded transcript / progress-report PDF for one student.
927
+ * School admin only. Uses gradebook + attendance (present/late/absent).
928
+ * No AcademicTerm yet — pass schoolYear and/or from/to (C1 dependency).
929
+ */
930
+ generateTranscript: import("@trpc/server").TRPCMutationProcedure<{
931
+ input: {
932
+ schoolId: string;
933
+ studentId: string;
934
+ from?: Date | undefined;
935
+ to?: Date | undefined;
936
+ schoolYear?: string | undefined;
937
+ };
938
+ output: {
939
+ pdfBase64: string;
940
+ fileName: string;
941
+ variant: import("../lib/transcriptPdf.js").TranscriptReportVariant;
942
+ studentId: string;
943
+ studentName: string;
944
+ academicTermSupported: false;
945
+ attendance: import("../services/attendanceRate.js").AttendanceRateSummary;
946
+ classCount: number;
947
+ };
948
+ meta: object;
949
+ }>;
950
+ /**
951
+ * Bulk generate transcripts for multiple students (max 50).
952
+ * Returns per-student PDFs plus any per-student errors.
953
+ */
954
+ generateTranscripts: import("@trpc/server").TRPCMutationProcedure<{
955
+ input: {
956
+ schoolId: string;
957
+ studentIds: string[];
958
+ from?: Date | undefined;
959
+ to?: Date | undefined;
960
+ schoolYear?: string | undefined;
961
+ };
962
+ output: {
963
+ transcripts: {
964
+ pdfBase64: string;
965
+ fileName: string;
966
+ variant: import("../lib/transcriptPdf.js").TranscriptReportVariant;
967
+ studentId: string;
968
+ studentName: string;
969
+ academicTermSupported: false;
970
+ attendance: import("../services/attendanceRate.js").AttendanceRateSummary;
971
+ classCount: number;
972
+ }[];
973
+ errors: {
974
+ studentId: string;
975
+ message: string;
976
+ }[];
977
+ };
978
+ meta: object;
979
+ }>;
655
980
  bulkUpdateMemberRoles: import("@trpc/server").TRPCMutationProcedure<{
656
981
  input: {
657
982
  schoolId: string;
658
- role: "ADMIN" | "TEACHER" | "STUDENT";
983
+ role: "ADMIN" | "TEACHER" | "STUDENT" | "ACCOUNTANT" | "PARENT";
659
984
  memberUserIds: string[];
660
985
  };
661
986
  output: {
@@ -673,6 +998,21 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
673
998
  };
674
999
  meta: object;
675
1000
  }>;
1001
+ /** Generate a bulk PDF of front-side student ID cards for selected members. */
1002
+ generateIdCards: import("@trpc/server").TRPCMutationProcedure<{
1003
+ input: {
1004
+ schoolId: string;
1005
+ studentUserIds: string[];
1006
+ };
1007
+ output: {
1008
+ pdfBase64: string;
1009
+ fileName: string;
1010
+ mimeType: "application/pdf";
1011
+ studentCount: number;
1012
+ skippedCount: number;
1013
+ };
1014
+ meta: object;
1015
+ }>;
676
1016
  listInvites: import("@trpc/server").TRPCQueryProcedure<{
677
1017
  input: {
678
1018
  schoolId: string;
@@ -702,7 +1042,7 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
702
1042
  input: {
703
1043
  email: string;
704
1044
  schoolId: string;
705
- role: "ADMIN" | "TEACHER" | "STUDENT";
1045
+ role: "ADMIN" | "TEACHER" | "STUDENT" | "ACCOUNTANT" | "PARENT";
706
1046
  displayName?: string | undefined;
707
1047
  username?: string | undefined;
708
1048
  };
@@ -792,5 +1132,21 @@ export declare const schoolRouter: import("@trpc/server").TRPCBuiltRouter<{
792
1132
  };
793
1133
  meta: object;
794
1134
  }>;
1135
+ /** C3: Bulk student CSV onboarding (username/password generated when omitted). */
1136
+ importStudentsCsv: import("@trpc/server").TRPCMutationProcedure<{
1137
+ input: {
1138
+ schoolId: string;
1139
+ csvText: string;
1140
+ dryRun?: boolean | undefined;
1141
+ };
1142
+ output: {
1143
+ dryRun: boolean;
1144
+ created: number;
1145
+ failed: number;
1146
+ total: number;
1147
+ results: import("../services/studentImport.js").StudentCsvRowResult[];
1148
+ };
1149
+ meta: object;
1150
+ }>;
795
1151
  }>>;
796
1152
  //# sourceMappingURL=school.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"school.d.ts","sourceRoot":"/","sources":["routers/school.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0CxB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6OvB,CAAC"}
1
+ {"version":3,"file":"school.d.ts","sourceRoot":"/","sources":["routers/school.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuExB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6GvB,8DAA8D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAO9D,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqIjF;;;;OAIG;;;;;;;;;;;;;;;;;;;;;IAcH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiCH,+EAA+E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2C/E,kFAAkF;;;;;;;;;;;;;;;;GAUlF,CAAC"}
@@ -1,13 +1,31 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dbf0db95-caa5-5600-ac0e-7d370691bb74")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e365815a-3112-5d63-972f-390a63a4a409")}catch(e){}}();
3
3
  import { z } from "zod";
4
4
  import { createTRPCRouter, protectedProcedure, publicProcedure, } from "../trpc.js";
5
5
  import { acceptInvite, addMember, bulkRemoveMembers, bulkUpdateMemberRoles, confirmSchoolAssetUpload, createInvite, createSchoolClass, createSchoolRecord, deleteSchoolClass, getAdminOverview, getCurrentSchool, getInvite, getMemberDetail, getMemberTimeline, getSchoolAssetUploadUrl, getStudentTimeline, listClasses, listInvites, listMemberIds, listMembers, removeMember, revokeInvite, searchMembers, updateClassMembers, updateMemberRole, updateSchoolDetails, } from "../services/school.js";
6
6
  import { getSchoolAiUsage } from "../services/aiUsage.js";
7
- const schoolRoleSchema = z.enum(["ADMIN", "TEACHER", "STUDENT"]);
7
+ import { listTodayAttendanceSummary, listStudentAttendanceStats, listExcusals, createExcusal, updateExcusal, revokeExcusal, } from "../services/attendance.js";
8
+ import { generateStudentIdCards } from "../services/idCard.js";
9
+ import { generateTranscript, generateTranscripts, } from "../services/transcript.js";
10
+ import { importStudentsCsv } from "../services/studentImport.js";
11
+ const schoolRoleSchema = z.enum([
12
+ "ADMIN",
13
+ "TEACHER",
14
+ "STUDENT",
15
+ "ACCOUNTANT",
16
+ "PARENT",
17
+ ]);
8
18
  const schoolIdSchema = z.object({
9
19
  schoolId: z.string(),
10
20
  });
21
+ /** Interim period params until AcademicTerm (C1) exists. */
22
+ const transcriptPeriodSchema = z.object({
23
+ schoolId: z.string(),
24
+ from: z.date().optional(),
25
+ to: z.date().optional(),
26
+ /** Free-text school year label (e.g. "2082 BS"). Prefer AcademicTerm (C1) later. */
27
+ schoolYear: z.string().max(64).optional(),
28
+ });
11
29
  export const schoolRouter = createTRPCRouter({
12
30
  getCurrent: protectedProcedure
13
31
  .input(z.object({ schoolId: z.string().optional() }).optional())
@@ -27,6 +45,7 @@ export const schoolRouter = createTRPCRouter({
27
45
  description: z.string().nullable().optional(),
28
46
  subdomain: z.string().nullable().optional(),
29
47
  logoId: z.string().nullable().optional(),
48
+ letterheadFileId: z.string().nullable().optional(),
30
49
  }))
31
50
  .mutation(({ ctx, input }) => updateSchoolDetails(ctx.user.id, input)),
32
51
  searchMembers: protectedProcedure
@@ -72,6 +91,50 @@ export const schoolRouter = createTRPCRouter({
72
91
  getAdminOverview: protectedProcedure
73
92
  .input(schoolIdSchema)
74
93
  .query(({ ctx, input }) => getAdminOverview(ctx.user.id, input.schoolId)),
94
+ /** School-admin: today's attendance rollup across classes. */
95
+ listTodayAttendanceSummary: protectedProcedure
96
+ .input(schoolIdSchema)
97
+ .query(({ ctx, input }) => listTodayAttendanceSummary(ctx.user.id, input.schoolId)),
98
+ /** School-admin: per-student attendance counts + % (excused excluded from %). */
99
+ listStudentAttendanceStats: protectedProcedure
100
+ .input(z.object({
101
+ schoolId: z.string(),
102
+ from: z.date().optional(),
103
+ to: z.date().optional(),
104
+ studentId: z.string().optional(),
105
+ }))
106
+ .query(({ ctx, input }) => listStudentAttendanceStats(ctx.user.id, input)),
107
+ listExcusals: protectedProcedure
108
+ .input(z.object({
109
+ schoolId: z.string(),
110
+ includeRevoked: z.boolean().optional(),
111
+ studentId: z.string().optional(),
112
+ }))
113
+ .query(({ ctx, input }) => listExcusals(ctx.user.id, input)),
114
+ createExcusal: protectedProcedure
115
+ .input(z.object({
116
+ schoolId: z.string(),
117
+ studentIds: z.array(z.string()).min(1),
118
+ startDate: z.date(),
119
+ endDate: z.date(),
120
+ reason: z.string().min(1),
121
+ note: z.string().nullable().optional(),
122
+ }))
123
+ .mutation(({ ctx, input }) => createExcusal(ctx.user.id, input)),
124
+ updateExcusal: protectedProcedure
125
+ .input(z.object({
126
+ schoolId: z.string(),
127
+ excusalId: z.string(),
128
+ studentIds: z.array(z.string()).min(1).optional(),
129
+ startDate: z.date().optional(),
130
+ endDate: z.date().optional(),
131
+ reason: z.string().min(1).optional(),
132
+ note: z.string().nullable().optional(),
133
+ }))
134
+ .mutation(({ ctx, input }) => updateExcusal(ctx.user.id, input)),
135
+ revokeExcusal: protectedProcedure
136
+ .input(z.object({ schoolId: z.string(), excusalId: z.string() }))
137
+ .mutation(({ ctx, input }) => revokeExcusal(ctx.user.id, input)),
75
138
  getAiUsage: protectedProcedure
76
139
  .input(z.object({
77
140
  schoolId: z.string(),
@@ -132,6 +195,35 @@ export const schoolRouter = createTRPCRouter({
132
195
  getMemberDetail: protectedProcedure
133
196
  .input(z.object({ schoolId: z.string(), memberUserId: z.string() }))
134
197
  .query(({ ctx, input }) => getMemberDetail(ctx.user.id, input)),
198
+ /**
199
+ * Generate a branded transcript / progress-report PDF for one student.
200
+ * School admin only. Uses gradebook + attendance (present/late/absent).
201
+ * No AcademicTerm yet — pass schoolYear and/or from/to (C1 dependency).
202
+ */
203
+ generateTranscript: protectedProcedure
204
+ .input(transcriptPeriodSchema
205
+ .extend({
206
+ studentId: z.string(),
207
+ })
208
+ .refine((v) => !v.from || !v.to || v.from <= v.to, {
209
+ message: "from must be on or before to",
210
+ path: ["from"],
211
+ }))
212
+ .mutation(({ ctx, input }) => generateTranscript(ctx.user.id, input)),
213
+ /**
214
+ * Bulk generate transcripts for multiple students (max 50).
215
+ * Returns per-student PDFs plus any per-student errors.
216
+ */
217
+ generateTranscripts: protectedProcedure
218
+ .input(transcriptPeriodSchema
219
+ .extend({
220
+ studentIds: z.array(z.string()).min(1).max(50),
221
+ })
222
+ .refine((v) => !v.from || !v.to || v.from <= v.to, {
223
+ message: "from must be on or before to",
224
+ path: ["from"],
225
+ }))
226
+ .mutation(({ ctx, input }) => generateTranscripts(ctx.user.id, input)),
135
227
  bulkUpdateMemberRoles: protectedProcedure
136
228
  .input(z.object({
137
229
  schoolId: z.string(),
@@ -145,6 +237,13 @@ export const schoolRouter = createTRPCRouter({
145
237
  memberUserIds: z.array(z.string()).min(1).max(200),
146
238
  }))
147
239
  .mutation(({ ctx, input }) => bulkRemoveMembers(ctx.user.id, input)),
240
+ /** Generate a bulk PDF of front-side student ID cards for selected members. */
241
+ generateIdCards: protectedProcedure
242
+ .input(z.object({
243
+ schoolId: z.string(),
244
+ studentUserIds: z.array(z.string()).min(1).max(100),
245
+ }))
246
+ .mutation(({ ctx, input }) => generateStudentIdCards(ctx.user.id, input)),
148
247
  listInvites: protectedProcedure
149
248
  .input(schoolIdSchema)
150
249
  .query(({ ctx, input }) => listInvites(ctx.user.id, input.schoolId)),
@@ -169,6 +268,14 @@ export const schoolRouter = createTRPCRouter({
169
268
  acceptInvite: protectedProcedure
170
269
  .input(z.object({ token: z.string() }))
171
270
  .mutation(({ ctx, input }) => acceptInvite(ctx.user.id, input.token)),
271
+ /** C3: Bulk student CSV onboarding (username/password generated when omitted). */
272
+ importStudentsCsv: protectedProcedure
273
+ .input(z.object({
274
+ schoolId: z.string(),
275
+ csvText: z.string().min(1).max(2000000),
276
+ dryRun: z.boolean().optional(),
277
+ }))
278
+ .mutation(({ ctx, input }) => importStudentsCsv(ctx.user.id, input)),
172
279
  });
173
280
  //# sourceMappingURL=school.js.map
174
- //# debugId=dbf0db95-caa5-5600-ac0e-7d370691bb74
281
+ //# debugId=e365815a-3112-5d63-972f-390a63a4a409