sexta-feira, 19 de dezembro de 2008
>> CRM 4.0 - AJAX + Preenchimento Automático de Lookup
Segue código template que ilustra isto, de forma que, ao selecionar uma Conta na Oportunidade, o sistema atualize a Lista de Preço da Oportunidade (existente na Conta).
Note que o código (JavaScript) utiliza o Web Services do CRM, método Retrieve para busca de dados de uma entidade, baseado no ID.
No [OnChange] do campo [Cliente Provável] da Oportunidade, adicionar o template abaixo:
P.S.: Substitua o nome [CAMPO_RETORNO] pelo nome do campo que representa o ID da Lista de Preço da Conta.
---- ONCHANGE FIELD ACTION ----
getAccountPriceLevel();
function getAccountPriceLevel()
{
var server = window.location.host;
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp.open("POST", "http://" + server + "/mscrmservices/2007/crmservice.asmx", true);
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
var soapBody = "<soap:Body><Retrieve xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\"><entityName>account</entityName>";
soapBody += "<id>" + crmForm.all.customerid.DataValue[0].id + "</id>";
soapBody += "<columnSet xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:ColumnSet\"><q1:Attributes>";
soapBody += "<q1:Attribute>CAMPO_RETORNO</q1:Attribute>";
soapBody += "</q1:Attributes></columnSet>";
soapBody += "</Retrieve></soap:Body>";
var soapXml = "<soap:Envelope " +
"xmlns: soap='http://schemas.xmlsoap.org/soap/envelope/' "+
"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "+
"xmlns:xsd='http://www.w3.org/2001/XMLSchema'>";
soapXml += GenerateAuthenticationHeader();
soapXml += soapBody;
soapXml += "</soap:Envelope>";
xmlhttp.onreadystatechange = StateChangeAccountPriceLevel;
xmlhttp.send(soapXml);
}
function StateChangeAccountPriceLevel()
{
if (xmlhttp.readyState == 4)
{
var oNodes = xmlhttp.responseXML.selectSingleNode("//RetrieveResult").childNodes;
var priceLevelID = oNodes[0].text;
if (crmForm.all.pricelevelid.DataValue == null)
{
var lookupData = new Array();
var lookupItem= new Object();
lookupItem.id = priceLevelID;
lookupItem.typename = 'pricelevel';
lookupItem.name = 'Lista de Preço Padrão';
lookupData[0] = lookupItem;
crmForm.all.pricelevelid.DataValue = lookupData;
}
}
}
quinta-feira, 18 de dezembro de 2008
>> CRM 4.0 - Data Migration Manager
Segue algumas orientações para uso do DMM:
1 - Demostração
Veja este "webcast" que ensina o uso do DMM - http://channel9.msdn.com/posts/jodonnell/Microsoft-Dynamics-CRM-40--Data-Migration-Manager-with-John-ODonnell/
2 - Restrições
- NÃO instale o DMM no Servidor do CRM (DMM só roda no [Windows Vista] ou [Windows XP]);
- Alguns desenvs instalam o DMM no Servidor do [SQL SERVER - 32 bits];
- Se o banco de dados for de [64 bits] o DMM Não vai funcionar;
- Use uma máquina Client, 32 bits com [local SQL Express] para o DataBase de Migração;
- Instale o DMM escolhendo a opção do banco de dados [SQL SERVER 2005 EXPRESS EDITION];
- Instale e rode o DMM com um usuário [local admin] e [CRM Admin]. Isto é importante porque o DMM usa o Web Services do CRM! Inclusive o DMM só pode ser usado pelo usuário que o instalou.
- DMM não pode ser usado enquanto o [Microsoft Office Outlook] estiver rodando;
Fonte adicional: http://rc.crm.dynamics.com/rc/regcont/en_us/Live/help/How_dmw_install.htm
terça-feira, 16 de dezembro de 2008
>> CRM 4.0 - "Limitações" no Acompanhamento de Atividades
Por exemplo, se você tentar efetuar um Acompanhamento (do tipo Tarefa) para uma atividade do tipo [Telefonema], atividade esta pertencente a uma [Campanha Rápida], ao salvar o acompanhamento, receberá a seguinte mensagem do CRM:
"[Campanhas rápidas] não podem ter [tarefa] como uma [atividade de acompanhamento]"
O que isto significa?
Seguindo o mesmo raciocínio do [KB 909824] que explica a impossibilidade de criação de [acompanhamento de atividade do tipo tarefa] para uma [atividade do tipo email]...
Podemos explicar este caso da seguinte forma:
"Quando você tenta criar um [acompanhamento do tipo tarefa], o Microsoft CRM configura o campo "Regarding" da [atividade de acompanhamento do tipo tarefa]. Para este campo, o Microsoft CRM tenta usar o valor do campo "Regarding" da [atividade de telefonema]. Contudo, não existe um relacionamento entre o [acompanhamento do tipo tarefa] e a [campanha rápida]."
Por este motivo aparece a msg de restrição.
Solução MS:
Use os seguintes tipos de atividades para acompanhamento:
- Telefonema;
- Carta;
- Fax;
- E-mail;
- Apontamento.
>> CRM 4.0 - Botão Acompanhamento de Atividades
Para que serve o botão de "Acompanhamento" existente nas telas de detalhes dos vários tipos de atividades do CRM?
O Acompanhamento (ou FollowUp) também é uma atividade no CRM, dos tipos tarefa, email, telefonema, etc. É um recurso que faz parte do Painel "Assistente de Formulário" do CRM.
Por exemplo, você pode criar uma atividade de serviço de acompanhamento futuro. Imagine uma empresa que acabou de concluir a troca de óleo para um cliente; você pode criar uma nova atividade de serviço para outra troca de óleo em seis meses, de forma a "associar" uma tarefa em outra.
Veja este exemplo: http://rc.crm.dynamics.com/rc/regcont/pt_br/op/articles/followup.aspx
sexta-feira, 12 de dezembro de 2008
>> CRM 4.0 - Revisar Quota Programaticamente
Juntando o "quebra-cabeça" para este caso, segue abaixo função Template.
public string ReviseQuote(string id)
{
// Set up the CRM Service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = 0;
token.OrganizationName = "OrgName";
CrmService CrmWebService = new CrmService();
CrmWebService.Url = "http://localhost:5555/mscrmservices/2007/crmservice.asmx";
CrmWebService.CrmAuthenticationTokenValue = token;
CrmWebService.Credentials = System.Net.CredentialCache.DefaultCredentials;
string idRet = string.Empty;
Boolean CloseQuoteRequestOk = true;
// 1 - CLOSE QUOTE ACTIVITY
crmSdk.BusinessEntity beQuote = CrmWebService.Retrieve(crmSdk.EntityName.quote.ToString(), new Guid(id), new crmSdk.AllColumns());
crmSdk.quote _quote = beQuote as crmSdk.quote;
if (_quote == null) return string.Empty;
quoteclose _quoteClose = new quoteclose();
Lookup _lookUp = new Lookup();
_lookUp.type = EntityName.quote.ToString();
_lookUp.Value = new Guid(id);
CrmDateTime _crmDate1 = new CrmDateTime();
CrmDateTime _crmDate2 = new CrmDateTime();
_crmDate1.Value = new DateTime(1999, 12, 31, 23, 0, 0).ToString("u");
_crmDate2.Value = DateTime.Now.ToString("s");
_quoteClose.quoteid = _lookUp;
_quoteClose.subject = "Oferta Fechada (Revisada) " + _quote.quotenumber;
_quoteClose.quotenumber = _quote.quotenumber;
_quoteClose.revision = _quote.revisionnumber;
_quoteClose.actualstart = _crmDate1;
_quoteClose.actualend = _crmDate2;
CloseQuoteRequest closeQuoteRequest = new CloseQuoteRequest();
closeQuoteRequest.QuoteClose = _quoteClose;
closeQuoteRequest.Status = 7; // Revised
try
{
CrmWebService.Execute(closeQuoteRequest);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
CloseQuoteRequestOk = false;
System.Diagnostics.EventLog.WriteEntry("Application", "CloseQuoteRequest ERROR => QuoteID: [" + id + "] / Message: " + ex.Detail.InnerText);
}
if (!CloseQuoteRequestOk) return string.Empty;
// 2 - REVISE QUOTE
ReviseQuoteRequest reviseReq = new ReviseQuoteRequest();
ColumnSet columns = new ColumnSet();
columns.Attributes = new string[] { "quoteid" };
reviseReq.ColumnSet = columns;
reviseReq.QuoteId = new Guid(id);
reviseReq.ReturnDynamicEntities = false;
ReviseQuoteResponse reviseResp = null;
try
{
reviseResp = (ReviseQuoteResponse)CrmWebService.Execute(reviseReq);
idRet = "{" + (reviseResp.BusinessEntity as quote).quoteid.Value.ToString().ToUpper() + "}";
}
catch (System.Web.Services.Protocols.SoapException ex)
{
idRet = string.Empty;
System.Diagnostics.EventLog.WriteEntry("Application", "ReviseQuoteRequest ERROR => QuoteID: [" + id + "] / Message: " + ex.Detail.InnerText);
}
return idRet;
}
quarta-feira, 10 de dezembro de 2008
>> CRM 4.0 - Envio de Email Template (com anexos)
A função SendEmailTemplate recebe como parâmetros o número, nome e ID da entidade como referência para o email (campo "referente a"), a descrição do Template do CRM a ser usado para envio do email, para quais usuários enviar e os anexos.
public static string SendEmailTemplate(int otc, string CrmEntityName, Guid oID, string templateTitle, string[] aUser, string[] aFiles)
{
// Set up the CRM Service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = 0;
token.OrganizationName = "OrgName";
CrmService CrmWebService = new CrmService();
CrmWebService.Url = "http://localhost:5555/mscrmservices/2007/crmservice.asmx";
CrmWebService.CrmAuthenticationTokenValue = token;
CrmWebService.Credentials = System.Net.CredentialCache.DefaultCredentials;
Guid emailTemplateID = getTemplate(CrmWebService, otc, templateTitle);
if (emailTemplateID.Equals(Guid.Empty))
{
string err = "Não foi possível localizar o Email template ";
err += "com a palavra chave [" + templateTitle + "] para a entidade [" + otc.ToString() + "].";
return err;
}
crmSdk.WhoAmIRequest userRequest = new crmSdk.WhoAmIRequest();
crmSdk.WhoAmIResponse userResponse = (crmSdk.WhoAmIResponse)CrmWebService.Execute(userRequest);
crmSdk.BusinessEntity beSystemUser = CrmWebService.Retrieve(crmSdk.EntityName.systemuser.ToString(), userResponse.UserId, new crmSdk.AllColumns());
crmSdk.systemuser _systemuser = beSystemUser as crmSdk.systemuser;
if (_systemuser.internalemailaddress == null)
{
string err = "Seu usuário, no CRM, não possui EMAIL cadastrado (Email Primário).";
return err;
}
crmSdk.Owner _owner = new crmSdk.Owner();
_owner.type = crmSdk.EntityName.systemuser.ToString();
_owner.Value = userResponse.UserId;
// Instantiate the Template as an EMAIL Object.
crmSdk.InstantiateTemplateRequest instTemplate = new crmSdk.InstantiateTemplateRequest();
instTemplate.TemplateId = emailTemplateID;
instTemplate.ObjectId = oID;
instTemplate.ObjectType = CrmEntityName;
crmSdk.InstantiateTemplateResponse instTemplateResponse = null;
try
{
instTemplateResponse = (crmSdk.InstantiateTemplateResponse)CrmWebService.Execute(instTemplate);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
return "InstantiateTemplateResponse Error - " + ex.Detail.InnerText;
}
catch (Exception ex)
{
return "InstantiateTemplateResponse Error - " + ex.Message;
}
//Convert the returned entity to an email entity, this is really just the merged template body
crmSdk.email emailFromTemplate = (crmSdk.email)instTemplateResponse.BusinessEntityCollection.BusinessEntities[0];
//Add Recipients to the email
CrmUtil.crmSdk.activityparty partyFROM = new CrmUtil.crmSdk.activityparty();
partyFROM.partyid = new CrmUtil.crmSdk.Lookup();
partyFROM.partyid.type = CrmUtil.crmSdk.EntityName.systemuser.ToString();
partyFROM.partyid.Value = userResponse.UserId;
crmSdk.activityparty[] aParties = new crmSdk.activityparty[aUser.Length];
int loop = 0;
for (int j = 0; j < aUser.Length; j++)
{
aParties[loop] = new crmSdk.activityparty();
aParties[loop].partyid = new crmSdk.Lookup();
aParties[loop].partyid.type = crmSdk.EntityName.systemuser.ToString();
aParties[loop].partyid.Value = new Guid(aUser[j]);
loop++;
}
emailFromTemplate.from = new crmSdk.activityparty[] { partyFROM };
emailFromTemplate.to = aParties;
emailFromTemplate.ownerid = _owner;
emailFromTemplate.regardingobjectid = new crmSdk.Lookup();
emailFromTemplate.regardingobjectid.type = CrmEntityName;
emailFromTemplate.regardingobjectid.Value = oID;
// Create the Email
crmSdk.TargetCreateEmail targetCreate = new crmSdk.TargetCreateEmail();
targetCreate.Email = emailFromTemplate;
crmSdk.CreateRequest request = new crmSdk.CreateRequest();
request.Target = targetCreate;
crmSdk.CreateResponse response = null;
try
{
response = (crmSdk.CreateResponse)CrmWebService.Execute(request);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
return "TargetCreateEmail Error - " + ex.Detail.InnerText;
}
// Add Attachments
string msgRet = AddAttachments(response.id, aFiles);
if (!string.IsNullOrEmpty(msgRet)) return msgRet;
// Send Email
crmSdk.SendEmailRequest req = new crmSdk.SendEmailRequest();
req.EmailId = response.id;
req.TrackingToken = "";
req.IssueSend = true;
crmSdk.SendEmailResponse res = null;
try
{
res = (crmSdk.SendEmailResponse)CrmWebService.Execute(req);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
return "SendEmailRequest - " + ex.Detail.InnerText;
}
return "Email criado com sucesso.";
}
private static Guid getTemplate(crmSdk.CrmService CrmWebService, int otc, string templateTitle)
{
crmSdk.QueryExpression _Query = new crmSdk.QueryExpression();
_Query.EntityName = crmSdk.EntityName.template.ToString();
_Query.ColumnSet = new crmSdk.AllColumns();
crmSdk.ConditionExpression _ce1 = new crmSdk.ConditionExpression();
crmSdk.ConditionExpression _ce2 = new crmSdk.ConditionExpression();
_ce1.AttributeName = "templatetypecode";
_ce1.Operator = crmSdk.ConditionOperator.Equal;
_ce1.Values = new object[] { otc };
_ce2.AttributeName = "title";
_ce2.Operator = crmSdk.ConditionOperator.Like;
_ce2.Values = new object[] { "%" + templateTitle + "%" };
crmSdk.FilterExpression _FilterExpression = new crmSdk.FilterExpression();
_FilterExpression.FilterOperator = crmSdk.LogicalOperator.And;
_FilterExpression.Conditions = new crmSdk.ConditionExpression[] { _ce1, _ce2 };
_Query.Criteria = _FilterExpression;
crmSdk.BusinessEntityCollection _Bec = CrmWebService.RetrieveMultiple(_Query);
Guid gResult = Guid.Empty;
if (_Bec.BusinessEntities.Length > 0)
{
crmSdk.template oTemplate = _Bec.BusinessEntities[0] as crmSdk.template;
gResult = oTemplate.templateid.Value;
}
return gResult;
}
private static string AddAttachments(crmSdk.CrmService CrmWebService, Guid emailID, string[] aFiles)
{
string retMsg = string.Empty;
string sServerPath = HttpContext.Current.Server.MapPath(@"\");
sServerPath = sServerPath.Replace(@"\", "||");
for (int i = 0; i < aFiles.Length; i++)
{
string fileNameCRM = aFiles[i];
RemoveSpecialChars(ref fileNameCRM);
string file = sServerPath + @"UploadFiles\\" + aFiles[i];
string Newfile = sServerPath + @"UploadFiles\\" + fileNameCRM;
file = file.Replace("||", "\\\\");
Newfile = Newfile.Replace("||", "\\\\");
string additionalError = "\nTentando adicionar anexo: " + Newfile;
FileInfo info = new FileInfo(file);
string sExtension = info.Extension;
try
{
string fileCompare1 = aFiles[i].Trim().ToLower();
string fileCompare2 = fileNameCRM.Trim().ToLower();
if (!fileCompare1.Equals(fileCompare2))
{
info.MoveTo(Newfile);
}
}
catch (IOException ex)
{
retMsg ="IOException (MoveTo) - " + ex.Message + additionalError;
return retMsg;
}
catch (Exception ex)
{
retMsg = "IOException (MoveTo) - " + ex.Message + additionalError;
return retMsg;
}
FileStream fl = File.OpenRead(Newfile);
byte[] byteData = new byte[fl.Length];
fl.Read(byteData, 0, (int)fl.Length);
fl.Close();
crmSdk.activitymimeattachment oMimeAttach = new crmSdk.activitymimeattachment();
oMimeAttach.activityid = new crmSdk.Lookup();
oMimeAttach.activityid.Value = emailID;
oMimeAttach.activityid.type = crmSdk.EntityName.email.ToString();
oMimeAttach.attachmentnumber = new crmSdk.CrmNumber();
oMimeAttach.attachmentnumber.Value = i;
oMimeAttach.filename = fileNameCRM;
oMimeAttach.body = Convert.ToBase64String(byteData, 0, byteData.Length);
try
{
CrmWebService.Create(oMimeAttach);
try { info.Delete(); }catch { }
}
catch (SoapException ex)
{
retMsg = "Activitymimeattachment Error - " + ex.Detail.InnerText + additionalError;
}
catch (Exception ex)
{
retMsg = "Activitymimeattachment Error - " + ex.Message + additionalError;
}
}
return retMsg;
}
private static string RemoveSpecialChars(ref string fileName)
{
fileName = Regex.Replace(fileName, @"[^\w\.@-]", "");
fileName = fileName.Replace("ª", "");
fileName = fileName.Replace("º", "");
return fileName;
}
>> CRM 4.0 - Converter System.DateTime para CRMDateTime
{
CrmDateTime crmDateTime = new CrmDateTime();
crmDateTime.date = dateTime.ToShortDateString();
crmDateTime.time = dateTime.ToShortTimeString();
TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
string sOffset = string.Empty;
if (offset.Hours < 0)
{
sOffset = "-" + (offset.Hours * -1).ToString().PadLeft(2, '0');
}
else
{
sOffset = "+" + offset.Hours.ToString().PadLeft(2, '0');
}
sOffset += ":" + offset.Minutes.ToString().PadLeft(2, '0');
crmDateTime.Value = dateTime.ToString(string.Format("yyyy-MM-ddTHH:mm:ss{0}", sOffset));
return crmDateTime;
}
>> CRM 4.0 Plugin - Dicas no uso do IPluginExecutionContext
1 - Detectar a Origem da execução do Plugin (Alteração ou Conversão de um registro em outro).
Por exemplo, para saber se a execução do seu Plugin tem como origem a Conversão de uma Quota em Pedido.
using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
public class Main_Plugin: IPlugin
{
public void Execute(IPluginExecutionContext context)
{
Boolean IsConvertionMode = (context.CallerOrigin.GetType() == typeof(AsyncServiceOrigin) && context.Depth > 1);
2 - Função genérica para recuperar o ID do registro do CRM para os Eventos de CREATE, UPDATE e DELETE.
public static Guid GetIDParam(DynamicEntity de, IPluginExecutionContext context, string propertyName)
{
Guid ret = Guid.Empty;
if (context.MessageName.Equals("Create"))
ret = (Guid)context.OutputParameters[ParameterName.Id];
else if (context.MessageName.Equals("Update"))
ret = ((Key)de.Properties[propertyName]).Value;
else if (context.MessageName.Equals("Delete"))
{
Moniker mon = (Moniker)context.InputParameters.Properties["Target"];
ret = mon.Id;
}
return ret;
}
3 - Passando dados entre Plugins
Compartilhar dados entre Plugins fica fácil com uso da Collection SharedVariables.
Imagine um Plugin de Account, com os Eventos de PRE-Update e POST-Update configurados. Uma determinada ação deverá ser tomada no evento de POST-Update; porém a ação somente será executada se ANTES da alteração do Account o registro possuia um status específico para um campo de Picklist.
Isto é possível 'guardando' o valor do Picklist na Collection SharedVariables (no PRE-Update) e consultando esta collection no POST-Update.
Segue template de código:
public class AccountPreHandler : IPlugin
{
public void Execute(IPluginExecutionContext context)
{
context.SharedVariables["statusAcct"] = [Get Picklist Value];
}
}
public class AccountPostHandler : IPlugin
{
public void Execute(IPluginExecutionContext context)
{
if (context.SharedVariables.Contains("statusAcct"))
{
int statusAcct = (int)context.SharedVariables["statusAcct"];
if (statusAcct==1)
// Do something...
}
}
}
sexta-feira, 5 de dezembro de 2008
>> Exchange Server & Active Sync Mobile
Um colega de trabalho, na empresa que estou atuando no momento, estava com este problema. Pesquisando nos principais fóruns sobre o assunto (around the world!), notei que a dificuldade é geral, e não existe uma solução simples devido a própria natureza do processo.
Porém consegui uma solução para o caso dele, seguindo os seguintes passos:
1 - Habilitar acesso OWA no Exchange Server Manager;
2 - Habilitar acesso ao OWA para determinado usuário no AD;
3 - Windows HOSTS File
- No Exchange Server, editar o arquivo hosts em C:\windows\system32\drivers\etc;
- Adicionar Public IP e FQDN do Exchange server (Windows server name + domain name, NÃO o Internet domain);
>> 1.1.1.1 server.contoso.local
4 - Exchange Virtual Directory
Desabilitar a opção "forms-based authentication".
Abra o Exchange Manager. Expanda o nó [Administrative Groups], expanda o nó [first administrative group] e também o nó [Servers]. Expanda [Protocols], depois [HTTP]. Abaixo de [HTTP], clique com o botão direito do mouse em [Exchange Virtual Server], e escolha [Properties]. Clique na aba [Settings], e limpe o checkbox [Enable Forms Based Authentication] e clique em OK.
Fonte: http://support.microsoft.com/default.aspx/kb/817379
5 - IIS
- Habilitar Integrated Windows Authentication;
- Habilitar Basic Authentication (opcional);
- Habilitar Kerberos / NTLM Authentication.
DOS Command:
- Ir ao diretório de scripts:
cd Inetpub\Adminscripts
- Consultar o tipo de autenticação:
cscript adsutil.vbs get w3svc/1/root/NTAuthenticationProviders
- Configurar o tipo de autenticação NTLM:
cscript adsutil.vbs set w3svc/1/root/NTAuthenticationProviders "Negotiate,NTLM";
P.S.: w3svc/1/root/ - O número "1" representa "Default Web Site" no IIS.
Links úteis:
85010014 error - http://www.tech-archive.net/Archive/PocketPC/microsoft.public.pocketpc.activesync/2006-02/msg00293.html
Exchange ActiveSync Errors and Solutions - http://www.pocketpcfaq.com/faqs/activesync/exchange_errors.php
OMA in Exchange 2003 - http://www.petri.co.il/configure_oma.htm
quinta-feira, 4 de dezembro de 2008
>> CRM - Número Sequencial Aleatório em JavaScript
Pensando nisto, criei um processo para fazer o mesmo (com exceção do número ser aleatório e não sequencial) totalmente em JavaScript.
P.S.: A função generateGuid() pode também ser útil em outros casos pois simula a geração do tipo GUID do banco de dados Sql.
Segue código template:
if (crmForm.FormType==1) // GERAR CÓDIGO SOMENTE NO CREATE DO FORM DO CRM
{
var seq = generateSeqNumber();
var seqPosStart = seq.length-4;
seq = seq.substr(seqPosStart,4);
var guid = generateGuid();
var guidPosStart = guid.length-6;
guid = guid.substr(guidPosStart,6);
crmForm.all.new_numerochamado.DataValue = "CHA-" + seq + "-" + guid;
}
function generateSeqNumber()
{
tmToday = new Date();
return String(tmToday.getTime());
}
function generateGuid()
{
var result, i, j;
result = '';
for(j=0; j<32; j++)
{
if( j == 8 j == 12 j == 16 j == 20)
result = result + '-';
i = Math.floor(Math.random()*16).toString(16).toUpperCase();
result = result + i;
}
return result;
}
segunda-feira, 1 de dezembro de 2008
>> [CRM + IE + [MaxConnPerServer=2]] = PostBack Errors
O CRM até criava o pedido normalmente, porém travava o IE para atualizar os dados do Pedido criado.
Geramos um diagóstico completo do Server (CRM/SQL/IIS/AD) e nada de errado aparecia nos logs.
Então chegamos a conclusão que o problema estava no IE. Por padrão, o IE trabalha com no máximo 2 sessões de download. Porém, no caso do CRM, fica muito restrita esta configuração. Aumentamos para 10 conexões simultâneas e o problema foi resolvido.
Os passos para correção são:
Inicie o editor do Registry (Regedt32.exe).
Localize a seguinte chave:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
No menu [Editar], aponte para [Novo] e clique em [DWORD Value], então adicione os seguintes valores de chave:
Value name: MaxConnectionsPer1_0Server
Value data: 10
Base: Decimal
Value Name: MaxConnectionsPerServer
Value data: 10
Base: Decimal
P.S.: A Microsoft recomenda baixar o número de conexões indicada no KB até que o erro volte a ocorrer.
Fonte: http://support.microsoft.com/kb/282402
>> Microsoft CRM Diagnostics Tool 4
CRM Server Report
– System Information
– Environment Variables
– TCPIP Parameters Registry
– Boot.ini Content
– .Net Framework Registration
– CRM Services Status and Logon Info
– CRM Registry Keys
– CRM Installed Files
- %ProgramFiles%
- GAC
– Web Sites Bindings
– ApplPool Indentities
– CRM WebSite Authentication
– SQL Server Information
– CRM System Settings
– CRM AD Groups Information
– Organization and Deployment Informations
(retrieve by SDK or SQL queries)
- SRS Data Connector Report
– System Information
– Environment Variables
– SRS Data Connector Installed files
- %ProgramFiles%\CRM Data Conn
- %ProgramFiles%\ReportServer
– ReportServer Settings (WMI)
– Report Manager Settings (WMI)
– RSReportServer.config content
– RSSrvPolicy.config content
– SRSDataConnectorSetup.log
- CRM E-Mail Router Report
– System Information
– Environment Variables
– CRM E-Mail Router nstalled files
– CRM E-Mail Router Service Info
– Microsoft.Crm.Tools.EmailAgent.Xml content
– Crm40ExchangeSetup.log
Segue aparência da Ferramenta:
Link para Download: https://community.dynamics.com/crm/b/crmjimwang/archive/2010/03/08/download-58-crm-4-0-diagnostics-tool-alternative-link.aspx
Para habilitar o Trace manualmente: http://support.microsoft.com/kb/907490/en-us
quinta-feira, 27 de novembro de 2008
>> CRM 4.0 - Exclusão física de registros
O serviço de exclusão física de registros no CRM 4.0 mudou desde a versão anterior (3.0). O processo de exclusão é gerenciado pelo mesmo sistema que controla Triggers de Workflows e todos os jobs de processos assíncronos, como o Duplicate Detection e a chamada de plugins assíncronos (CrmAsyncService.exe). O tempo padrão é de 1440 minutos (24 hs) para o serviço de exclusão física de registros (tabela ScaleGroupOrganizationMaintenanceJobs do BD MSCRM_CONFIG). Segue link para baixar utilitário para poder mudar este tempo.
http://code.msdn.microsoft.com/ScaleGroupJobEditor/Release/ProjectReleases.aspx?ReleaseId=676
Se desejar "forçar" a exclusão física dos registros, podemos fazer isto por executar um Update na tabela de Jobs do CRM da seguinte forma:
USE MSCRM_CONFIG
UPDATE ScaleGroupOrganizationMaintenanceJobs
SET NextRunTime = getdate() -- Right Now!
WHERE OperationType = 14 -- Deletion Service
Após o Update, reinicie o serviço assíncrono do CRM.
>> Dicas JavaScript (ASP.NET & MSCRM 4.0)
JS ASP.NET - Função para obter o valor de algum dos parâmetros da Query String da página.
function getQueryStringParam(name)
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null ) return "";
else
return results[1];
}
JS ASP.NET - Função para Converter o primeiro caractere de toda frase em Maiúsculo.
function UCWords(str)
{
var arrStr = str.split(" ");
var strOut = "";
var i = 0;
var stringValues = "da-de-do-das-dos";
while (i < arrStr.length)
{
if (stringValues.indexOf(arrStr[i].toLowerCase()) < 0)
{
firstChar = arrStr[i].substring(0,1);
remainChar = arrStr[i].substring(1);
firstChar = firstChar.toUpperCase();
remainChar = remainChar.toLowerCase();
strOut += firstChar + remainChar + ' ';
}
else
strOut += arrStr[i] + ' ';
i++;
}
return strOut.substr(0,strOut.length - 1);
}
JS ASP.NET - Adicionar / Remover itens em um DropDownList.
function ClearDropDownList(list)
{
for(i=list.options.length-1; i>=0 ;i--)
{
list.remove(i);
}
}
function addDropDownListOption(list, text, value)
{
var optn = document.createElement("OPTION");
optn.text = text;
optn.value = value;
list.options.add(optn);
}
JS MSCRM 4.0 - Validação de campo Data via JavaScript.
if (ValidateDate(crmForm.all.requestdeliveryby))
{
// Custom code...
}
function ValidateDate(field){
var checkstr = "0123456789";
var DateField = field;
var Datevalue = "";
var DateTemp = "";
var seperator = ".";
var leap = 0;
var err = 0;
var i;
err = 0;
var day = DateField.DataValue.getDate();
var month = (DateField.DataValue.getMonth()+1);
var year = DateField.DataValue.getYear();
DateValue = day + "/" + month + "/" + year;
/* Delete all chars except 0..9 */
for (i = 0; i < DateValue.length; i++) {
if (checkstr.indexOf(DateValue.substr(i,1)) >= 0) {
DateTemp = DateTemp + DateValue.substr(i,1);
}
}
DateValue = DateTemp;
/* Validation of month*/
if ((month < 1) || (month > 12)) {
err = 21;
}
/* Validation of day*/
if (day < 1) {
err = 22;
}
/* Validation leap-year / february / day */
if ((year % 4 == 0) || (year % 100 == 0) || (year % 400 == 0)) {
leap = 1;
}
if ((month == 2) && (leap == 1) && (day > 29)) {
err = 23;
}
if ((month == 2) && (leap != 1) && (day > 28)) {
err = 24;
}
/* Validation of other months */
if ((day > 31) && ((month == "01") || (month == "03") || (month == "05") || (month == "07") || (month == "08") || (month == "10") || (month == "12"))) {
err = 25;
}
if ((day > 30) && ((month == "04") || (month == "06") || (month == "09") || (month == "11"))) {
err = 26;
}
/* if 00 ist entered, no error, deleting the entry */
if ((day == 0) && (month == 0) && (year == 00)) {
err = 0; day = ""; month = ""; year = ""; seperator = "";
}
if (err != 0)
{
alert("Data Inválida!");
DateField.focus();
}
return (err == 0);
}
JS MSCRM 4.0 - Inserir / Formatar objetos dinamicamente na página do CRM.
with(crmForm.all.new_labelicms)
{
style.border = 0;
style.color = '#6699cc';
style.fonteSize = '7px';
style.fontWeight = 'bold';
style.overflow = 'hidden';
Disabled = true;
DataValue = 'Obs % ICMS: No caso de venda direta...'
}
/* Insert Adjacent Elements */
var server = window.location.host;
var oImg = document.createElement("<" + "img src='http://" + server + "/_imgs/ico/16_alert.gif'" + " />");
var oHr = document.createElement("<" + "HR class='ms-crm-MenuList-Spacer'" + ">");
var oSpn = document.createElement("<" + "span" + ">");
oSpn.innerText = ' Observações';
oSpn.style.fontWeight = 'bold';
crmForm.all.mit_labelicms.insertAdjacentElement("BeforeBegin",oImg);
crmForm.all.mit_labelicms.insertAdjacentElement("BeforeBegin",oSpn);
crmForm.all.mit_labelicms.insertAdjacentElement("BeforeBegin",oHr);
JS MSCRM 4.0 - AJAX no CRM - Chamada assíncrona em um Web Services Customizado.
function FillUOMProduct()
{
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
var server = window.location.host;
var params = "?productID=" + crmForm.all.productid.DataValue[0].id;
params += "&fields=productnumber,defaultuomid";
var url="http://"+ server+"/WebServicesCRM/Product.asmx/GetProductById"+params;
xmlHttpRequest.open("GET", url, true);
xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttpRequest.setRequestHeader ("SOAPAction", "http://tempuri.org/GetProductById");
xmlHttpRequest.onreadystatechange = HandleStateChangeProduct;
xmlHttpRequest.send();
}
function HandleStateChangeProduct()
{
if (xmlHttpRequest.readyState == 4)
{
var doc = new ActiveXObject('Microsoft.XMLDOM');
var result = xmlHttpRequest.responseXML.xml;
doc.loadXML(result);
}
}
quarta-feira, 19 de novembro de 2008
>> CRM 4.0; IE6; KB953838; Error!!
Soluções:
1 - Instalar o IE7, ou:
2 - Desinstalar o KB953838, ou:
3 - Efetuar o download da Blank.aspx (qq diretório); right-click no arquivo -> Abrir como -> Escolher Programa -> selecionar IE, marcando o checkbox para sempre usar este tipo de programa;
>> Unable to Load Client Print Control - CRM 4.0
Pesquisando sobre o assunto e a mensagem de erro descobri a causa, um HotFix de Segurança da Microsoft (KB956391).
Para solucionar o problema, vai ser necessário atualizações de Service Packs, do Report Viewer e do Sql Server (2005 / 2008).
Segue links para Download dos pacotes:
Microsoft Report Viewer Redistributable 2005 Service Pack 1
http://www.microsoft.com/downloads/details.aspx?FamilyID=82833f27-081d-4b72-83ef-2836360a904d&DisplayLang=en
Security Update for SQL Server 2005 Service Pack 3
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=ae7387c3-348c-4faa-8ae5-949fdfbe59c4
______________________________________________________________________
Microsoft Report Viewer Redistributable 2008 Service Pack 1
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=bb196d5d-76c2-4a0e-9458-267d22b6aac6
Security Update for SQL Server 2008 Service Pack 1
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=66ab3dbb-bf3e-4f46-9559-ccc6a4f9dc19
P.S.: Se o servidor do [Reporting Services] não for o mesmo do [Sql Server], existe a necessidade da instalação do [Microsoft Dynamics CRM Data Connector for Reporting Services] no servidor do Sql Server, para que a autenticação funcione corretamente na execução de relatórios pelo CRM.
terça-feira, 18 de novembro de 2008
>> ResizeControls - aspx
>> Busca do ID de um Web Site no IIS
<< C# - VS.NET 2005 - Console Application >>
using System.DirectoryServices;
using System;
public class IISAdmin
{
public static void GetWebsiteID(string websiteName)
{
DirectoryEntry w3svc = new DirectoryEntry("IIS://localhost/w3svc");
foreach(DirectoryEntry de in w3svc.Children)
{
if(de.SchemaClassName == "IIsWebServer" && de.Properties["ServerComment"][0].ToString() == websiteName)
{
Console.Write(de.Name);
}
}
}
public static void Main()
{
GetWebsiteID("Default Web Site");
}
}
>> .NET 2.0 - Chamada Web Services - Sem "Add Web References"
Basta passar para a função "CallWebServices" a URL, o nome da função e os parâmetros do Web Services.
Exemplo de uso da função:
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Text;
List<'Hashtable> oParams = new List<'Hashtable>();
Hashtable ht1 = new Hashtable();
ht1.Add("paramName", "productid");
ht1.Add("paramValue", "413D080B-09A7-DB11-89C7-0016356BE094");
oParams.Add(ht1);
string xml = CallWebServices("http://localhost/MyWS/product.asmx", "GetProductPriceList", oParams);
public static string CallWebServices(string url, string functionName, List<'Hashtable> oParams)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = System.Net.CredentialCache.DefaultCredentials;
request.Headers.Add("SOAPAction", "\"http://tempuri.org/" + functionName + "\"");
request.Method = "POST";
request.ContentType = "text/xml; charset=utf-8";
request.Accept = "text/xml";
request.Timeout = 10000;
Stream requestStream = request.GetRequestStream();
string soapEnvelope = "";
soapEnvelope += "
soapEnvelope += " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"";
soapEnvelope += " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
soapEnvelope += "
soapEnvelope += " <" + functionName + " xmlns=\"http://tempuri.org/\">";
if (oParams.Count > 0)
{
Boolean hashListOk = (oParams[0].Contains("paramName") && oParams[0].Contains("paramValue"));
if (!hashListOk) return string.Empty;
foreach (Hashtable ht in oParams)
{
soapEnvelope += "<" + ht["paramName"].ToString() + ">" + ht["paramValue"].ToString() + "" + ht["paramName"].ToString() + ">";
}
}
soapEnvelope += " " + functionName + ">";
soapEnvelope += "
soapEnvelope += " ";
// Convert the string into a byte array.
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] ByteArray = encoder.GetBytes(soapEnvelope);
// Write data to the stream.
requestStream.Write(ByteArray, 0, ByteArray.Length);
requestStream.Flush();
requestStream.Close();
StreamReader esr = null;
string result = string.Empty;
try
{
esr = new StreamReader(request.GetResponse().GetResponseStream());
result = esr.ReadToEnd();
}
catch (System.Web.Services.Protocols.SoapException ex)
{
string x = ex.Detail.InnerText;
}
catch (Exception ex)
{
string x = ex.Message;
}
return result;
}
>> Artigos - ASP.NET 1.1
Gostaria de compartilhar com vocês algumas dicas e códigos para facilitar no entendimento e desenvolvimento na plataforma .NET, mais especificamente no ASP.NET 1.1 (em breve também para as versões 2.0 e 3.5) .
Abaixo segue links de artigos que publiquei no site do msdn para desenvolvedores, o SharePedia (http://www.msdnbrasil.com.br/Sharepedia/).
P.S.: Para baixar os artigos, é necessária uma conta no Passport.NET ou Windows Live da Microsoft.
- Navegando entre Forms - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52345
- Mantendo informações de estado em uma aplicação Web - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52270
- Entendendo Transações - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52644
- Autenticação e autorização de usuários - segurança na sua aplicação Web - PARTE I - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52199
- Autenticação e autorização de usuários - segurança na sua aplicação Web - PARTE II - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52200
- Autenticação e autorização de usuários - segurança na sua aplicação Web - PARTE III - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52201
- WebApp - Trabalhando com objetos – Parte I - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52266
- WebApp - Trabalhando com objetos – Parte II - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52267
- Tratamento de erros/exceptions - ASP.NET - http://www.msdnbrasil.com.br/secure/sharepedia/download.aspx?id=52034