Hoje venho mostrar para vocês uma função que desenvolvi para exportar uma lista de contatos para importar na Locaweb.
Se você assina o serviço de e-Mail Marketing da Locaweb, ou de algum outro provedor como o UOL, foi criado uma rotina em AdvPL para gerar a lista de contatos de Clientes (SA1), Fornecedores (SA2) e Vendedores (SA3).
Sendo que a lista exporta os e-mails e nome dos contatos, e você pode até adaptar para pegar outros campos.
A grande diferença dessa função para uma query sql, é que nessa é validado alguns caracteres especiais do e-Mail e até inclusive se colocam mais de um separado por ;.
A tela de parâmetros, você define o diretório, quais cadastros ira exportar, e se ira exportar de um estado especifico.
Abaixo o código fonte criado:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} zExpMail
Função que gera a exportação csv de contatos para a Locaweb
@author Atilio
@since 16/01/2017
@version 1.0
@type function
/*/
User Function zExpMail()
Local aArea := GetArea()
Local aPergs := {}
Local cMsg := ""
Private cDiretorio := GetTempPath() + Space(50)
Private lVendedor := .F.
Private lCliente := .F.
Private lFornece := .F.
Private cEstado := Space(2)
Private cArqCli := "clientes_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".csv"
Private cArqVen := "vendedores_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".csv"
Private cArqFor := "fornecedores_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".csv"
//Adicionando os parametros
aAdd(aPergs, {1, "Diretorio", cDiretorio, "", ".T.", "", ".T.", 100, .T.})
aAdd(aPergs, {2, "Exportar Clientes", 1, {"1=Sim", "2=Nao"}, 40, ".T.", .F.})
aAdd(aPergs, {2, "Exportar Vendedores", 1, {"1=Sim", "2=Nao"}, 40, ".T.", .F.})
aAdd(aPergs, {2, "Exportar Fornecedores", 1, {"1=Sim", "2=Nao"}, 40, ".T.", .F.})
aAdd(aPergs, {1, "Filtrar Estado", cEstado, "", ".T.", "12", ".T.", 60, .F.})
//Se foi confirmado a rotina
If ParamBox(aPergs, "Informe os parametros")
//Atualizando as variaveis
cDiretorio := Alltrim(MV_PAR01)
lCliente := (Val(cValToChar(MV_PAR02)) == 1)
lVendedor := (Val(cValToChar(MV_PAR03)) == 1)
lFornece := (Val(cValToChar(MV_PAR04)) == 1)
cEstado := Alltrim(MV_PAR05)
//Verifica se a última posição é uma \
If SubStr(cDiretorio, Len(cDiretorio), 1) != '\'
cDiretorio += '\'
EndIf
//Se o diretório existir, continua com o processamento
If ExistDir(cDiretorio)
If lVendedor .Or. lCliente .Or. lFornece
//Chama o processamento para gerar os arquivos
Processa({|| fGeraArq()}, "Gerando arquivos...")
//Monta e mostra a mensagem que será exibida
cMsg := "Arquivos gerados com sucesso!" + CRLF
If lCliente
cMsg += "- " + cDiretorio + cArqCli + CRLF
EndIf
If lVendedor
cMsg += "- " + cDiretorio + cArqVen + CRLF
EndIf
If lFornece
cMsg += "- " + cDiretorio + cArqFor + CRLF
EndIf
Aviso("Atenção", cMsg, {"Ok"}, 2)
Else
MsgAlert("Escolha pelo menos uma opção para geração dos arquivos!", "Atenção")
EndIf
Else
MsgAlert("Diretório não existe!", "Atenção")
EndIf
EndIf
RestArea(aArea)
Return
/*---------------------------------------------------------------------*
| Func: fGeraArq |
| Autor: Daniel Atilio |
| Data: 16/01/2017 |
| Desc: Função para geração dos arquivos csv |
*---------------------------------------------------------------------*/
Static Function fGeraArq()
Local aArea := GetArea()
Local cQryAux := ""
Local nAtual := 0
Local nTotal := 0
Local cLinha := ""
Local cNomeAtu := ""
Local cEmailAtu := ""
Local aEmails := {}
Local nPosAtu := 00
Local oFWriter
//Se for exportar os dados dos clientes
If lCliente
cQryAux := " SELECT " + CRLF
cQryAux += " A1_NOME AS NOME, A1_EMAIL AS EMAIL " + CRLF
cQryAux += " FROM " + CRLF
cQryAux += " "+RetSQLName('SA1')+" SA1 " + CRLF
cQryAux += " WHERE " + CRLF
cQryAux += " A1_FILIAL = '"+FWxFilial('SA1')+"' " + CRLF
cQryAux += " AND A1_MSBLQL != '1' " + CRLF
If !Empty(cEstado)
cQryAux += " AND A1_EST = '"+cEstado+"' " + CRLF
EndIf
cQryAux += " AND SA1.D_E_L_E_T_ = ' ' " + CRLF
PLSQuery(cQryAux, "QRY_CLI")
//Setando o tamanho da regua
DbSelectArea("QRY_CLI")
Count To nTotal
ProcRegua(nTotal)
nAtual := 0
QRY_CLI->(DbGoTop())
//Cria o arquivo
oFWriter := FWFileWriter():New(cDiretorio + cArqCli, .T.)
//Se houve falhas, encerra a rotina
If ! oFWriter:Create()
lCliente := .F.
MsgAlert("O arquivo '"+cDirect+cArqCli+"' não pode ser criado!", "Atenção")
Else
cLinha := "Email;Nome"
oFWriter:Write(cLinha + CRLF)
//Enquanto houver clientes
While ! QRY_CLI->(EoF())
nAtual++
IncProc("Processando cliente "+cValToChar(nAtual)+" de "+cValToChar(nTotal)+"...")
//Pegando o nome atual
cNomeAtu := FwNoAccent(Alltrim(QRY_CLI->NOME))
//Retira outros caracteres especiais do nome
cNomeAtu := fRetira(cNomeAtu)
//Pegando o email
cEmailAtu := FwNoAccent(Alltrim(QRY_CLI->EMAIL))
//Se tiver e-Mail e nome e se o email for válido
If !Empty(cNomeAtu) .And. !Empty(cEmailAtu) .And. fEmailVali(cEmailAtu)
cLinha := ""
//Se tiver ; no campo de e-Mail
If ";" $ cEmailAtu
aEmails := StrTokArr(cEmailAtu, ';')
//Percorre os emails
For nPosAtu := 1 To Len(aEmails)
cLinha := aEmails[nPosAtu]+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
Next
//Senão, será apenas uma linha única
Else
cLinha := cEmailAtu+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
EndIf
EndIf
QRY_CLI->(DbSkip())
EndDo
//Fecha o ponteiro do arquivo
oFWriter:Close()
Endif
QRY_CLI->(DbCloseArea())
EndIf
//Se for exportar os dados dos vendedores
If lVendedor
cQryAux := " SELECT " + CRLF
cQryAux += " A3_NOME AS NOME, A3_EMAIL AS EMAIL " + CRLF
cQryAux += " FROM " + CRLF
cQryAux += " "+RetSQLName('SA3')+" SA3 " + CRLF
cQryAux += " WHERE " + CRLF
cQryAux += " A3_FILIAL = '"+FWxFilial('SA3')+"' " + CRLF
cQryAux += " AND A3_MSBLQL != '1' " + CRLF
If !Empty(cEstado)
cQryAux += " AND A3_EST = '"+cEstado+"' " + CRLF
EndIf
cQryAux += " AND SA3.D_E_L_E_T_ = ' ' " + CRLF
PLSQuery(cQryAux, "QRY_VEN")
//Setando o tamanho da regua
DbSelectArea("QRY_VEN")
Count To nTotal
ProcRegua(nTotal)
nAtual := 0
QRY_VEN->(DbGoTop())
//Cria o arquivo
oFWriter := FWFileWriter():New(cDiretorio + cArqVen, .T.)
//Se houve falhas, encerra a rotina
If ! oFWriter:Create()
lVendedor := .F.
MsgAlert("O arquivo '"+cDirect+cArqVen+"' não pode ser criado!", "Atenção")
Else
cLinha := "Email;Nome"
oFWriter:Write(cLinha + CRLF)
//Enquanto houver clientes
While ! QRY_VEN->(EoF())
nAtual++
IncProc("Processando vendedor "+cValToChar(nAtual)+" de "+cValToChar(nTotal)+"...")
//Pegando o nome atual
cNomeAtu := FwNoAccent(Alltrim(QRY_VEN->NOME))
//Retira outros caracteres especiais do nome
cNomeAtu := fRetira(cNomeAtu)
//Pegando o email
cEmailAtu := FwNoAccent(Alltrim(QRY_VEN->EMAIL))
//Se tiver e-Mail e nome e se o email for válido
If !Empty(cNomeAtu) .And. !Empty(cEmailAtu) .And. fEmailVali(cEmailAtu)
cLinha := ""
//Se tiver ; no campo de e-Mail
If ";" $ cEmailAtu
aEmails := StrTokArr(cEmailAtu, ';')
//Percorre os emails
For nPosAtu := 1 To Len(aEmails)
cLinha := aEmails[nPosAtu]+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
Next
//Senão, será apenas uma linha única
Else
cLinha := cEmailAtu+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
EndIf
EndIf
QRY_VEN->(DbSkip())
EndDo
//Fecha o ponteiro do arquivo
oFWriter:Close()
Endif
QRY_VEN->(DbCloseArea())
EndIf
If lFornece
cQryAux := " SELECT " + CRLF
cQryAux += " A2_NOME AS NOME, A2_EMAIL AS EMAIL " + CRLF
cQryAux += " FROM " + CRLF
cQryAux += " "+RetSQLName('SA2')+" SA2 " + CRLF
cQryAux += " WHERE " + CRLF
cQryAux += " A2_FILIAL = '"+FWxFilial('SA2')+"' " + CRLF
cQryAux += " AND A2_MSBLQL != '1' " + CRLF
If !Empty(cEstado)
cQryAux += " AND A2_EST = '"+cEstado+"' " + CRLF
EndIf
cQryAux += " AND SA2.D_E_L_E_T_ = ' ' " + CRLF
PLSQuery(cQryAux, "QRY_FOR")
//Setando o tamanho da regua
DbSelectArea("QRY_FOR")
Count To nTotal
ProcRegua(nTotal)
nAtual := 0
QRY_FOR->(DbGoTop())
//Cria o arquivo
oFWriter := FWFileWriter():New(cDiretorio + cArqFor, .T.)
//Se houve falhas, encerra a rotina
If ! oFWriter:Create()
lFornece := .F.
MsgAlert("O arquivo '"+cDirect+cArqFor+"' não pode ser criado!", "Atenção")
Else
cLinha := "Email;Nome"
oFWriter:Write(cLinha + CRLF)
//Enquanto houver clientes
While ! QRY_FOR->(EoF())
nAtual++
IncProc("Processando fornecedor "+cValToChar(nAtual)+" de "+cValToChar(nTotal)+"...")
//Pegando o nome atual
cNomeAtu := FwNoAccent(Alltrim(QRY_FOR->NOME))
//Retira outros caracteres especiais do nome
cNomeAtu := fRetira(cNomeAtu)
//Pegando o email
cEmailAtu := FwNoAccent(Alltrim(QRY_FOR->EMAIL))
//Se tiver e-Mail e nome e se o email for válido
If !Empty(cNomeAtu) .And. !Empty(cEmailAtu) .And. fEmailVali(cEmailAtu)
cLinha := ""
//Se tiver ; no campo de e-Mail
If ";" $ cEmailAtu
aEmails := StrTokArr(cEmailAtu, ';')
//Percorre os emails
For nPosAtu := 1 To Len(aEmails)
cLinha := aEmails[nPosAtu]+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
Next
//Senão, será apenas uma linha única
Else
cLinha := cEmailAtu+";"+cNomeAtu
oFWriter:Write(cLinha + CRLF)
EndIf
EndIf
QRY_FOR->(DbSkip())
EndDo
//Fecha o ponteiro do arquivo
oFWriter:Close()
Endif
QRY_FOR->(DbCloseArea())
EndIf
RestArea(aArea)
Return
/*---------------------------------------------------------------------*
| Func: fRetira |
| Autor: Daniel Atilio |
| Data: 16/01/2017 |
| Desc: Função que retira caracteres especiais de uma string |
*---------------------------------------------------------------------*/
Static Function fRetira(cOrigem)
Local cNovo := ""
Default cOrigem := ""
cNovo := cOrigem
//Retira os caracteres especiais
cNovo := StrTran(cNovo, "´", "")
cNovo := StrTran(cNovo, "'", "")
cNovo := StrTran(cNovo, "#", "")
cNovo := StrTran(cNovo, "%", "")
cNovo := StrTran(cNovo, "*", "")
cNovo := StrTran(cNovo, "&", "E")
cNovo := StrTran(cNovo, ">", "")
cNovo := StrTran(cNovo, "<", "")
cNovo := StrTran(cNovo, "!", "")
cNovo := StrTran(cNovo, "@", "")
cNovo := StrTran(cNovo, "$", "")
cNovo := StrTran(cNovo, "(", "")
cNovo := StrTran(cNovo, ")", "")
cNovo := StrTran(cNovo, "_", "")
cNovo := StrTran(cNovo, "=", "")
cNovo := StrTran(cNovo, "+", "")
cNovo := StrTran(cNovo, "{", "")
cNovo := StrTran(cNovo, "}", "")
cNovo := StrTran(cNovo, "[", "")
cNovo := StrTran(cNovo, "]", "")
cNovo := StrTran(cNovo, "/", "")
cNovo := StrTran(cNovo, "?", "")
cNovo := StrTran(cNovo, ".", "")
cNovo := StrTran(cNovo, "\", "")
cNovo := StrTran(cNovo, "|", "")
cNovo := StrTran(cNovo, ":", "")
cNovo := StrTran(cNovo, ";", "")
cNovo := StrTran(cNovo, '"', '')
cNovo := StrTran(cNovo, '°', '')
cNovo := StrTran(cNovo, 'ª', '')
cNovo := StrTran(cNovo, ",", "")
cNovo := StrTran(cNovo, "-", "")
Return cNovo
/*---------------------------------------------------------------------*
| Func: fEmailVali |
| Autor: Daniel Atilio |
| Data: 16/01/2017 |
| Desc: Função que verifica se o email é válido |
*---------------------------------------------------------------------*/
Static Function fEmailVali(cEmailVld)
Local lRet := .T.
If '@' $ cEmailVld
lRet := Iif("´" $ cEmailVld, .F., lRet)
lRet := Iif("'" $ cEmailVld, .F., lRet)
lRet := Iif("#" $ cEmailVld, .F., lRet)
lRet := Iif("%" $ cEmailVld, .F., lRet)
lRet := Iif("*" $ cEmailVld, .F., lRet)
lRet := Iif("&" $ cEmailVld, .F., lRet)
lRet := Iif(">" $ cEmailVld, .F., lRet)
lRet := Iif("<" $ cEmailVld, .F., lRet)
lRet := Iif("!" $ cEmailVld, .F., lRet)
lRet := Iif("$" $ cEmailVld, .F., lRet)
lRet := Iif("(" $ cEmailVld, .F., lRet)
lRet := Iif(")" $ cEmailVld, .F., lRet)
lRet := Iif("=" $ cEmailVld, .F., lRet)
lRet := Iif("+" $ cEmailVld, .F., lRet)
lRet := Iif("{" $ cEmailVld, .F., lRet)
lRet := Iif("}" $ cEmailVld, .F., lRet)
lRet := Iif("[" $ cEmailVld, .F., lRet)
lRet := Iif("]" $ cEmailVld, .F., lRet)
lRet := Iif("/" $ cEmailVld, .F., lRet)
lRet := Iif("?" $ cEmailVld, .F., lRet)
lRet := Iif("\" $ cEmailVld, .F., lRet)
lRet := Iif("|" $ cEmailVld, .F., lRet)
lRet := Iif(":" $ cEmailVld, .F., lRet)
lRet := Iif('"' $ cEmailVld, .F., lRet)
lRet := Iif('°' $ cEmailVld, .F., lRet)
lRet := Iif('ª' $ cEmailVld, .F., lRet)
lRet := Iif("," $ cEmailVld, .F., lRet)
Else
lRet := .F.
EndIf
Return lRet
Bom pessoal, por hoje é só.
Abraços e até a próxima.

Fala mestre, ótimo post!
Uma observação…. precisaria tratar se o usuário, informar dois @ no e-mail.
Ex: email@mail@mail.com
Fala Miguel.
Nossa verdade, acho que para uma versão 2.0 irei adicionar a condição.
Grande abraço jovem.