diff --git a/app/services/app_store/send_on_app_store_service.rb b/app/services/app_store/send_on_app_store_service.rb index ab5f7418d..9e52b4b1b 100644 --- a/app/services/app_store/send_on_app_store_service.rb +++ b/app/services/app_store/send_on_app_store_service.rb @@ -9,8 +9,7 @@ class AppStore::SendOnAppStoreService < Base::SendOnChannelService validate_feature_enabled! validate_message_support! source_id = channel.reply_to_review(review_id, reply_content) - message.update!(source_id: source_id) if source_id.present? - Messages::StatusUpdateService.new(message, 'delivered').perform + sync_response_message(source_id) rescue StandardError => e ChatwootExceptionTracker.new(e, account: message.account).capture_exception Messages::StatusUpdateService.new(message, 'failed', e.message).perform @@ -33,4 +32,34 @@ class AppStore::SendOnAppStoreService < Base::SendOnChannelService def reply_content message.outgoing_content.presence || message.content end + + def existing_response_message(source_id) + return if source_id.blank? + + message.conversation.messages.where.not(id: message.id).find_by(source_id: source_id) + end + + def sync_response_message(source_id) + response_message = existing_response_message(source_id) + + if response_message.present? + update_existing_response_message(response_message, source_id) + message.destroy! + Messages::StatusUpdateService.new(response_message, 'delivered').perform + else + message.update!(source_id: source_id) if source_id.present? + Messages::StatusUpdateService.new(message, 'delivered').perform + end + end + + def update_existing_response_message(response_message, source_id) + content_attributes = (response_message.content_attributes || {}).deep_merge( + 'external_echo' => true, + 'app_store' => { + 'response_id' => source_id + } + ) + + response_message.update!(content: reply_content, content_attributes: content_attributes) + end end diff --git a/spec/services/app_store/send_on_app_store_service_spec.rb b/spec/services/app_store/send_on_app_store_service_spec.rb index ae073017f..bb88d7f25 100644 --- a/spec/services/app_store/send_on_app_store_service_spec.rb +++ b/spec/services/app_store/send_on_app_store_service_spec.rb @@ -32,16 +32,38 @@ RSpec.describe AppStore::SendOnAppStoreService do end it 'updates the existing App Store response when the conversation already has one' do - create(:message, message_type: :outgoing, inbox: inbox, conversation: conversation, account: inbox.account, content: 'Old reply', - source_id: 'response-1') + existing_response = create( + :message, + message_type: :outgoing, + inbox: inbox, + conversation: conversation, + account: inbox.account, + content: 'Old reply', + source_id: 'response-1', + content_attributes: { + external_echo: true, + app_store: { + response_id: 'response-1', + response_state: 'PUBLISHED' + } + } + ) message = create(:message, message_type: :outgoing, inbox: inbox, conversation: conversation, account: inbox.account, content: 'Updated reply') allow(channel).to receive(:reply_to_review).and_return('response-1') - described_class.new(message: message).perform + expect { described_class.new(message: message).perform } + .to change { conversation.messages.reload.count }.by(-1) expect(channel).to have_received(:reply_to_review).with('review-1', 'Updated reply') - expect(Messages::StatusUpdateService).to have_received(:new).with(message, 'delivered') + expect { message.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect(existing_response.reload.content).to eq('Updated reply') + expect(existing_response.content_attributes['external_echo']).to be true + expect(existing_response.content_attributes['app_store']).to include( + 'response_id' => 'response-1', + 'response_state' => 'PUBLISHED' + ) + expect(Messages::StatusUpdateService).to have_received(:new).with(existing_response, 'delivered') end it 'marks the message as failed when attachments are present' do