{
  "filename": "orders/services.py",
  "rule": "Order notification callbacks are registered with transaction.on_commit inside the atomic block, so a rolled-back order update does not send a notification.",
  "fixed": "from django.db import transaction\n\ndef confirm_order(order, notify):\n    with transaction.atomic():\n        order.status = \"confirmed\"\n        order.save(update_fields=[\"status\"])\n        transaction.on_commit(lambda: notify(order.pk))\n    return order\n",
  "broken": "from django.db import transaction\n\ndef confirm_order(order, notify):\n    with transaction.atomic():\n        order.status = \"confirmed\"\n        order.save(update_fields=[\"status\"])\n        notify(order.pk)\n    return order\n",
  "test": {
    "filename": "orders/tests.py",
    "source": "from unittest.mock import Mock\nfrom django.db import transaction\nfrom django.test import TestCase\nfrom .models import Order\nfrom .services import confirm_order\n\nclass ConfirmationTests(TestCase):\n    def test_notification_waits_for_commit(self):\n        order = Order.objects.create()\n        notify = Mock()\n        with self.captureOnCommitCallbacks(execute=True) as callbacks:\n            confirm_order(order, notify)\n            notify.assert_not_called()\n        self.assertEqual(len(callbacks), 1)\n        notify.assert_called_once_with(order.pk)\n\n    def test_rollback_discards_notification(self):\n        order = Order.objects.create()\n        notify = Mock()\n        with self.captureOnCommitCallbacks(execute=True):\n            try:\n                with transaction.atomic():\n                    confirm_order(order, notify)\n                    raise ValueError(\"abort\")\n            except ValueError:\n                pass\n        notify.assert_not_called()\n        order.refresh_from_db()\n        self.assertEqual(order.status, \"pending\")\n",
    "command": "python manage.py test orders"
  }
}