Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers, document generators, FCC compliance tools, Canada CRTC formation, Ansible infrastructure, and deployment scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
f8cd37ac8c
1823 changed files with 145167 additions and 0 deletions
242
api/src/routes/bundles.ts
Normal file
242
api/src/routes/bundles.ts
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/**
|
||||
* Service bundle routes.
|
||||
*
|
||||
* Bundles give 20% off when purchasing all services in a category
|
||||
* or a curated cross-category package.
|
||||
*/
|
||||
|
||||
import { Router } from "express";
|
||||
import { pool } from "../db.js";
|
||||
import { submitLimiter } from "../middleware/rate-limit.js";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Service prices in cents (must match the current site pricing)
|
||||
// discountable: true = our service fee (eligible for bundle discount)
|
||||
// false = pass-through fee (state fees — NOT discountable)
|
||||
const SERVICE_PRICES: Record<string, { price: number; name: string; quote: boolean; discountable: boolean }> = {
|
||||
"flsa-audit": { price: 149900, name: "FLSA / Wage & Hour Audit", quote: false, discountable: true },
|
||||
"contractor-classification": { price: 49900, name: "Contractor Classification Review", quote: false, discountable: true },
|
||||
"handbook-review": { price: 99900, name: "Employee Handbook Review", quote: false, discountable: true },
|
||||
"policy-development": { price: 0, name: "Workplace Policy Development", quote: true, discountable: true },
|
||||
"ccpa-audit": { price: 249900, name: "CCPA/CPRA Compliance Audit", quote: false, discountable: true },
|
||||
"privacy-policy": { price: 49900, name: "Privacy Policy Generation", quote: false, discountable: true },
|
||||
"data-mapping": { price: 0, name: "Data Mapping & Inventory", quote: true, discountable: true },
|
||||
"breach-response": { price: 199900, name: "Breach Response Planning", quote: false, discountable: true },
|
||||
"consent-audit": { price: 129900, name: "SMS/Call Consent Audit", quote: false, discountable: true },
|
||||
"dnc-compliance": { price: 79900, name: "DNC Compliance Review", quote: false, discountable: true },
|
||||
"campaign-review": { price: 59900, name: "Campaign Compliance Review", quote: false, discountable: true },
|
||||
"fcc-499a": { price: 79900, name: "FCC 499A Filing", quote: false, discountable: true },
|
||||
"stir-shaken": { price: 0, name: "STIR/SHAKEN Implementation", quote: true, discountable: true },
|
||||
"ipes-isp": { price: 129900, name: "IPES & ISP Registrations", quote: false, discountable: true },
|
||||
"database-management": { price: 49900, name: "Telecom Database Management", quote: false, discountable: true },
|
||||
"state-puc": { price: 39900, name: "State PUC/PSC Filings", quote: false, discountable: true },
|
||||
"formation": { price: 17900, name: "Business Formation (Basic)", quote: false, discountable: true },
|
||||
"state-registration": { price: 24900, name: "State Registration", quote: false, discountable: true },
|
||||
"annual-reports": { price: 9900, name: "Annual Report Filing", quote: false, discountable: true },
|
||||
"registered-agent": { price: 9900, name: "Registered Agent Service", quote: false, discountable: false },
|
||||
};
|
||||
|
||||
// These are NEVER discountable — pass-through costs and third-party fees
|
||||
// State filing fees: calculated separately per state, added at order time
|
||||
|
||||
function calculateBundlePrice(services: string[], discountPct: number) {
|
||||
let discountableTotal = 0; // our service fees — eligible for bundle discount
|
||||
let nonDiscountableTotal = 0; // pass-through fees — never discounted
|
||||
let hasQuoteItems = false;
|
||||
const items: Array<{ slug: string; name: string; price: number; quote: boolean; discountable: boolean }> = [];
|
||||
|
||||
for (const slug of services) {
|
||||
const svc = SERVICE_PRICES[slug];
|
||||
if (!svc) continue;
|
||||
items.push({ slug, name: svc.name, price: svc.price, quote: svc.quote, discountable: svc.discountable });
|
||||
if (svc.quote) {
|
||||
hasQuoteItems = true;
|
||||
} else if (svc.discountable) {
|
||||
discountableTotal += svc.price;
|
||||
} else {
|
||||
nonDiscountableTotal += svc.price;
|
||||
}
|
||||
}
|
||||
|
||||
const originalTotal = discountableTotal + nonDiscountableTotal;
|
||||
const discountCents = Math.round((discountableTotal * discountPct) / 100);
|
||||
const finalTotal = originalTotal - discountCents;
|
||||
|
||||
return { items, originalTotal, discountableTotal, nonDiscountableTotal, discountPct, discountCents, finalTotal, hasQuoteItems };
|
||||
}
|
||||
|
||||
// GET /api/v1/bundles — List all active bundles with calculated pricing
|
||||
router.get("/api/v1/bundles", async (_req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT * FROM service_bundles WHERE active = TRUE ORDER BY display_order, name",
|
||||
);
|
||||
|
||||
const bundles = result.rows.map((b: any) => {
|
||||
const calc = calculateBundlePrice(b.services, b.discount_pct);
|
||||
return {
|
||||
slug: b.slug,
|
||||
name: b.name,
|
||||
description: b.description,
|
||||
category: b.category,
|
||||
discount_pct: b.discount_pct,
|
||||
services: calc.items,
|
||||
original_total_cents: calc.originalTotal,
|
||||
discount_cents: calc.discountCents,
|
||||
final_total_cents: calc.finalTotal,
|
||||
has_quote_items: calc.hasQuoteItems,
|
||||
savings_text: `Save $${(calc.discountCents / 100).toFixed(0)} (${b.discount_pct}% off)`,
|
||||
};
|
||||
});
|
||||
|
||||
res.json({ bundles });
|
||||
} catch (err) {
|
||||
console.error("[bundles] List error:", err);
|
||||
res.status(500).json({ error: "Could not load bundles." });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/v1/bundles/:slug — Single bundle with pricing
|
||||
router.get("/api/v1/bundles/:slug", async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT * FROM service_bundles WHERE slug = $1 AND active = TRUE",
|
||||
[req.params.slug],
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
res.status(404).json({ error: "Bundle not found." });
|
||||
return;
|
||||
}
|
||||
|
||||
const b = result.rows[0];
|
||||
const calc = calculateBundlePrice(b.services, b.discount_pct);
|
||||
|
||||
res.json({
|
||||
bundle: {
|
||||
slug: b.slug,
|
||||
name: b.name,
|
||||
description: b.description,
|
||||
category: b.category,
|
||||
discount_pct: b.discount_pct,
|
||||
services: calc.items,
|
||||
original_total_cents: calc.originalTotal,
|
||||
discount_cents: calc.discountCents,
|
||||
final_total_cents: calc.finalTotal,
|
||||
has_quote_items: calc.hasQuoteItems,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[bundles] Get error:", err);
|
||||
res.status(500).json({ error: "Could not load bundle." });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/v1/bundles/order — Place a bundle order
|
||||
router.post("/api/v1/bundles/order", submitLimiter, async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
bundle_slug, customer_name, customer_email, customer_phone,
|
||||
customer_company, discount_code,
|
||||
} = req.body ?? {};
|
||||
|
||||
if (!bundle_slug || !customer_name || !customer_email) {
|
||||
res.status(400).json({ error: "Missing required fields: bundle_slug, customer_name, customer_email" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the bundle
|
||||
const bundleResult = await pool.query(
|
||||
"SELECT * FROM service_bundles WHERE slug = $1 AND active = TRUE",
|
||||
[bundle_slug],
|
||||
);
|
||||
if (bundleResult.rows.length === 0) {
|
||||
res.status(404).json({ error: "Bundle not found." });
|
||||
return;
|
||||
}
|
||||
const bundle = bundleResult.rows[0];
|
||||
const calc = calculateBundlePrice(bundle.services, bundle.discount_pct);
|
||||
|
||||
// Discount code — only applies to discountable service fees (NOT state fees)
|
||||
let discountCodeCents = 0;
|
||||
if (discount_code) {
|
||||
const dcResult = await pool.query("SELECT * FROM discount_codes WHERE code = $1 AND active = TRUE", [discount_code.toUpperCase()]);
|
||||
if (dcResult.rows.length > 0) {
|
||||
const dc = dcResult.rows[0];
|
||||
// Apply discount code ONLY to the already-discounted service fee total (after bundle discount)
|
||||
const discountableAfterBundle = calc.discountableTotal - calc.discountCents;
|
||||
if (dc.discount_type === "percent") {
|
||||
discountCodeCents = Math.round((discountableAfterBundle * dc.discount_value) / 100);
|
||||
} else {
|
||||
discountCodeCents = Math.min(dc.discount_value, discountableAfterBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grand total: discounted service fees + non-discountable fees
|
||||
const grandTotal = calc.finalTotal - discountCodeCents;
|
||||
|
||||
const year = new Date().getFullYear();
|
||||
const short = uuidv4().split("-")[0]!.toUpperCase();
|
||||
const orderNumber = `BDL-${year}-${short}`;
|
||||
|
||||
const result = await pool.query(
|
||||
`INSERT INTO bundle_orders (
|
||||
bundle_slug, order_number, customer_name, customer_email, customer_phone, customer_company,
|
||||
original_total_cents, discount_pct, discount_cents, final_total_cents,
|
||||
discount_code, discount_code_cents, status
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,'received')
|
||||
RETURNING id, order_number`,
|
||||
[
|
||||
bundle_slug, orderNumber, customer_name, customer_email.toLowerCase().trim(),
|
||||
customer_phone || null, customer_company || null,
|
||||
calc.originalTotal, bundle.discount_pct, calc.discountCents, grandTotal,
|
||||
discount_code ? discount_code.toUpperCase() : null, discountCodeCents,
|
||||
],
|
||||
);
|
||||
|
||||
// Create commission if this order used an agent's referral code
|
||||
if (discount_code) {
|
||||
try {
|
||||
const { createCommission } = await import("./agents.js");
|
||||
// Check if the discount code belongs to a sales agent
|
||||
const agentCheck = await pool.query(
|
||||
"SELECT sa.agent_code FROM sales_agents sa JOIN discount_codes dc ON sa.discount_code_id = dc.id WHERE dc.code = $1 AND sa.active = TRUE",
|
||||
[discount_code.toUpperCase()],
|
||||
);
|
||||
if (agentCheck.rows.length > 0) {
|
||||
await createCommission({
|
||||
agentCode: agentCheck.rows[0].agent_code,
|
||||
orderType: "bundle",
|
||||
orderId: result.rows[0].id,
|
||||
orderNumber: result.rows[0].order_number,
|
||||
serviceSlug: bundle_slug,
|
||||
customerName: customer_name,
|
||||
customerEmail: customer_email,
|
||||
orderAmountCents: grandTotal,
|
||||
discountCents: discountCodeCents,
|
||||
});
|
||||
}
|
||||
} catch (commErr) {
|
||||
console.error("[bundles] Commission creation failed (non-blocking):", commErr);
|
||||
}
|
||||
}
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
order_number: result.rows[0].order_number,
|
||||
bundle: bundle.name,
|
||||
original_total: `$${(calc.originalTotal / 100).toFixed(2)}`,
|
||||
bundle_discount: `- $${(calc.discountCents / 100).toFixed(2)} (${bundle.discount_pct}% bundle discount)`,
|
||||
code_discount: discountCodeCents > 0 ? `- $${(discountCodeCents / 100).toFixed(2)}` : null,
|
||||
total: `$${(grandTotal / 100).toFixed(2)}`,
|
||||
message: "Bundle order received. We will begin processing within one business day.",
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[bundles] Order error:", err);
|
||||
res.status(500).json({ error: "Could not place bundle order." });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Loading…
Add table
Add a link
Reference in a new issue