云计算百科
云计算领域专业知识百科平台

电子发票 | 数电发票 Golang SDK | 发票接口 | 开票api |开票、验真、红冲一站式集成

电子发票 | 数电发票 Golang SDK | 发票接口 | 开票api |开票、验真、红冲一站式集成

发票 Golang SDK 专为电子发票、数电发票(全电发票)场景设计,支持开票、红冲、版式文件下载等核心功能,快速对接税务平台API。

关键词: 电子发票SDK,数电票Golang,开票接口,发票api,发票开具,发票红冲,全电发票集成


📖 核心功能

基础认证

  • ✅ 获取授权 – 快速接入税务平台身份认证
  • ✅ 人脸二维码登录 – 支持数电发票平台扫码登录
  • ✅ 认证状态查询 – 实时获取纳税人身份状态

发票开具

  • 🟦 数电蓝票开具 – 支持增值税普通/专用电子发票
  • 📄 版式文件下载 – 自动获取销项发票PDF/OFD/XML文件

发票红冲

  • 🔍 红冲前蓝票查询 – 精确检索待红冲的电子发票
  • 🛑 红字信息表申请 – 生成红冲凭证
  • 🔄 负数发票开具 – 自动化红冲流程

🚀 快速安装

安装

go get github.com/fapiaoapi/invoice-sdk-golang

📦 查看pkg.go.dev最新版本


📚 查看完整中文文档


🔍 为什么选择此SDK?

  • 精准覆盖中国数电发票标准 – 严格遵循国家最新接口规范
  • 开箱即用 – 无需处理XML/签名等底层细节,专注业务逻辑
  • 企业级验证 – 已在生产环境处理超100万张电子发票

📊 支持的开票类型

发票类型状态
数电发票(普通发票) ✅ 支持
数电发票(增值税专用发票) ✅ 支持
数电发票(铁路电子客票) ✅ 支持
数电发票(航空运输电子客票行程单) ✅ 支持
数电票(二手车销售统一发票) ✅ 支持
数电纸质发票(增值税专用发票) ✅ 支持
数电纸质发票(普通发票) ✅ 支持
数电纸质发票(机动车发票) ✅ 支持
数电纸质发票(二手车发票) ✅ 支持

开票demo

package main

import (
"bufio"
"context"
"fmt"
"os"
"strconv"
"time"
"github.com/fapiaoapi/invoice-sdk-golang"
"github.com/redis/go-redis/v9"
"github.com/skip2/go-qrcode"
)

var (
appKey = ""
appSecret = ""
nsrsbh = "" // 统一社会信用代码
title = "" // 名称(营业执照)
username = "" // 手机号码(电子税务局)
password = "" // 个人用户密码(电子税务局)
xhdwdzdh = "重庆市两江区xxxx 1912284xxxx" // 地址和电话 空格隔开
xhdwyhzh = "中国工商银行 31000867092xxxx" // 开户行和银行账号 空格隔开
token = ""
accountType = "6" // 默认6 6基础 7标准
debug = true // true 是否开启调试模式 false 不开启
)

