1

My question is basically the same as question 289297, if I correctly understand its OP's intent. I am posting my own in the hope of giving the issue more visibility, and also because it is not an answer to that question.

Let me first describe what I am trying to do: My package is planned to be an extension to the built-in Opportunity to Quote syncing feature. It contains two custom objects (tables), one for the Opportunity to Quote field mappings, the other for the OpportunityLineItem to QuoteLineItem field mappings. Both of these tables have two fields where the user can enter the names of the fields he wants synced. The user's entries are validated in a before-trigger that makes sure the two fields are compatible.

to be compatible,

  • a field must not be synced by the built-in feature: hard-coded list determined by experiment.
  • a field must not be a formula field: DescribeFieldResult.isCalculated().
  • a field must not be an auto number field: DescribeFieldResult.isAutoNumber().
  • a field must not be an ADDRESS field.
  • both fields must have the same nillability: DescribeFieldResult.isNillable().
  • both fields must have the same type: DescribeFieldResult.getType().
  • if the type is REFERENCE, both fields must refer to the same (set of) objects: DescribeFieldResult.getReferenceTo().

and, last but not least:

  • both fields must be updateable by the code that keeps the mapped fields in sync when the user inserts or updates a row in one of the four entities involved.

This last item is where my problem is. DescribeFieldResult.isUpdateable() does not help here, because its results are user-dependent, even when called from the method of a class marked without sharing that executes in a trigger context. Also, the isUpdateable returns false in cases where demonstrably the trigger code can successfully update a field to keep it in sync with the corresponding field of the partner row.

tentative and partial answers to my problem, always assuming the the trigger context:

  • a custom field, whether in a custom object or in a standard object, is always updateable: hard to verify; easy to implement in code, should this be correct.
  • a standard object's standard field is updateable if the Standard Object Reference mentions Update in the field's Properties: hard to verify, and even, should this be correct, hard to use in code. A hard coded white list does not look like an attractive solution.
  • a standard object's standard field is not updateable if the field's Set Field-Level Security page contains a non-editable checkmark in all rows: if correct, there must be a programmatic way that determines the non-updateability of the field - said page does it.
  • in a comment to the above mentioned question 289297, @SarcasticSully mentions that "Admin cannot remove update access to any required field": if correct, how does one test for the required field property? is non-nillability the same as being required?

BTW: A possible, though not very clean, way of testing the updateability of a field could be: Start a sub-transaction (is this possible in Apex?), create a row of the object in question and update the field, then roll back the sub-transaction while catching exceptions: now really, lets be serious!

Any ideas or hints will be extremely welcome!

After thinking some more about my question

I have abandoned the idea of deciding in code in a general way whether a given field will be writeable (IsUpdateable()) in the trigger.

  • As far as I can see custom fields (as in MyCustomField__c) can always be written to in the trigger, and are therefore usable as synced fields, as long as the conditions enumerated above are met.
  • Of standard fields there are not many in the context of syncing Quotes and Opportunities that could usefully and meaningfully be synchronized in addition to the fields that the built-in implementation synchronizes.
  • In all cases suitable tests should allow one to decide whether a given field can be made to sync with a proposed partner field.

1 Answer 1

2

Security changes may invalidate your configuration after setup. For example, an administrator might change a field's accessibility after setting up the configuration. Or, the field level security might be different for different profiles, or even permission sets. You should not verify this last requirement during setup, only during execution. For this, I suggest using the new security features that were introduced in the last couple releases or so.

SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.UPDATABLE, recordsToUpdate);
update securityDecision.getRecords();

You can also check to see which fields were removed via getRemovedFields(), which returns a Map<String, Set<String>> that describes which fields were removed for each object (the Map's key is the object from which fields were removed, the Set contains the fields removed). You could use this for error logging/reporting.

However, as you can see, this will automatically ensure that the runtime constraints for updatability will be enforced. Now you just need to check for data types, etc, as in the first part of your question.

1
  • you must excuse me - I am still somewhat of a newbie - now: I am confused because I thought that Apex code as such does not heed the individual user's permissions and access rights; in addition, the code that does the work at runtime always executes in the context of a (after insert/update) trigger and is contained in a class marked without sharing. Should this not exclude any influence of permission sets, profiles or field-level security?
    – willeg
    Feb 20, 2021 at 19:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .