[], 'reminders' => [], 'reconfirmations' => [], 'actions' => [], 'reconfirmation_replies' => [], ]; // 1. Load synced Twilio templates from whatsapp_templates setting $templateSetting = WhatsappTemplate::where('restaurant_id', $restaurantId)->first(); if (!$templateSetting) { return $result; } $twilioTemplates = $templateSetting->templates ?? []; if (empty($twilioTemplates)) { return $result; } // Index Twilio templates by name for quick lookup // Also group by language $twilioByNameAndLang = []; foreach ($twilioTemplates as $t) { $name = $t['name'] ?? ''; $lang = $t['language'] ?? ''; if ($name && $lang) { $twilioByNameAndLang[$name . '::' . $lang] = $t; } } // 2. Load default template definitions from JSON files $defaultTemplatesPath = defined('ALEXR_DIR_TEMPLATES_WHATSAPP') ? ALEXR_DIR_TEMPLATES_WHATSAPP : ''; if (!$defaultTemplatesPath || !is_dir($defaultTemplatesPath)) { return $result; } // Load all language JSON files $defaultTemplatesByLang = []; $files = glob($defaultTemplatesPath . 'templates_*.json'); foreach ($files as $file) { if (preg_match('/templates_([a-z]{2})\.json$/', $file, $matches)) { $langCode = $matches[1]; $content = file_get_contents($file); $decoded = json_decode($content, true); if (is_array($decoded)) { $defaultTemplatesByLang[$langCode] = $decoded; } } } if (empty($defaultTemplatesByLang)) { return $result; } // 3. Build mapping from JSON template key -> setting key // In JSON: booking_confirmed -> In settings: booking_booked // In JSON: booking_user_reconfirmed -> In settings: booking_confirmed $jsonKeyToSettingKey = [ 'booking_pending' => 'booking_pending', 'booking_pending_payment' => 'booking_pending_payment', 'booking_confirmed' => 'booking_booked', 'booking_user_reconfirmed' => 'booking_confirmed', 'booking_denied' => 'booking_denied', 'booking_cancelled' => 'booking_cancelled', 'booking_no_show' => 'booking_no_show', 'booking_finished' => 'booking_finished', ]; // 4. For each JSON template, build a list of possible Twilio template name // patterns. The JSON template_name is the exact name used when uploading // to Twilio (e.g. "booking_confirmed_es"). But users might also have // custom templates with different names, so we match by template_name from JSON. // Build: jsonKey => lang => template_name (from JSON) $jsonTemplateNames = []; foreach ($defaultTemplatesByLang as $lang => $templates) { foreach ($templates as $jsonKey => $tmplDef) { $templateName = $tmplDef['template_name'] ?? ''; if ($templateName) { $jsonTemplateNames[$jsonKey][$lang] = $templateName; } } } // 5. Find the best Twilio template match for a given JSON template key + language // Strategy: look for a Twilio template whose name matches the JSON template_name // exactly, or starts with the base prefix. $findTwilioTemplate = function($jsonKey, $lang) use ($twilioTemplates, $jsonTemplateNames) { $expectedName = $jsonTemplateNames[$jsonKey][$lang] ?? ''; // First: exact match by template_name from JSON if ($expectedName) { foreach ($twilioTemplates as $t) { if (($t['name'] ?? '') === $expectedName && ($t['language'] ?? '') === $lang) { return $t; } } } // Second: match by prefix pattern. The JSON template_name follows the pattern // "{base_name}_{lang}" so we can extract the base and match any template // whose name starts with that base and has the correct language. $baseName = $expectedName ? preg_replace('/_' . preg_quote($lang, '/') . '$/', '', $expectedName) : $jsonKey; // For "booking_confirmed" JSON key, baseName would be "booking_confirmed" // For "reminder" JSON key, baseName would be "booking_reminder" (from template_name) // For "reconfirmation" JSON key, baseName would be "booking_reconfirmation" foreach ($twilioTemplates as $t) { $tName = $t['name'] ?? ''; $tLang = $t['language'] ?? ''; if ($tLang !== $lang) continue; // Check if the Twilio template name starts with the base name if (strpos($tName, $baseName) === 0) { return $t; } } return null; }; // Helper to build field_mapping from a JSON template definition's variables // and a Twilio template's variables $buildFieldMapping = function($jsonTemplateDef, $twilioTemplate) { $jsonVariables = $jsonTemplateDef['variables'] ?? []; $twilioVariables = $twilioTemplate['variables'] ?? []; $fieldMapping = []; // The JSON variables map is: templateVar => bookingField // We want the field_mapping to be: templateVar => bookingField // but only for variables that actually exist in the Twilio template if (!empty($twilioVariables)) { foreach ($twilioVariables as $varName => $exampleValue) { if (isset($jsonVariables[$varName])) { $fieldMapping[$varName] = $jsonVariables[$varName]; } } } else { // If Twilio template has no variables info, use the JSON definition $fieldMapping = $jsonVariables; } return $fieldMapping; }; // 6. Map whatsapp_messages $messageSetting = WhatsappMessage::where('restaurant_id', $restaurantId)->first(); $isNewMessageSetting = false; if (!$messageSetting) { $messageSetting = new WhatsappMessage; $messageSetting->restaurant_id = $restaurantId; $messageSetting->setupDefaultValues()->save(); $isNewMessageSetting = true; } if ($messageSetting) { $languages = evavel_languages_allowed(); $changed = false; foreach ($jsonKeyToSettingKey as $jsonKey => $settingKey) { $currentValue = $messageSetting->{$settingKey}; if (!is_array($currentValue)) { $currentValue = []; } foreach ($languages as $lang => $label) { // Check if already mapped $existing = $currentValue[$lang] ?? []; if (!empty($existing['template_sid'])) { continue; // Already mapped, skip } // Find matching Twilio template $twilioMatch = $findTwilioTemplate($jsonKey, $lang); if (!$twilioMatch) { continue; } // Get JSON definition for field mapping $jsonDef = $defaultTemplatesByLang[$lang][$jsonKey] ?? null; if (!$jsonDef) { continue; } $fieldMapping = $buildFieldMapping($jsonDef, $twilioMatch); $currentValue[$lang] = [ 'template_sid' => $twilioMatch['sid'] ?? $twilioMatch['id'] ?? '', 'template_name' => $twilioMatch['name'] ?? '', 'field_mapping' => $fieldMapping, ]; $result['messages'][] = $settingKey . '/' . $lang . ' -> ' . ($twilioMatch['name'] ?? ''); $changed = true; } $messageSetting->{$settingKey} = $currentValue; } // Enable booking_pending and booking_booked by default only on first creation if ($isNewMessageSetting) { $messageSetting->booking_pending_enable = 1; $messageSetting->booking_booked_enable = 1; $changed = true; } if ($changed) { $messageSetting->save(); } } // 7. Map whatsapp_reminder(s) $reminders = WhatsappReminder::where('restaurant_id', $restaurantId)->get(); if (!$reminders || count($reminders) === 0) { $reminder = new WhatsappReminder; $reminder->restaurant_id = $restaurantId; $reminder->setupDefaultValues()->save(); $reminders = [$reminder]; } if ($reminders) { $languages = evavel_languages_allowed(); foreach ($reminders as $reminder) { $currentValue = $reminder->whatsapp_reminder; if (!is_array($currentValue)) { $currentValue = []; } $changed = false; foreach ($languages as $lang => $label) { $existing = $currentValue[$lang] ?? []; if (!empty($existing['template_sid'])) { continue; } $twilioMatch = $findTwilioTemplate('reminder', $lang); if (!$twilioMatch) { continue; } $jsonDef = $defaultTemplatesByLang[$lang]['reminder'] ?? null; if (!$jsonDef) { continue; } $fieldMapping = $buildFieldMapping($jsonDef, $twilioMatch); $currentValue[$lang] = [ 'template_sid' => $twilioMatch['sid'] ?? $twilioMatch['id'] ?? '', 'template_name' => $twilioMatch['name'] ?? '', 'field_mapping' => $fieldMapping, ]; $result['reminders'][] = 'reminder#' . $reminder->id . '/' . $lang . ' -> ' . ($twilioMatch['name'] ?? ''); $changed = true; } if ($changed) { $reminder->whatsapp_reminder = $currentValue; $reminder->save(); } } } // 8. Map whatsapp_reconfirmation(s) $reconfirmations = WhatsappReconfirmation::where('restaurant_id', $restaurantId)->get(); if (!$reconfirmations || count($reconfirmations) === 0) { $reconfirmation = new WhatsappReconfirmation; $reconfirmation->restaurant_id = $restaurantId; $reconfirmation->setupDefaultValues()->save(); $reconfirmations = [$reconfirmation]; } if ($reconfirmations) { $languages = evavel_languages_allowed(); foreach ($reconfirmations as $reconfirmation) { $currentValue = $reconfirmation->whatsapp_reconfirmation; if (!is_array($currentValue)) { $currentValue = []; } $changed = false; foreach ($languages as $lang => $label) { $existing = $currentValue[$lang] ?? []; if (!empty($existing['template_sid'])) { continue; } $twilioMatch = $findTwilioTemplate('reconfirmation', $lang); if (!$twilioMatch) { // Also try "reconfirm" prefix since some templates use that foreach ($twilioTemplates as $t) { $tName = $t['name'] ?? ''; $tLang = $t['language'] ?? ''; if ($tLang === $lang && strpos($tName, 'reconfirm') === 0) { $twilioMatch = $t; break; } } } if (!$twilioMatch) { continue; } $jsonDef = $defaultTemplatesByLang[$lang]['reconfirmation'] ?? null; if (!$jsonDef) { continue; } $fieldMapping = $buildFieldMapping($jsonDef, $twilioMatch); $currentValue[$lang] = [ 'template_sid' => $twilioMatch['sid'] ?? $twilioMatch['id'] ?? '', 'template_name' => $twilioMatch['name'] ?? '', 'field_mapping' => $fieldMapping, ]; $result['reconfirmations'][] = 'reconfirmation#' . $reconfirmation->id . '/' . $lang . ' -> ' . ($twilioMatch['name'] ?? ''); $changed = true; } if ($changed) { $reconfirmation->whatsapp_reconfirmation = $currentValue; $reconfirmation->save(); } } } // 9. Map action_reply template to action_fallback in WhatsappAction $actionSetting = WhatsappAction::where('restaurant_id', $restaurantId)->first(); $isNewActionSetting = false; if (!$actionSetting) { $actionSetting = new WhatsappAction; $actionSetting->restaurant_id = $restaurantId; $actionSetting->setupDefaultValues()->save(); $isNewActionSetting = true; } if ($actionSetting) { $languages = evavel_languages_allowed(); $currentValue = $actionSetting->action_fallback; if (!is_array($currentValue)) { $currentValue = []; } $changed = false; foreach ($languages as $lang => $label) { $existing = $currentValue[$lang] ?? []; // Only map if template_sid is empty if (!empty($existing['template_sid'])) { continue; } // Find matching Twilio template for action_reply $twilioMatch = $findTwilioTemplate('action_reply', $lang); if (!$twilioMatch) { continue; } // Get JSON definition for field mapping $jsonDef = $defaultTemplatesByLang[$lang]['action_reply'] ?? null; if (!$jsonDef) { continue; } $fieldMapping = $buildFieldMapping($jsonDef, $twilioMatch); // Preserve existing keywords if any, only fill template data $currentValue[$lang] = array_merge( $existing, [ 'response_type' => 'template', 'template_sid' => $twilioMatch['sid'] ?? $twilioMatch['id'] ?? '', 'template_name' => $twilioMatch['name'] ?? '', 'field_mapping' => $fieldMapping, ] ); $result['actions'][] = 'action_fallback/' . $lang . ' -> ' . ($twilioMatch['name'] ?? ''); $changed = true; } if ($changed) { $actionSetting->action_fallback = $currentValue; } // Enable action_fallback by default on first creation if ($isNewActionSetting) { $actionSetting->action_fallback_enable = 1; $changed = true; } if ($changed) { $actionSetting->save(); } } /* NO LOS VOY A USAR PORQUE YA TENTO MENSAJES POR DEFECTO // 10. Fill default reconfirmation reply messages if empty $messagesPath = defined('ALEXR_DIR_TEMPLATES_WHATSAPP_MESSAGES') ? ALEXR_DIR_TEMPLATES_WHATSAPP_MESSAGES : ''; if ($messagesPath && is_dir($messagesPath)) { $repliesFile = $messagesPath . 'reconfirmation_replies.json'; if (file_exists($repliesFile)) { $repliesContent = file_get_contents($repliesFile); $defaultReplies = json_decode($repliesContent, true); if (is_array($defaultReplies) && !empty($reconfirmations)) { $languages = evavel_languages_allowed(); foreach ($reconfirmations as $reconfirmation) { $replyMessages = $reconfirmation->reply_messages; if (!is_array($replyMessages)) { $replyMessages = []; } $changed = false; foreach ($languages as $lang => $label) { if (!isset($defaultReplies[$lang])) { continue; } $currentConfirm = trim($replyMessages[$lang]['reply_on_confirm'] ?? ''); $currentCancel = trim($replyMessages[$lang]['reply_on_cancel'] ?? ''); // Only fill if both are empty for this language if (empty($currentConfirm) && empty($currentCancel)) { $replyMessages[$lang] = [ 'reply_on_confirm' => $defaultReplies[$lang]['reply_on_confirm'] ?? '', 'reply_on_cancel' => $defaultReplies[$lang]['reply_on_cancel'] ?? '', ]; $result['reconfirmation_replies'][] = 'reconfirmation#' . $reconfirmation->id . '/' . $lang; $changed = true; } } if ($changed) { $reconfirmation->reply_messages = $replyMessages; $reconfirmation->save(); } } } } } */ return $result; }