28 de agosto de 2009

Criar mensagem TISS em formato XML conforme padrão da ANS com o Caché

Atualmente trabalho em uma empresa que desenvolve softwares para gestão hospitalar e como todos que trabalham com isso ja precisei desenvolver algo relacionado ao novo modelo de faturamento hospitalar para convenios (planos de saude).

Vou dar uma breve explicação de, o que é o tal TISS, porem, não vou entrar em detalhes. A ANS (www.ans.gov.br) ou Agencia Nacional de Saude Suplementar criou um modelo que os hospitais (prestadores de serviços) devem usar para poder cobrar dos convenios (planos de saude) suas faturas (serviços prestados aos conveniados/pacientes). Este modelo se resume a um arquivo XML definido por um padrão especificado em um schema.

Aqui na empresa utilizamos o banco de dados Caché da InterSystems para realizar o trabalho de criação do arquivo XML contendo o faturamento eletronico do hospital para ser enviado ao convenio.

Vou mostrar abaixo um exemplo pratico de como fazer isso. Para esta tarefa utilizarei o Caché na versão 2009.1.

Vamos la:

1 - Acesse este link onde contem os schemas XML que descrevem como os arquivos XMLs devem ser criados. Crie uma pasta em seu computador, como por exemplo "C:\schemastiss" e faça o download para dentro dela dos seguintes arquivos:

tissCancelaGuiaV2_01_03.wsdl
tissComplexTypesV2_01_03.xsd
tissGuiasV2_01_03.xsd
tissLoteGuiasV2_01_03.wsdl
tissnetV2_01_03.xsd
tissSimpleTypesV2_01_03.xsd
tissSolicitacaoDemonstrativoRetornoV2_01_03.wsdl
tissSolicitacaoProcedimentoV2_01_03.wsdl
tissSolicitacaoStatusAutorizacaoV2_01_03.wsdl
tissSolicitacaoStatusProtocoloV2_01_03.wsdl
tissTransmiteMensagemV2_01_03.wsdl
tissTransmiteMensagemZIPV2_01_03.wsdl
tissV2_01_03.xsd
tissVerificaElegibilidadeV2_01_03.wsdl

2 - Agora que temos os schemas baixados, vamos importalos no Caché para que ele crie as classes relacionadas. Abra o studio do Caché e va em "Ferramentas->Suplementos->Suplementos". Selecione a opção "Assistente de Criação de Esquema XML". Redimensione a tela que abrir para usar todo seu desktop pois ficará mais facil a visualização. No campo "Arquivo de Esquema:" selcione ele e informe o caminho do arquivo principal/raiz dos schemas que é o "C:\schemastiss\tissV2_01_03.xsd". Clique em "Avançar". Será mostrado o conteudo do arquivo, clique em "Avançar" novamente. Selecione a opção "Adicionar Parâmetro de Classe NAMESPACE" e clique em "Avançar". Serão listadas todas as classes que o Caché irá criar, role até abaixo e clique em "Avançar". Pronto, deve mostrar todas as classes que foram salvas, role até abaixo e clique em "Terminar". O Caché irá abrir todas as classes criadas e compila-las, por isso deve demorar um pouco e parecer que o studio esta travado, porem, basta aguardar um pouco.

3 - Agora ja temos tudo que precisamos para popular nossa mensagem TISS e exporta-la para XML. Agora crie uma nova classe no Caché igual a esta abaixo:

******************************************************************************
Include %occStatus

