Skip to content

Commit

Permalink
Handle incoming SDI SOAP requests
Browse files Browse the repository at this point in the history
Our SOAP server needs to be able to parse different types of incoming
requests. Here we prepare a structure that accepts the different types
of messages that SDI might send us and we parse the message.

We still need to decide how we want to pass in the handling of the message.
  • Loading branch information
noplisu committed Jun 13, 2024
1 parent 2f45540 commit 399e072
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
35 changes: 35 additions & 0 deletions sdi/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@ import (
"bytes"
"encoding/xml"
"fmt"
"io"
"log"
"mime"
"mime/multipart"
"strings"

resty "github.com/go-resty/resty/v2"
)

// SDIEnvelope defines messages received by
type SDIEnvelope struct {
XMLName xml.Name `xml:"Envelope"`
Body struct {
FileSubmissionMetadata *FileSubmissionMetadata `xml:"MetadatiInvioFile,omitempty"`
NonDeliveryNotificationMessage *NonDeliveryNotificationMessage `xml:"NotificaMancataConsegna,omitempty"`
InvoiceTransmissionCertificate *InvoiceTransmissionCertificate `xml:"AttestazioneTrasmissioneFattura,omitempty"`
} `xml:"Body"`
}

// parseMultipartResponse parses a multipart HTTP response and deserializes the content into the provided structure
func parseMultipartResponse(resp *resty.Response, response interface{}) error {
mediaType, params, err := mime.ParseMediaType(resp.Header().Get("Content-Type"))
Expand Down Expand Up @@ -48,3 +60,26 @@ func parseMultipartResponse(resp *resty.Response, response interface{}) error {
}
return nil
}

func ParseMessage(body io.ReadCloser) error {
data, err := io.ReadAll(body)
if err != nil {
return err
}
env := new(SDIEnvelope)
err = xml.Unmarshal(data, env)
if err != nil {
return err
}
if env.Body.FileSubmissionMetadata != nil {
log.Printf("parsing MetadatiInvioFile:\n")
}
if env.Body.NonDeliveryNotificationMessage != nil {
log.Printf("parsing NotificaMancataConsegna:\n")
}
if env.Body.InvoiceTransmissionCertificate != nil {
log.Printf("parsing AttestazioneTrasmissioneFattura:\n")
}

return nil
}
103 changes: 103 additions & 0 deletions sdi/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package sdi_test

import (
"bytes"
"io"
"log"
"os"
"strings"
"testing"

sdi "github.com/invopop/gobl.fatturapa/sdi"
"github.com/stretchr/testify/assert"
)

func TestParseMessage(t *testing.T) {
t.Run("parse MetadatiInvioFile", func(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()

message := `<?xml version='1.0' encoding='UTF-8'?>` +
`<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:typ='http://www.fatturapa.gov.it/sdi/ws/trasmissione/v1.0/types'>` +
`<soapenv:Header/>` +
`<soapenv:Body>` +
`<ns3:MetadatiInvioFile xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.fatturapa.gov.it/sdi/messaggi/v1.0" versione="1.0">` +
`<IdentificativoSdI>29218239</IdentificativoSdI>` +
`<NomeFile>ESB85905495_00010.xml</NomeFile>` +
`<CodiceDestinatario>WSBKWM</CodiceDestinatario>` +
`<Formato>FPA12</Formato>` +
`<TentativiInvio>1</TentativiInvio>` +
`<MessageId>176121330</MessageId>` +
`</ns3:MetadatiInvioFile>` +
`</soapenv:Body>` +
`</soapenv:Envelope>`
reader := strings.NewReader(message)

sdi.ParseMessage(io.NopCloser(reader))

assert.Contains(t, buf.String(), "parsing MetadatiInvioFile")
})

t.Run("parse NotificaMancataConsegna", func(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()

message := `<?xml version='1.0' encoding='UTF-8'?>` +
`<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:typ='http://www.fatturapa.gov.it/sdi/ws/trasmissione/v1.0/types'>` +
`<soapenv:Header/>` +
`<soapenv:Body>` +
`<ns3:NotificaMancataConsegna xmlns:ns3="http://www.fatturapa.gov.it/sdi/messaggi/v1.0" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" versione="1.0">` +
`<IdentificativoSdI>29218239</IdentificativoSdI>` +
`<NomeFile>ESB85905495_00010.xml</NomeFile>` +
`<DataOraRicezione>2024-05-31T14:54:02.000+02:00</DataOraRicezione>` +
`<Descrizione>Non è stato possibile recapitare la fattura/e al destinatario.Sono in corso le necessarie verifiche,al termine delle quali si procederà ad un nuovo tentativo di trasmissione. Si rimanda pertanto ad un momento successivo l'invio della ricevuta di consegna.</Descrizione>` +
`<MessageId>176130653</MessageId>` +
`<Note/>` +
`</ns3:NotificaMancataConsegna>` +
`</soapenv:Body>` +
`</soapenv:Envelope>`
reader := strings.NewReader(message)

sdi.ParseMessage(io.NopCloser(reader))

assert.Contains(t, buf.String(), "parsing NotificaMancataConsegna")
})

t.Run("parse AttestazioneTrasmissioneFattura", func(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()

message := `<?xml version='1.0' encoding='UTF-8'?>` +
`<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:typ='http://www.fatturapa.gov.it/sdi/ws/trasmissione/v1.0/types'>` +
`<soapenv:Header/>` +
`<soapenv:Body>` +
`<ns3:AttestazioneTrasmissioneFattura xmlns:ns3="http://www.fatturapa.gov.it/sdi/messaggi/v1.0" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" versione="1.0">` +
`<IdentificativoSdI>29218239</IdentificativoSdI>` +
`<NomeFile>ESB85905495_00010.xml</NomeFile>` +
`<DataOraRicezione>2024-05-31T14:54:02.000+02:00</DataOraRicezione>` +
`<Destinatario>` +
`<Codice>WSBKWM</Codice>` +
`<Descrizione>Amministrazione di test - Ufficio_test</Descrizione>` +
`</Destinatario>` +
`<MessageId>176197456</MessageId>` +
`<Note>Fattura</Note>` +
`<HashFileOriginale>bc0c40728a04f06d52412d946a939540583cbe0ea0edaa5c0ba8097fc0519d16</HashFileOriginale>` +
`</ns3:AttestazioneTrasmissioneFattura>` +
`</soapenv:Body>` +
`</soapenv:Envelope>`
reader := strings.NewReader(message)

sdi.ParseMessage(io.NopCloser(reader))

assert.Contains(t, buf.String(), "parsing AttestazioneTrasmissioneFattura")
})
}
7 changes: 7 additions & 0 deletions sdi/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ func MessageHandler(w http.ResponseWriter, req *http.Request) {
}
log.Printf("Incoming request:\n%s", requestDump)

err = ParseMessage(req.Body)
if err != nil {
log.Printf("Failed to parse body: %s\n", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}

responseBody := []byte(soapEmptyResponse())
response := &http.Response{
Status: "200 OK",
Expand Down

0 comments on commit 399e072

Please sign in to comment.