Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 16x 12x 12x 7x 1x 6x 2x 2x 1x 5x 5x 5x 5x 12x 12x 1x 11x 1x 10x 10x 1x 9x 1x 8x 1x | // Inquiry Service - Business Logic Layer
// Trimmed to create-only — pro/admin management removed (CRM replaces them).
// Marketplace inquiry submission still uses create().
import type { Dal } from "../dal";
import type { Inquiry } from "../db/schema";
import { INQUIRY_TYPES } from "../db/schema";
import { NotFoundError, ValidationError } from "../lib/errors";
import { parseIndianPhone } from "@interioring/utils/validation/phone";
import {
validateCustomerName,
customerNameErrorMessage,
normalizeCustomerName,
} from "@interioring/utils/validation/customer-name";
import { isValidEnum } from "../lib/utils";
export type CreateInquiryInput = {
proId: string;
projectId?: string;
type: string;
customerName: string;
customerPhone: string;
customerEmail?: string;
customerLocation?: string;
requirement?: string;
notes?: string;
sourcePage?: string;
requirementType?: string;
sourceType?: string;
};
export class InquiryService {
constructor(private dal: Dal) {}
async create(input: CreateInquiryInput): Promise<Inquiry> {
this.validateInput(input);
// Verify pro exists
const pro = await this.dal.pros.findById(input.proId);
if (!pro) {
throw new NotFoundError("Pro", input.proId);
}
// Verify project if provided
if (input.projectId) {
const project = await this.dal.projects.findById(input.projectId);
if (!project) {
throw new NotFoundError("Project", input.projectId);
}
}
const parsedPhone = parseIndianPhone(input.customerPhone);
Iif (!parsedPhone) {
throw new ValidationError("Invalid Indian phone number");
}
const inquiry = await this.dal.inquiries.create({
proId: input.proId,
projectId: input.projectId,
type: input.type as Inquiry["type"],
status: "new",
customerName: normalizeCustomerName(input.customerName),
customerPhone: parsedPhone.e164,
customerEmail: input.customerEmail?.trim(),
customerLocation: input.customerLocation?.trim(),
requirement: input.requirement?.trim(),
notes: input.notes?.trim(),
sourcePage: input.sourcePage,
requirementType: input.requirementType,
sourceType: input.sourceType,
});
return inquiry;
}
private validateInput(input: CreateInquiryInput): void {
const nameError = validateCustomerName(input.customerName ?? "");
if (nameError) {
throw new ValidationError(customerNameErrorMessage(nameError));
}
if (!input.customerPhone?.trim()) {
throw new ValidationError("Customer phone is required");
}
const parsed = parseIndianPhone(input.customerPhone);
if (!parsed || parsed.type !== "mobile") {
throw new ValidationError(
"Customer phone must be a valid 10-digit Indian mobile number",
);
}
if (!input.type) {
throw new ValidationError("Inquiry type is required");
}
if (!isValidEnum(input.type, INQUIRY_TYPES)) {
throw new ValidationError(
`Invalid inquiry type. Must be one of: ${INQUIRY_TYPES.join(", ")}`,
);
}
}
}
|