Class TISS.Mensagem [ Abstract ]
{

ClassMethod Criar()
{
#Dim objMensagemTISS As ans.mensagemTISS
#Dim objCabecalhoTransacao As ans.cabecalhoTransacao
#Dim objIdentificacaoTransacao As ans.identificacaoTransacao
#Dim objStatus As %Status
#Dim objOrigem As ans.origem
#Dim objIdentificacaoPrestadorExecutante As ans.ctidentificacaoPrestadorExecutante
#Dim objDestino As ans.destino
#Dim objGuiaConsulta As ans.ctguiaConsulta
#Dim objCabecalhoGuia As ans.ctcabecalhoGuia
#Dim objBeneficiario As ans.ctbeneficiario
#Dim objContratado As ans.ctcontratado
#Dim objIdentificacaoPrestadorExecutante2 As ans.ctidentificacaoPrestadorExecutante
#Dim objIdentificacaoProfissional As ans.ctidentificacaoProfissional
#Dim objConselhoProfissional As ans.ctconselhoProfissional
#Dim objDadosAtendimento As ans.dadosAtendimento
#Dim objProcedimento As ans.procedimento
#Dim objPrestadorParaOperadora As ans.prestadorParaOperadora
#Dim objLoteGuias As ans.ctloteGuias
#Dim objGuiaFaturamento As ans.guiaFaturamento
#Dim objGuias2 As ans.guias2
#Dim objEpilogo As ans.epilogo

/// Vamos identificar que "tipo de transação" nossa mensagem tiss vai ser.
Set objIdentificacaoTransacao = ##class(ans.identificacaoTransacao).%New()
Set objIdentificacaoTransacao.tipoTransacao = "ENVIO_LOTE_GUIAS"
Set objIdentificacaoTransacao.sequencialTransacao = 1
Set objIdentificacaoTransacao.dataRegistroTransacao = "28/08/2009"
Set objIdentificacaoTransacao.horaRegistroTransacao = "10:00"
Set objStatus = objIdentificacaoTransacao.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Vamos identificar a "origem" da nossa mensagem tiss (geralmente o hospital que esta enviando).
Set objIdentificacaoPrestadorExecutante = ##class(ans.ctidentificacaoPrestadorExecutante).%New()
Set objIdentificacaoPrestadorExecutante.codigoPrestadorNaOperadora = "12345"
Set objStatus = objIdentificacaoPrestadorExecutante.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objOrigem = ##class(ans.origem).%New()
Set objOrigem.codigoPrestadorNaOperadora = objIdentificacaoPrestadorExecutante
Set objStatus = objOrigem.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Vamos identificar o "destino" da nossa mensagem tiss (geralmente o convenio).
Set objDestino = ##class(ans.destino).%New()
Set objDestino.registroANS = "123456"
Set objStatus = objDestino.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Com as informações populadas acima ja podemos montar o cabeçalho da mensagem TISS.
Set objCabecalhoTransacao = ##class(ans.cabecalhoTransacao).%New()
Set objCabecalhoTransacao.identificacaoTransacao = objIdentificacaoTransacao
Set objCabecalhoTransacao.origem = objOrigem
Set objCabecalhoTransacao.destino = objDestino
Set objCabecalhoTransacao.versaoPadrao = "2.01.03"
Set objStatus = objCabecalhoTransacao.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Agora vou popular a instancia que conterá minha guia para faturar uma consulta medica.
; Cabeçalho da guia.
Set objCabecalhoGuia = ##class(ans.ctcabecalhoGuia).%New()
Set objCabecalhoGuia.registroANS = "123456"
Set objCabecalhoGuia.dataEmissaoGuia = "28/08/2009"
Set objCabecalhoGuia.numeroGuiaPrestador = "1"
Set objStatus = objCabecalhoGuia.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; Paciente que recebeu o atendimento.
Set objBeneficiario = ##class(ans.ctbeneficiario).%New()
Set objBeneficiario.numeroCarteira = "1"
Set objBeneficiario.nomeBeneficiario = "Alexandre da Silva"
Set objBeneficiario.nomePlano = "Basico"
Set objStatus = objBeneficiario.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; Pessoa / empresa que vai receber o valor cobrado na guia (pode ser o proprio hospital, uma clinica terceirizada ou o proprio medico que fez o atendimento).
Set objIdentificacaoPrestadorExecutante2 = ##class(ans.ctidentificacaoPrestadorExecutante).%New()
Set objIdentificacaoPrestadorExecutante2.codigoPrestadorNaOperadora = "12345"
Set objStatus = objIdentificacaoPrestadorExecutante2.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objContratado = ##class(ans.ctcontratado).%New()
Set objContratado.identificacao = objIdentificacaoPrestadorExecutante2
Set objContratado.nomeContratado = "Hospital XYZ"
Set objStatus = objContratado.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; Medico que atendeu o paciente (executou o serviço).
Set objConselhoProfissional = ##class(ans.ctconselhoProfissional).%New()
Set objConselhoProfissional.siglaConselho = "CRM"
Set objConselhoProfissional.numeroConselho = "123456789"
Set objConselhoProfissional.ufConselho = "SC"
Set objStatus = objConselhoProfissional.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objIdentificacaoProfissional = ##class(ans.ctidentificacaoProfissional).%New()
Set objIdentificacaoProfissional.nomeProfissional = "Humberto"
Set objIdentificacaoProfissional.conselhoProfissional = objConselhoProfissional
Set objStatus = objIdentificacaoProfissional.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; Dados/detalhes do atendimento medico.
Set objProcedimento = ##class(ans.procedimento).%New()
Set objProcedimento.codigoTabela = "01"
Set objProcedimento.codigoProcedimento = "12345678"
Set objStatus = objProcedimento.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objDadosAtendimento = ##class(ans.dadosAtendimento).%New()
Set objDadosAtendimento.dataAtendimento = "28/08/2009"
Set objDadosAtendimento.procedimento = objProcedimento
Set objDadosAtendimento.tipoConsulta = "1"
Set objDadosAtendimento.tipoSaida = "1"
Set objStatus = objDadosAtendimento.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; Identificar que diz que é uma de faturamento normal (pode ser de reapresentação).
Set objGuiaFaturamento = ##class(ans.guiaFaturamento).%New()
Set objStatus = objGuiaFaturamento.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objGuiaConsulta = ##class(ans.ctguiaConsulta).%New()
Set objGuiaConsulta.identificacaoGuia = objCabecalhoGuia
Set objGuiaConsulta.beneficiario = objBeneficiario
Set objGuiaConsulta.dadosContratado = objContratado
Set objGuiaConsulta.profissionalExecutante = objIdentificacaoProfissional
Set objGuiaConsulta.dadosAtendimento = objDadosAtendimento
Set objGuiaConsulta.guiaFaturamento = objGuiaFaturamento
Set objStatus = objGuiaConsulta.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Vamos criar agora alguns objetos que são necessarios para complementar a estrutura
/// da mensagem tiss.
; Lote (uma mensagem tiss pode ter um lote com varias guias).
Set objGuias2 = ##class(ans.guias2).%New()
Set objGuias2.guiaFaturamento = objGuiaFaturamento
Set objStatus = objGuias2.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objLoteGuias = ##class(ans.ctloteGuias).%New()
Set objLoteGuias.numeroLote = 1
Set objLoteGuias.guias = objGuias2
Set objStatus = objLoteGuias.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// E finalmente a mensagem TISS.
; Identificar que diz que esta mensagem TISS é uma mensagem de HOSPITAL PARA CONVENIO (pode ser o inverso tambem).
Set objPrestadorParaOperadora = ##class(ans.prestadorParaOperadora).%New()
Set objPrestadorParaOperadora.loteGuias = objLoteGuias
Set objStatus = objPrestadorParaOperadora.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

; A mensagem TISS contem um calculo de HASH sobre os valores de cada TAG.
Set objEpilogo = ##class(ans.epilogo).%New()
Set objEpilogo.hash = "¥"
Set objStatus = objEpilogo.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objMensagemTISS = ##class(ans.mensagemTISS).%New()
Set objMensagemTISS.cabecalho = objCabecalhoTransacao
Set objMensagemTISS.prestadorParaOperadora = objPrestadorParaOperadora
Set objMensagemTISS.epilogo = objEpilogo
Set objStatus = objMensagemTISS.%Save()
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

/// Agora ja temos nosso objeto contendo uma mensagem TISS quase pronto para ser exportado
/// para XML. Antes de exportar, vamos fazer o calculo do HASH correto e atribuir novamente
/// o valor a propriedade correspondente.
Set objStatus = ..CalcularHASH(objMensagemTISS)
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Set objStatus = ..ExportarParaArquivoXML(objMensagemTISS)
if $$$ISERR(objStatus) {
do ##class(%SYSTEM.Status).DisplayError(objStatus)
Quit
}

Write "MENSAGEM TISS CRIADA COM SUCESSO!"
}

ClassMethod CalcularHASH(pobjMensagemTISS As ans.mensagemTISS) As %Status [ Private ]
{
#Dim objStream As %Stream.Object
#Dim objStatus As %Status
#Dim objTextReader As %XML.TextReader
#Dim vTexto As %String
#Dim vlCalculoHash As %String
#Dim vlHash16Bytes As %String

Set objStatus = pobjMensagemTISS.XMLExportToStream(.objStream)
if $$$ISERR(objStatus) {Quit objStatus}

    Set objStatus = ##class(%XML.TextReader).ParseStream(objStream,.objTextReader)
if $$$ISERR(objStatus) {Quit objStatus}
 
    Set vTexto = ""
    while objTextReader.Read() {
    if ((objTextReader.Value '= "") && (objTextReader.Value '= "¥")) {
Set vTexto = vTexto_objTextReader.Value
    }
    }
 
Set vlHash16Bytes = ##class(%SYSTEM.Encryption).MD5Hash(vTexto)
Set vlCalculoHash=""
for i=1:1:$Length(vlHash16Bytes) {
Set vlCalculoHash=vlCalculoHash_$Translate($Justify($ZHex($Ascii(vlHash16Bytes,i)),2)," ","0")
}
    Set pobjMensagemTISS.epilogo.hash = $ZCONVERT(vlCalculoHash,"L")
 
    Set objStatus = pobjMensagemTISS.epilogo.%Save()
    if $$$ISERR(objStatus) {Quit objStatus}
 
    Set objStatus = pobjMensagemTISS.%Save()
    if $$$ISERR(objStatus) {Quit objStatus}
 
    Quit $$$OK
}

ClassMethod ExportarParaArquivoXML(pobjMensagemTISS As ans.mensagemTISS) As %Status [ Private ]
{
#Dim objBinaryStream As %FileBinaryStream
#Dim objXmlWriter As %XML.Writer
#Dim objStatus As %Status
#Dim objFile As %File

Set objBinaryStream = ##class(%FileBinaryStream).%New()

    Set objXmlWriter = ##class(%XML.Writer).%New()
    Set objXmlWriter.Charset = "UTF-8"
    Set objXmlWriter.SuppressXmlns = 1
    Set objStatus = objXmlWriter.AddNamespace("http://www.ans.gov.br/padroes/tiss/schemas","ans")
    if $$$ISERR(objStatus) {Quit objStatus}

    Set objStatus = objXmlWriter.OutputToStream(.objBinaryStream)
    if $$$ISERR(objStatus) {Quit objStatus}
 
    Set objStatus = objXmlWriter.RootObject(pobjMensagemTISS)
    if $$$ISERR(objStatus) {Quit objStatus}
 
    Set objXmlWriter=""

Set objFile = ##class(%File).%New("C:\schemastiss\mensagem\mensagemtiss.xml")
Set objStatus = objFile.Open("WSN")
if $$$ISERR(objStatus) {Quit objStatus}

Set objStatus = objFile.CopyFrom(objBinaryStream)
if $$$ISERR(objStatus) {Quit objStatus}

do objFile.Close()
Set objFile = ""

Set objBinaryStream = ""

Quit $$$OK
}

}
******************************************************************************

