كيفية إصلاح CANNOT_UPDATE_CONVERTED_LEAD في عمليات نشر Salesforce

يحاول كود Apex أو API تحديث Lead بعد تحويله بالفعل، فيمنع Salesforce عملية الكتابة.

يظهر أثناء: عمليات DML وقت التشغيل، غالبًا داخل trigger أو batch job أو اختبار Apex

المعنى

يظهر CANNOT_UPDATE_CONVERTED_LEAD عندما يحاول كود Apex أو استدعاء API تحديث سجل Lead تم تحويله بالفعل. بمجرد التحويل، يصبح الـ Lead للقراءة فقط باستثناء مجموعة صغيرة من الحقول التي لا يزال Salesforce يسمح بها، لذا يُرفض أي تحديث آخر بدلًا من تجاهله بصمت.

إنه خطأ وقت تشغيل وليس خطأ وقت نشر: يتم نشر الـ trigger أو الـ batch job نفسه بنجاح، ولا يظهر الفشل إلا عند تنفيذ الكود فعليًا على سجل محوّل، وغالبًا ما يحدث ذلك داخل اختبارات Apex التي يتطلبها نشر الإنتاج.

التشخيص

الأسباب الشائعة

الـ trigger أو batch job يعالج الـ Leads دون التحقق من IsConverted
تقوم الأتمتة بتحديث سجلات الـ Lead بشكل مجمّع دون استبعاد السجلات المحوّلة بالفعل.
سكريبت الترحيل يحدّث الـ Leads دون استبعاد المحوّلة منها
يتعامل ترحيل البيانات مع كائن الـ Lead بشكل واسع ولا يقصر التحديث على السجلات غير المحوّلة فقط.
حالة تسابق (race condition) بين الاستعلام وعملية DML
يتم تحويل الـ Lead بين وقت استعلام Apex عنه ووقت محاولة نفس المعاملة تحديثه.

الحل

  1. استبعد السجلات ذات IsConverted = true قبل تحديث الـ Leads
    أضف IsConverted = false إلى أي استعلام أو جملة WHERE التي تُشغّل تحديثًا مجمّعًا للـ Leads.
    List<Lead> leads = [
        SELECT Id, Status FROM Lead
        WHERE IsConverted = false AND Id IN :leadIds
    ];
    update leads;
  2. أضف تحققات IsConverted إلى منطق الـ trigger
    احمِ معالجات trigger الخاصة بالـ Lead بحيث يتم تخطي السجلات المحوّلة بدلًا من تمريرها إلى منطق التحديث.
  3. حدّث السجل الناتج بدلًا من ذلك
    بمجرد تحويل الـ Lead، حدّث الـ Contact أو الـ Account أو الـ Opportunity الذي أنشأه بدلًا من الـ Lead الأصلي.
من واقع الاستخدام

إزاي Serpent بتمنع ده

نظرًا لأن Serpent يشغّل مجموعة اختبارات Apex الكاملة على كل مهمة قبل أن تصبح مؤهلة للدمج، فإن الـ trigger الذي لا يستبعد الـ Leads المحوّلة يفشل كفشل اختبار على الفرع الذي أدخله، وليس عند إصدار الإنتاج. راجع مكتبة أخطاء نشر Salesforce.

الـ metadata والبيانات في مسار نشر واحد داخل Serpent

الوقاية

اجعل تصفية IsConverted حارسًا قياسيًا في معالج الـ trigger
أضف تحقق IsConverted إلى مساعد trigger مشترك أو فئة أساس للمعالج بحيث ترثه كل أتمتة تخص الـ Lead، بدلًا من الاعتماد على تذكّر كل مطوّر.
غطِّ حالة Lead محوّل في فئة اختبار كل trigger خاص بالـ Lead
أضف طريقة اختبار تحوّل Lead في منتصف الاختبار وتتحقق من أن الـ trigger يتخطاه بشكل نظيف، بحيث يفشل الفلتر المفقود في CI بدلًا من الإنتاج.
قيّد نطاق مهام الـ Lead المجمّعة بدقة
امنح مهام الـ batch وسكريبتات الترحيل جملة WHERE صريحة وضيقة بدلًا من معالجة كائن الـ Lead بأكمله.
أسئلة شائعة

CANNOT_UPDATE_CONVERTED_LEAD، تمت الإجابة

هل يمكنني تحديث أي حقل على الإطلاق في Lead محوّل؟
مجموعة صغيرة من الحقول فقط، مثل الحقول المرتبطة بـ ConvertedContactId التي يديرها Salesforce بنفسه، أما حقول العمل العادية في Lead محوّل فمقفلة.
هل ينطبق هذا أيضًا على حذف الـ Leads، أم فقط على التحديثات؟
يتم التعامل مع الحذف بشكل منفصل وهو مسموح به عمومًا على الـ Leads المحوّلة إذا كانت إعدادات المؤسسة تسمح بحذف الـ Leads أصلًا؛ هذا الخطأ تحديدًا يتعلق بعمليات DML من نوع التحديث.
لماذا ينجح نفس الـ trigger في scratch org لكنه يفشل في full sandbox؟
من غير المرجح أن تحتوي بيانات اختبار الـ scratch org على Leads محوّلة ما لم ينشئها الاختبار صراحةً. أما نسخة full sandbox من الإنتاج فتكاد تحتوي بالتأكيد على Leads محوّلة تلامسها مهمة الـ batch الآن.

ابدأ مجانًا. بلا بطاقة ائتمان، بلا تثبيت، بلا التزام.

الإعداد في أقل من 15 دقيقة. لا حاجة لتوظيف DevOps.

هل تريد معرفة كيف يمكنكم الشحن أسرع قبل البدء؟ لنتحدث

بدون التزام.