diff --git a/handlers/business_updates.py b/handlers/business_updates.py index 4a5f8ee..7ff4092 100644 --- a/handlers/business_updates.py +++ b/handlers/business_updates.py @@ -268,8 +268,6 @@ def _notify_incoming(bcid: str, customer_chat_id: int, text: str) -> None: # ============================================================================= def on_edited_business_message(message) -> None: # Informational only: do NOT generate a new reply (prevents edit loops). - if not database.get_bool("monitoring_mode"): - return bcid = getattr(message, "business_connection_id", None) if not bcid: return @@ -278,11 +276,24 @@ def on_edited_business_message(message) -> None: sender = getattr(message, "from_user", None) if sender and owner_user_id and sender.id == owner_user_id: return # owner edited their own message + invalidated = database.invalidate_approvals_for_messages( + bcid, message.chat.id, [message.message_id] + ) + log.info( + "customer edited message chat=%s (invalidated %d approvals)", + utils.mask_id(message.chat.id), invalidated, + ) + if not database.get_bool("monitoring_mode"): + return name = business_service.customer_display_name(bcid, message.chat.id) text = (getattr(message, "text", None) or getattr(message, "caption", None) or "").strip() + cancellation = ( + "\nThe pending approval for the earlier version was cancelled." + if invalidated else "" + ) handlers.notify_owner( f"✏️ {utils.escape(name)} edited a message: " - f"{utils.escape(text[:300])}" + f"{utils.escape(text[:300])}{cancellation}" ) diff --git a/tests/unit/handlers/test_business_updates.py b/tests/unit/handlers/test_business_updates.py index 8f35d0f..f1b53b2 100644 --- a/tests/unit/handlers/test_business_updates.py +++ b/tests/unit/handlers/test_business_updates.py @@ -196,7 +196,55 @@ def test_deliver_auto_warns_when_delivery_is_unconfirmed( assert db.get_recent_memory("bc1", 5, 10) == [] -# --- deleted messages -------------------------------------------------------- +# --- edited / deleted messages ---------------------------------------------- +def test_edited_customer_message_invalidates_approval(penv, make_message, mocker): + aid = penv.db.insert_pending_approval("bc1", 5, 22, "before", "reply") + notify = mocker.patch("handlers.notify_owner") + + bu.on_edited_business_message( + make_message( + business_connection_id="bc1", chat_id=5, message_id=22, text="after" + ) + ) + + assert penv.db.get_approval(aid)["status"] == "invalidated" + assert "pending approval for the earlier version was cancelled" in notify.call_args.args[0] + + +def test_edited_customer_message_invalidates_with_monitoring_off( + penv, make_message, mocker +): + penv.db.set_setting("monitoring_mode", False) + aid = penv.db.insert_pending_approval("bc1", 5, 22, "before", "reply") + notify = mocker.patch("handlers.notify_owner") + + bu.on_edited_business_message( + make_message( + business_connection_id="bc1", chat_id=5, message_id=22, text="after" + ) + ) + + assert penv.db.get_approval(aid)["status"] == "invalidated" + notify.assert_not_called() + + +def test_edited_owner_message_does_not_invalidate_customer_approval( + penv, make_message, mocker +): + aid = penv.db.insert_pending_approval("bc1", 5, 22, "customer", "reply") + notify = mocker.patch("handlers.notify_owner") + + bu.on_edited_business_message( + make_message( + business_connection_id="bc1", user_id=999, chat_id=5, + message_id=22, text="owner edit", + ) + ) + + assert penv.db.get_approval(aid)["status"] == "pending" + notify.assert_not_called() + + def test_deleted_invalidates_approval(penv): aid = penv.db.insert_pending_approval("bc1", 5, 22, "c", "r") deleted = SimpleNamespace(business_connection_id="bc1",