The "conversation continuity via email" toggle was visible to all accounts regardless of whether they had `inbound_emails` enabled. Without inbound email infrastructure, replies to those follow-up emails land in the agent's personal inbox instead of routing back into Chatwoot. The feature appears to work but silently breaks the reply path. The toggle is now gated on the `inbound_emails` feature flag. On self-hosted without the feature, the toggle is hidden entirely. On cloud, it remains visible but disabled with upgrade messaging. On the backend, `inbound_emails` is added to the manually managed features list in `InternalAttributesService` so that Stripe webhook plan syncs don't override it when support enables it for an account. --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
69 lines
2.0 KiB
Ruby
69 lines
2.0 KiB
Ruby
class Internal::Accounts::InternalAttributesService
|
|
attr_reader :account
|
|
|
|
# List of keys that can be managed through this service
|
|
# TODO: Add account_notes field in future
|
|
# This field can be used to store notes about account on Chatwoot cloud
|
|
VALID_KEYS = %w[manually_managed_features].freeze
|
|
|
|
def initialize(account)
|
|
@account = account
|
|
end
|
|
|
|
# Get a value from internal_attributes
|
|
def get(key)
|
|
validate_key!(key)
|
|
account.internal_attributes[key]
|
|
end
|
|
|
|
# Set a value in internal_attributes
|
|
def set(key, value)
|
|
validate_key!(key)
|
|
|
|
# Create a new hash to avoid modifying the original
|
|
new_attrs = account.internal_attributes.dup || {}
|
|
new_attrs[key] = value
|
|
|
|
# Update the account
|
|
account.internal_attributes = new_attrs
|
|
account.save
|
|
end
|
|
|
|
# Get manually managed features
|
|
def manually_managed_features
|
|
get('manually_managed_features') || []
|
|
end
|
|
|
|
# Set manually managed features
|
|
def manually_managed_features=(features)
|
|
features = [] if features.nil?
|
|
features = [features] unless features.is_a?(Array)
|
|
|
|
# Clean up the array: remove empty strings, whitespace, and validate against valid features
|
|
valid_features = valid_feature_list
|
|
features = features.compact
|
|
.map(&:strip)
|
|
.reject(&:empty?)
|
|
.select { |f| valid_features.include?(f) }
|
|
.uniq
|
|
|
|
set('manually_managed_features', features)
|
|
end
|
|
|
|
# Get list of valid features that can be manually managed
|
|
def valid_feature_list
|
|
Enterprise::Billing::ReconcilePlanFeaturesService::BUSINESS_PLAN_FEATURES +
|
|
Enterprise::Billing::ReconcilePlanFeaturesService::ENTERPRISE_PLAN_FEATURES +
|
|
%w[inbound_emails]
|
|
end
|
|
|
|
# Account notes functionality removed for now
|
|
# Will be re-implemented when UI is ready
|
|
|
|
private
|
|
|
|
def validate_key!(key)
|
|
raise ArgumentError, "Invalid internal attribute key: #{key}" unless VALID_KEYS.include?(key)
|
|
end
|
|
end
|