Skip to content

Commit

Permalink
Código oagora organizado em pacotes e módulos
Browse files Browse the repository at this point in the history
  • Loading branch information
cewitte committed Apr 1, 2021
1 parent 45770a8 commit aca0f2b
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 138 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ Essa implementação foi baseada no **"Manual técnico de integração web servi

O manual SCPP está disponível aqui no diretório "manual-correios", apenas em português do Brasil.

Por fim, peço desculpas por manter todo o código em um único arquivo (`main.go`) em vez de empacotá-lo corretamente. Ainda assim, o código é tão curto que não faria muito sentido fazê-lo. Você notará que metade do código são comentários ou a função `main()` de teste.

Mais uma coisa: todos os comentários e a maioria das variáveis estão em português brasileiro. Normalmente prefiro fazer tudo em inglês, mas dada a especificidade desta implementação, a decisão me parece justificada.
Todos os comentários e a maioria dos nomes de variáveis estão em português brasileiro. Normalmente prefiro fazer tudo em inglês, mas dada a especificidade desta implementação, a decisão me parece justificada.

#### Contribuições
Suas contribuições são bem vindas. Que tal um Pull Request?
Expand All @@ -46,9 +44,7 @@ This implementation was based on the **"Technical manual for integrating web ser

The PTCS manual is available under the "manual-correios" folder, only in Brazilian Portuguese though.

At last, I apologize for keeping all the code in a single file (`main.go`) instead of correctly packaging it. Still, IMHO the code is so short that it wouln't make too much sense to do so. You will notice that half of it are comments or the `func main()` for tests.

One more thing: all comments and most variables are in Brazilian Portuguese. I usually prefer doing everything in English, but given the specificity of this implementation, the decision is justified.
All comments and most variables names are in Brazilian Portuguese. I usually prefer doing everything in English, but given the specificity of this implementation, the decision is justified.

#### Contributions
Your contributions are welcome. What about a Pull Request?
Expand Down
131 changes: 131 additions & 0 deletions correios/correios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2021 Carlos Eduardo Witte (@cewitte)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package correios

import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strconv"

"golang.org/x/net/html/charset"
)

var (
URL string = "http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx"
)

// CodigosVigentes implementa um map[string]string
// Atenção! Os códigos abaixo podem não estar mais válidos. Dados obtidos do "Manual técnico de integração web services ao Sistema Calculador de Preço e Prazo - SCPP.pdf" na versão 2.2 de 25/09/2019.
// Clientes com contrato devem consultar os códigos vigentes no contrato.
var CodigosVigentes = map[string]string{
"SEDEX à vista": "04014",
"PAC à vista": "04510",
"SEDEX 12 (à vista)": "04782",
"SEDEX 10 (à vista)": "04790",
"SEDEX Hoje à vista": "04804",
}

// CalcPrecoPrazo encapsula os parâmetros de uma requisição para o WebService dos Correios que informa o preço, prazo e outras opção de uma encomenda a ser entregue pelos Correios.
type CalcPrecoPrazo struct {
NCdEmpresa string // Sem contrato, enviar vazio.
SDsSenha string // Sem contrato, enviar vazio.
NCdServico string // Consultar códigos vigentes.
SCepOrigem string // Sem hífen.
SCepDestino string // Sem hífen.
NVlPeso string // Quilogramas.
NCdFormato int // 1-Caixa/Pcte; 2-Rolo/prisma. 3-Envel.
NVlComprimento float64 // Cm.
NVlAltura float64 // Cm. Se envelope, informar 0.
NVlLargura float64 // Cm
NVlDiametro float64 // Cm
SCdMaoPropria string // S ou N (Sim ou Não).
NVlValorDeclarado float64 // Se não quiser, informar zero.
SCdAvisoRecebimento string // Se não quiser, informar zero.
}

// Servicos representa o XML de retorno dos correios.
type Servicos struct {
XMLName xml.Name `xml:"Servicos"`
Text string `xml:",chardata"`
CServico []struct {
Text string `xml:",chardata"`
Codigo string `xml:"Codigo"`
Valor string `xml:"Valor"`
PrazoEntrega string `xml:"PrazoEntrega"`
ValorSemAdicionais string `xml:"ValorSemAdicionais"`
ValorMaoPropria string `xml:"ValorMaoPropria"`
ValorAvisoRecebimento string `xml:"ValorAvisoRecebimento"`
ValorValorDeclarado string `xml:"ValorValorDeclarado"`
EntregaDomiciliar string `xml:"EntregaDomiciliar"`
EntregaSabado string `xml:"EntregaSabado"`
ObsFim string `xml:"obsFim"`
Erro string `xml:"Erro"`
MsgErro string `xml:"MsgErro"`
} `xml:"cServico"`
}

