*/ private const LEGACY_TYPES = [ 'send_notification', ]; /** * Old underscore template keys from early seed data. * * @var array */ private const TEMPLATE_KEY_MAP = [ 'booking_confirmed' => 'booking.confirmed.customer', 'booking_reminder_24h' => 'booking.reminder.customer', 'booking_reminder_1h' => 'booking.reminder.customer', 'booking_cancelled' => 'booking.cancelled.customer', 'review_request' => 'booking.followup.customer', 'booking_noshow' => 'booking.noshow.customer', ]; /** * Whether any step still uses a retired action type. * * @param list> $actions Steps. * * @since 0.1.0 */ public function needs_repair( array $actions ): bool { foreach ( $actions as $step ) { $type = isset( $step['type'] ) ? (string) $step['type'] : ''; if ( in_array( $type, self::LEGACY_TYPES, true ) ) { return true; } } return false; } /** * Upgrade legacy steps to the current action schema. * * @param list> $actions Steps. * @return list> * * @since 0.1.0 */ public function repair_actions( array $actions ): array { $out = []; foreach ( $actions as $index => $step ) { if ( ! is_array( $step ) ) { continue; } $out[] = $this->repair_step( $step, $index ); } return $out; } /** * One demo send step for seed data. * * @param string $template_key Template key. * @param int $delay Delay minutes. * @param int $sort Sort order. * @return array * * @since 0.1.0 */ public function demo_send_step( string $template_key, int $delay = 0, int $sort = 0 ): array { return [ 'type' => 'send_notification_template', 'config' => [ 'template_key' => $template_key ], 'delay_minutes' => $delay, 'sort_order' => $sort, 'context_mode' => 'snapshot', 'recipient' => 'customer', 'intent' => 'transactional', ]; } /** * Upgrade one legacy step. * * @param array $step Step. * @param int $index Sort fallback. * @return array */ private function repair_step( array $step, int $index ): array { $type = isset( $step['type'] ) ? (string) $step['type'] : ''; if ( 'send_notification' !== $type ) { return $step; } $config = isset( $step['config'] ) && is_array( $step['config'] ) ? $step['config'] : []; $raw = ''; if ( isset( $config['template_key'] ) && is_string( $config['template_key'] ) ) { $raw = $config['template_key']; } elseif ( isset( $step['template_key'] ) && is_string( $step['template_key'] ) ) { $raw = $step['template_key']; } return [ 'type' => 'send_notification_template', 'config' => [ 'template_key' => $this->normalise_template_key( $raw ), ], 'delay_minutes' => (int) ( $step['delay_minutes'] ?? 0 ), 'sort_order' => (int) ( $step['sort_order'] ?? $index ), 'context_mode' => isset( $step['context_mode'] ) ? (string) $step['context_mode'] : 'snapshot', 'recipient' => isset( $step['recipient'] ) ? (string) $step['recipient'] : 'customer', 'intent' => isset( $step['intent'] ) ? (string) $step['intent'] : 'transactional', ]; } /** * Map underscore keys to dotted template keys. * * @param string $key Raw key. */ private function normalise_template_key( string $key ): string { $key = trim( $key ); if ( '' === $key ) { return 'booking.confirmed.customer'; } if ( isset( self::TEMPLATE_KEY_MAP[ $key ] ) ) { return self::TEMPLATE_KEY_MAP[ $key ]; } if ( str_contains( $key, '.' ) ) { return $key; } return str_replace( '_', '.', $key ) . '.customer'; } }