Skip to content

Commit b48d1d3

Browse files
authored
update resolution options
1 parent 11c5307 commit b48d1d3

1 file changed

Lines changed: 240 additions & 5 deletions

File tree

support/dynamics-365/field-service/scheduling/missing-form-context-bookable-resource.md

Lines changed: 240 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ ms.custom: sap:Schedule Board
99
---
1010
#
1111

12-
This article helps resolve issues ........ in Microsoft Dynamics 365 Field Service.
12+
This article helps resolve issues caused by missing form context for internal handlers on the bookable resource form in Microsoft Dynamics 365 Field Service.
1313

1414
## Symptoms
1515

1616
When opening the form to create a bookable resource, the error message **Cannot read properties of undefined (reading 'getFormContext')** appears when selecting a user from the field.
1717

1818
## Cause
1919

20-
There was a change in the internal handler for the userID field. It now requires a context to be passed in from the form.
20+
The system uses a customized form that is based on an old version of the bookable resource form. There was a change in the internal handlers for *onchange* events. They require the execution context to be passed in from the form.
2121

2222
## Resolution
2323

24-
You can fix this through an update of the form settings in Power Apps or with a script that you run in the browser's console.
24+
You can address such isuses through Power Apps, by editing the form definitions of the customized forms in the corresponding customizations.xml file, or by running a script in the browser console to update the onchange event. The following resolutions assume that the script error references the function Mscrm.userid_onchange. If the error shows on other fields and references other functions, adapt the resolution steps to these fuctions.
2525

2626
### Update the form in Power Apps
2727

@@ -44,5 +44,240 @@ You can fix this through an update of the form settings in Power Apps or with a
4444

4545
1. Save and publish the updated form.
4646