Não esqueça de compilar sua classe apos cria-la

Quando eu coloco o fonte aqui no editor do BLOG as identações são perdidas :(. Caso alguem tenha dificuldade solicite o codigo fonte por e-mail que envio.

4 - Abra o terminal do Caché e mande compilar todas as classes do pacote da "ans". O comando a ser executado é este: do ##class(%SYSTEM.OBJ).CompilePackage("ans").

5 - Dentro da pasta onde estão os schemas, crie uma subpasta chamada "mensagem". Será dentro desta pasta que o arquivo XML será criado pelo codigo da classe. Se vc quizer, pode alterar.

6 - Agora basta acessar o terminal do Caché e executar nosso metodo para criar o arquivo XML com a mensagem TISS. O comando a ser executado é este: do ##class(TISS.Mensagem).Criar().

Pronto, se tudo ocorreu corretamente ja temos nossa mensagem tiss no formato XML pronta em "C:\schemastiss\mensagem\mensagemtiss.xml".

Abraço a todos!

5 comentários:

  1. Fala Xandy.
    Parabéns pelo artigo. Para os analistas Caché, que trabalham com saúde, é uma mão na roda.

    Vai uma dica ae: Você pode postar em novos artigos os processos da guia Tiss com diagramas, casos de uso, etc. Ou até mesmo aquele "protótipo de artigo", enviado por e-mail, que ficou excelente.

    Abraços e sucesso maninho

    ResponderExcluir
  2. E ai meu ;)

    Pode crer, estou tentando montar mais algum artigo sobre o assunto pra postar aqui.

    abraço!

    ResponderExcluir
  3. a proposta custa 39,90 se voce quiser trabalher em casa entre no site www.trabalheemcasaoverdadeiro.com.br/1996987 clicar quero ser produtor mas condido de convite 1996987 telefone esta ai no site.

    ResponderExcluir
  4. Bom dia. Tem um exemplo de como fazer isso usando banco de dados firebird e em asp.net com c#?

    Att

    ResponderExcluir
    Respostas
    1. Olá Antonio,

      Não tenho. Mas, posso prestar este serviço pra vc se quiser. Minha especialidade é Delphi e Caché. Mas, tenho um pouco de conhecimento em C#. Se vc conhecer C#, podemos usar seu conhecimento em C# e meu conhecimento em TISS para fazer juntos esta implementação.

      Enfim, estou a disposição para ajudar da melhor maneira. Caso tenha interesse, entre em contato.

      Abraço!

      Excluir