@studious-lms/server 1.24.0 → 1.26.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.
- package/data/curriculum/nepal-cdc-g4-g5/subjects/english.json +4 -4
- package/data/curriculum/nepal-cdc-g4-g5/subjects/mathematics.json +1 -1
- package/data/curriculum/nepal-cdc-g4-g5/subjects/science-technology.json +4 -4
- package/data/curriculum/nepal-cdc-g4-g5/subjects/social-studies.json +4 -4
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/attendance.js +17 -14
- package/dist/models/attendance.js.map +1 -1
- package/dist/models/marketplace.d.ts +37 -0
- package/dist/models/marketplace.d.ts.map +1 -1
- package/dist/models/marketplace.js +10 -2
- package/dist/models/marketplace.js.map +1 -1
- package/dist/models/module.d.ts +228 -0
- package/dist/models/module.d.ts.map +1 -0
- package/dist/models/module.js +69 -0
- package/dist/models/module.js.map +1 -0
- package/dist/models/moduleItem.d.ts +5 -1
- package/dist/models/moduleItem.d.ts.map +1 -1
- package/dist/models/moduleItem.js +19 -4
- package/dist/models/moduleItem.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
- package/dist/pipelines/gradeWorksheet.js +4 -2
- package/dist/pipelines/gradeWorksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +768 -6
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/fees.d.ts +1 -1
- package/dist/routers/marketplace.d.ts +41 -0
- package/dist/routers/marketplace.d.ts.map +1 -1
- package/dist/routers/marketplace.js +13 -3
- package/dist/routers/marketplace.js.map +1 -1
- package/dist/routers/module.d.ts +345 -0
- package/dist/routers/module.d.ts.map +1 -0
- package/dist/routers/module.js +82 -0
- package/dist/routers/module.js.map +1 -0
- package/dist/routers/moduleItem.d.ts.map +1 -1
- package/dist/routers/moduleItem.js +7 -6
- package/dist/routers/moduleItem.js.map +1 -1
- package/dist/routers/parent.d.ts +2 -1
- package/dist/routers/parent.d.ts.map +1 -1
- package/dist/routers/school.d.ts +1 -1
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +14 -4
- package/dist/routers/school.js.map +1 -1
- package/dist/services/academicCalendar.d.ts.map +1 -1
- package/dist/services/academicCalendar.js +30 -2
- package/dist/services/academicCalendar.js.map +1 -1
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +8 -3
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +6 -2
- package/dist/services/attendance.d.ts.map +1 -1
- package/dist/services/attendance.js +8 -4
- package/dist/services/attendance.js.map +1 -1
- package/dist/services/class.d.ts +14 -9
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +4 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/fees.d.ts.map +1 -1
- package/dist/services/fees.js +24 -4
- package/dist/services/fees.js.map +1 -1
- package/dist/services/feesAuthz.d.ts +2 -5
- package/dist/services/feesAuthz.d.ts.map +1 -1
- package/dist/services/feesAuthz.js +5 -8
- package/dist/services/feesAuthz.js.map +1 -1
- package/dist/services/marketplace.d.ts +36 -0
- package/dist/services/marketplace.d.ts.map +1 -1
- package/dist/services/marketplace.js +36 -6
- package/dist/services/marketplace.js.map +1 -1
- package/dist/services/module.d.ts +288 -0
- package/dist/services/module.d.ts.map +1 -0
- package/dist/services/module.js +518 -0
- package/dist/services/module.js.map +1 -0
- package/dist/services/moduleItem.d.ts.map +1 -1
- package/dist/services/moduleItem.js +23 -7
- package/dist/services/moduleItem.js.map +1 -1
- package/dist/services/parentPortal.d.ts +3 -5
- package/dist/services/parentPortal.d.ts.map +1 -1
- package/dist/services/parentPortal.js +29 -43
- package/dist/services/parentPortal.js.map +1 -1
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +52 -16
- package/dist/services/school.js.map +1 -1
- package/dist/services/studentImport.d.ts.map +1 -1
- package/dist/services/studentImport.js +38 -25
- package/dist/services/studentImport.js.map +1 -1
- package/dist/services/transcript.d.ts +2 -3
- package/dist/services/transcript.d.ts.map +1 -1
- package/dist/services/transcript.js +13 -25
- package/dist/services/transcript.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260708013000_add_modules/migration.sql +100 -0
- package/prisma/schema.prisma +93 -0
- package/scripts/import-nepal-cdc-curriculum.ts +29 -6
- package/src/models/attendance.ts +10 -12
- package/src/models/marketplace.ts +19 -0
- package/src/models/module.ts +77 -0
- package/src/models/moduleItem.ts +20 -2
- package/src/pipelines/gradeWorksheet.ts +6 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/marketplace.ts +16 -0
- package/src/routers/module.ts +118 -0
- package/src/routers/moduleItem.ts +6 -4
- package/src/routers/school.ts +16 -6
- package/src/services/academicCalendar.ts +28 -0
- package/src/services/assignment.ts +12 -1
- package/src/services/attendance.ts +7 -3
- package/src/services/class.ts +2 -2
- package/src/services/fees.ts +25 -2
- package/src/services/feesAuthz.ts +3 -7
- package/src/services/marketplace.ts +47 -3
- package/src/services/module.ts +683 -0
- package/src/services/moduleItem.ts +28 -4
- package/src/services/parentPortal.ts +26 -39
- package/src/services/school.ts +52 -15
- package/src/services/studentImport.ts +37 -25
- package/src/services/transcript.ts +11 -23
package/dist/services/fees.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Payment gateway intentionally deferred; this is a manual ledger.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
!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]="
|
|
6
|
+
!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]="17f46206-bcf6-5721-9d78-09801ff55dea")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { findActiveSchoolAdminMembership } from "../models/school.js";
|
|
9
9
|
import { createFeeInvoices, createFeePayment, createFeePlan, getFeeInvoice, getFeePayment, getFeePlan, listActiveStudentIds, listFeeInvoices, listFeePlans, listPlanEnrollmentIds, listStudentBalances, setFeePlanEnrollments, sumPaymentsForInvoice, updateFeePlan, updateInvoiceStatus, } from "../models/fees.js";
|
|
@@ -18,6 +18,16 @@ async function requireAdmin(schoolId, userId) {
|
|
|
18
18
|
}
|
|
19
19
|
return membership;
|
|
20
20
|
}
|
|
21
|
+
async function assertActiveSchoolStudents(schoolId, studentIds) {
|
|
22
|
+
const activeIds = new Set(await listActiveStudentIds(schoolId));
|
|
23
|
+
const invalid = studentIds.filter((id) => !activeIds.has(id));
|
|
24
|
+
if (invalid.length > 0) {
|
|
25
|
+
throw new TRPCError({
|
|
26
|
+
code: "BAD_REQUEST",
|
|
27
|
+
message: "One or more students are not active members of this school",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
21
31
|
function assertMonth(month) {
|
|
22
32
|
if (month < 1 || month > 12) {
|
|
23
33
|
throw new TRPCError({
|
|
@@ -74,6 +84,7 @@ export async function createPlan(userId, input) {
|
|
|
74
84
|
amountNpr: input.amountNpr,
|
|
75
85
|
});
|
|
76
86
|
if (input.studentIds?.length) {
|
|
87
|
+
await assertActiveSchoolStudents(input.schoolId, input.studentIds);
|
|
77
88
|
const updated = await setFeePlanEnrollments(plan.id, input.studentIds);
|
|
78
89
|
return { plan: updated };
|
|
79
90
|
}
|
|
@@ -105,6 +116,7 @@ export async function setPlanStudents(userId, input) {
|
|
|
105
116
|
throw new TRPCError({ code: "NOT_FOUND", message: "Fee plan not found" });
|
|
106
117
|
}
|
|
107
118
|
await requireAdmin(existing.schoolId, userId);
|
|
119
|
+
await assertActiveSchoolStudents(existing.schoolId, input.studentIds);
|
|
108
120
|
const plan = await setFeePlanEnrollments(input.planId, input.studentIds);
|
|
109
121
|
return { plan };
|
|
110
122
|
}
|
|
@@ -122,7 +134,10 @@ export async function generateMonthlyInvoices(userId, input) {
|
|
|
122
134
|
});
|
|
123
135
|
}
|
|
124
136
|
let studentIds = input.studentIds;
|
|
125
|
-
if (
|
|
137
|
+
if (studentIds?.length) {
|
|
138
|
+
await assertActiveSchoolStudents(input.schoolId, studentIds);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
126
141
|
const enrolled = await listPlanEnrollmentIds(plan.id);
|
|
127
142
|
studentIds = enrolled.length
|
|
128
143
|
? enrolled
|
|
@@ -295,7 +310,12 @@ export async function getReceiptPdf(userId, paymentId) {
|
|
|
295
310
|
},
|
|
296
311
|
{
|
|
297
312
|
label: "Paid at",
|
|
298
|
-
value:
|
|
313
|
+
value: new Intl.DateTimeFormat("en-CA", {
|
|
314
|
+
timeZone: "Asia/Kathmandu",
|
|
315
|
+
year: "numeric",
|
|
316
|
+
month: "2-digit",
|
|
317
|
+
day: "2-digit",
|
|
318
|
+
}).format(payment.paidAt),
|
|
299
319
|
},
|
|
300
320
|
],
|
|
301
321
|
footerNote: "Manual ledger receipt — gateway integration deferred.",
|
|
@@ -307,4 +327,4 @@ export async function getReceiptPdf(userId, paymentId) {
|
|
|
307
327
|
};
|
|
308
328
|
}
|
|
309
329
|
//# sourceMappingURL=fees.js.map
|
|
310
|
-
//# debugId=
|
|
330
|
+
//# debugId=17f46206-bcf6-5721-9d78-09801ff55dea
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fees.js","sources":["services/fees.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Fee ledger service — school-admin gated monthly invoicing + payment recording.\n * Payment gateway intentionally deferred; this is a manual ledger.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { FeeInvoiceStatus, FeePaymentMethod } from \"@prisma/client\";\nimport { findActiveSchoolAdminMembership } from \"../models/school.js\";\nimport {\n createFeeInvoices,\n createFeePayment,\n createFeePlan,\n getFeeInvoice,\n getFeePayment,\n getFeePlan,\n listActiveStudentIds,\n listFeeInvoices,\n listFeePlans,\n listPlanEnrollmentIds,\n listStudentBalances,\n setFeePlanEnrollments,\n sumPaymentsForInvoice,\n updateFeePlan,\n updateInvoiceStatus,\n} from \"../models/fees.js\";\nimport {\n buildFeePdf,\n formatNpr,\n monthLabel,\n} from \"../lib/feePdf.js\";\n\nasync function requireAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can manage fees\",\n });\n }\n return membership;\n}\n\nfunction assertMonth(month: number) {\n if (month < 1 || month > 12) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"month must be between 1 and 12\",\n });\n }\n}\n\nfunction invoicePaidTotal(payments: { amountNpr: number }[]): number {\n return payments.reduce((s, p) => s + p.amountNpr, 0);\n}\n\nfunction deriveStatus(\n amountNpr: number,\n paidNpr: number,\n current: FeeInvoiceStatus\n): FeeInvoiceStatus {\n if (current === \"VOID\") return \"VOID\";\n if (paidNpr <= 0) return \"UNPAID\";\n if (paidNpr >= amountNpr) return \"PAID\";\n return \"PARTIAL\";\n}\n\nfunction withBalance<\n T extends {\n amountNpr: number;\n status: FeeInvoiceStatus;\n payments: { amountNpr: number }[];\n },\n>(invoice: T) {\n const paidNpr = invoicePaidTotal(invoice.payments);\n return {\n ...invoice,\n paidNpr,\n balanceNpr: Math.max(0, invoice.amountNpr - paidNpr),\n };\n}\n\nexport async function listPlans(userId: string, schoolId: string) {\n await requireAdmin(schoolId, userId);\n const plans = await listFeePlans(schoolId);\n return { plans };\n}\n\nexport async function getPlan(userId: string, planId: string) {\n const plan = await getFeePlan(planId);\n if (!plan) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(plan.schoolId, userId);\n return { plan };\n}\n\nexport async function createPlan(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n description?: string | null;\n amountNpr: number;\n studentIds?: string[];\n }\n) {\n await requireAdmin(input.schoolId, userId);\n if (input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n const plan = await createFeePlan({\n schoolId: input.schoolId,\n name: input.name.trim(),\n description: input.description?.trim() || null,\n amountNpr: input.amountNpr,\n });\n if (input.studentIds?.length) {\n const updated = await setFeePlanEnrollments(plan.id, input.studentIds);\n return { plan: updated };\n }\n return { plan };\n}\n\nexport async function updatePlan(\n userId: string,\n input: {\n planId: string;\n name?: string;\n description?: string | null;\n amountNpr?: number;\n isActive?: boolean;\n }\n) {\n const existing = await getFeePlan(input.planId);\n if (!existing) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(existing.schoolId, userId);\n if (input.amountNpr != null && input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n const plan = await updateFeePlan(input.planId, {\n name: input.name?.trim(),\n description: input.description,\n amountNpr: input.amountNpr,\n isActive: input.isActive,\n });\n return { plan };\n}\n\nexport async function setPlanStudents(\n userId: string,\n input: { planId: string; studentIds: string[] }\n) {\n const existing = await getFeePlan(input.planId);\n if (!existing) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(existing.schoolId, userId);\n const plan = await setFeePlanEnrollments(input.planId, input.studentIds);\n return { plan };\n}\n\nexport async function generateMonthlyInvoices(\n userId: string,\n input: {\n schoolId: string;\n feePlanId: string;\n year: number;\n month: number;\n studentIds?: string[];\n dueDate?: Date | null;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n assertMonth(input.month);\n\n const plan = await getFeePlan(input.feePlanId);\n if (!plan || plan.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n if (!plan.isActive) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot generate invoices for an inactive fee plan\",\n });\n }\n\n let studentIds = input.studentIds;\n if (!studentIds?.length) {\n const enrolled = await listPlanEnrollmentIds(plan.id);\n studentIds = enrolled.length\n ? enrolled\n : await listActiveStudentIds(input.schoolId);\n }\n\n if (!studentIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No students to invoice\",\n });\n }\n\n const result = await createFeeInvoices(\n studentIds.map((studentId) => ({\n schoolId: input.schoolId,\n feePlanId: plan.id,\n studentId,\n year: input.year,\n month: input.month,\n amountNpr: plan.amountNpr,\n currency: plan.currency,\n dueDate: input.dueDate ?? null,\n }))\n );\n\n const invoices = await listFeeInvoices({\n schoolId: input.schoolId,\n feePlanId: plan.id,\n year: input.year,\n month: input.month,\n });\n\n return {\n createdCount: result.count,\n invoices: invoices.map(withBalance),\n };\n}\n\nexport async function listInvoices(\n userId: string,\n input: {\n schoolId: string;\n year?: number;\n month?: number;\n studentId?: string;\n feePlanId?: string;\n status?: FeeInvoiceStatus;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n if (input.month != null) assertMonth(input.month);\n const invoices = await listFeeInvoices(input);\n return { invoices: invoices.map(withBalance) };\n}\n\nexport async function getInvoice(userId: string, invoiceId: string) {\n const invoice = await getFeeInvoice(invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n return { invoice: withBalance(invoice) };\n}\n\nexport async function recordPayment(\n userId: string,\n input: {\n invoiceId: string;\n amountNpr: number;\n method: FeePaymentMethod;\n reference?: string | null;\n paidAt?: Date;\n notes?: string | null;\n }\n) {\n const invoice = await getFeeInvoice(input.invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n\n if (invoice.status === \"VOID\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot record payment on a void invoice\",\n });\n }\n if (input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n if (\n (input.method === \"BANK\" || input.method === \"ESEWA_REF\") &&\n !input.reference?.trim()\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"reference is required for BANK and ESEWA_REF payments\",\n });\n }\n\n const paidSoFar = invoicePaidTotal(invoice.payments);\n const balance = Math.max(0, invoice.amountNpr - paidSoFar);\n if (input.amountNpr > balance) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Payment exceeds balance (${formatNpr(balance)})`,\n });\n }\n\n const payment = await createFeePayment({\n schoolId: invoice.schoolId,\n invoiceId: invoice.id,\n amountNpr: input.amountNpr,\n method: input.method,\n reference: input.reference?.trim() || null,\n paidAt: input.paidAt,\n recordedById: userId,\n notes: input.notes?.trim() || null,\n });\n\n const aggregate = await sumPaymentsForInvoice(invoice.id);\n const newPaid = aggregate._sum.amountNpr ?? 0;\n const status = deriveStatus(invoice.amountNpr, newPaid, invoice.status);\n await updateInvoiceStatus(invoice.id, status);\n\n const refreshed = await getFeeInvoice(invoice.id);\n return {\n payment,\n invoice: refreshed ? withBalance(refreshed) : null,\n };\n}\n\nexport async function listBalances(userId: string, schoolId: string) {\n await requireAdmin(schoolId, userId);\n const balances = await listStudentBalances(schoolId);\n return { balances };\n}\n\nexport async function getInvoicePdf(userId: string, invoiceId: string) {\n const invoice = await getFeeInvoice(invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n\n const paidNpr = invoicePaidTotal(invoice.payments);\n const balanceNpr = Math.max(0, invoice.amountNpr - paidNpr);\n const studentName =\n invoice.student.profile?.displayName || invoice.student.username;\n\n const bytes = await buildFeePdf({\n schoolName: invoice.school.name,\n title: \"Fee Invoice\",\n subtitle: `${invoice.feePlan.name} · ${monthLabel(invoice.year, invoice.month)}`,\n letterhead: invoice.school.letterhead\n ? {\n path: invoice.school.letterhead.path,\n type: invoice.school.letterhead.type,\n }\n : null,\n lines: [\n { label: \"Invoice ID\", value: invoice.id.slice(0, 8).toUpperCase() },\n { label: \"Student\", value: studentName },\n { label: \"Period\", value: monthLabel(invoice.year, invoice.month) },\n { label: \"Plan\", value: invoice.feePlan.name },\n { label: \"Amount\", value: formatNpr(invoice.amountNpr) },\n { label: \"Paid\", value: formatNpr(paidNpr) },\n { label: \"Balance\", value: formatNpr(balanceNpr) },\n { label: \"Status\", value: invoice.status },\n ],\n footerNote: \"Manual ledger — not a gateway receipt. Keep for school records.\",\n });\n\n return {\n fileName: `invoice-${invoice.year}-${String(invoice.month).padStart(2, \"0\")}-${invoice.id.slice(0, 8)}.pdf`,\n contentType: \"application/pdf\",\n base64: Buffer.from(bytes).toString(\"base64\"),\n };\n}\n\nexport async function getReceiptPdf(userId: string, paymentId: string) {\n const payment = await getFeePayment(paymentId);\n if (!payment) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Payment not found\" });\n }\n await requireAdmin(payment.schoolId, userId);\n\n const invoice = payment.invoice;\n const studentName =\n invoice.student.profile?.displayName || invoice.student.username;\n\n const bytes = await buildFeePdf({\n schoolName: invoice.school.name,\n title: \"Payment Receipt\",\n subtitle: `${invoice.feePlan.name} · ${monthLabel(invoice.year, invoice.month)}`,\n letterhead: invoice.school.letterhead\n ? {\n path: invoice.school.letterhead.path,\n type: invoice.school.letterhead.type,\n }\n : null,\n lines: [\n { label: \"Receipt ID\", value: payment.id.slice(0, 8).toUpperCase() },\n { label: \"Student\", value: studentName },\n { label: \"Period\", value: monthLabel(invoice.year, invoice.month) },\n { label: \"Amount paid\", value: formatNpr(payment.amountNpr) },\n { label: \"Method\", value: payment.method },\n {\n label: \"Reference\",\n value: payment.reference?.trim() || \"—\",\n },\n {\n label: \"Paid at\",\n value: payment.paidAt.toISOString().slice(0, 10),\n },\n ],\n footerNote: \"Manual ledger receipt — gateway integration deferred.\",\n });\n\n return {\n fileName: `receipt-${payment.id.slice(0, 8)}.pdf`,\n contentType: \"application/pdf\",\n base64: Buffer.from(bytes).toString(\"base64\"),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"f88adefd-f266-510d-92db-2aeb2cb27715"}
|
|
1
|
+
{"version":3,"file":"fees.js","sources":["services/fees.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Fee ledger service — school-admin gated monthly invoicing + payment recording.\n * Payment gateway intentionally deferred; this is a manual ledger.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { FeeInvoiceStatus, FeePaymentMethod } from \"@prisma/client\";\nimport { findActiveSchoolAdminMembership } from \"../models/school.js\";\nimport {\n createFeeInvoices,\n createFeePayment,\n createFeePlan,\n getFeeInvoice,\n getFeePayment,\n getFeePlan,\n listActiveStudentIds,\n listFeeInvoices,\n listFeePlans,\n listPlanEnrollmentIds,\n listStudentBalances,\n setFeePlanEnrollments,\n sumPaymentsForInvoice,\n updateFeePlan,\n updateInvoiceStatus,\n} from \"../models/fees.js\";\nimport {\n buildFeePdf,\n formatNpr,\n monthLabel,\n} from \"../lib/feePdf.js\";\n\nasync function requireAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can manage fees\",\n });\n }\n return membership;\n}\n\nasync function assertActiveSchoolStudents(\n schoolId: string,\n studentIds: string[]\n) {\n const activeIds = new Set(await listActiveStudentIds(schoolId));\n const invalid = studentIds.filter((id) => !activeIds.has(id));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more students are not active members of this school\",\n });\n }\n}\n\nfunction assertMonth(month: number) {\n if (month < 1 || month > 12) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"month must be between 1 and 12\",\n });\n }\n}\n\nfunction invoicePaidTotal(payments: { amountNpr: number }[]): number {\n return payments.reduce((s, p) => s + p.amountNpr, 0);\n}\n\nfunction deriveStatus(\n amountNpr: number,\n paidNpr: number,\n current: FeeInvoiceStatus\n): FeeInvoiceStatus {\n if (current === \"VOID\") return \"VOID\";\n if (paidNpr <= 0) return \"UNPAID\";\n if (paidNpr >= amountNpr) return \"PAID\";\n return \"PARTIAL\";\n}\n\nfunction withBalance<\n T extends {\n amountNpr: number;\n status: FeeInvoiceStatus;\n payments: { amountNpr: number }[];\n },\n>(invoice: T) {\n const paidNpr = invoicePaidTotal(invoice.payments);\n return {\n ...invoice,\n paidNpr,\n balanceNpr: Math.max(0, invoice.amountNpr - paidNpr),\n };\n}\n\nexport async function listPlans(userId: string, schoolId: string) {\n await requireAdmin(schoolId, userId);\n const plans = await listFeePlans(schoolId);\n return { plans };\n}\n\nexport async function getPlan(userId: string, planId: string) {\n const plan = await getFeePlan(planId);\n if (!plan) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(plan.schoolId, userId);\n return { plan };\n}\n\nexport async function createPlan(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n description?: string | null;\n amountNpr: number;\n studentIds?: string[];\n }\n) {\n await requireAdmin(input.schoolId, userId);\n if (input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n const plan = await createFeePlan({\n schoolId: input.schoolId,\n name: input.name.trim(),\n description: input.description?.trim() || null,\n amountNpr: input.amountNpr,\n });\n if (input.studentIds?.length) {\n await assertActiveSchoolStudents(input.schoolId, input.studentIds);\n const updated = await setFeePlanEnrollments(plan.id, input.studentIds);\n return { plan: updated };\n }\n return { plan };\n}\n\nexport async function updatePlan(\n userId: string,\n input: {\n planId: string;\n name?: string;\n description?: string | null;\n amountNpr?: number;\n isActive?: boolean;\n }\n) {\n const existing = await getFeePlan(input.planId);\n if (!existing) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(existing.schoolId, userId);\n if (input.amountNpr != null && input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n const plan = await updateFeePlan(input.planId, {\n name: input.name?.trim(),\n description: input.description,\n amountNpr: input.amountNpr,\n isActive: input.isActive,\n });\n return { plan };\n}\n\nexport async function setPlanStudents(\n userId: string,\n input: { planId: string; studentIds: string[] }\n) {\n const existing = await getFeePlan(input.planId);\n if (!existing) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n await requireAdmin(existing.schoolId, userId);\n await assertActiveSchoolStudents(existing.schoolId, input.studentIds);\n const plan = await setFeePlanEnrollments(input.planId, input.studentIds);\n return { plan };\n}\n\nexport async function generateMonthlyInvoices(\n userId: string,\n input: {\n schoolId: string;\n feePlanId: string;\n year: number;\n month: number;\n studentIds?: string[];\n dueDate?: Date | null;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n assertMonth(input.month);\n\n const plan = await getFeePlan(input.feePlanId);\n if (!plan || plan.schoolId !== input.schoolId) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Fee plan not found\" });\n }\n if (!plan.isActive) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot generate invoices for an inactive fee plan\",\n });\n }\n\n let studentIds = input.studentIds;\n if (studentIds?.length) {\n await assertActiveSchoolStudents(input.schoolId, studentIds);\n } else {\n const enrolled = await listPlanEnrollmentIds(plan.id);\n studentIds = enrolled.length\n ? enrolled\n : await listActiveStudentIds(input.schoolId);\n }\n\n if (!studentIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No students to invoice\",\n });\n }\n\n const result = await createFeeInvoices(\n studentIds.map((studentId) => ({\n schoolId: input.schoolId,\n feePlanId: plan.id,\n studentId,\n year: input.year,\n month: input.month,\n amountNpr: plan.amountNpr,\n currency: plan.currency,\n dueDate: input.dueDate ?? null,\n }))\n );\n\n const invoices = await listFeeInvoices({\n schoolId: input.schoolId,\n feePlanId: plan.id,\n year: input.year,\n month: input.month,\n });\n\n return {\n createdCount: result.count,\n invoices: invoices.map(withBalance),\n };\n}\n\nexport async function listInvoices(\n userId: string,\n input: {\n schoolId: string;\n year?: number;\n month?: number;\n studentId?: string;\n feePlanId?: string;\n status?: FeeInvoiceStatus;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n if (input.month != null) assertMonth(input.month);\n const invoices = await listFeeInvoices(input);\n return { invoices: invoices.map(withBalance) };\n}\n\nexport async function getInvoice(userId: string, invoiceId: string) {\n const invoice = await getFeeInvoice(invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n return { invoice: withBalance(invoice) };\n}\n\nexport async function recordPayment(\n userId: string,\n input: {\n invoiceId: string;\n amountNpr: number;\n method: FeePaymentMethod;\n reference?: string | null;\n paidAt?: Date;\n notes?: string | null;\n }\n) {\n const invoice = await getFeeInvoice(input.invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n\n if (invoice.status === \"VOID\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot record payment on a void invoice\",\n });\n }\n if (input.amountNpr <= 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"amountNpr must be positive\",\n });\n }\n if (\n (input.method === \"BANK\" || input.method === \"ESEWA_REF\") &&\n !input.reference?.trim()\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"reference is required for BANK and ESEWA_REF payments\",\n });\n }\n\n const paidSoFar = invoicePaidTotal(invoice.payments);\n const balance = Math.max(0, invoice.amountNpr - paidSoFar);\n if (input.amountNpr > balance) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Payment exceeds balance (${formatNpr(balance)})`,\n });\n }\n\n const payment = await createFeePayment({\n schoolId: invoice.schoolId,\n invoiceId: invoice.id,\n amountNpr: input.amountNpr,\n method: input.method,\n reference: input.reference?.trim() || null,\n paidAt: input.paidAt,\n recordedById: userId,\n notes: input.notes?.trim() || null,\n });\n\n const aggregate = await sumPaymentsForInvoice(invoice.id);\n const newPaid = aggregate._sum.amountNpr ?? 0;\n const status = deriveStatus(invoice.amountNpr, newPaid, invoice.status);\n await updateInvoiceStatus(invoice.id, status);\n\n const refreshed = await getFeeInvoice(invoice.id);\n return {\n payment,\n invoice: refreshed ? withBalance(refreshed) : null,\n };\n}\n\nexport async function listBalances(userId: string, schoolId: string) {\n await requireAdmin(schoolId, userId);\n const balances = await listStudentBalances(schoolId);\n return { balances };\n}\n\nexport async function getInvoicePdf(userId: string, invoiceId: string) {\n const invoice = await getFeeInvoice(invoiceId);\n if (!invoice) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invoice not found\" });\n }\n await requireAdmin(invoice.schoolId, userId);\n\n const paidNpr = invoicePaidTotal(invoice.payments);\n const balanceNpr = Math.max(0, invoice.amountNpr - paidNpr);\n const studentName =\n invoice.student.profile?.displayName || invoice.student.username;\n\n const bytes = await buildFeePdf({\n schoolName: invoice.school.name,\n title: \"Fee Invoice\",\n subtitle: `${invoice.feePlan.name} · ${monthLabel(invoice.year, invoice.month)}`,\n letterhead: invoice.school.letterhead\n ? {\n path: invoice.school.letterhead.path,\n type: invoice.school.letterhead.type,\n }\n : null,\n lines: [\n { label: \"Invoice ID\", value: invoice.id.slice(0, 8).toUpperCase() },\n { label: \"Student\", value: studentName },\n { label: \"Period\", value: monthLabel(invoice.year, invoice.month) },\n { label: \"Plan\", value: invoice.feePlan.name },\n { label: \"Amount\", value: formatNpr(invoice.amountNpr) },\n { label: \"Paid\", value: formatNpr(paidNpr) },\n { label: \"Balance\", value: formatNpr(balanceNpr) },\n { label: \"Status\", value: invoice.status },\n ],\n footerNote: \"Manual ledger — not a gateway receipt. Keep for school records.\",\n });\n\n return {\n fileName: `invoice-${invoice.year}-${String(invoice.month).padStart(2, \"0\")}-${invoice.id.slice(0, 8)}.pdf`,\n contentType: \"application/pdf\",\n base64: Buffer.from(bytes).toString(\"base64\"),\n };\n}\n\nexport async function getReceiptPdf(userId: string, paymentId: string) {\n const payment = await getFeePayment(paymentId);\n if (!payment) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Payment not found\" });\n }\n await requireAdmin(payment.schoolId, userId);\n\n const invoice = payment.invoice;\n const studentName =\n invoice.student.profile?.displayName || invoice.student.username;\n\n const bytes = await buildFeePdf({\n schoolName: invoice.school.name,\n title: \"Payment Receipt\",\n subtitle: `${invoice.feePlan.name} · ${monthLabel(invoice.year, invoice.month)}`,\n letterhead: invoice.school.letterhead\n ? {\n path: invoice.school.letterhead.path,\n type: invoice.school.letterhead.type,\n }\n : null,\n lines: [\n { label: \"Receipt ID\", value: payment.id.slice(0, 8).toUpperCase() },\n { label: \"Student\", value: studentName },\n { label: \"Period\", value: monthLabel(invoice.year, invoice.month) },\n { label: \"Amount paid\", value: formatNpr(payment.amountNpr) },\n { label: \"Method\", value: payment.method },\n {\n label: \"Reference\",\n value: payment.reference?.trim() || \"—\",\n },\n {\n label: \"Paid at\",\n value: new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: \"Asia/Kathmandu\",\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n }).format(payment.paidAt),\n },\n ],\n footerNote: \"Manual ledger receipt — gateway integration deferred.\",\n });\n\n return {\n fileName: `receipt-${payment.id.slice(0, 8)}.pdf`,\n contentType: \"application/pdf\",\n base64: Buffer.from(bytes).toString(\"base64\"),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"17f46206-bcf6-5721-9d78-09801ff55dea"}
|
|
@@ -35,15 +35,12 @@ export declare function requireFeeReadAccess(schoolId: string, userId: string):
|
|
|
35
35
|
role: import(".prisma/client").$Enums.SchoolMembershipRole;
|
|
36
36
|
}>;
|
|
37
37
|
export declare function canManageFees(role: SchoolMembershipRole): boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Placeholder procedure surface until A2 fee models exist.
|
|
40
|
-
* Returns capability flags so the client can show/hide fee UI.
|
|
41
|
-
*/
|
|
38
|
+
/** Returns capability flags so the client can show/hide fee UI. */
|
|
42
39
|
export declare function getFeeCapabilities(userId: string, schoolId: string): Promise<{
|
|
43
40
|
role: import(".prisma/client").$Enums.SchoolMembershipRole;
|
|
44
41
|
canManageFees: boolean;
|
|
45
42
|
canViewFees: boolean;
|
|
46
|
-
feesImplemented:
|
|
43
|
+
feesImplemented: true;
|
|
47
44
|
message: string;
|
|
48
45
|
}>;
|
|
49
46
|
//# sourceMappingURL=feesAuthz.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feesAuthz.d.ts","sourceRoot":"/","sources":["services/feesAuthz.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAatD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,EAAE,EAC/B,OAAO,SAA+C;;;;;;;;GAOvD;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;GAO3E;AAED,uFAAuF;AACvF,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;GAO1E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,WAEvD;AAED
|
|
1
|
+
{"version":3,"file":"feesAuthz.d.ts","sourceRoot":"/","sources":["services/feesAuthz.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAatD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,EAAE,EAC/B,OAAO,SAA+C;;;;;;;;GAOvD;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;GAO3E;AAED,uFAAuF;AACvF,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;GAO1E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,WAEvD;AAED,mEAAmE;AACnE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;GAexE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
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]="
|
|
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]="f50124b5-bc63-5ef8-9de9-4ff9ab16fa71")}catch(e){}}();
|
|
3
3
|
import { TRPCError } from "@trpc/server";
|
|
4
4
|
import { findActiveSchoolMembership } from "../models/school.js";
|
|
5
5
|
const FEE_WRITE_ROLES = ["ADMIN", "ACCOUNTANT"];
|
|
@@ -28,10 +28,7 @@ export async function requireFeeReadAccess(schoolId, userId) {
|
|
|
28
28
|
export function canManageFees(role) {
|
|
29
29
|
return FEE_WRITE_ROLES.includes(role);
|
|
30
30
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Placeholder procedure surface until A2 fee models exist.
|
|
33
|
-
* Returns capability flags so the client can show/hide fee UI.
|
|
34
|
-
*/
|
|
31
|
+
/** Returns capability flags so the client can show/hide fee UI. */
|
|
35
32
|
export async function getFeeCapabilities(userId, schoolId) {
|
|
36
33
|
const membership = await findActiveSchoolMembership(schoolId, userId);
|
|
37
34
|
if (!membership) {
|
|
@@ -44,9 +41,9 @@ export async function getFeeCapabilities(userId, schoolId) {
|
|
|
44
41
|
role: membership.role,
|
|
45
42
|
canManageFees: canManageFees(membership.role),
|
|
46
43
|
canViewFees: FEE_READ_ROLES.includes(membership.role),
|
|
47
|
-
feesImplemented:
|
|
48
|
-
message: "Fee
|
|
44
|
+
feesImplemented: true,
|
|
45
|
+
message: "Fee features are available.",
|
|
49
46
|
};
|
|
50
47
|
}
|
|
51
48
|
//# sourceMappingURL=feesAuthz.js.map
|
|
52
|
-
//# debugId=
|
|
49
|
+
//# debugId=f50124b5-bc63-5ef8-9de9-4ff9ab16fa71
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feesAuthz.js","sources":["services/feesAuthz.ts"],"sourceRoot":"/","sourcesContent":["/**\n * C7: Fees authorization stubs for ACCOUNTANT (+ ADMIN).\n *\n * A2 owns full fee models; this module only provides reusable gates that\n * fee routers can call once they land.\n */\nimport { SchoolMembershipRole } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\nimport { findActiveSchoolMembership } from \"../models/school.js\";\n\nconst FEE_WRITE_ROLES: SchoolMembershipRole[] = [\"ADMIN\", \"ACCOUNTANT\"];\nconst FEE_READ_ROLES: SchoolMembershipRole[] = [\n \"ADMIN\",\n \"ACCOUNTANT\",\n \"TEACHER\",\n \"PARENT\",\n \"STUDENT\",\n];\n\nexport async function requireSchoolRoles(\n schoolId: string,\n userId: string,\n allowed: SchoolMembershipRole[],\n message = \"You do not have permission for this action\"\n) {\n const membership = await findActiveSchoolMembership(schoolId, userId);\n if (!membership || !allowed.includes(membership.role)) {\n throw new TRPCError({ code: \"FORBIDDEN\", message });\n }\n return membership;\n}\n\n/** Admin or accountant may create/update fee structures and record payments. */\nexport async function requireFeeWriteAccess(schoolId: string, userId: string) {\n return requireSchoolRoles(\n schoolId,\n userId,\n FEE_WRITE_ROLES,\n \"Only school admins or accountants can manage fees\"\n );\n}\n\n/** Broad read access stub — parents/students should be scoped to own records by A2. */\nexport async function requireFeeReadAccess(schoolId: string, userId: string) {\n return requireSchoolRoles(\n schoolId,\n userId,\n FEE_READ_ROLES,\n \"You are not a member of this school\"\n );\n}\n\nexport function canManageFees(role: SchoolMembershipRole) {\n return FEE_WRITE_ROLES.includes(role);\n}\n\n
|
|
1
|
+
{"version":3,"file":"feesAuthz.js","sources":["services/feesAuthz.ts"],"sourceRoot":"/","sourcesContent":["/**\n * C7: Fees authorization stubs for ACCOUNTANT (+ ADMIN).\n *\n * A2 owns full fee models; this module only provides reusable gates that\n * fee routers can call once they land.\n */\nimport { SchoolMembershipRole } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\nimport { findActiveSchoolMembership } from \"../models/school.js\";\n\nconst FEE_WRITE_ROLES: SchoolMembershipRole[] = [\"ADMIN\", \"ACCOUNTANT\"];\nconst FEE_READ_ROLES: SchoolMembershipRole[] = [\n \"ADMIN\",\n \"ACCOUNTANT\",\n \"TEACHER\",\n \"PARENT\",\n \"STUDENT\",\n];\n\nexport async function requireSchoolRoles(\n schoolId: string,\n userId: string,\n allowed: SchoolMembershipRole[],\n message = \"You do not have permission for this action\"\n) {\n const membership = await findActiveSchoolMembership(schoolId, userId);\n if (!membership || !allowed.includes(membership.role)) {\n throw new TRPCError({ code: \"FORBIDDEN\", message });\n }\n return membership;\n}\n\n/** Admin or accountant may create/update fee structures and record payments. */\nexport async function requireFeeWriteAccess(schoolId: string, userId: string) {\n return requireSchoolRoles(\n schoolId,\n userId,\n FEE_WRITE_ROLES,\n \"Only school admins or accountants can manage fees\"\n );\n}\n\n/** Broad read access stub — parents/students should be scoped to own records by A2. */\nexport async function requireFeeReadAccess(schoolId: string, userId: string) {\n return requireSchoolRoles(\n schoolId,\n userId,\n FEE_READ_ROLES,\n \"You are not a member of this school\"\n );\n}\n\nexport function canManageFees(role: SchoolMembershipRole) {\n return FEE_WRITE_ROLES.includes(role);\n}\n\n/** Returns capability flags so the client can show/hide fee UI. */\nexport async function getFeeCapabilities(userId: string, schoolId: string) {\n const membership = await findActiveSchoolMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You are not a member of this school\",\n });\n }\n return {\n role: membership.role,\n canManageFees: canManageFees(membership.role),\n canViewFees: FEE_READ_ROLES.includes(membership.role),\n feesImplemented: true as const,\n message: \"Fee features are available.\",\n };\n}\n"],"names":[],"mappings":";;AAOA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,MAAM,eAAe,GAA2B,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AACxE,MAAM,cAAc,GAA2B;IAC7C,OAAO;IACP,YAAY;IACZ,SAAS;IACT,QAAQ;IACR,SAAS;CACV,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,MAAc,EACd,OAA+B,EAC/B,OAAO,GAAG,4CAA4C;IAEtD,MAAM,UAAU,GAAG,MAAM,0BAA0B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAgB,EAAE,MAAc;IAC1E,OAAO,kBAAkB,CACvB,QAAQ,EACR,MAAM,EACN,eAAe,EACf,mDAAmD,CACpD,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc;IACzE,OAAO,kBAAkB,CACvB,QAAQ,EACR,MAAM,EACN,cAAc,EACd,qCAAqC,CACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,OAAO,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,QAAgB;IACvE,MAAM,UAAU,GAAG,MAAM,0BAA0B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,SAAS,CAAC;YAClB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,qCAAqC;SAC/C,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,aAAa,EAAE,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC;QAC7C,WAAW,EAAE,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;QACrD,eAAe,EAAE,IAAa;QAC9B,OAAO,EAAE,6BAA6B;KACvC,CAAC;AACJ,CAAC","debug_id":"f50124b5-bc63-5ef8-9de9-4ff9ab16fa71"}
|
|
@@ -228,6 +228,42 @@ export declare function reportMarketplaceListing(userId: string, listingId: stri
|
|
|
228
228
|
reportCount: number;
|
|
229
229
|
isHidden: boolean;
|
|
230
230
|
}>;
|
|
231
|
+
export declare function updateMarketplaceListingDetails(userId: string, input: {
|
|
232
|
+
listingId: string;
|
|
233
|
+
title?: string;
|
|
234
|
+
description?: string | null;
|
|
235
|
+
visibility?: "SCHOOL" | "PUBLIC";
|
|
236
|
+
tags?: string[];
|
|
237
|
+
}): Promise<{
|
|
238
|
+
school: {
|
|
239
|
+
id: string;
|
|
240
|
+
name: string;
|
|
241
|
+
} | null;
|
|
242
|
+
author: {
|
|
243
|
+
id: string;
|
|
244
|
+
username: string;
|
|
245
|
+
profile: {
|
|
246
|
+
displayName: string | null;
|
|
247
|
+
} | null;
|
|
248
|
+
};
|
|
249
|
+
} & {
|
|
250
|
+
type: import(".prisma/client").$Enums.MarketplaceListingType;
|
|
251
|
+
payload: Prisma.JsonValue;
|
|
252
|
+
id: string;
|
|
253
|
+
createdAt: Date;
|
|
254
|
+
updatedAt: Date;
|
|
255
|
+
schoolId: string | null;
|
|
256
|
+
tags: string[];
|
|
257
|
+
description: string | null;
|
|
258
|
+
title: string;
|
|
259
|
+
worksheetId: string | null;
|
|
260
|
+
markSchemeId: string | null;
|
|
261
|
+
authorId: string;
|
|
262
|
+
fileId: string | null;
|
|
263
|
+
visibility: import(".prisma/client").$Enums.MarketplaceVisibility;
|
|
264
|
+
reportCount: number;
|
|
265
|
+
isHidden: boolean;
|
|
266
|
+
}>;
|
|
231
267
|
export declare function hideMarketplaceListing(userId: string, listingId: string, isHidden: boolean): Promise<{
|
|
232
268
|
school: {
|
|
233
269
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marketplace.d.ts","sourceRoot":"/","sources":["services/marketplace.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,MAAM,EAEP,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"marketplace.d.ts","sourceRoot":"/","sources":["services/marketplace.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* worksheets, and files. Exercise/poll types are out of scope for B1 v1.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
!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]="
|
|
6
|
+
!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]="89284a2e-a306-525a-955c-e752537ee131")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { v4 as uuidv4 } from "uuid";
|
|
9
9
|
import { prisma } from "../lib/prisma.js";
|
|
10
10
|
import { copyFile } from "../lib/googleCloudStorage.js";
|
|
11
11
|
import { classTeacherOrSchoolAdminWhere } from "../models/access.js";
|
|
12
12
|
import { findOrCreateScopeRoot } from "../models/cloudStorage.js";
|
|
13
|
-
import { createMarketplaceListing, deleteMarketplaceListing, findMarketplaceListingById, incrementMarketplaceReportCount, searchMarketplaceListings, setMarketplaceListingHidden, } from "../models/marketplace.js";
|
|
13
|
+
import { createMarketplaceListing, deleteMarketplaceListing, findMarketplaceListingById, incrementMarketplaceReportCount, searchMarketplaceListings, setMarketplaceListingHidden, updateMarketplaceListing, } from "../models/marketplace.js";
|
|
14
14
|
import { findActiveSchoolAdminMembership, findSchoolMembership, listUserSchoolMemberships, } from "../models/school.js";
|
|
15
15
|
import { duplicateWorksheetWithClient } from "../models/worksheet.js";
|
|
16
16
|
function normalizeTags(tags) {
|
|
@@ -86,13 +86,16 @@ function asPayload(raw) {
|
|
|
86
86
|
}
|
|
87
87
|
export async function listMarketplace(userId, input) {
|
|
88
88
|
const memberships = await listUserSchoolMemberships(userId);
|
|
89
|
+
if (input.schoolId &&
|
|
90
|
+
!memberships.some((m) => m.schoolId === input.schoolId)) {
|
|
91
|
+
return { items: [], nextCursor: undefined };
|
|
92
|
+
}
|
|
89
93
|
const schoolIds = input.schoolId
|
|
90
|
-
?
|
|
91
|
-
? [input.schoolId]
|
|
92
|
-
: []
|
|
94
|
+
? [input.schoolId]
|
|
93
95
|
: memberships.map((m) => m.schoolId);
|
|
94
96
|
return searchMarketplaceListings({
|
|
95
97
|
schoolIds,
|
|
98
|
+
scopeSchoolId: input.schoolId,
|
|
96
99
|
type: input.type,
|
|
97
100
|
search: input.search,
|
|
98
101
|
tags: input.tags,
|
|
@@ -511,6 +514,33 @@ export async function reportMarketplaceListing(userId, listingId) {
|
|
|
511
514
|
// C10 light stub — increment only; no reporter dedupe table yet.
|
|
512
515
|
return incrementMarketplaceReportCount(listingId);
|
|
513
516
|
}
|
|
517
|
+
export async function updateMarketplaceListingDetails(userId, input) {
|
|
518
|
+
const listing = await findMarketplaceListingById(input.listingId);
|
|
519
|
+
if (!listing) {
|
|
520
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "Listing not found" });
|
|
521
|
+
}
|
|
522
|
+
const isAuthor = listing.authorId === userId;
|
|
523
|
+
const isSchoolAdmin = listing.schoolId != null &&
|
|
524
|
+
Boolean(await findActiveSchoolAdminMembership(listing.schoolId, userId));
|
|
525
|
+
if (!isAuthor && !isSchoolAdmin) {
|
|
526
|
+
throw new TRPCError({
|
|
527
|
+
code: "FORBIDDEN",
|
|
528
|
+
message: "Only the author or a school admin can edit this listing",
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
if (input.visibility === "SCHOOL" && listing.schoolId == null) {
|
|
532
|
+
throw new TRPCError({
|
|
533
|
+
code: "BAD_REQUEST",
|
|
534
|
+
message: "Listing has no school; it cannot use school visibility",
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return updateMarketplaceListing(input.listingId, {
|
|
538
|
+
title: input.title,
|
|
539
|
+
description: input.description,
|
|
540
|
+
visibility: input.visibility,
|
|
541
|
+
tags: input.tags ? normalizeTags(input.tags) : undefined,
|
|
542
|
+
});
|
|
543
|
+
}
|
|
514
544
|
export async function hideMarketplaceListing(userId, listingId, isHidden) {
|
|
515
545
|
const listing = await findMarketplaceListingById(listingId);
|
|
516
546
|
if (!listing) {
|
|
@@ -625,4 +655,4 @@ export async function listPublishableSources(userId, input) {
|
|
|
625
655
|
return { markSchemes, worksheets, files };
|
|
626
656
|
}
|
|
627
657
|
//# sourceMappingURL=marketplace.js.map
|
|
628
|
-
//# debugId=
|
|
658
|
+
//# debugId=89284a2e-a306-525a-955c-e752537ee131
|