feat(02-03): Subscriber and ServicePlan Prisma models + service layer
- Add SubscriberStatus (ACTIVE/SUSPENDED/CANCELLED) and BillingType (PREPAID/POSTPAID) enums - Add ServicePlan model with name, speed, monthlyPrice, billingType, soft-delete - Add Subscriber model with accountNumber, billingDay, status lifecycle, creditBalance - Add TenantSettings model with autoSuspendDays and prepaidLeadDays - Migrate: 20260304145633_add_subscriber_models - Extend prisma-tenant.ts with subscriber, servicePlan, tenantSettings query scoping - Create service-plan-service.ts: createServicePlan, updateServicePlan, listServicePlans, deactivateServicePlan - Create subscriber-service.ts: createSubscriber, updateSubscriber, changeSubscriberStatus, searchSubscribers, getSubscriber, generateAccountNumber
This commit is contained in:
@@ -30,7 +30,7 @@ import { prisma } from "@/lib/prisma";
|
||||
* Extend this list as new models are added in later phases:
|
||||
* e.g., "subscriber", "invoice", "servicePlan", "payment"
|
||||
*/
|
||||
export const TENANT_SCOPED_MODELS = ["user", "account", "accountingPeriod"] as const;
|
||||
export const TENANT_SCOPED_MODELS = ["user", "account", "accountingPeriod", "subscriber", "servicePlan", "tenantSettings"] as const;
|
||||
|
||||
export type TenantScopedModel = (typeof TENANT_SCOPED_MODELS)[number];
|
||||
|
||||
@@ -354,6 +354,260 @@ export function withTenantContext(tenantId: string) {
|
||||
return query(args);
|
||||
},
|
||||
},
|
||||
|
||||
subscriber: {
|
||||
async findMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirst({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirstOrThrow({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUnique({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
return prisma.subscriber.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUniqueOrThrow({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
const result = await prisma.subscriber.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
if (!result) {
|
||||
throw new Error("Record not found");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async create({ args, query }) {
|
||||
args.data = { ...args.data, tenantId } as typeof args.data;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async createMany({ args, query }) {
|
||||
if (Array.isArray(args.data)) {
|
||||
args.data = args.data.map((item) => ({ ...item, tenantId })) as typeof args.data;
|
||||
} else {
|
||||
args.data = { ...args.data, tenantId } as typeof args.data;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async update({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async updateMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async delete({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async deleteMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async upsert({ args, query }) {
|
||||
args.where = { ...args.where, tenantId } as typeof args.where;
|
||||
args.create = { ...args.create, tenantId } as typeof args.create;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async count({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async aggregate({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async groupBy({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
},
|
||||
|
||||
servicePlan: {
|
||||
async findMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirst({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirstOrThrow({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUnique({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
return prisma.servicePlan.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUniqueOrThrow({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
const result = await prisma.servicePlan.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
if (!result) {
|
||||
throw new Error("Record not found");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async create({ args, query }) {
|
||||
args.data = { ...args.data, tenantId } as typeof args.data;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async createMany({ args, query }) {
|
||||
if (Array.isArray(args.data)) {
|
||||
args.data = args.data.map((item) => ({ ...item, tenantId })) as typeof args.data;
|
||||
} else {
|
||||
args.data = { ...args.data, tenantId } as typeof args.data;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async update({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async updateMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async delete({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async deleteMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async upsert({ args, query }) {
|
||||
args.where = { ...args.where, tenantId } as typeof args.where;
|
||||
args.create = { ...args.create, tenantId } as typeof args.create;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async count({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async aggregate({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async groupBy({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
},
|
||||
|
||||
tenantSettings: {
|
||||
async findMany({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirst({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findFirstOrThrow({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUnique({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
return prisma.tenantSettings.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async findUniqueOrThrow({ args, query }) {
|
||||
if (args.where && "id" in args.where && !("tenantId" in (args.where as object))) {
|
||||
const result = await prisma.tenantSettings.findFirst({
|
||||
...args,
|
||||
where: { ...args.where, tenantId },
|
||||
});
|
||||
if (!result) {
|
||||
throw new Error("Record not found");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async create({ args, query }) {
|
||||
args.data = { ...args.data, tenantId } as typeof args.data;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async update({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async upsert({ args, query }) {
|
||||
args.where = { ...args.where, tenantId } as typeof args.where;
|
||||
args.create = { ...args.create, tenantId } as typeof args.create;
|
||||
return query(args);
|
||||
},
|
||||
|
||||
async count({ args, query }) {
|
||||
args.where = { ...args.where, tenantId };
|
||||
return query(args);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user