// PrecoPrazo é o método que monta o HTTP GET Request, conecta a URL dos Correios, baixa o XML de resposta e faz o unmarshalling do XML de retorno para um objeto Servicos.
func (params *CalcPrecoPrazo) PrecoPrazo() (*Servicos, error) {
req, err := http.NewRequest("GET", URL, nil)
if err != nil {
return nil, err
}

vals := req.URL.Query()
vals.Add("nCDEmpresa", params.NCdEmpresa)
vals.Add("sDsSenha", params.SDsSenha)
vals.Add("nCdServico", params.NCdServico)
vals.Add("sCepOrigem", params.SCepOrigem)
vals.Add("sCepDestino", params.SCepDestino)
vals.Add("nVlPeso", params.NVlPeso)
vals.Add("nCdFormato", strconv.Itoa(params.NCdFormato))
vals.Add("nVlComprimento", fmt.Sprintf("%.2f", params.NVlComprimento))
vals.Add("nVlAltura", fmt.Sprintf("%.2f", params.NVlAltura))
vals.Add("nVlLargura", fmt.Sprintf("%.2f", params.NVlLargura))
vals.Add("nVlDiametro", fmt.Sprintf("%.2f", params.NVlDiametro))
vals.Add("sCdMaoPropria", params.SCdMaoPropria)
vals.Add("nVlValorDeclarado", fmt.Sprintf("%.2f", params.NVlValorDeclarado))
vals.Add("sCdAvisoRecebimento", params.SCdAvisoRecebimento)
vals.Add("StrRetorno", "xml")
vals.Add("nIndicaCalculo", "3")

req.URL.RawQuery = vals.Encode()
req.Header.Add("Accept", "application/xml")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

var srv Servicos
xmlData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
reader := bytes.NewReader(xmlData)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReaderLabel
err = decoder.Decode(&srv)
if err != nil {
return nil, err
}

return &srv, nil
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/cewitte/correioscalc

go 1.16

require golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c h1:KHUzaHIpjWVlVVNh65G3hhuj3KB1HnjY6Cq5cTvRQT8=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
149 changes: 17 additions & 132 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,143 +15,28 @@
package main

import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"

"golang.org/x/net/html/charset"
"github.com/cewitte/correioscalc/correios"
"github.com/cewitte/correioscalc/maptricks"
)

var (
URL string = "http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx"
)

// CodigosVigentes implementa um map[string]string
// Atenção! Os códigos abaixo podem não estar mais válidos. Dados obtidos do "Manual técnico de integração web services ao Sistema Calculador de Preço e Prazo - SCPP.pdf" na versão 2.2 de 25/09/2019.
// Clientes com contrato devem consultar os códigos vigentes no contrato.
var CodigosVigentes = map[string]string{
"SEDEX à vista": "04014",
"PAC à vista": "04510",
"SEDEX 12 (à vista)": "04782",
"SEDEX 10 (à vista)": "04790",
"SEDEX Hoje à vista": "04804",
}

// ReverseMap permite inverter um map[string]string, isto é, chave-valor é invertido para valor-chave. Use a função abaixo para reverter o mapa acima para chave: código e valor: nome. Pode ser útil para interpretar o retorno dos Correios.
func ReverseMap(m map[string]string) map[string]string {
n := make(map[string]string)
for k, v := range m {
n[v] = k
}
return n
}

// CalcPrecoPrazo encapsula os parâmetros de uma requisição para o WebService dos Correios que informa o preço, prazo e outras opção de uma encomenda a ser entregue pelos Correios.
type CalcPrecoPrazo struct {
nCdEmpresa string // Sem contrato, enviar vazio.
sDsSenha string // Sem contrato, enviar vazio.
nCdServico string // Consultar códigos vigentes.
sCepOrigem string // Sem hífen.
sCepDestino string // Sem hífen.
nVlPeso string // Quilogramas.
nCdFormato int // 1-Caixa/Pcte; 2-Rolo/prisma. 3-Envel.
nVlComprimento float64 // Cm.
nVlAltura float64 // Cm. Se envelope, informar 0.
nVlLargura float64 // Cm
nVlDiametro float64 // Cm
sCdMaoPropria string // S ou N (Sim ou Não).
nVlValorDeclarado float64 // Se não quiser, informar zero.
sCdAvisoRecebimento string // Se não quiser, informar zero.
}

// Teste é um objeto que representa o seguinte request HTTP GET': http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?nCdEmpresa=08082650&sDsSenha=564321&sCepOrigem=70002900&sCepDestino=04547000&nVlPeso=1&nCdFormato=1&nVlComprimento=20&nVlAltura=20&nVlLargura=20&sCdMaoPropria=N&nVlValorDeclarado=0&sCdAvisoRecebimento=n&nCdServico=04510&nVlDiametro=0&StrRetorno=xml&nIndicaCalculo=3
var Teste = CalcPrecoPrazo{
nCdEmpresa: "08082650",
sDsSenha: "564321",
nCdServico: "04014",
sCepOrigem: "70002900",
sCepDestino: "04547000",
nVlPeso: "1",
nCdFormato: 1,
nVlComprimento: 20,
nVlAltura: 20,
nVlLargura: 20,
sCdMaoPropria: "N",
nVlValorDeclarado: 0,
sCdAvisoRecebimento: "N",
}

