diff --git a/apps/bridge-worker/tasks/fetch-signal-messages.ts b/apps/bridge-worker/tasks/fetch-signal-messages.ts index bd7a470..aa1a612 100644 --- a/apps/bridge-worker/tasks/fetch-signal-messages.ts +++ b/apps/bridge-worker/tasks/fetch-signal-messages.ts @@ -58,7 +58,7 @@ const processMessage = async ({ const { attachments } = dataMessage; const rawTimestamp = dataMessage?.timestamp; - + // Debug logging for group detection console.log(`[fetch-signal-messages] Processing message:`, { sourceUuid, @@ -77,22 +77,13 @@ const processMessage = async ({ const formattedAttachments = await fetchAttachments(attachments); const primaryAttachment = formattedAttachments[0] ?? {}; const additionalAttachments = formattedAttachments.slice(1); - - // Extract group ID if this is a group message - const groupId = dataMessage?.groupV2?.id || dataMessage?.groupContext?.id || dataMessage?.groupInfo?.groupId; - - // IMPORTANT: Always use phoneNumber as 'to' for compatibility with Zammad - // The group ID will be passed via the isGroup flag and potentially in metadata - const toRecipient = phoneNumber; - - console.log(`[fetch-signal-messages] Setting recipient:`, { - isGroup, - groupId, - phoneNumber, - toRecipient, - note: 'Using phoneNumber as to for Zammad compatibility', - }); - + + const groupId = + dataMessage?.groupV2?.id || + dataMessage?.groupContext?.id || + dataMessage?.groupInfo?.groupId; + const toRecipient = groupId ?? phoneNumber; + const primaryMessage = { token: id, to: toRecipient, @@ -104,8 +95,6 @@ const processMessage = async ({ filename: primaryAttachment.filename, mimeType: primaryAttachment.mimeType, isGroup, - // Include groupId if this is a group message - ...(isGroup && groupId ? { groupId } : {}), }; const formattedMessages = [primaryMessage]; @@ -157,8 +146,10 @@ const fetchSignalMessagesTask = async ({ number: phoneNumber, }); - console.log(`[fetch-signal-messages] Fetching messages for bot ${id} (${phoneNumber})`); - + console.log( + `[fetch-signal-messages] Fetching messages for bot ${id} (${phoneNumber})`, + ); + for (const message of messages) { const formattedMessages = await processMessage({ id, @@ -175,7 +166,7 @@ const fetchSignalMessagesTask = async ({ hasMessage: !!formattedMessage.message, hasAttachment: !!formattedMessage.attachment, }); - + await worker.addJob( "signal/receive-signal-message", formattedMessage, diff --git a/apps/bridge-worker/tasks/signal/receive-signal-message.ts b/apps/bridge-worker/tasks/signal/receive-signal-message.ts index 9401f9a..abdec2f 100644 --- a/apps/bridge-worker/tasks/signal/receive-signal-message.ts +++ b/apps/bridge-worker/tasks/signal/receive-signal-message.ts @@ -13,7 +13,6 @@ interface ReceiveSignalMessageTaskOptions { filename?: string; mimeType?: string; isGroup?: boolean; - groupId?: string; // Group ID from the message envelope } const receiveSignalMessageTask = async ({ @@ -27,18 +26,15 @@ const receiveSignalMessageTask = async ({ filename, mimeType, isGroup, - groupId, }: ReceiveSignalMessageTaskOptions): Promise => { console.log(`[receive-signal-message] Processing incoming message:`, { messageId, from, to, isGroup, - groupId, hasMessage: !!message, hasAttachment: !!attachment, token, - toFormat: to?.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i) ? 'UUID' : 'phone', }); const worker = await getWorkerUtils(); const row = await db @@ -53,7 +49,7 @@ const receiveSignalMessageTask = async ({ // Check if auto-group creation is enabled and this is NOT already a group message const enableAutoGroups = process.env.BRIDGE_SIGNAL_AUTO_GROUPS === "true"; - + console.log(`[receive-signal-message] Auto-groups config:`, { enableAutoGroups, isGroup, @@ -61,11 +57,15 @@ const receiveSignalMessageTask = async ({ }); // If this is already a group message and auto-groups is enabled, - // use the provided groupId or keep the original 'to' - if (enableAutoGroups && isGroup && groupId) { - // Store the group ID for metadata but keep using phone number for 'to' - console.log(`[receive-signal-message] Message is from existing group: ${groupId}`); - finalTo = groupId; // Store for metadata + // use group provided in 'to' + if (enableAutoGroups && isGroup && to) { + // Signal sends the internal ID (base64) in group messages + // We should NOT add "group." prefix - that's for sending messages, not receiving + console.log( + `[receive-signal-message] Message is from existing group with internal ID`, + ); + + finalTo = to; } else if (enableAutoGroups && !isGroup && from && to) { try { const config = new Configuration({ @@ -73,8 +73,20 @@ const receiveSignalMessageTask = async ({ }); const groupsClient = new GroupsApi(config); + // Always create a new group for direct messages to the helpdesk + // This ensures each conversation gets its own group/ticket + console.log( + `[receive-signal-message] Creating new group for user ${from}`, + ); + + // Include timestamp to make each group unique + const timestamp = new Date() + .toISOString() + .replace(/[:.]/g, "-") + .substring(0, 19); + const groupName = `Support: ${from} (${timestamp})`; + // Create new group for this conversation - const groupName = `Support: ${from}`; const createGroupResponse = await groupsClient.v1GroupsNumberPost({ number: row.phoneNumber, data: { @@ -84,118 +96,140 @@ const receiveSignalMessageTask = async ({ }, }); + console.log( + `[receive-signal-message] Full group creation response from Signal API:`, + JSON.stringify(createGroupResponse, null, 2), + ); + if (createGroupResponse.id) { - // We need to get the internal_id for this group - // Sometimes the API needs a moment to return the new group, so retry if needed - let internalId: string | undefined; - let retries = 3; - - while (retries > 0 && !internalId) { - try { - const groupsResponse = await groupsClient.v1GroupsNumberGet({ - number: row.phoneNumber, - }); - - // Find the group we just created to get its internal_id - const createdGroup = groupsResponse.find(g => g.id === createGroupResponse.id); - internalId = createdGroup?.internal_id; - - if (!internalId && retries > 1) { - console.log(`[receive-signal-message] Group not found in list yet, retrying...`); - await new Promise(resolve => setTimeout(resolve, 1000)); - } - } catch (error) { - console.error(`[receive-signal-message] Error fetching groups:`, error); - } - retries--; - } - - createdInternalId = internalId; // Store for use in webhook payload - - if (!internalId) { - console.warn( - `[receive-signal-message] Warning: Could not get internal_id for group ${createGroupResponse.id}. Group matching may fail for subsequent messages.`, - ); - } else { - console.log( - `[receive-signal-message] Successfully retrieved internal_id: ${internalId} for group: ${createGroupResponse.id}`, - ); - } - + // The createGroupResponse.id already contains the full group identifier (group.BASE64) finalTo = createGroupResponse.id; - console.log( - `[receive-signal-message] Created new Signal group:`, - { - groupId: finalTo, - internalId, - groupName, - forPhoneNumber: from, - botNumber: row.phoneNumber, - response: createGroupResponse, - }, - ); - // Send a system notification to Zammad about group creation + // Fetch the group details to get the actual internalId + // The base64 part of the ID is NOT the same as the internalId! try { - const systemNote = `Signal Auto-Group Created\n` + - `Group Name: ${groupName}\n` + - `Group ID: ${finalTo}\n\n` + - `Note: The user's initial message has been forwarded to the Signal group with attribution.`; - - await worker.addJob("common/notify-webhooks", { - backendId, - payload: { - to: to, - from: "system", - message_id: `system-group-created-${Date.now()}`, - sent_at: new Date().toISOString(), - message: systemNote, - isGroup: true, - group_id: finalTo, - internal_group_id: internalId, // Also pass the internal_id - internal: true, // Mark as internal note - system_message: true // Additional flag to indicate system message - } + console.log( + `[receive-signal-message] Fetching group details to get internalId...`, + ); + const groups = await groupsClient.v1GroupsNumberGet({ + number: row.phoneNumber, }); - - console.log(`[receive-signal-message] Sent group creation notification to Zammad`); - } catch (notifyError) { - console.error("[receive-signal-message] Error sending system notification:", notifyError); - // Continue processing even if notification fails + + console.log( + `[receive-signal-message] All groups for bot:`, + JSON.stringify(groups.slice(0, 3), null, 2), // Show first 3 to avoid too much output + ); + + const createdGroup = groups.find((g) => g.id === finalTo); + if (createdGroup) { + console.log( + `[receive-signal-message] Found created group details:`, + JSON.stringify(createdGroup, null, 2), + ); + } + + if (createdGroup && createdGroup.internalId) { + createdInternalId = createdGroup.internalId; + console.log( + `[receive-signal-message] Got actual internalId: ${createdInternalId}`, + ); + } else { + // Fallback: extract base64 part from ID + if (finalTo.startsWith("group.")) { + createdInternalId = finalTo.substring(6); + } + } + } catch (fetchError) { + console.log( + `[receive-signal-message] Could not fetch group details, using ID base64 part`, + ); + // Fallback: extract base64 part from ID + if (finalTo.startsWith("group.")) { + createdInternalId = finalTo.substring(6); + } } + console.log(`[receive-signal-message] Group created successfully:`, { + fullGroupId: finalTo, + internalId: createdInternalId, + }); + console.log(`[receive-signal-message] Created new Signal group:`, { + groupId: finalTo, + internalId: createdInternalId, + groupName, + forPhoneNumber: from, + botNumber: row.phoneNumber, + response: createGroupResponse, + }); + } + + // Now handle notifications and message forwarding for both new and existing groups + if (finalTo && finalTo.startsWith("group.")) { // Forward the user's initial message to the group using quote feature try { - console.log(`[receive-signal-message] Forwarding initial message to group using quote feature`); - - // Build the attribution message + console.log( + `[receive-signal-message] Forwarding initial message to group using quote feature`, + ); + const attributionMessage = `Message from ${from}:\n"${message}"\n\n---\nSupport team: Your request has been received. An agent will respond shortly.`; - + await worker.addJob("signal/send-signal-message", { - token: backendId, - to: finalTo, // Send to the newly created group + token: row.token, + to: finalTo, message: attributionMessage, - conversationId: null, // No ticket ID yet since we're still processing the initial message - // Quote the original message for context + conversationId: null, quoteMessage: message, quoteAuthor: from, - quoteTimestamp: Date.parse(sentAt), // Convert ISO string to milliseconds + quoteTimestamp: Date.parse(sentAt), }); - - console.log(`[receive-signal-message] Successfully forwarded initial message to group ${finalTo}`); + + console.log( + `[receive-signal-message] Successfully forwarded initial message to group ${finalTo}`, + ); } catch (forwardError) { - console.error("[receive-signal-message] Error forwarding message to group:", forwardError); - // Continue processing even if forwarding fails + console.error( + "[receive-signal-message] Error forwarding message to group:", + forwardError, + ); + } + + // Send a response to the original DM informing about the group + try { + console.log( + `[receive-signal-message] Sending group notification to original DM`, + ); + + const dmNotification = `Hello! A private support group has been created for your conversation.\n\nGroup name: ${groupName}\n\nPlease look for the new group in your Signal app to continue the conversation. Our support team will respond there shortly.\n\nThank you for contacting support!`; + + await worker.addJob("signal/send-signal-message", { + token: row.token, + to: from, + message: dmNotification, + conversationId: null, + }); + + console.log( + `[receive-signal-message] Successfully sent group notification to user DM`, + ); + } catch (dmError) { + console.error( + "[receive-signal-message] Error sending DM notification:", + dmError, + ); } } } catch (error: any) { // Check if error is because group already exists - const errorMessage = error?.response?.data?.error || error?.message || error; - const isAlreadyExists = errorMessage?.toString().toLowerCase().includes('already') || - errorMessage?.toString().toLowerCase().includes('exists'); - + const errorMessage = + error?.response?.data?.error || error?.message || error; + const isAlreadyExists = + errorMessage?.toString().toLowerCase().includes("already") || + errorMessage?.toString().toLowerCase().includes("exists"); + if (isAlreadyExists) { - console.log(`[receive-signal-message] Group might already exist for ${from}, continuing with original recipient`); + console.log( + `[receive-signal-message] Group might already exist for ${from}, continuing with original recipient`, + ); } else { console.error("[receive-signal-message] Error creating Signal group:", { error: errorMessage, @@ -204,17 +238,11 @@ const receiveSignalMessageTask = async ({ botNumber: row.phoneNumber, }); } - // Continue with original 'to' if group creation fails } } - // WORKAROUND: Zammad doesn't accept UUID group IDs in the 'to' field - // Instead, we use the bot's phone number and include group metadata - const isGroupMessage = isGroup || finalTo !== to || !!groupId; - const effectiveGroupId = groupId || (finalTo !== to ? finalTo : undefined); - const payload = { - to: to, // Always use the bot's phone number, not the group ID + to: finalTo, from, message_id: messageId, sent_at: sentAt, @@ -222,25 +250,8 @@ const receiveSignalMessageTask = async ({ attachment, filename, mime_type: mimeType, - isGroup: isGroupMessage, - // Include group ID as metadata if this is a group message - ...(effectiveGroupId ? { group_id: effectiveGroupId } : {}), - // Include internal_group_id if we created a new group - ...(createdInternalId ? { internal_group_id: createdInternalId } : {}), + is_group: finalTo.startsWith("group"), }; - - console.log(`[receive-signal-message] Sending webhook notification:`, { - backendId, - originalTo: to, - finalTo, - toChanged: to !== finalTo, - payloadIsGroup: payload.isGroup, - payloadTo: payload.to, - payloadGroupId: (payload as any).group_id, - payloadInternalGroupId: (payload as any).internal_group_id, - messageId: payload.message_id, - createdNewGroup: !!createdInternalId, - }); await worker.addJob("common/notify-webhooks", { backendId, payload }); }; diff --git a/apps/bridge-worker/tasks/signal/send-signal-message.ts b/apps/bridge-worker/tasks/signal/send-signal-message.ts index 6ae90d2..94ed34a 100644 --- a/apps/bridge-worker/tasks/signal/send-signal-message.ts +++ b/apps/bridge-worker/tasks/signal/send-signal-message.ts @@ -45,13 +45,13 @@ const sendSignalMessageTask = async ({ let groupCreated = false; try { - // Check if 'to' is a group ID (UUID format) vs phone number - const isGroupId = - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test( - to, - ); + // Check if 'to' is a group ID (UUID format, group.base64 format, or base64) vs phone number + const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(to); + const isGroupPrefix = to.startsWith('group.'); + const isBase64 = /^[A-Za-z0-9+/]+=*$/.test(to) && to.length > 20; // Base64 internal_id + const isGroupId = isUUID || isGroupPrefix || isBase64; const enableAutoGroups = process.env.BRIDGE_SIGNAL_AUTO_GROUPS === "true"; - + console.log(`[send-signal-message] Recipient analysis:`, { to, isGroupId, @@ -73,44 +73,46 @@ const sendSignalMessageTask = async ({ }); if (createGroupResponse.id) { - // Get the internal_id for this group - // Sometimes the API needs a moment to return the new group, so retry if needed - let internalId: string | undefined; - let retries = 3; - - while (retries > 0 && !internalId) { - try { - const groupsResponse = await groupsClient.v1GroupsNumberGet({ - number: bot.phoneNumber, - }); - - // Find the group we just created to get its internal_id - const createdGroup = groupsResponse.find(g => g.id === createGroupResponse.id); - internalId = createdGroup?.internal_id; - - if (!internalId && retries > 1) { - console.log(`[send-signal-message] Group not found in list yet, retrying...`); - await new Promise(resolve => setTimeout(resolve, 1000)); - } - } catch (error) { - console.error(`[send-signal-message] Error fetching groups:`, error); - } - retries--; - } - + // The createGroupResponse.id already contains the full group identifier (group.BASE64) finalTo = createGroupResponse.id; groupCreated = true; - console.log( - `[send-signal-message] Created new Signal group:`, - { - groupId: finalTo, - internalId, - groupName, - conversationId, - originalRecipient: to, - botNumber: bot.phoneNumber, - }, - ); + + // Fetch the group details to get the actual internalId + let internalId: string | undefined; + try { + const groups = await groupsClient.v1GroupsNumberGet({ + number: bot.phoneNumber, + }); + + const createdGroup = groups.find(g => g.id === finalTo); + if (createdGroup && createdGroup.internalId) { + internalId = createdGroup.internalId; + console.log( + `[send-signal-message] Got actual internalId: ${internalId}`, + ); + } else { + // Fallback: extract base64 part from ID + if (finalTo.startsWith('group.')) { + internalId = finalTo.substring(6); + } + } + } catch (fetchError) { + console.log( + `[send-signal-message] Could not fetch group details, using ID base64 part`, + ); + // Fallback: extract base64 part from ID + if (finalTo.startsWith('group.')) { + internalId = finalTo.substring(6); + } + } + console.log(`[send-signal-message] Created new Signal group:`, { + groupId: finalTo, + internalId, + groupName, + conversationId, + originalRecipient: to, + botNumber: bot.phoneNumber, + }); // Notify Zammad about the new group ID via webhook await worker.addJob("common/notify-webhooks", { @@ -141,24 +143,32 @@ const sendSignalMessageTask = async ({ originalTo: to, recipientChanged: to !== finalTo, groupCreated, + isGroupRecipient: finalTo.startsWith('group.'), }); - + // Build the message data with optional quote parameters const messageData: signalApi.ApiSendMessageV2 = { number, recipients: [finalTo], message, }; + + console.log(`[send-signal-message] Message data being sent:`, { + number, + recipients: [finalTo], + message: message.substring(0, 50) + '...', + hasQuoteParams: !!(quoteMessage && quoteAuthor && quoteTimestamp), + }); // Add quote parameters if all are provided if (quoteMessage && quoteAuthor && quoteTimestamp) { messageData.quoteTimestamp = quoteTimestamp; messageData.quoteAuthor = quoteAuthor; messageData.quoteMessage = quoteMessage; - + console.log(`[send-signal-message] Including quote in message:`, { quoteAuthor, - quoteMessage: quoteMessage.substring(0, 50) + '...', + quoteMessage: quoteMessage.substring(0, 50) + "...", quoteTimestamp, }); } @@ -167,16 +177,32 @@ const sendSignalMessageTask = async ({ data: messageData, }); - console.log( - `[send-signal-message] Message sent successfully:`, - { - to: finalTo, - groupCreated, - response: response?.timestamp || 'no timestamp', - }, - ); - } catch (error) { - console.error({ error }); + console.log(`[send-signal-message] Message sent successfully:`, { + to: finalTo, + groupCreated, + response: response?.timestamp || "no timestamp", + }); + } catch (error: any) { + // Try to get the actual error message from the response + if (error.response) { + try { + const errorBody = await error.response.text(); + console.error(`[send-signal-message] Signal API error:`, { + status: error.response.status, + statusText: error.response.statusText, + body: errorBody, + sentTo: finalTo, + messageDetails: { + fromNumber: number, + toRecipients: [finalTo], + hasQuote: !!(quoteMessage), + }, + }); + } catch (e) { + console.error(`[send-signal-message] Could not parse error response`); + } + } + console.error(`[send-signal-message] Full error:`, error); throw error; } }; diff --git a/packages/zammad-addon-bridge/src/app/controllers/channels_cdr_signal_controller.rb b/packages/zammad-addon-bridge/src/app/controllers/channels_cdr_signal_controller.rb index 1837726..010de95 100644 --- a/packages/zammad-addon-bridge/src/app/controllers/channels_cdr_signal_controller.rb +++ b/packages/zammad-addon-bridge/src/app/controllers/channels_cdr_signal_controller.rb @@ -147,17 +147,11 @@ class ChannelsCdrSignalController < ApplicationController receiver_phone_number = params[:to].strip sender_phone_number = params[:from].strip - # Check if this is a group message using the isGroup flag from bridge-worker + # Check if this is a group message using the is_group flag from bridge-worker # This flag is set when: # 1. The original message came from a Signal group # 2. Bridge-worker created a new group for the conversation - # Note: We can't rely on UUID format alone because users with privacy settings - # may have UUID identifiers instead of phone numbers - is_group_message = params[:isGroup] == true || params[:is_group] == true - # Group ID is now sent as a separate field to avoid 422 errors - # when 'to' contains a UUID instead of a phone number - group_id = params[:group_id] || (is_group_message ? params[:to] : nil) - + is_group_message = params[:is_group].to_s == 'true' || params[:is_group].to_s == 'true' customer = User.find_by(phone: sender_phone_number) customer ||= User.find_by(mobile: sender_phone_number) @@ -211,47 +205,38 @@ class ChannelsCdrSignalController < ApplicationController # find ticket or create one state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id) - # For group messages, find ticket by group_id (either UUID or internal_id) - # Signal uses two different IDs for the same group: - # - UUID (management ID): returned when creating groups via API - # - internal_id (base64): used in message envelopes - if is_group_message && group_id + if is_group_message Rails.logger.info "=== SIGNAL GROUP TICKET LOOKUP ===" - Rails.logger.info "Looking for ticket with group_id: #{group_id}" + Rails.logger.info "Looking for ticket with group_id: #{receiver_phone_number}" Rails.logger.info "Customer ID: #{customer.id}" + Rails.logger.info "Customer Phone: #{sender_phone_number}" Rails.logger.info "Channel ID: #{channel.id}" - + begin - # Find ticket using Ruby filtering to match group_id or internal_group_id all_tickets = Ticket.where(customer_id: customer.id) .where.not(state_id: state_ids) - .order(:updated_at) - + .order(updated_at: :desc) + Rails.logger.info "Found #{all_tickets.count} active tickets for customer" - + ticket = all_tickets.find do |t| begin has_preferences = t.preferences.is_a?(Hash) has_cdr_signal = has_preferences && t.preferences['cdr_signal'].is_a?(Hash) - - if has_cdr_signal - stored_group_id = t.preferences['cdr_signal']['group_id'] - stored_internal_id = t.preferences['cdr_signal']['internal_group_id'] - stored_channel_id = t.preferences['channel_id'] - - Rails.logger.info "Ticket ##{t.number} (ID: #{t.id}):" - Rails.logger.info " - stored_group_id: #{stored_group_id}" - Rails.logger.info " - stored_internal_id: #{stored_internal_id}" - Rails.logger.info " - stored_channel_id: #{stored_channel_id}" - Rails.logger.info " - incoming_group_id: #{group_id}" - - # Match on either the UUID or the internal_id - matches = group_id == stored_group_id || group_id == stored_internal_id + has_channel_id = has_preferences && t.preferences['channel_id'] == channel.id + + if has_cdr_signal && has_channel_id + stored_chat_id = t.preferences['cdr_signal']['chat_id'] + + Rails.logger.info " - stored_chat_id: #{stored_chat_id}" + Rails.logger.info " - incoming_group_id: #{receiver_phone_number}" + + matches = receiver_phone_number == chat_id Rails.logger.info " - MATCH: #{matches}" - + matches else - Rails.logger.info "Ticket ##{t.number} has no cdr_signal preferences" + Rails.logger.info "Ticket ##{t.number} has no cdr_signal preferences or wrong channel" false end rescue => e @@ -259,15 +244,15 @@ class ChannelsCdrSignalController < ApplicationController false end end - + if ticket - Rails.logger.info "=== FOUND MATCHING TICKET: ##{ticket.number} ===" + Rails.logger.info "=== FOUND MATCHING TICKET BY GROUP ID: ##{ticket.number} ===" else - Rails.logger.info "=== NO MATCHING TICKET FOUND - WILL CREATE NEW ===" + Rails.logger.info "=== NO MATCHING TICKET BY GROUP ID - CHECKING BY PHONE NUMBER ===" end - rescue ActiveRecord::StatementInvalid => e - Rails.logger.error "Error finding ticket by group_id: #{e.message}" - ticket = nil + rescue => e + Rails.logger.error "Error during group ticket lookup: #{e.message}" + Rails.logger.error e.backtrace.join("\n") end else Rails.logger.info "Not a group message or no group_id, finding most recent ticket" @@ -281,28 +266,19 @@ class ChannelsCdrSignalController < ApplicationController ticket.state = Ticket::State.find_by(default_follow_up: true) if ticket.state_id != new_state.id else # Set up chat_id based on whether this is a group message - chat_id = is_group_message ? group_id : sender_phone_number + chat_id = is_group_message ? receiver_phone_number : sender_phone_number # Build preferences with group_id included if needed cdr_signal_prefs = { bot_token: channel.options[:bot_token], # change to bot id chat_id: chat_id } - - # Add group_id to preferences if this is a group message - if is_group_message && group_id - cdr_signal_prefs[:group_id] = group_id - # Also store internal_group_id if provided - cdr_signal_prefs[:internal_group_id] = params[:internal_group_id] if params[:internal_group_id].present? - - Rails.logger.info "Creating ticket with group preferences: group_id=#{group_id}, internal_group_id=#{params[:internal_group_id]}" - end - + Rails.logger.info "=== CREATING NEW TICKET ===" Rails.logger.info "Preferences to be stored:" Rails.logger.info " - channel_id: #{channel.id}" Rails.logger.info " - cdr_signal: #{cdr_signal_prefs.inspect}" - + ticket = Ticket.new( group_id: channel.group_id, title: title, @@ -316,21 +292,16 @@ class ChannelsCdrSignalController < ApplicationController ticket.save! - # Check if this is a system message - is_system_message = params[:system_message] == true || params[:from] == 'system' - article_params = { from: sender_phone_number, to: receiver_phone_number, - sender_id: is_system_message ? - Ticket::Article::Sender.find_by(name: 'System').id : - Ticket::Article::Sender.find_by(name: 'Customer').id, + sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id, subject: title, body: body, content_type: 'text/plain', message_id: "cdr_signal.#{message_id}", ticket_id: ticket.id, - internal: params[:internal] == true || is_system_message, + internal: params[:internal] == true, preferences: { cdr_signal: { timestamp: sent_at, @@ -357,9 +328,7 @@ class ChannelsCdrSignalController < ApplicationController ticket.with_lock do ta = article_create(ticket, article_params) - # Use 'note' type for system messages, 'cdr_signal' for regular messages - article_type = is_system_message ? 'note' : 'cdr_signal' - ta.update!(type_id: Ticket::Article::Type.find_by(name: article_type).id) + ta.update!(type_id: Ticket::Article::Type.find_by(name: 'cdr_signal').id) end ticket.update!(create_article_type_id: Ticket::Article::Type.find_by(name: 'cdr_signal').id) @@ -406,7 +375,7 @@ class ChannelsCdrSignalController < ApplicationController # Find the ticket by ID or number # Try to find by both ID and number since ticket numbers can be numeric - ticket = Ticket.find_by(id: params[:conversation_id]) || + ticket = Ticket.find_by(id: params[:conversation_id]) || Ticket.find_by(number: params[:conversation_id]) unless ticket @@ -418,8 +387,6 @@ class ChannelsCdrSignalController < ApplicationController # Update ticket preferences with the group information ticket.preferences ||= {} ticket.preferences[:cdr_signal] ||= {} - ticket.preferences[:cdr_signal][:group_id] = params[:group_id] - ticket.preferences[:cdr_signal][:internal_group_id] = params[:internal_group_id] if params[:internal_group_id].present? ticket.preferences[:cdr_signal][:chat_id] = params[:group_id] ticket.preferences[:cdr_signal][:original_recipient] = params[:original_recipient] if params[:original_recipient].present? ticket.preferences[:cdr_signal][:group_created_at] = params[:timestamp] if params[:timestamp].present?