import { ok, err } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { InvalidNameError, InvalidTypeError, CompanyNotFoundError, CompanyInactiveError, DuplicateNameError, MissingRequiredFieldsError, InvalidCountryError, InvalidTimezoneError, } from "../lib/errors.generated"; export interface CreateSiteInput { name: string; type: string; companyId: string; street: string; city: string; state?: string; postalCode: string; country: string; timezone: string; } const VALID_SITE_TYPES = ["OFFICE", "WAREHOUSE", "STORE", "FACTORY", "DISTRIBUTION_CENTER"]; function isValidCountryCode(code: string): boolean { try { const displayNames = new Intl.DisplayNames(["en"], { type: "region" }); const name = displayNames.of(code); return name !== undefined && name !== code; } catch { return false; } } function isValidTimezone(tz: string): boolean { try { Intl.DateTimeFormat(undefined, { timeZone: tz }); return true; } catch { return false; } } /** * Function: createSite * * Creates a new operational site within a company, capturing its classification, * physical address, and timezone. */ export async function run>( db: Transaction, input: CreateSiteInput & CF, ) { const { name, type, companyId, street, city, state, postalCode, country, timezone, ...customFields } = input; // 1. Validate name non-empty if (!name || name.trim() === "") { return err(new InvalidNameError(String(name))); } // 2. Validate type in allowed list if (!VALID_SITE_TYPES.includes(type)) { return err(new InvalidTypeError(type)); } // 3. Find company by companyId const company = await db .selectFrom("Company") .selectAll() .where("id", "=", companyId) .executeTakeFirst(); if (!company) { return err(new CompanyNotFoundError(companyId)); } // 4. Company must be ACTIVE if (company.status !== "ACTIVE") { return err(new CompanyInactiveError(companyId)); } // 5. Check name uniqueness in company with forUpdate() const existingSite = await db .selectFrom("Site") .selectAll() .where("name", "=", name) .where("companyId", "=", companyId) .forUpdate() .executeTakeFirst(); if (existingSite) { return err(new DuplicateNameError(name)); } // 6. Validate address fields if (!street || street.trim() === "") { return err(new MissingRequiredFieldsError("street")); } if (!city || city.trim() === "") { return err(new MissingRequiredFieldsError("city")); } if (!postalCode || postalCode.trim() === "") { return err(new MissingRequiredFieldsError("postalCode")); } if (!country || country.trim() === "") { return err(new MissingRequiredFieldsError("country")); } // 7. Validate country code if (!isValidCountryCode(country)) { return err(new InvalidCountryError(country)); } // 8. Validate timezone if (!isValidTimezone(timezone)) { return err(new InvalidTimezoneError(timezone)); } // 9. Insert with status "ACTIVE" const site = await db .insertInto("Site") .values({ ...(customFields as Record), name, type, companyId, street, city, state: state ?? null, postalCode, country, timezone, status: "ACTIVE", }) .returningAll() .executeTakeFirstOrThrow(); return ok({ site }); }