iachat/app/controllers/api/v1/accounts/captain/units_controller.rb
Rodribm10 fa1dd8b6cb feat(lifecycle): expose concierge config update on UnitsController
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 10:35:03 -03:00

148 lines
4.7 KiB
Ruby

class Api::V1::Accounts::Captain::UnitsController < Api::V1::Accounts::BaseController
before_action :ensure_captain_enabled
before_action :set_unit, only: [:show, :update, :destroy, :update_concierge]
def index
@units = Current.account.captain_units.includes(:inboxes)
@units = filter_units_by_user_access(@units)
render json: @units.map { |u| format_unit(u) }
end
def show
render json: format_unit(@unit)
end
def create
@unit = Current.account.captain_units.build(unit_params)
@unit.captain_brand_id ||= default_brand.id
ActiveRecord::Base.transaction do
@unit.save!
sync_inboxes!(@unit, inbox_ids_param)
end
render json: format_unit(@unit), status: :created
rescue ActiveRecord::RecordInvalid
render json: { errors: @unit.errors.full_messages }, status: :unprocessable_entity
end
def update
ActiveRecord::Base.transaction do
@unit.update!(unit_params)
sync_inboxes!(@unit, inbox_ids_param) if params[:captain_unit].key?(:inbox_ids)
end
render json: format_unit(@unit)
rescue ActiveRecord::RecordInvalid
render json: { errors: @unit.errors.full_messages }, status: :unprocessable_entity
end
def destroy
@unit.destroy!
head :no_content
end
def update_concierge
return render json: { error: 'Unauthorized' }, status: :unauthorized unless Current.user.administrator?
@unit.update!(concierge_params)
render json: format_unit(@unit)
rescue ActiveRecord::RecordInvalid
render json: { errors: @unit.errors.full_messages }, status: :unprocessable_entity
end
private
def ensure_captain_enabled
# Dependendo da regra de negócio, pode-se verificar as features da conta aqui original
end
# Administrador vê todas as unidades; agente só vê unidades vinculadas a
# alguma caixa de entrada a qual ele tem acesso.
def filter_units_by_user_access(scope)
return scope if Current.user.administrator?
accessible_inbox_ids = Current.user.assigned_inboxes.pluck(:id)
return scope.none if accessible_inbox_ids.empty?
scope.joins(:inboxes).where(inboxes: { id: accessible_inbox_ids }).distinct
end
def default_brand
@default_brand ||= Captain::Brand.where(account_id: Current.account.id).first ||
Captain::Brand.create!(
account_id: Current.account.id,
name: 'Marca padrão'
)
end
def set_unit
@unit = Current.account.captain_units.includes(:inboxes).find(params[:id])
end
def unit_params
params.require(:captain_unit).permit(
:name,
:inter_client_id,
:inter_client_secret,
:inter_pix_key,
:inter_account_number,
:inter_cert_content,
:inter_key_content,
:proactive_pix_polling_enabled
)
end
def concierge_params
params.require(:captain_unit).permit(
:concierge_inbox_id,
concierge_config: [:persona_name, :knowledge, { variables: {} }]
)
end
def inbox_ids_param
return [] unless params[:captain_unit].key?(:inbox_ids)
Array(params[:captain_unit][:inbox_ids]).map(&:to_i).select(&:positive?)
end
# Sincroniza a lista de inboxes de uma unit: adiciona novas, remove ausentes.
# Garante que apenas inboxes da mesma conta sejam aceitas.
def sync_inboxes!(unit, ids)
valid_ids = Current.account.inboxes.where(id: ids).pluck(:id)
# Remove vínculos não presentes na nova lista
unit.unit_inboxes.where.not(inbox_id: valid_ids).destroy_all
# Adiciona novos vínculos (ignora duplicatas via uniqueness)
existing_ids = unit.unit_inboxes.pluck(:inbox_id)
(valid_ids - existing_ids).each do |inbox_id|
unit.unit_inboxes.create!(inbox_id: inbox_id)
end
end
def format_unit(unit) # rubocop:disable Metrics/AbcSize
inboxes = unit.inboxes.to_a
{
id: unit.id,
name: unit.name,
inter_client_id: unit.inter_client_id,
inter_pix_key: unit.inter_pix_key,
inter_account_number: unit.inter_account_number,
inbox_ids: inboxes.map(&:id),
inbox_names: inboxes.map(&:name),
# Mantém inbox_id e inbox_name como atalho para compatibilidade com código legado
inbox_id: inboxes.first&.id,
inbox_name: inboxes.first&.name,
has_cert: unit.inter_cert_content.present? || unit.resolved_inter_cert_path.present?,
has_key: unit.inter_key_content.present? || unit.resolved_inter_key_path.present?,
has_client_secret: unit.inter_client_secret.present?,
proactive_pix_polling_enabled: unit.proactive_pix_polling_enabled
}.merge(format_concierge(unit))
end
def format_concierge(unit)
{
concierge_inbox_id: unit.concierge_inbox_id,
concierge_config: unit.concierge_config || {}
}
end
end