1+ using System ;
2+ using Microsoft . Xrm . Sdk ;
3+
4+ namespace SystemIntake . Plugins
5+ {
6+ public class ActivityLog_Create_SyncTargetStepToReviewAndRequest : IPlugin
7+ {
8+ private const string ActivityLogEntity = "new_activitylogs" ;
9+
10+ // Activity Log fields
11+ private const string TargetStepField = "new_process_target_step" ; // Choice (global)
12+ private const string ReviewLookupField = "new_adminreview" ; // Lookup -> cr69a_systemintakeadmin
13+ private const string RequestLookupField = "new_systemintake" ; // Lookup -> new_systemintake (Request)
14+
15+ // Review fields
16+ private const string ReviewEntity = "cr69a_systemintakeadmin" ;
17+ private const string ReviewStepField = "new_admingovernancetasklist" ; // Choice (same global)
18+ private const string ReviewReadyForReviewField = "cr69a_readyforreview" ; // Two Options (Yes/No)
19+
20+ // Request fields
21+ private const string RequestEntity = "new_systemintake" ;
22+ private const string RequestStepField = "new_admingovernanceprocessstep" ; // Choice (same global)
23+ private const string RequestReadyForReviewField = "cr69a_readyforreview" ; // Two Options (Yes/No)
24+
25+ private const int PostOperationStage = 40 ;
26+
27+ //TODO: Consider shared PluginTracing helper to standardize Start/End/Exception tracing across plugins.
28+ //Keep it in same assembly initially to avoid dependency deployment complexity.
29+
30+ public void Execute ( IServiceProvider serviceProvider )
31+ {
32+ var tracing = ( ITracingService ) serviceProvider . GetService ( typeof ( ITracingService ) ) ;
33+ var context = ( IPluginExecutionContext ) serviceProvider . GetService ( typeof ( IPluginExecutionContext ) ) ;
34+
35+ if ( context == null )
36+ {
37+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: context is null. Exiting." ) ;
38+ return ;
39+ }
40+
41+ tracing ? . Trace (
42+ "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Start. Message={0}, PrimaryEntity={1}, Stage={2}, Mode={3}, Depth={4}, UserId={5}, InitiatingUserId={6}, CorrelationId={7}, OperationId={8}" ,
43+ context . MessageName ,
44+ context . PrimaryEntityName ,
45+ context . Stage ,
46+ context . Mode ,
47+ context . Depth ,
48+ context . UserId ,
49+ context . InitiatingUserId ,
50+ context . CorrelationId ,
51+ context . OperationId
52+ ) ;
53+
54+ try
55+ {
56+ if ( ! string . Equals ( context . PrimaryEntityName , ActivityLogEntity , StringComparison . OrdinalIgnoreCase ) )
57+ {
58+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Not target entity ({0}). Exiting." , ActivityLogEntity ) ;
59+ return ;
60+ }
61+
62+ if ( ! string . Equals ( context . MessageName , "Create" , StringComparison . OrdinalIgnoreCase ) )
63+ {
64+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Not Create message. Exiting." ) ;
65+ return ;
66+ }
67+
68+ // PostOperation only
69+ if ( context . Stage != PostOperationStage )
70+ {
71+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Not PostOperation (Stage {0}). Exiting." , PostOperationStage ) ;
72+ return ;
73+ }
74+
75+ object targetObj ;
76+ if ( ! context . InputParameters . TryGetValue ( "Target" , out targetObj ) )
77+ {
78+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Missing Target in InputParameters. Exiting." ) ;
79+ return ;
80+ }
81+
82+ var target = targetObj as Entity ;
83+ if ( target == null )
84+ {
85+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Target is not an Entity. Exiting." ) ;
86+ return ;
87+ }
88+
89+ tracing ? . Trace (
90+ "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Target received. LogicalName={0}, Id={1}" ,
91+ target . LogicalName ,
92+ target . Id
93+ ) ;
94+
95+ var reviewRef = target . GetAttributeValue < EntityReference > ( ReviewLookupField ) ;
96+ var requestRef = target . GetAttributeValue < EntityReference > ( RequestLookupField ) ;
97+
98+ // Step is optional now (we still want to clear Ready for Review even if step isn't set)
99+ var step = target . GetAttributeValue < OptionSetValue > ( TargetStepField ) ;
100+
101+ tracing ? . Trace (
102+ "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Parsed fields. ReviewRef={0}, RequestRef={1}, Step={2}" ,
103+ reviewRef != null ? $ "{ reviewRef . LogicalName } :{ reviewRef . Id } " : "(null)" ,
104+ requestRef != null ? $ "{ requestRef . LogicalName } :{ requestRef . Id } " : "(null)" ,
105+ step != null ? step . Value . ToString ( ) : "(null)"
106+ ) ;
107+
108+ var serviceFactory = ( IOrganizationServiceFactory ) serviceProvider . GetService ( typeof ( IOrganizationServiceFactory ) ) ;
109+ var service = serviceFactory . CreateOrganizationService ( context . UserId ) ;
110+
111+ // Update Review (if present)
112+ if ( reviewRef != null )
113+ {
114+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Updating Review {0}:{1}" , reviewRef . LogicalName , reviewRef . Id ) ;
115+
116+ var reviewUpdate = new Entity ( ReviewEntity , reviewRef . Id ) ;
117+
118+ // Sync step only if provided on the log
119+ if ( step != null )
120+ {
121+ reviewUpdate [ ReviewStepField ] = new OptionSetValue ( step . Value ) ;
122+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Review step set to {0}" , step . Value ) ;
123+ }
124+ else
125+ {
126+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Review step not provided; leaving step unchanged." ) ;
127+ }
128+
129+ // Always set Ready for Review = false when an Activity Log is created
130+ reviewUpdate [ ReviewReadyForReviewField ] = false ;
131+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Review ReadyForReview set to false." ) ;
132+
133+ service . Update ( reviewUpdate ) ;
134+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Review update succeeded." ) ;
135+ }
136+ else
137+ {
138+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Review lookup not present; skipping Review update." ) ;
139+ }
140+
141+ // Update Request (if present)
142+ if ( requestRef != null )
143+ {
144+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Updating Request {0}:{1}" , requestRef . LogicalName , requestRef . Id ) ;
145+
146+ var requestUpdate = new Entity ( RequestEntity , requestRef . Id ) ;
147+
148+ // Sync step only if provided on the log
149+ if ( step != null )
150+ {
151+ requestUpdate [ RequestStepField ] = new OptionSetValue ( step . Value ) ;
152+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Request step set to {0}" , step . Value ) ;
153+ }
154+ else
155+ {
156+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Request step not provided; leaving step unchanged." ) ;
157+ }
158+
159+ // Always set Ready for Review = false when an Activity Log is created
160+ requestUpdate [ RequestReadyForReviewField ] = false ;
161+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Request ReadyForReview set to false." ) ;
162+
163+ service . Update ( requestUpdate ) ;
164+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Request update succeeded." ) ;
165+ }
166+ else
167+ {
168+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Request lookup not present; skipping Request update." ) ;
169+ }
170+ }
171+ catch ( Exception ex )
172+ {
173+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: Exception: {0}" , ex ) ;
174+ throw ;
175+ }
176+ finally
177+ {
178+ tracing ? . Trace ( "ActivityLog_Create_SyncTargetStepToReviewAndRequest: End." ) ;
179+ }
180+ }
181+ }
182+ }
0 commit comments