func main() {

// 从缓存redis中获取Token
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Redis服务地址(默认端口6379)
Password: "test123456", // Redis密码(无密码则留空)
DB: 0, // 使用默认数据库
})
// 创建客户端
client := invoice.NewClient(appKey, appSecret, debug)
//一 获取授权
GetToken(rdb, client, false)
//二 开具蓝票
invoiceResponse := BlueTicket(client)
switch invoiceResponse.Code {
case 200:
// 三 下载发票
DownloadPdfOfdXml(client, invoiceResponse.Fphm, invoiceResponse.Kprq)
case 420:
fmt.Println("登录(短信认证)")
// 1. 发短信验证码
loginResponse, err3 := client.LoginDppt(nsrsbh, username, password, "")
if err3 != nil {
fmt.Printf("发送短信验证码失败: %v\\n", err3)
return
}
if loginResponse.Code == 200 {

fmt.Println("请输入验证码")
fmt.Printf("请在300秒内(%s前)输入验证码: ", time.Now().Add(300*time.Second).Format("2006-01-02 15:04:05"))
input := make(chan string, 1)
go func() {
sms, _ := bufio.NewReader(os.Stdin).ReadString('\\n')
input <- sms
}()
select {
case sms := <-input:
fmt.Printf("\\n你输入了: %s", sms)
// 2. 输入验证码
loginResponse2, err4 := client.LoginDppt(nsrsbh, username, password, sms)
if err4 != nil {
fmt.Printf("短信验证失败: %v\\n", err4)
return
}
if loginResponse2.Code == 200 {
fmt.Println(string(loginResponse2.Data))
fmt.Println("短信验证成功")
invoiceResponse := BlueTicket(client)
if invoiceResponse.Code == 200 {
DownloadPdfOfdXml(client, invoiceResponse.Fphm, invoiceResponse.Kprq)
}
}
case <-time.After(300 * time.Second):
fmt.Println("\\n\\n[错误] 输入超时!")
}
}

case 430:
fmt.Println("人脸认证")
// 1. 获取人脸二维码
qrCodeResponse, err5 := client.GetFaceImg(nsrsbh, map[string]string{
"username": username,
"type": "1",
})
if err5 != nil {
fmt.Printf("获取人脸二维码失败: %v\\n", err5)
return
}
switch qrCodeResponse.Ewmly {
case "swj":
//判断 Ewmly 不为空 长度小于500 字符串转二维码图片base64
if qrCodeResponse.Ewm != "" && len(qrCodeResponse.Ewm) <= 500 {
//go get github.com/skip2/go-qrcode
// qrBase64, err6 := StringToQRCodeBase64(qrCodeResponse.Ewm)
// if err6 != nil {
// fmt.Printf("生成二维码base64失败: %v\\n", err6)
// return
// } else {
// qrCodeResponse.Ewm = qrBase64
// // 可选:加上 data URL 前缀,方便在 HTML 中直接使用
// qrCodeResponse.Ewm = "data:image/png;base64," + qrBase64
// fmt.Printf("人脸二维码base64: %s\\n", qrCodeResponse.Ewm)
// }
}
fmt.Println("请使用电子税务局app扫码")
StringToQrcode(qrCodeResponse.Ewm)
fmt.Println("成功做完人脸认证,请输入数字 1")
fmt.Printf("请在300秒内(%s前)输入内容: ", time.Now().Add(300*time.Second).Format("2006-01-02 15:04:05"))
input := make(chan string, 1)
go func() {
text, _ := bufio.NewReader(os.Stdin).ReadString('\\n')
input <- text
}()
select {
case text := <-input:
fmt.Printf("\\n你输入了: %s", text)
rzid := qrCodeResponse.Rzid
faceStatusResponse, err6 := client.GetFaceState(nsrsbh, rzid, map[string]string{
"username": username,
"type": "1",
})
if err6 != nil {
fmt.Printf("获取人脸认证状态失败: %v\\n", err6)
return
}
if faceStatusResponse != nil {
switch faceStatusResponse.Slzt {
case "1":
fmt.Println("未认证")
case "2":
fmt.Println("成功")
invoiceResponse := BlueTicket(client)
if invoiceResponse.Code == 200 {
DownloadPdfOfdXml(client, invoiceResponse.Fphm, invoiceResponse.Kprq)
}
case "3":
fmt.Println("二维码过期–>重新获取人脸二维码")
}
}
case <-time.After(300 * time.Second):
fmt.Println("\\n\\n[错误] 输入超时!")
}

case "grsds":
fmt.Println("个人所得税app扫码")
}
case 401:
fmt.Printf("%d 授权失败: %s\\n", invoiceResponse.Code, invoiceResponse.Msg)
// 重新授权获取token
fmt.Println("成功")
GetToken(rdb, client, true)
invoiceResponse := BlueTicket(client)
if invoiceResponse.Code == 200 {
DownloadPdfOfdXml(client, invoiceResponse.Fphm, invoiceResponse.Kprq)
}
default:
fmt.Printf("异常 %d %s\\n", invoiceResponse.Code, invoiceResponse.Msg)
}

}

func BlueTicket(client *invoice.Client) *invoice.InvoiceResponse {
/**
* 开具数电发票
*/
invoiceParams := map[string]string{
"username": username,
"fpqqlsh": appKey + strconv.FormatInt(time.Now().Unix(), 10),//建议使用你们的订单ID
"fplxdm": "82",
"kplx": "0",
"xhdwsbh": nsrsbh,
"xhdwmc": title,
"xhdwdzdh": xhdwdzdh,
"xhdwyhzh": xhdwyhzh,
"ghdwmc": "xxxxxx公司",
"ghdwsbh": "500912xxxxxxx",
"zsfs": "0",
"hjje": "9.99",
"hjse": "0.1",
"jshj": "10",
}

items := []invoice.InvoiceItem{
{
Fphxz: "0",
Spmc: "*信息技术服务*软件开发服务",
Je: "10",
Sl: "0.01",
Se: "0.1",
Hsbz: "1",
Spbm: "3040201010000000000",
},
}

invoiceResponse, err := client.BlueTicket(invoiceParams, items)
if err != nil {
fmt.Printf("开票失败: %v\\n", err)

}
if invoiceResponse == nil {
fmt.Println("开票失败: 响应为空")
}
return invoiceResponse
}

