Project Server 计划工时不更新
Project Server Planned Work Does not update
我正在开发 Project Server 2010 时间表导入程序。
它与 Project Web App(他们导入)中的实际时间配合得很好。
问题
问题是客户需要根据输入的实际工时更新计划工时。
调用 timesheetClient.QueueUpdateTimesheet() 后,它不会根据 Project Server 自动工作计划功能更新计划工作:<
如果您查看屏幕截图,则有 22 小时和 10 小时,但没有 "Zaplanowana" -> 计划值!
如果您只需单击文本并手动输入它们,就会出现计划的工作。
我可以手动更改timesheetDs.TS_ACT_PLAN_VALUE
,但我不想手动编写复杂的工作计划算法(相信我,在 Project 世界中它真的很复杂)。
actual.TS_ACT_VALUE = 1000 * 60 * hours;
actual.TS_ACT_PLAN_VALUE = ???;
两种可能的解决方案
1。破解 PWA 时间表 JSGrid
(Javascript controll) 通过尝试模拟用户手动编辑行,这是 "quite" 困难
window.timesheetComponent.get_TimesheetSatellite().GetJsGridControlInstance()
2。尝试使用 PWA 时间表控件使用的相同网络服务
问题是它没有记录。
我们可以(理论上)在 /pwa/_vti_bin/PSI/ProjectServer.svc
上调用 TimeSheetSendGridUpdatesForSave 操作,下一次调用以检索小时数(通过官方 TimesheetClient 读取时间表)或 TimeSheetGetTimesheetForGridJsonFromViewUid
作为 pwa js 客户端调用,将导致更新的计划小时数
该方法有一个我还没有解决的问题 - 如何进行身份验证 - 关于第二个问题的更多信息
关键词:计划工作、计划时间、pwa 计划、项目服务器 2010、planowane godziny
免责声明优先
使用风险自负。此代码不可移植,这意味着 Microsoft 没有义务通知您其内部网络服务中发生了某些更改。
工作解决方案
尝试使用与 PWA 时间表控件相同的网络服务
问题是它没有记录。
我们可以在 /pwa/_vti_bin/PSI/ProjectServer.svc
.
上调用 TimeSheetSendGridUpdatesForSave 操作
如何?
首先,您必须在标准 dll 之外针对 PSI 进行身份验证。
我自己描述和解决的问题
然后你需要用数据调用webservice。
例如,我们将使用此请求,它将我任务的实际小时数更改为 12 小时。以下代码段是从 Chrome DevTools -> 'Network' 选项卡复制的,当您更改时间并单击实际 PWA 时间表客户端上的保存(在浏览器中 http://servername/pwa/Timesheet.aspx?tsUID=06b92bf0-806e-44d5-8c94-616c50471920
)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<TimeSheetSendGridUpdatesForSave
xmlns="http://schemas.microsoft.com/office/project/server/webservices/PWA/">
<jobUid>{ba875aee-a59f-4c8f-974e-cd5f21dff7b6}</jobUid>
<tsUid>{06b92bf0-806e-44d5-8c94-616c50471920}</tsUid>
<changesJson>[
{
"updates": [
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2a",
"newProp": { "dataValue": "720000", "hasDataValue": true }
},
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2t",
"newProp": { "dataValue": "720000", "hasDataValue": true }
}
],
"changeNumber": 20
}
]
</changesJson>
<viewOptionsJson>{"dateFormat":3,"workFormat":2,"durationFormat":7,"filterType":5,"loadViewProperties":false,"newTasks":[],"importTasks":[],"removedLines":[]}</viewOptionsJson>
</TimeSheetSendGridUpdatesForSave>
</soap:Body>
</soap:Envelope>
在 SOAP UI 的 Auth 选项卡中,您必须提供凭据 作为拥有时间表的用户 。您不能只从管理员帐户发出请求,因为 PSI 会 return
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Server</faultcode>
<faultstring xml:lang="pl-PL">ProjectServerError(s) LastError=GeneralInvalidOperation Instructions: Pass this into PSClientError constructor to access all error information</faultstring>
<detail>
<errinfo>
<general>
<class name="Nie można wprowadzić zmian w grafiku. Grafik nie został przesłany lub został odwołany.">
<error id="20011" name="GeneralInvalidOperation" uid="36ec16f4-db82-4fee-8922-2cd8d4084829"/>
</class>
</general>
</errinfo>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
就像下面的 gif 一样
2019 年 8 月 27 日更新
呼叫代码:
[TestMethod]
public void SampleChangeHoursInPlainDotNetWebClient()
{
var httpClient = new WebClient();
httpClient.UseDefaultCredentials = true; // you have to be in a timesheets user scope (windows auth, ntlm)
httpClient.Headers.Add("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
httpClient.Headers.Add("Content-Type", "text/xml; charset=UTF-8");
httpClient.Headers.Add("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
httpClient.Headers.Add("Accept-Encoding", "gzip, deflate");
httpClient.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
httpClient.Headers.Add("AsmxRoutedCall", "true");
httpClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>";
var response = httpClient.UploadString("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc", "POST", data);
}
使用 RestSharp:
[TestMethod]
public void SampleChangeHours()
{
var client = new RestClient("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
client.Authenticator = new NtlmAuthenticator(new NetworkCredential("test1","Start123!@#","CORPNET"));
request.AddHeader("Host", "preprod2010");
request.AddHeader("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
request.AddHeader("Connection", "keep-alive");
request.AddHeader("Content-Type", "text/xml; charset=UTF-8");
request.AddHeader("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
request.AddHeader("Accept-Encoding", "gzip, deflate");
request.AddHeader("X-FORMS_BASED_AUTH_ACCEPTED", "f");
request.AddHeader("AsmxRoutedCall", "true");
request.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
request.AddParameter("undefined", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
}
我正在开发 Project Server 2010 时间表导入程序。 它与 Project Web App(他们导入)中的实际时间配合得很好。
问题
问题是客户需要根据输入的实际工时更新计划工时。
调用 timesheetClient.QueueUpdateTimesheet() 后,它不会根据 Project Server 自动工作计划功能更新计划工作:<
如果您查看屏幕截图,则有 22 小时和 10 小时,但没有 "Zaplanowana" -> 计划值!
如果您只需单击文本并手动输入它们,就会出现计划的工作。
我可以手动更改timesheetDs.TS_ACT_PLAN_VALUE
,但我不想手动编写复杂的工作计划算法(相信我,在 Project 世界中它真的很复杂)。
actual.TS_ACT_VALUE = 1000 * 60 * hours;
actual.TS_ACT_PLAN_VALUE = ???;
两种可能的解决方案
1。破解 PWA 时间表 JSGrid
(Javascript controll) 通过尝试模拟用户手动编辑行,这是 "quite" 困难
window.timesheetComponent.get_TimesheetSatellite().GetJsGridControlInstance()
2。尝试使用 PWA 时间表控件使用的相同网络服务
问题是它没有记录。
我们可以(理论上)在 /pwa/_vti_bin/PSI/ProjectServer.svc
上调用 TimeSheetSendGridUpdatesForSave 操作,下一次调用以检索小时数(通过官方 TimesheetClient 读取时间表)或 TimeSheetGetTimesheetForGridJsonFromViewUid
作为 pwa js 客户端调用,将导致更新的计划小时数
该方法有一个我还没有解决的问题 - 如何进行身份验证 - 关于第二个问题的更多信息
关键词:计划工作、计划时间、pwa 计划、项目服务器 2010、planowane godziny
免责声明优先
使用风险自负。此代码不可移植,这意味着 Microsoft 没有义务通知您其内部网络服务中发生了某些更改。
工作解决方案
尝试使用与 PWA 时间表控件相同的网络服务
问题是它没有记录。
我们可以在 /pwa/_vti_bin/PSI/ProjectServer.svc
.
如何?
首先,您必须在标准 dll 之外针对 PSI 进行身份验证。
我自己描述和解决的问题
然后你需要用数据调用webservice。
例如,我们将使用此请求,它将我任务的实际小时数更改为 12 小时。以下代码段是从 Chrome DevTools -> 'Network' 选项卡复制的,当您更改时间并单击实际 PWA 时间表客户端上的保存(在浏览器中 http://servername/pwa/Timesheet.aspx?tsUID=06b92bf0-806e-44d5-8c94-616c50471920
)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<TimeSheetSendGridUpdatesForSave
xmlns="http://schemas.microsoft.com/office/project/server/webservices/PWA/">
<jobUid>{ba875aee-a59f-4c8f-974e-cd5f21dff7b6}</jobUid>
<tsUid>{06b92bf0-806e-44d5-8c94-616c50471920}</tsUid>
<changesJson>[
{
"updates": [
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2a",
"newProp": { "dataValue": "720000", "hasDataValue": true }
},
{
"type": 2,
"recordKey": "a81cc5f7-307a-46ce-a131-77e15468c29f",
"fieldKey": "TPD_col2t",
"newProp": { "dataValue": "720000", "hasDataValue": true }
}
],
"changeNumber": 20
}
]
</changesJson>
<viewOptionsJson>{"dateFormat":3,"workFormat":2,"durationFormat":7,"filterType":5,"loadViewProperties":false,"newTasks":[],"importTasks":[],"removedLines":[]}</viewOptionsJson>
</TimeSheetSendGridUpdatesForSave>
</soap:Body>
</soap:Envelope>
在 SOAP UI 的 Auth 选项卡中,您必须提供凭据 作为拥有时间表的用户 。您不能只从管理员帐户发出请求,因为 PSI 会 return
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Server</faultcode>
<faultstring xml:lang="pl-PL">ProjectServerError(s) LastError=GeneralInvalidOperation Instructions: Pass this into PSClientError constructor to access all error information</faultstring>
<detail>
<errinfo>
<general>
<class name="Nie można wprowadzić zmian w grafiku. Grafik nie został przesłany lub został odwołany.">
<error id="20011" name="GeneralInvalidOperation" uid="36ec16f4-db82-4fee-8922-2cd8d4084829"/>
</class>
</general>
</errinfo>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
就像下面的 gif 一样
2019 年 8 月 27 日更新
呼叫代码:
[TestMethod]
public void SampleChangeHoursInPlainDotNetWebClient()
{
var httpClient = new WebClient();
httpClient.UseDefaultCredentials = true; // you have to be in a timesheets user scope (windows auth, ntlm)
httpClient.Headers.Add("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
httpClient.Headers.Add("Content-Type", "text/xml; charset=UTF-8");
httpClient.Headers.Add("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
httpClient.Headers.Add("Accept-Encoding", "gzip, deflate");
httpClient.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
httpClient.Headers.Add("AsmxRoutedCall", "true");
httpClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>";
var response = httpClient.UploadString("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc", "POST", data);
}
使用 RestSharp:
[TestMethod]
public void SampleChangeHours()
{
var client = new RestClient("http://preprod2010/pwa/_vti_bin/PSI/ProjectServer.svc");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
client.Authenticator = new NtlmAuthenticator(new NetworkCredential("test1","Start123!@#","CORPNET"));
request.AddHeader("Host", "preprod2010");
request.AddHeader("SOAPAction", "http://schemas.microsoft.com/office/project/server/webservices/PWA/TimeSheetSendGridUpdatesForSave");
request.AddHeader("Connection", "keep-alive");
request.AddHeader("Content-Type", "text/xml; charset=UTF-8");
request.AddHeader("Accept-Language", "en-US,en;q=0.9,pl;q=0.8");
request.AddHeader("Accept-Encoding", "gzip, deflate");
request.AddHeader("X-FORMS_BASED_AUTH_ACCEPTED", "f");
request.AddHeader("AsmxRoutedCall", "true");
request.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
request.AddParameter("undefined", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><TimeSheetSendGridUpdatesForSave xmlns=\"http://schemas.microsoft.com/office/project/server/webservices/PWA/\"><jobUid>{ad8bd458-564c-49c5-8955-dfa577556d4a}</jobUid><tsUid>{6856cac1-7c88-4020-bdb5-c4e1b1a54b85}</tsUid><changesJson>[{\"updates\":[{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0a\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TS_LINE_STATUS\",\"newProp\":{\"dataValue\":\"0\",\"hasDataValue\":true,\"localizedValue\":\"Nieprzes%u0142ane\",\"hasLocalizedValue\":true}},{\"type\":2,\"recordKey\":\"f88b5297-1985-4c2c-8717-554167471e81\",\"fieldKey\":\"TPD_col0t\",\"newProp\":{\"dataValue\":\"300000\",\"hasDataValue\":true}}],\"changeNumber\":2},]</changesJson><viewOptionsJson>{\"dateFormat\":3,\"workFormat\":2,\"durationFormat\":7,\"filterType\":5,\"loadViewProperties\":true,\"newTasks\":[],\"importTasks\":[],\"removedLines\":[]}</viewOptionsJson></TimeSheetSendGridUpdatesForSave></soap:Body></soap:Envelope>", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
}