47-
Edit the handler and make sure that the "Pass execution context as first parameter" is checked
48-
Save and publish the form
47+
### Update the customizations.xml file
48+
49+
1. Open the customizations.xml file in an editor.
50+
51+
1. In the *Handler* element of the *Mscrm.userid_onchange* function, ensure that the *passExecutionContext* attribute is set to **true**.
52+
53+
### Run a script in the browser console
54+
55+
To ensure this script has the permission to find and update the required information, you need to run it in a browser tab that has an active session with your enviornment. Additionally, your user account needs the permisssions to update the XML of the customized bookable resource form.
56+
57+
1. Open the environment in your browser. The following steps describe how to run the script in Microsoft Edge.
58+
59+
1. Open **DevTools** by pressing F12 or by selecting the ellipsis (…) > **More tools** > **Developer tools**
60+
61+
1. In **DevTools**, select the **Console** tab and select **Clear Console**.
62+
63+
1. Copy and paste the code below into the console window.
64+
65+
1. Update the ORG constant to the URL for the environment.
66+
67+
1. Run the code and review the script output.
68+
69+
```JavaScript
70+
const ORG = "<YOUR-ENVIRONMENT-URL>"; // for example "contoso.crm.dynamics.com"
71+
72+
async function fixBookableResourceForms() {
73+
74+
console.log("Starting Bookable Resource Form fetch process...");
75+
76+
let publishXML = false;
77+
78+
try {
79+
80+
const response = await fetch(`https://${ORG}/api/data/v9.2/systemforms?$filter=objecttypecode eq 'bookableresource'`);
81+
82+
if (!response.ok) {
83+
84+
throw new Error(`Error fetching resources: ${response.statusText}`);
85+
86+
}
87+
88+
const data = await response.json();
89+
90+
const forms = data.value;
91+
92+
if(forms.length !== 0) {
93+
94+
for (const form of forms) {
95+
96+
console.log(` Checking form ${form.name} (${form.formid})...`);
97+
98+
const formXML = form.formxml;
99+
100+
const parser = new DOMParser();
101+
102+
const xmlDoc = parser.parseFromString(formXML, "text/xml");
103+
104+
const handlers = xmlDoc.getElementsByTagName("Handler");
105+
106+
const userIdHandlers = []
107+
108+
for (let i = 0; i < handlers.length; i++) {
109+
110+
const handler = handlers[i];
111+
112+
if (
113+
114+
handler.getAttribute("functionName") === "Mscrm.userid_onchange" &&
115+
116+
handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js"
117+
118+
) {
119+
120+
userIdHandlers.push(handler);
121+
122+
}
123+
124+
}
125+
126+
if (userIdHandlers.length > 1) {
127+
128+
console.warn(`Form ${form.name} (${form.formid}) has more than 1 Mscrm.userid_onchange event handlers (has ${userIdHandlers.length}).`);
129+
130+
}
131+
132+
else if (userIdHandlers.length === 0) {
133+
134+
console.warn(`Form ${form.name} (${form.formid}) has 0 Mscrm.userid_onchange event handlers.`);
135+
136+
continue;
137+
138+
}
139+
140+
await Promise.all(userIdHandlers.map(async handler => {
141+
142+
if (
143+
144+
handler.getAttribute("functionName") === "Mscrm.userid_onchange" &&
145+
146+
handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js" &&
147+
148+
handler.getAttribute("passExecutionContext") === "true"
149+
150+
) {
151+
152+
console.log(` Form ${form.name} (${form.formid}) has the correct Mscrm.userid_onchange event handler.`);
153+
154+
}
155+
156+
else if (
157+
158+
handler.getAttribute("functionName") === "Mscrm.userid_onchange" &&
159+
160+
handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js" &&
161+
162+
(handler.getAttribute("passExecutionContext") === "false" || handler.getAttribute("passExecutionContext") === null)
163+
164+
) {
165+
166+
console.log(` Form ${form.name} (${form.formid}) has the Mscrm.userid_onchange event handler but the passExecutionContext attribute is not set to true. Setting it to true...`);
167+
168+
handler.setAttribute("passExecutionContext", "true");
169+
170+
const serializer = new XMLSerializer();
171+
172+
const updatedXml = serializer.serializeToString(xmlDoc);
173+
174+
await updateBookableResourceForms(form, updatedXml);
175+
176+
publishXML = true;
177+
178+
}
179+
180+
return Promise.resolve();
181+
182+
}));
183+
184+
}
185+
186+
} else {
187+
188+
console.log("No Bookable Resource forms found. Nothing was done");
189+
190+
}
191+
192+
} catch (error) {
193+
194+
console.error(error.message);
195+
196+
}
197+
198+
if(publishXML) {
199+
200+
console.log("Publishing changes...");
201+
202+
await publishChanges();
203+
204+
publishXML = false;
205+
206+
}
207+
208+
console.log("Finished");
209+
210+
}
211+
212+
async function updateBookableResourceForms(form, formxml) {
213+
214+
console.log(` Updating Bookable Resource Form ${form.name} (${form.formid}) ...`);
215+
216+
try {
217+
218+
const reqBody = JSON.stringify({formxml: formxml});
219+
220+
const updateResponse = await fetch(`https://${ORG}/api/data/v9.2/systemforms(${form.formid})`, {
221+
222+
method: 'PATCH',
223+
224+
headers: {
225+
226+
'Content-Type': 'application/json'
227+
228+
},
229+
230+
body: reqBody
231+
232+
});
233+
234+
if (!updateResponse.ok) {
235+
236+
throw new Error(`Error updating form ${formid}: ${updateResponse.statusText}`);
237+
238+
}
239+
240+
console.log(` Form ${form.name} (${form.formid}) updated successfully.`);
241+
242+
} catch (error) {
243+
244+
console.error(error.message);
245+
246+
}
247+
248+
console.log(` Done updating Bookable Resource Form ${form.name} (${form.formid}).`);
249+
250+
}
251+
252+
async function publishChanges() {
253+
254+
console.log(" Starting publish XML process...");
255+
256+
const publishResponse = await fetch(`https://${ORG}/api/data/v9.2/PublishXml`, {
257+
258+
method: 'POST',
259+
260+
headers: {
261+
262+
'Content-Type': 'application/json'
263+
264+
},
265+
266+
body: '{"ParameterXml": "<importexportxml><entities><entity>bookableresource</entity></entities></importexportxml>"}'
267+
268+
});
269+
270+
if (!publishResponse.ok) {
271+
272+
throw new Error(`Error publishing XML: ${publishResponse.statusText}`);
273+
274+
}
275+
276+
console.log(" Done publish XML process.");
277+
278+
}
279+
280+
// Call the function
281+
282+
fixBookableResourceForms()
283+
```

0 commit comments

Comments
 (0)