func DownloadPdfOfdXml(client *invoice.Client, fphm string, kprq string) {
fmt.Printf("发票号码: %s\\n", fphm)
fmt.Printf("开票日期: %s\\n", kprq)
/**
* 获取销项数电版式文件 文档 PDF/OFD/XML
*/
pdfResponse, err2 := client.GetVersionFile(nsrsbh, fphm, "4", map[string]string{
"kprq": kprq,
"username": username,
})
if err2 != nil {
fmt.Printf("下载发票失败: %v\\n", err2)
} else if pdfResponse.Code == 200 {
fmt.Printf("下载发票结果: %s\\n", string(pdfResponse.Data))
}
}

// 获取token 从redis获取或重新获取
func GetToken(rdb *redis.Client, client *invoice.Client, forceUpdate bool) {
key := nsrsbh + "@" + username + "@TOKEN"
if forceUpdate {
/**
* 获取授权Token文档
*/
authResult, authErr := client.GetAuthorization(nsrsbh, accountType, "", "")
// authResult, authErr := client.GetAuthorization(nsrsbh, accountType, username, password)
if authErr != nil {
fmt.Printf("授权失败: %v\\n", authErr)
} else {
token = authResult.Token
client.SetToken(token)
//缓存Token到redis 过期时间30天 key建议是nsrsbh+'@TOKEN'
err := rdb.Set(context.Background(), key, token, 30*24*time.Hour).Err()
if err != nil {
fmt.Printf("缓存Token到Redis失败: %v\\n", err)
}
fmt.Printf("授权成功,Token: %s\\n", token)
}
} else {
result, err := rdb.Get(context.Background(), key).Result()
if err == nil && result != "" {
token = result
client.SetToken(token)
fmt.Printf("Token from Redis")
} else if err != nil && err != redis.Nil {
fmt.Printf("从Redis获取Token异常: %v\\n", err)
} else {
authResult, authErr := client.GetAuthorization(nsrsbh, accountType, "", "")
// authResult, authErr := client.GetAuthorization(nsrsbh, accountType, username, password)
if authErr != nil {
fmt.Printf("授权失败: %v\\n", authErr)
} else {
token = authResult.Token
client.SetToken(token)
//缓存Token到redis 过期时间30天 key建议是nsrsbh+'@TOKEN'
err := rdb.Set(context.Background(), key, token, 30*24*time.Hour).Err()
if err != nil {
fmt.Printf("缓存Token到Redis失败: %v\\n", err)
}
fmt.Printf("授权成功,Token: %s\\n", token)
}
}
}
}

func StringToQrcode(text string) {
qr, err := qrcode.New(text, qrcode.Low)
if err != nil {
panic(err)
}

matrix := qr.Bitmap()

for y := 0; y < len(matrix); y += 2 {
for x := 0; x < len(matrix[y]); x++ {
top := matrix[y][x]
bottom := false
if y+1 < len(matrix) {
bottom = matrix[y+1][x]
}

switch {
case top && bottom:
fmt.Print("█")
case top && !bottom:
fmt.Print("▀")
case !top && bottom:
fmt.Print("▄")
default:
fmt.Print(" ")
}
}
fmt.Println()
}

}

// func StringToQRCodeBase64(text string) (string, error) {
// // 生成二维码(PNG 格式写入内存 buffer)
// var buf bytes.Buffer
// qr, err := qrcode.New(text, qrcode.Medium)
// if err != nil {
// return "", err
// }
// if err := qr.Write(256, &buf); err != nil {
// return "", err
// }

// // 将字节转为 Base64
// encoded := base64.StdEncoding.EncodeToString(buf.Bytes())

// return encoded, nil
// }

赞(0)
未经允许不得转载:网硕互联帮助中心 » 电子发票 | 数电发票 Golang SDK | 发票接口 | 开票api |开票、验真、红冲一站式集成
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!