diff --git a/apps/bridge-worker/tasks/formstack/create-ticket-from-form.ts b/apps/bridge-worker/tasks/formstack/create-ticket-from-form.ts index a28eb89..84062dc 100644 --- a/apps/bridge-worker/tasks/formstack/create-ticket-from-form.ts +++ b/apps/bridge-worker/tasks/formstack/create-ticket-from-form.ts @@ -1,5 +1,5 @@ import { createLogger } from "@link-stack/logger"; -import { Zammad, getOrCreateUser } from "../../lib/zammad.js"; +import { Zammad, getUser } from "../../lib/zammad.js"; const logger = createLogger('create-ticket-from-form'); @@ -43,47 +43,29 @@ const createTicketFromFormTask = async ( ? `${name.first || ''} ${name.last || ''}`.trim() : 'Unknown'; - // Build address string - let addressString = ''; - if (address) { - const parts = [ - address.address, - address.city, - address.state, - address.zip, - ].filter(Boolean); - addressString = parts.join(', '); + // Get organization name from form data + const organizationName = type_of_organization || ''; + + // Build ticket title - matching ngo-isac-uploader pattern + let title = fullName; + if (organizationName) { + title += ` - ${organizationName}`; + } + if (type_of_help_requested) { + title += ` - ${type_of_help_requested}`; } - // Build ticket title - const title = `Help Request: ${type_of_help_requested || 'General'} - ${fullName}`; - - // Build ticket body with all form information - const body = `

Contact Information

- - -

Request Details

- - - ${description_of_issue ? `

Description of Issue

${description_of_issue}

` : ''} - - ${how_did_you_hear_about_us ? `

How they heard about us: ${how_did_you_hear_about_us}

` : ''} + // Build article body - only description and metadata + // All other fields go into custom Zammad ticket fields + const body = description_of_issue + ? `

${description_of_issue}


-

Form ID: ${FormID} | Submission ID: ${UniqueID} | Received: ${receivedAt}

`; +

Submitted via Formstack | Form ID: ${FormID} | Submission ID: ${UniqueID} | Received: ${receivedAt}

` + : `

No description provided

+ +
+

Submitted via Formstack | Form ID: ${FormID} | Submission ID: ${UniqueID} | Received: ${receivedAt}

`; // Get Zammad configuration from environment const zammadUrl = process.env.ZAMMAD_URL || 'http://zammad-nginx:8080'; @@ -97,29 +79,78 @@ const createTicketFromFormTask = async ( const zammad = Zammad({ token: zammadToken }, zammadUrl); try { - // Get or create user based on phone number, Signal number, or email + // Get or create user based on contact info + // Priority: signal_number > phone_number > email_address let customer; - const contactInfo = signal_number || phone_number || email_address; - if (contactInfo) { - customer = await getOrCreateUser(zammad, contactInfo); - } else { - // Create user with just the name if no contact info + // Try to find existing user by phone or email + if (signal_number || phone_number) { + const phoneToSearch = signal_number || phone_number; + customer = await getUser(zammad, phoneToSearch); + if (customer) { + logger.info({ customerId: customer.id, method: 'phone' }, 'Found existing user by phone'); + } + } + + if (!customer && email_address) { + // Search by email if phone search didn't work + const emailResults = await zammad.user.search(`email:${email_address}`); + if (emailResults.length > 0) { + customer = emailResults[0]; + logger.info({ customerId: customer.id, method: 'email' }, 'Found existing user by email'); + } + } + + if (!customer) { + // Create new user with all available contact information + logger.info('Creating new user from form submission'); customer = await zammad.user.create({ - firstname: name?.first, - lastname: name?.last, + firstname: name?.first || '', + lastname: name?.last || '', + email: email_address || `${UniqueID}@formstack.local`, + phone: signal_number || phone_number || '', note: `User created from Formstack submission ${UniqueID}`, }); } - logger.info({ customerId: customer.id, customerEmail: customer.email }, 'Customer identified/created'); + logger.info({ + customerId: customer.id, + customerEmail: customer.email, + customerPhone: customer.phone, + }, 'Customer identified/created'); - // Create the ticket + // Build address parts + const streetAddress = address?.address || ''; + const cityValue = address?.city || ''; + const stateValue = address?.state || ''; + const zipValue = address?.zip || ''; + + // Create the ticket with custom fields mapped to Zammad attributes + // Following the pattern from ngo-isac-uploader where all form data + // goes into structured fields rather than HTML body const ticket = await zammad.ticket.create({ title, group: "Users", // Default group - you may want to make this configurable - note: `This ticket was created automatically from Formstack form ${FormID}.`, customer_id: customer.id, + + // Custom fields - these will be populated in Zammad's ticket attributes + // NOTE: 'organization', 'formstack_form_id', 'formstack_submission_id' + // fields could not be created due to naming conflicts, so metadata + // is included in the ticket body instead + signal_number: signal_number || undefined, + type_of_help_requested: type_of_help_requested || undefined, + type_of_organization: type_of_organization || undefined, + urgency_level: urgency_level || undefined, + city: cityValue || undefined, + us_state: stateValue || undefined, + zip_code: zipValue || undefined, + street_address: streetAddress || undefined, + preferred_contact_method: preferred_contact_method || undefined, + available_times: available_times_for_contact || undefined, + where_heard: how_did_you_hear_about_us || undefined, + preferred_language: preferred_language || undefined, + + // Article with just the description article: { body, subject: title, diff --git a/docker/compose/link.yml b/docker/compose/link.yml index 5cc1ded..0ad481f 100644 --- a/docker/compose/link.yml +++ b/docker/compose/link.yml @@ -33,4 +33,5 @@ services: DATABASE_USER: ${DATABASE_USER} DATABASE_PASSWORD: ${DATABASE_PASSWORD} DATABASE_URL: ${DATABASE_URL} + FORMSTACK_SHARED_SECRET: ${FORMSTACK_SHARED_SECRET} LOG_LEVEL: debug