Skip to content

Commit

Permalink
support generating QR codes
Browse files Browse the repository at this point in the history
  • Loading branch information
toudi committed Dec 18, 2023
1 parent 236afc2 commit 110d023
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Dokumentację znajdziesz w katalogu `docs`. Masz kilka możliwości jej odczytania:

## Wersja online

Dostępna pod adresem https://ksef.po-godzinach.info/

## Lokalne przebudowanie

```shell
Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineConfig({
{ text: 'Wysyłka faktur', items: [
{text: 'Sesja wsadowa (batch)', link: '/content/komendy/upload/batch'},
{text: 'Sesja interaktywna', link: '/content/komendy/upload/interaktywna'},
{text: 'Kody QR', link: '/content/qrcode'},
]},
{ text: 'Pobieranie faktur', link: '/content/komendy/download'},
{ text: 'Pobieranie UPO', link: '/content/komendy/upo'},
Expand Down
24 changes: 24 additions & 0 deletions docs/content/qrcode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Kod QR na wizualizacji faktury

Stosunkowo niedawno (tj. około wersji 1.5 API) wizualizacje PDF oferowane przez ministerstwo zaczęły zawierać kod QR służący do weryfikacji, czy faktura istnieje w zasobach KSeF. Po krótkiej analizie treści obrazka stwierdziłem, że zawiera ona sumę `sha256` dokumentu źródłowego faktury (co jest zrozumiałe) oraz jej numer referencyjny w KSeF (co jest niezbyt szczęśliwe). Link zapisany w kodzie jest postaci następującej:

```text
https://{środowisko}/web/verify/{numerFakturyWKSeF}/{sumaKontrolna}
```

gdzie `sumaKontrolna` to skrót `sha256` (w postaci bajtów) zaenkodowany przez `base64`

Oznacza to, że jedyną możliwością wygenerowania kodu QR (przynajmniej na chwilę obecną) jest wysłanie faktury do KSeF ponieważ inaczej nie otrzymamy jej numeru referencyjnego. To przeczy wcześniejszym założeniom ministerstwa finansów jakoby kody QR można było generować off-line tj. w przypadku niedostępności KSeF.

Tak czy siak, program wygeneruje dla Ciebie link który możesz przepuścić przez dowolną bibiotekę do obsługi kodów QR i wygenerować obrazek i zapisze go w pliku rejestru:

```yaml
invoices:
- referenceNumber: FV 00/11/22 - TEST QR
ksefReferenceNumber: 1111111111-22222222-XXXXXXXXXXXX-ZZ
qrcode-url: https://ksef-test.mf.gov.pl/web/verify/1111111111-22222222-XXXXXXXXXXXX-ZZ/VPuBCK3cwQvsnprWQSwWSglJvokGtUH%2FQCsPyUPiXK0%3D
```
Oprócz tego, program wygeneruje przykładowy kod QR i zapisze go jako plik `{numerFakturyKSeF}.svg`. Możesz użyć go jeśli nie posiadasz żadnej biblioteki do generowania kodów QR.

Zauważysz zapewne, że pewne znaki są kodowane w postaci `urlsafe` i wydaje się to być działanie zamierzone ze strony ministerstwa finansów.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/wamuir/svg-qr-code v0.0.0-20210725140500-9525ec975db7 // indirect
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
golang.org/x/crypto v0.14.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTK
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/wamuir/svg-qr-code v0.0.0-20210725140500-9525ec975db7 h1:hpwKjWkjcZlKE+hzD1bGKqVu5QMUkd+Q47WogtmJtnQ=
github.com/wamuir/svg-qr-code v0.0.0-20210725140500-9525ec975db7/go.mod h1:Ln9b+pO1ObOm82e3uBNx5r3SSO/U7mnZsFdGnX3vIog=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
Expand Down
1 change: 1 addition & 0 deletions internal/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type InvoiceSubject struct {
type Invoice struct {
ReferenceNumber string `json:"invoiceReferenceNumber" yaml:"referenceNumber,omitempty"`
SEIReferenceNumber string `json:"ksefReferenceNumber" yaml:"ksefReferenceNumber,omitempty"`
SEIQRCode string `yaml:"qrcode-url" json:"-"`
InvoicingDate string `json:"invoicingDate" yaml:"invoicingDate,omitempty"`
SubjectFrom InvoiceSubject `json:"subjectBy,omitempty" yaml:"subjectFrom,omitempty"`
SubjectTo InvoiceSubject `json:"subjectTo,omitempty" yaml:"subjectTo,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions internal/sei/api/status/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "errors"
type KsefInvoiceIdType struct {
InvoiceNumber string `xml:"NumerFaktury" json:"invoiceNumber" yaml:"invoiceNumber"`
KSeFInvoiceReferenceNo string `xml:"NumerKSeFDokumentu" json:"ksefDocumentId" yaml:"ksefDocumentId"`
DocumentChecksum string `xml:"SkrotDokumentu"`
}

type StatusInfo struct {
Expand Down
15 changes: 15 additions & 0 deletions internal/sei/api/upo/api_download_upo.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"net/url"
"os"
"path"

qrsvg "github.com/wamuir/svg-qr-code"
)

const (
Expand All @@ -33,6 +35,7 @@ type UPO struct {
}

const endpointStatus = "common/Status/%s"
const qrcodeUrl = "https://%s/web/verify/%s/%s"

func DownloadUPO(a *client.APIClient, registry *registryPkg.InvoiceRegistry, outputFormat string, outputPath string) error {
var upoStatus upoStatusType
Expand Down Expand Up @@ -64,7 +67,19 @@ func DownloadUPO(a *client.APIClient, registry *registryPkg.InvoiceRegistry, out
registry.Invoices = append(registry.Invoices, registryPkg.Invoice{
ReferenceNumber: invoiceId.InvoiceNumber,
SEIReferenceNumber: invoiceId.KSeFInvoiceReferenceNo,
SEIQRCode: fmt.Sprintf(
qrcodeUrl,
a.Environment.Host,
invoiceId.KSeFInvoiceReferenceNo,
url.QueryEscape(invoiceId.DocumentChecksum),
),
})
qr, err := qrsvg.New(registry.Invoices[len(registry.Invoices)-1].SEIQRCode)
if err == nil {
// if there's an error outputting the qrcode there's nothing we can do
// about it anyway.
_ = os.WriteFile(path.Join(path.Dir(outputPath), invoiceId.KSeFInvoiceReferenceNo+".svg"), []byte(qr.String()), 0644)
}
}

if err = registry.Save(path.Join(path.Dir(outputPath), "registry.yaml")); err != nil {
Expand Down

0 comments on commit 110d023

Please sign in to comment.