diff --git a/build.gradle b/build.gradle index 510d1b8..df396cf 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'com.flexcodelabs' -version = '0.0.70' +version = '0.0.71' description = 'Flextuma App' java { diff --git a/src/main/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageService.java b/src/main/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageService.java index 232b969..2ab72b8 100644 --- a/src/main/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageService.java +++ b/src/main/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageService.java @@ -157,20 +157,28 @@ public Pagination listConversations(int page, int pageS Map conversations = new LinkedHashMap<>(); Map unreadCounts = new LinkedHashMap<>(); Map configsByConnectorId = new LinkedHashMap<>(); + // Resolved once per unique config (not per message) via the same fallback + // resolveConnector() already uses for media downloads and read receipts -- a config + // with no connector explicitly linked still needs an outbound match, or its contacts' + // replies never update the list (the bug this whole map exists to fix). + Map resolvedConnectorsByConfigId = new LinkedHashMap<>(); for (WhatsAppInboxMessage message : recent) { - String key = message.getConfig().getId() + ":" + message.getFromNumber(); + WhatsAppWebhookConfig config = message.getConfig(); + String key = config.getId() + ":" + message.getFromNumber(); unreadCounts.merge(key, message.getReadAt() == null ? 1L : 0L, Long::sum); conversations.putIfAbsent(key, WhatsAppConversationDTO.builder() - .configId(message.getConfig().getId()) - .phoneNumberId(message.getConfig().getPhoneNumberId()) + .configId(config.getId()) + .phoneNumberId(config.getPhoneNumberId()) .fromNumber(message.getFromNumber()) .contactName(message.getContactName()) .lastMessageContent(previewContent(message)) .lastMessageType(message.getMessageType()) .lastMessageAt(message.getReceivedAt()) .build()); - if (message.getConfig().getConnector() != null) { - configsByConnectorId.putIfAbsent(message.getConfig().getConnector().getId(), message.getConfig()); + SmsConnector connector = resolvedConnectorsByConfigId.computeIfAbsent(config.getId(), + id -> mediaService.resolveConnector(config)); + if (connector != null) { + configsByConnectorId.putIfAbsent(connector.getId(), config); } } diff --git a/src/test/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageServiceTest.java b/src/test/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageServiceTest.java index 8b35c3d..9cb7454 100644 --- a/src/test/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageServiceTest.java +++ b/src/test/java/com/flexcodelabs/flextuma/modules/whatsapp/services/WhatsAppInboxMessageServiceTest.java @@ -141,6 +141,7 @@ void listConversations_shouldReflectOutboundReply_sentAfterLastInboundMessage() when(repository.findAll(any(Specification.class), any(Pageable.class))) .thenReturn(new PageImpl<>(List.of(inbound))); + when(mediaService.resolveConnector(config)).thenReturn(connector); SmsLog outboundReply = new SmsLog(); outboundReply.setRecipient("255655392445"); @@ -161,6 +162,43 @@ void listConversations_shouldReflectOutboundReply_sentAfterLastInboundMessage() assertEquals(1, conversation.unreadCount()); } + @Test + void listConversations_shouldReflectOutboundReply_whenConfigHasNoConnectorLinkedDirectly() { + // WhatsAppWebhookConfig.connector is optional; resolveConnector() falls back to the + // owner's first active WhatsApp connector. Outbound-activity matching must go through + // that same fallback, not require an explicit link, or replies from tenants who never + // set it never update the list. + SmsConnector connector = new SmsConnector(); + connector.setId(UUID.randomUUID()); + + WhatsAppWebhookConfig config = new WhatsAppWebhookConfig(); + config.setId(UUID.randomUUID()); + config.setPhoneNumberId("104725069208652"); + // Deliberately left null: config.setConnector(...) is not called. + + LocalDateTime inboundAt = LocalDateTime.now().minusHours(2); + WhatsAppInboxMessage inbound = message(config, "255655392445", "whatup", inboundAt, false); + + when(repository.findAll(any(Specification.class), any(Pageable.class))) + .thenReturn(new PageImpl<>(List.of(inbound))); + when(mediaService.resolveConnector(config)).thenReturn(connector); + + SmsLog outboundReply = new SmsLog(); + outboundReply.setRecipient("255655392445"); + outboundReply.setContent("I see"); + outboundReply.setConnector(connector); + outboundReply.setCreated(inboundAt.plusHours(2)); + + when(smsLogService.findAllPaginated(any(Pageable.class), any(), any(), any())) + .thenReturn(Pagination.builder().data(List.of(outboundReply)).build()); + + Pagination result = service.listConversations(0, 25); + + WhatsAppConversationDTO conversation = result.getData().get(0); + assertEquals("I see", conversation.lastMessageContent()); + assertEquals(inboundAt.plusHours(2), conversation.lastMessageAt()); + } + @Test void listConversations_shouldExposeTypeAndNullContent_whenMediaMessageHasNoCaption() { WhatsAppWebhookConfig config = new WhatsAppWebhookConfig();