// Servicos representa o XML de retorno dos correios.
type Servicos struct {
XMLName xml.Name `xml:"Servicos"`
Text string `xml:",chardata"`
CServico []struct {
Text string `xml:",chardata"`
Codigo string `xml:"Codigo"`
Valor string `xml:"Valor"`
PrazoEntrega string `xml:"PrazoEntrega"`
ValorSemAdicionais string `xml:"ValorSemAdicionais"`
ValorMaoPropria string `xml:"ValorMaoPropria"`
ValorAvisoRecebimento string `xml:"ValorAvisoRecebimento"`
ValorValorDeclarado string `xml:"ValorValorDeclarado"`
EntregaDomiciliar string `xml:"EntregaDomiciliar"`
EntregaSabado string `xml:"EntregaSabado"`
ObsFim string `xml:"obsFim"`
Erro string `xml:"Erro"`
MsgErro string `xml:"MsgErro"`
} `xml:"cServico"`
}

// PrecoPrazo é o método que monta o HTTP GET Request, conecta a URL dos Correios, baixa o XML de resposta e faz o unmarshalling do XML de retorno para um objeto Servicos.
func (params *CalcPrecoPrazo) PrecoPrazo() (*Servicos, error) {
req, err := http.NewRequest("GET", URL, nil)
if err != nil {
return nil, err
}

vals := req.URL.Query()
vals.Add("nCDEmpresa", params.nCdEmpresa)
vals.Add("sDsSenha", params.sDsSenha)
vals.Add("nCdServico", params.nCdServico)
vals.Add("sCepOrigem", params.sCepOrigem)
vals.Add("sCepDestino", params.sCepDestino)
vals.Add("nVlPeso", params.nVlPeso)
vals.Add("nCdFormato", strconv.Itoa(params.nCdFormato))
vals.Add("nVlComprimento", fmt.Sprintf("%.2f", params.nVlComprimento))
vals.Add("nVlAltura", fmt.Sprintf("%.2f", params.nVlAltura))
vals.Add("nVlLargura", fmt.Sprintf("%.2f", params.nVlLargura))
vals.Add("nVlDiametro", fmt.Sprintf("%.2f", params.nVlDiametro))
vals.Add("sCdMaoPropria", params.sCdMaoPropria)
vals.Add("nVlValorDeclarado", fmt.Sprintf("%.2f", params.nVlValorDeclarado))
vals.Add("sCdAvisoRecebimento", params.sCdAvisoRecebimento)
vals.Add("StrRetorno", "xml")
vals.Add("nIndicaCalculo", "3")

req.URL.RawQuery = vals.Encode()
req.Header.Add("Accept", "application/xml")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

var srv Servicos
xmlData, err := ioutil.ReadAll(resp.Body)
reader := bytes.NewReader(xmlData)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReaderLabel
err = decoder.Decode(&srv)
if err != nil {
return nil, err
}

return &srv, nil
var Teste = correios.CalcPrecoPrazo{
NCdEmpresa: "08082650",
SDsSenha: "564321",
NCdServico: "04014",
SCepOrigem: "70002900",
SCepDestino: "04547000",
NVlPeso: "1",
NCdFormato: 1,
NVlComprimento: 20,
NVlAltura: 20,
NVlLargura: 20,
SCdMaoPropria: "N",
NVlValorDeclarado: 0,
SCdAvisoRecebimento: "N",
}

// 1, 2, 3 Testando: som, som, som.
Expand All @@ -162,7 +47,7 @@ func main() {
}

// Vamos inverter o mapa de códigos para localizar o nome do serviço (Sedex, PAC, etc.) pelo código.
codNome := ReverseMap(CodigosVigentes)
codNome := maptricks.ReverseMap(correios.CodigosVigentes)

// Os dados verdadeiramente úteis vêm dentro do slice srv.CServico.
for _, v := range srv.CServico {
Expand Down
10 changes: 10 additions & 0 deletions maptricks/maptricks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package maptricks

// ReverseMap permite inverter um map[string]string, isto é, chave-valor é invertido para valor-chave. Use a função abaixo para reverter o mapa acima para chave: código e valor: nome. Pode ser útil para interpretar o retorno dos Correios.
func ReverseMap(m map[string]string) map[string]string {
n := make(map[string]string)
for k, v := range m {
n[v] = k
}
return n
}

0 comments on commit aca0f2b

Please sign in to comment.