44 KiB
44 KiB
// File: intelligence_finance_v1/go.mod
module intelligence_finance_v1
go 1.21
// File: intelligence_finance_v1/crypto.go
package intelligence_finance_v1
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"math/big"
"sort"
"strings"
"time"
)
// GenerateTimestamp 生成秒级时间戳字符串
func GenerateTimestamp() string {
return fmt.Sprintf("%d", time.Now().Unix())
}
// GenerateNonce 生成指定长度的加密安全随机字符串
func GenerateNonce(length int) (string, error) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", err
}
b[i] = charset[num.Int64()]
}
return string(b), nil
}
// HmacSHA256Base64 使用HmacSHA256算法对数据进行签名,返回Base64编码结果
func HmacSHA256Base64(secret, data string) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(data))
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
// BuildSignString 按字典序排序拼接参数(排除空值和签名字段)
func BuildSignString(params map[string]string) string {
keys := make([]string, 0, len(params))
for k, v := range params {
if v != "" && k != "sign" && k != "signature" && k != "x-bfl-signature" {
keys = append(keys, k)
}
}
sort.Strings(keys)
var parts []string
for _, k := range keys {
parts = append(parts, fmt.Sprintf("%s=%s", k, params[k]))
}
return strings.Join(parts, "&")
}
// BuildSignStringOrdered 按固定顺序拼接参数
func BuildSignStringOrdered(params map[string]string, orderedKeys []string) string {
var parts []string
for _, k := range orderedKeys {
if v, ok := params[k]; ok && v != "" {
parts = append(parts, fmt.Sprintf("%s=%s", k, v))
}
}
return strings.Join(parts, "&")
}
// File: intelligence_finance_v1/types.go
package intelligence_finance_v1
// ============================================================
// 通用请求/响应结构
// ============================================================
// CommonResponse 通用API响应结构
type CommonResponse struct {
Code int `json:"code"`
Msg string `json:"msg,omitempty"`
Data interface{} `json:"data,omitempty"`
}
// NotificationRequest 回调通知请求结构
type NotificationRequest struct {
BizType string `json:"bizType"`
BizID string `json:"bizId"`
Data string `json:"data,omitempty"`
}
// ============================================================
// 接口1:订单开票请求/响应
// ============================================================
// CreateInvoiceRequest 提交订单开票申请请求
type CreateInvoiceRequest struct {
CompanyCode string `json:"companyCode,omitempty"`
OrderID string `json:"orderId"`
InvoiceType int `json:"invoiceType"`
Products []InvoiceProduct `json:"products"`
Remark string `json:"remark,omitempty"`
Purchaser string `json:"purchaser"`
TaxNum string `json:"taxnum,omitempty"`
PurchaserAddr string `json:"purchaserAddress,omitempty"`
PurchaserTel string `json:"purchaserTel,omitempty"`
BankName string `json:"bankName,omitempty"`
BankAccount string `json:"bankAccount,omitempty"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
ApplyPerson string `json:"applyPerson,omitempty"`
Payee string `json:"payee,omitempty"`
Reviewer string `json:"reviewer,omitempty"`
InvoiceRemark string `json:"invoiceRemark,omitempty"`
NaturalPerson string `json:"naturalPerson,omitempty"`
AdditionInfo string `json:"additionInfo,omitempty"`
}
// InvoiceProduct 货物/服务明细
type InvoiceProduct struct {
ProductName string `json:"productName"`
RevenueCode string `json:"revenueCode"`
AmountIncludeTax float64 `json:"amountIncludeTax"`
Specs string `json:"specs,omitempty"`
Unit string `json:"unit,omitempty"`
Quantity float64 `json:"quantity"`
Discount float64 `json:"discount,omitempty"`
TaxSign int `json:"taxSign,omitempty"`
TaxRate float64 `json:"taxRate,omitempty"`
}
// CreateInvoiceResponse 提交订单开票申请响应
type CreateInvoiceResponse struct {
Status int `json:"status"`
ErrorMsg string `json:"errorMsg,omitempty"`
DataList []InvoiceData `json:"dataList"`
}
// InvoiceData 发票数据
type InvoiceData struct {
DeviceCode string `json:"deviceCode"`
Drawer string `json:"drawer"`
Email string `json:"email"`
InvoiceType string `json:"invoiceType"`
IssueType string `json:"issueType"`
ListFlag string `json:"listFlag"`
Mobile string `json:"mobile"`
OriginalInvCode string `json:"originalInvCode,omitempty"`
OriginalInvNo string `json:"originalInvNo,omitempty"`
AdditionInfo string `json:"additionInfo,omitempty"`
Payee string `json:"payee"`
PurchaserAddress string `json:"purchaserAddress"`
PurchaserBankAccount string `json:"purchaserBankAccount"`
PurchaserBankName string `json:"purchaserBankName"`
PurchaserName string `json:"purchaserName"`
PurchaserTaxNo string `json:"purchaserTaxNo"`
PurchaserTel string `json:"purchaserTel"`
NaturalPerson string `json:"naturalPerson,omitempty"`
Remark string `json:"remark"`
Reviewer string `json:"reviewer"`
SellerAddress string `json:"sellerAddress,omitempty"`
SellerBankAccount string `json:"sellerBankAccount"`
SellerBankName string `json:"sellerBankName"`
SellerName string `json:"sellerName"`
CheckCode string `json:"checkCode"`
CipherText string `json:"cipherText"`
DrewDate string `json:"drewDate,omitempty"`
InvoiceCode string `json:"invoiceCode"`
InvoiceNo string `json:"invoiceNo"`
InvoiceStatus string `json:"invoiceStatus"`
LayoutFileURL string `json:"layoutFileUrl,omitempty"`
PdfURL string `json:"pdfUrl,omitempty"`
OfdURL string `json:"ofdUrl,omitempty"`
XmlURL string `json:"xmlUrl,omitempty"`
TotalExcludeTax string `json:"totalExcludeTax"`
TotalIncludeTax string `json:"totalIncludeTax"`
TotalTaxAmount string `json:"totalTaxAmount"`
LevyingType string `json:"levyingType"`
Details []InvoiceDetail `json:"details"`
}
// InvoiceDetail 商品明细
type InvoiceDetail struct {
Amount string `json:"amount,omitempty"`
Quantity string `json:"quantity,omitempty"`
DeductionAmount string `json:"deductionAmount,omitempty"`
TaxAmount string `json:"taxAmount,omitempty"`
ItemTitle string `json:"itemTitle"`
TaxCode string `json:"taxCode"`
ItemType string `json:"itemType"`
ItemName string `json:"itemName"`
Specs string `json:"specs,omitempty"`
TaxFreePolicy string `json:"taxFreePolicy"`
PreferentialPolicy string `json:"preferentialPolicy"`
TaxRate string `json:"taxRate"`
TaxSign string `json:"taxSign"`
Unit string `json:"unit,omitempty"`
UnitPrice string `json:"unitPrice,omitempty"`
}
// ============================================================
// 接口2:开票状态查询请求/响应
// ============================================================
// QueryInvoiceStatusRequest 查询订单开票状态请求
type QueryInvoiceStatusRequest struct {
OrderID string `json:"orderId"`
}
// QueryInvoiceStatusResponse 查询订单开票状态响应
type QueryInvoiceStatusResponse struct {
Status int `json:"status"`
Message string `json:"message"`
Data []InvoiceData `json:"data"`
}
// ============================================================
// 接口3:创建付款单据请求/响应
// ============================================================
// CreatePaymentRequest 创建付款单据请求
type CreatePaymentRequest struct {
Code string `json:"code"`
YidaAppType string `json:"yidaAppType,omitempty"`
EmpAccountUserID string `json:"empAccountUserId,omitempty"`
Department *Department `json:"department,omitempty"`
Usage string `json:"usage,omitempty"`
PaymentUserID string `json:"paymentUserId,omitempty"`
Customer *Customer `json:"customer,omitempty"`
PrincipalID string `json:"principalId,omitempty"`
Remark string `json:"remark,omitempty"`
Supplier *Supplier `json:"supplier,omitempty"`
Title string `json:"title,omitempty"`
Project *Project `json:"project,omitempty"`
PaymentUserIDListStr string `json:"paymentUserIdListStr,omitempty"`
NeedPayment bool `json:"needPayment,omitempty"`
PaymentDetailListJsonStr string `json:"paymentDetailListJsonStr,omitempty"`
PaymentDetailList []PaymentDetail `json:"paymentDetailList,omitempty"`
Company *Company `json:"company,omitempty"`
Amount string `json:"amount,omitempty"`
RecipientAccountInfo *RecipientAccount `json:"recipientAccountInfo,omitempty"`
EnterpriseAccount *EnterpriseAccount `json:"enterpriseAccount,omitempty"`
Category []Category `json:"category,omitempty"`
UserID string `json:"userId"`
OccurDate int64 `json:"occurDate,omitempty"`
Product *Product `json:"product,omitempty"`
YidaFormUUID string `json:"yidaFormUuid,omitempty"`
CanEditPaymentInfo bool `json:"canEditPaymentInfo,omitempty"`
PaymentUserIDList []string `json:"paymentUserIdList,omitempty"`
YidaProcInsID string `json:"yidaProcInsId,omitempty"`
SyncPaymentOrder bool `json:"syncPaymentOrder,omitempty"`
}
// Department 部门信息
type Department struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Customer 客户信息
type Customer struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Supplier 供应商信息
type Supplier struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Project 项目信息
type Project struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Category 收支类别信息
type Category struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Product 商品信息
type Product struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// Company 企业主体信息
type Company struct {
Code string `json:"code,omitempty"`
Name string `json:"name"`
}
// EnterpriseAccount 企业账号信息
type EnterpriseAccount struct {
EnterpriseAccountCode string `json:"enterpriseAccountCode,omitempty"`
AccountCategory string `json:"accountCategory"`
AccountType string `json:"accountType,omitempty"`
CardNo string `json:"cardNo,omitempty"`
AccountName string `json:"accountName,omitempty"`
OfficialNumber string `json:"officialNumber,omitempty"`
OfficialName string `json:"officialName,omitempty"`
Name string `json:"name,omitempty"`
Code string `json:"code,omitempty"`
City string `json:"city,omitempty"`
Province string `json:"province,omitempty"`
}
// RecipientAccount 收款账户信息
type RecipientAccount struct {
AccountCategory string `json:"accountCategory"`
AccountType string `json:"accountType,omitempty"`
CardNo string `json:"cardNo,omitempty"`
AccountName string `json:"accountName,omitempty"`
}
// PaymentDetail 付款明细
type PaymentDetail struct {
Amount string `json:"amount,omitempty"`
InvoiceInfo *InvoiceInfo `json:"invoiceInfo,omitempty"`
ProductCode string `json:"productCode,omitempty"`
ProjectCode string `json:"projectCode,omitempty"`
Remark string `json:"remark,omitempty"`
PrincipalID string `json:"principalId,omitempty"`
Tax string `json:"tax,omitempty"`
}
// InvoiceInfo 付款明细发票信息
type InvoiceInfo struct {
InvoiceNo string `json:"invoiceNo,omitempty"`
InvoiceCode string `json:"invoiceCode,omitempty"`
}
// CreatePaymentResponse 创建付款单据响应
type CreatePaymentResponse struct {
Code string `json:"code"`
}
// ============================================================
// 接口4:支付完成通知(平台回调)
// ============================================================
// PaymentNotification 支付完成通知数据结构
type PaymentNotification struct {
Code string `json:"code"`
InstanceID string `json:"instanceId"`
CorpID string `json:"corpId"`
PaymentStatus string `json:"paymentStatus"`
PaymentTime string `json:"paymentTime"`
UserID string `json:"userId"`
FailReason string `json:"failReason,omitempty"`
PayerAccountInfo *PayerAccountInfo `json:"payerAccountInfo,omitempty"`
PayeeAccountInfo *PayeeAccountInfo `json:"payeeAccountInfo,omitempty"`
RelatedRowNumberList []string `json:"relatedRowNumberList,omitempty"`
Source string `json:"source,omitempty"`
Template string `json:"template,omitempty"`
Amount string `json:"amount,omitempty"`
}
// PayerAccountInfo 付款账户信息
type PayerAccountInfo struct {
BankOpenDTO *BankOpenDTO `json:"bankOpenDTO,omitempty"`
EnterpriseAccountCode string `json:"enterpriseAccountCode,omitempty"`
AccountType string `json:"accountType,omitempty"`
}
// PayeeAccountInfo 收款账户信息
type PayeeAccountInfo struct {
BankOpenDTO *BankOpenDTO `json:"bankOpenDTO,omitempty"`
}
// BankOpenDTO 银行信息
type BankOpenDTO struct {
BankCode string `json:"bankCode,omitempty"`
BankName string `json:"bankName,omitempty"`
BankBranchCode string `json:"bankBranchCode,omitempty"`
BankBranchName string `json:"bankBranchName,omitempty"`
AccountName string `json:"accountName,omitempty"`
BankCardNo string `json:"bankCardNo,omitempty"`
Type string `json:"type,omitempty"`
}
// ============================================================
// 接口5:支付状态查询请求/响应
// ============================================================
// QueryPaymentStatusRequest 查询支付状态请求
type QueryPaymentStatusRequest struct {
Code string `json:"code"`
UserID string `json:"userId"`
}
// QueryPaymentStatusResponse 查询支付状态响应(与PaymentNotification结构一致)
type QueryPaymentStatusResponse struct {
PaymentNotification
}
// ============================================================
// 接口6:创建供应商请求/响应
// ============================================================
// CreateSupplierRequest 创建供应商请求
type CreateSupplierRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// CreateSupplierBizData 创建供应商业务数据
type CreateSupplierBizData struct {
CorpID string `json:"corpId"`
Creator string `json:"creator"`
SupplierInfo *SupplierInfo `json:"supplierInfo,omitempty"`
}
// SupplierInfo 供应商数据
type SupplierInfo struct {
Name string `json:"name"`
CorpID string `json:"corpId"`
UserDefineCode string `json:"userDefineCode,omitempty"`
Description string `json:"description,omitempty"`
ContactAddress string `json:"contactAddress,omitempty"`
ContactCompanyTelephone string `json:"contactCompanyTelephone,omitempty"`
ContactEmail string `json:"contactEmail,omitempty"`
ContactName string `json:"contactName,omitempty"`
ContactTelephone string `json:"contactTelephone,omitempty"`
Creator string `json:"creator"`
InvoiceAccount string `json:"invoiceAccount,omitempty"`
InvoiceAddress string `json:"invoiceAddress,omitempty"`
InvoiceBankName string `json:"invoiceBankName,omitempty"`
InvoiceName string `json:"invoiceName,omitempty"`
InvoiceTaxNo string `json:"invoiceTaxNo,omitempty"`
PurchaserTel string `json:"purchaserTel,omitempty"`
BankName string `json:"bankName,omitempty"`
InvoiceTelephone string `json:"invoiceTelephone,omitempty"`
AccountName string `json:"accountName,omitempty"`
AccountType string `json:"accountType,omitempty"`
}
// CreateSupplierResponse 创建供应商响应
type CreateSupplierResponse struct {
InvokeID string `json:"invokeId,omitempty"`
BizType string `json:"bizType"`
Data string `json:"data,omitempty"`
}
// CreateSupplierResponseData 创建供应商响应数据
type CreateSupplierResponseData struct {
Result string `json:"result,omitempty"`
Success bool `json:"success"`
}
// SupplierInfoResponse 供应商信息(响应)
type SupplierInfoResponse struct {
SupplierID string `json:"supplierId"`
SupplierName string `json:"supplierName"`
Name string `json:"name"`
CorpID string `json:"corpId"`
UserDefineCode string `json:"userDefineCode,omitempty"`
Description string `json:"description,omitempty"`
ContactAddress string `json:"contactAddress,omitempty"`
ContactCompanyTelephone string `json:"contactCompanyTelephone,omitempty"`
ContactEmail string `json:"contactEmail,omitempty"`
ContactName string `json:"contactName,omitempty"`
ContactTelephone string `json:"contactTelephone,omitempty"`
Creator string `json:"creator"`
InvoiceAccount string `json:"invoiceAccount,omitempty"`
InvoiceAddress string `json:"invoiceAddress,omitempty"`
InvoiceBankName string `json:"invoiceBankName,omitempty"`
}
// ============================================================
// 接口7:根据名称查询供应商请求/响应
// ============================================================
// QuerySupplierByNameRequest 根据名称查询供应商请求
type QuerySupplierByNameRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// QuerySupplierByNameBizData 根据名称查询供应商业务数据
type QuerySupplierByNameBizData struct {
CorpID string `json:"corpId"`
Name string `json:"name"`
}
// QuerySupplierByNameResponse 根据名称查询供应商响应
type QuerySupplierByNameResponse struct {
InvokeID string `json:"invokeId,omitempty"`
BizType string `json:"bizType"`
Data string `json:"data,omitempty"`
Result string `json:"result,omitempty"`
Success bool `json:"success"`
}
// QuerySupplierByNameResult 供应商查询结果重要字段
type QuerySupplierByNameResult struct {
SupplierName string `json:"supplierName"`
UserDefineCode string `json:"userDefineCode,omitempty"`
InvoiceName string `json:"invoiceName,omitempty"`
SupplierID string `json:"supplierId"`
CorpID string `json:"corpId"`
ContactTelephone string `json:"contactTelephone,omitempty"`
ContactEmail string `json:"contactEmail,omitempty"`
ContactName string `json:"contactName,omitempty"`
InvoiceBankName string `json:"invoiceBankName,omitempty"`
InvoiceAccount string `json:"invoiceAccount,omitempty"`
Description string `json:"description,omitempty"`
InvoiceAddress string `json:"invoiceAddress,omitempty"`
InvoiceTaxNo string `json:"invoiceTaxNo,omitempty"`
ContactCompanyTelephone string `json:"contactCompanyTelephone,omitempty"`
CreateTime int64 `json:"createTime,omitempty"`
InvoiceTelephone string `json:"invoiceTelephone,omitempty"`
ContactAddress string `json:"contactAddress,omitempty"`
}
// ============================================================
// 接口8:更新供应商请求/响应
// ============================================================
// UpdateSupplierRequest 更新供应商请求
type UpdateSupplierRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// UpdateSupplierBizData 更新供应商业务数据
type UpdateSupplierBizData struct {
SupplierID string `json:"supplierId"`
Name string `json:"name"`
CorpID string `json:"corpId"`
UserDefineCode string `json:"userDefineCode,omitempty"`
Description string `json:"description,omitempty"`
ContactAddress string `json:"contactAddress,omitempty"`
ContactCompanyTelephone string `json:"contactCompanyTelephone,omitempty"`
ContactEmail string `json:"contactEmail,omitempty"`
ContactName string `json:"contactName,omitempty"`
ContactTelephone string `json:"contactTelephone,omitempty"`
UserID string `json:"userId"`
InvoiceAccount string `json:"invoiceAccount,omitempty"`
InvoiceAddress string `json:"invoiceAddress,omitempty"`
InvoiceBankName string `json:"invoiceBankName,omitempty"`
InvoiceName string `json:"invoiceName,omitempty"`
InvoiceTaxNo string `json:"invoiceTaxNo,omitempty"`
PurchaserTel string `json:"purchaserTel,omitempty"`
BankName string `json:"bankName,omitempty"`
InvoiceTelephone string `json:"invoiceTelephone,omitempty"`
AccountName string `json:"accountName,omitempty"`
AccountType string `json:"accountType,omitempty"`
BankBranchCode string `json:"bankBranchCode,omitempty"`
BankCode string `json:"bankCode,omitempty"`
BankCity string `json:"bankCity,omitempty"`
BankProvince string `json:"bankProvince,omitempty"`
}
// UpdateSupplierResponse 更新供应商响应
type UpdateSupplierResponse struct {
InvokeID string `json:"invokeId,omitempty"`
BizType string `json:"bizType"`
Data string `json:"data,omitempty"`
}
// UpdateSupplierResponseData 更新供应商响应数据
type UpdateSupplierResponseData struct {
Result string `json:"result,omitempty"`
Success bool `json:"success"`
}
// ============================================================
// 接口9:根据用户自定义编码查询供应商请求/响应
// ============================================================
// QuerySupplierByUserDefineCodeRequest 根据用户自定义编码查询供应商请求
type QuerySupplierByUserDefineCodeRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// QuerySupplierByUserDefineCodeBizData 根据自定义编码查询供应商业务数据
type QuerySupplierByUserDefineCodeBizData struct {
CorpID string `json:"corpId"`
UserDefineCode string `json:"userDefineCode"`
}
// QuerySupplierByUserDefineCodeResponse 根据自定义编码查询供应商响应
type QuerySupplierByUserDefineCodeResponse struct {
InvokeID string `json:"invokeId,omitempty"`
BizType string `json:"bizType"`
Data string `json:"data,omitempty"`
}
// QuerySupplierByUserDefineCodeResponseData 响应数据
type QuerySupplierByUserDefineCodeResponseData struct {
Success bool `json:"success"`
}
// QuerySupplierByUserDefineCodeResult 供应商查询结果重要字段
type QuerySupplierByUserDefineCodeResult struct {
UserDefineCode string `json:"userDefineCode"`
SupplierName string `json:"supplierName"`
ModifiedTime int64 `json:"modifiedTime,omitempty"`
Creator string `json:"creator,omitempty"`
SupplierID string `json:"supplierId"`
Code string `json:"code,omitempty"`
CorpID string `json:"corpId"`
CreateTime int64 `json:"createTime,omitempty"`
Name string `json:"name"`
ID int64 `json:"id,omitempty"`
Status string `json:"status,omitempty"`
}
// File: intelligence_finance_v1/errors.go
package intelligence_finance_v1
import "fmt"
// SDKError SDK通用错误类型
type SDKError struct {
Code int `json:"code"`
Message string `json:"message"`
Err error `json:"-"`
}
// Error 实现error接口
func (e *SDKError) Error() string {
if e.Err != nil {
return fmt.Sprintf("code=%d, message=%s, err=%v", e.Code, e.Message, e.Err)
}
return fmt.Sprintf("code=%d, message=%s", e.Code, e.Message)
}
// Unwrap 返回包装的错误
func (e *SDKError) Unwrap() error {
return e.Err
}
// NewSDKError 创建SDK错误
func NewSDKError(code int, message string, err error) *SDKError {
return &SDKError{
Code: code,
Message: message,
Err: err,
}
}
// 预定义错误码
const (
ErrCodeSuccess = 0
ErrCodeUnknown = -1
ErrCodeInvalidParam = 1001
ErrCodeSignatureFailed = 1002
ErrCodeNetworkError = 1003
ErrCodeRequestTimeout = 1004
ErrCodeServerError = 2001
ErrCodeUnauthorized = 2002
ErrCodeNotFound = 2003
ErrCodeRateLimit = 2004
)
// 预定义错误
var (
ErrUnknown = NewSDKError(ErrCodeUnknown, "未知错误", nil)
ErrInvalidParam = NewSDKError(ErrCodeInvalidParam, "参数无效", nil)
ErrSignatureFailed = NewSDKError(ErrCodeSignatureFailed, "签名失败", nil)
ErrNetworkError = NewSDKError(ErrCodeNetworkError, "网络错误", nil)
ErrRequestTimeout = NewSDKError(ErrCodeRequestTimeout, "请求超时", nil)
ErrServerError = NewSDKError(ErrCodeServerError, "服务端错误", nil)
ErrUnauthorized = NewSDKError(ErrCodeUnauthorized, "未授权", nil)
ErrNotFound = NewSDKError(ErrCodeNotFound, "未找到", nil)
ErrRateLimit = NewSDKError(ErrCodeRateLimit, "请求频率限制", nil)
)
// File: intelligence_finance_v1/client.go
package intelligence_finance_v1
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// Client 业财连接SDK客户端
type Client struct {
baseURL string
tenantID string
clientID string
clientSecret string
httpClient *http.Client
debug bool
}
// ClientOption 客户端配置选项
type ClientOption func(*Client)
// WithHTTPClient 设置自定义HTTP客户端
func WithHTTPClient(httpClient *http.Client) ClientOption {
return func(c *Client) {
c.httpClient = httpClient
}
}
// WithDebug 开启调试模式
func WithDebug(debug bool) ClientOption {
return func(c *Client) {
c.debug = debug
}
}
// WithTimeout 设置请求超时时间
func WithTimeout(timeout time.Duration) ClientOption {
return func(c *Client) {
c.httpClient.Timeout = timeout
}
}
// NewClient 创建新的SDK客户端
// - baseURL: API基础地址
// - tenantID: 平台分配的租户唯一标识
// - clientID: 平台分配的应用标识
// - clientSecret: 平台分配的客户端密钥
// - opts: 可选配置项
func NewClient(baseURL, tenantID, clientID, clientSecret string, opts ...ClientOption) *Client {
c := &Client{
baseURL: baseURL,
tenantID: tenantID,
clientID: clientID,
clientSecret: clientSecret,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
for _, opt := range opts {
opt(c)
}
return c
}
// doRequest 发送HTTP请求,自动添加签名和认证头
func (c *Client) doRequest(ctx context.Context, path string, request interface{}, response interface{}) error {
bodyBytes, err := json.Marshal(request)
if err != nil {
return NewSDKError(ErrCodeInvalidParam, "请求序列化失败", err)
}
if c.debug {
fmt.Printf("[DEBUG] Request URL: %s%s\n", c.baseURL, path)
fmt.Printf("[DEBUG] Request Body: %s\n", string(bodyBytes))
}
// 生成时间戳和随机数
timestamp := GenerateTimestamp()
nonce, err := GenerateNonce(16)
if err != nil {
return NewSDKError(ErrCodeSignatureFailed, "生成随机数失败", err)
}
// 签名数据:timestamp + nonce
signData := timestamp + nonce
signature := HmacSHA256Base64(c.clientSecret, signData)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+path, bytes.NewReader(bodyBytes))
if err != nil {
return NewSDKError(ErrCodeNetworkError, "创建请求失败", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("tenant-id", c.tenantID)
req.Header.Set("client-id", c.clientID)
req.Header.Set("x-bfl-signature-timestamp", timestamp)
req.Header.Set("x-bfl-signature-nonce", nonce)
req.Header.Set("x-bfl-signature", signature)
if c.debug {
fmt.Printf("[DEBUG] Headers: tenant-id=%s, client-id=%s, x-bfl-signature=%s\n", c.tenantID, c.clientID, signature)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return NewSDKError(ErrCodeNetworkError, "请求发送失败", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return NewSDKError(ErrCodeNetworkError, "读取响应失败", err)
}
if c.debug {
fmt.Printf("[DEBUG] Response Status: %s\n", resp.Status)
fmt.Printf("[DEBUG] Response Body: %s\n", string(respBody))
}
// 解析通用响应
var commonResp CommonResponse
if err := json.Unmarshal(respBody, &commonResp); err != nil {
return NewSDKError(ErrCodeUnknown, "响应解析失败", err)
}
if commonResp.Code != 0 {
return NewSDKError(commonResp.Code, commonResp.Msg, nil)
}
// 如果有data字段且response不为nil,反序列化data到response
if commonResp.Data != nil && response != nil {
dataBytes, err := json.Marshal(commonResp.Data)
if err != nil {
return NewSDKError(ErrCodeUnknown, "响应数据序列化失败", err)
}
if err := json.Unmarshal(dataBytes, response); err != nil {
return NewSDKError(ErrCodeUnknown, "响应数据解析失败", err)
}
}
return nil
}
// ============================================================
// 接口1:订单开票
// ============================================================
// CreateInvoice 提交订单开票申请
// 文档:接口1 - 提交订单开票申请
func (c *Client) CreateInvoice(ctx context.Context, req *CreateInvoiceRequest) (*CreateInvoiceResponse, error) {
path := "/api/v1/invoice/create"
var resp CreateInvoiceResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口2:开票状态查询
// ============================================================
// QueryInvoiceStatus 查询订单开票状态
// 文档:接口2 - 查询订单开票状态
func (c *Client) QueryInvoiceStatus(ctx context.Context, req *QueryInvoiceStatusRequest) (*QueryInvoiceStatusResponse, error) {
path := "/api/v1/invoice/query"
var resp QueryInvoiceStatusResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口3:创建付款单据
// ============================================================
// CreatePayment 创建付款单据
// 文档:接口3 - 创建付款单据
func (c *Client) CreatePayment(ctx context.Context, req *CreatePaymentRequest) (*CreatePaymentResponse, error) {
path := "/api/v1/payment/create"
var resp CreatePaymentResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口4:支付完成通知(平台回调客户)
// 此接口由客户提供,平台调用。客户需实现HTTP Handler处理回调。
// ============================================================
// HandlePaymentNotification 处理支付完成通知
// 文档:接口4 - 支付完成通知回调处理
// 该函数用于解析平台发起的支付完成通知请求,返回SUCCESS或FAILED
func HandlePaymentNotification(body []byte) (string, error) {
var notification PaymentNotification
if err := json.Unmarshal(body, ¬ification); err != nil {
return "FAILED", NewSDKError(ErrCodeInvalidParam, "解析通知数据失败", err)
}
// 业务处理由调用方自行实现,此处仅返回成功
// 调用方应在此函数基础上扩展业务逻辑
return "SUCCESS", nil
}
// ============================================================
// 接口5:支付状态查询
// ============================================================
// QueryPaymentStatus 查询支付状态
// 文档:接口5 - 查询支付状态
func (c *Client) QueryPaymentStatus(ctx context.Context, req *QueryPaymentStatusRequest) (*QueryPaymentStatusResponse, error) {
path := "/api/v1/payment/query"
var resp QueryPaymentStatusResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口6:创建供应商
// ============================================================
// CreateSupplier 创建供应商
// 文档:接口6 - 创建供应商
func (c *Client) CreateSupplier(ctx context.Context, req *CreateSupplierRequest) (*CreateSupplierResponse, error) {
path := "/api/v1/supplier/create"
var resp CreateSupplierResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口7:根据名称查询供应商
// ============================================================
// QuerySupplierByName 根据供应商名称查询供应商
// 文档:接口7 - 根据名称查询供应商
func (c *Client) QuerySupplierByName(ctx context.Context, req *QuerySupplierByNameRequest) (*QuerySupplierByNameResponse, error) {
path := "/api/v1/supplier/queryByName"
var resp QuerySupplierByNameResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口8:更新供应商
// ============================================================
// UpdateSupplier 更新供应商信息
// 文档:接口8 - 更新供应商
func (c *Client) UpdateSupplier(ctx context.Context, req *UpdateSupplierRequest) (*UpdateSupplierResponse, error) {
path := "/api/v1/supplier/update"
var resp UpdateSupplierResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// ============================================================
// 接口9:根据用户自定义编码查询供应商
// ============================================================
// QuerySupplierByUserDefineCode 根据用户自定义编码查询供应商
// 文档:接口9 - 根据用户自定义编码查询供应商
func (c *Client) QuerySupplierByUserDefineCode(ctx context.Context, req *QuerySupplierByUserDefineCodeRequest) (*QuerySupplierByUserDefineCodeResponse, error) {
path := "/api/v1/supplier/queryByCode"
var resp QuerySupplierByUserDefineCodeResponse
if err := c.doRequest(ctx, path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// File: intelligence_finance_v1/example_test.go
package intelligence_finance_v1
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
)
// ExampleNewClient 展示了如何创建SDK客户端
func ExampleNewClient() {
// 创建客户端
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
WithTimeout(30*time.Second),
WithDebug(true),
)
_ = client
fmt.Println("Client created successfully")
}
// ExampleClient_CreateInvoice 展示了如何提交订单开票申请
func ExampleClient_CreateInvoice() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &CreateInvoiceRequest{
OrderID: "ORDER20240101001",
InvoiceType: 9, // 数电普票
Purchaser: "测试购买方有限公司",
TaxNum: "91110108MA12345678",
Phone: "13800138000",
Email: "test@example.com",
Products: []InvoiceProduct{
{
ProductName: "办公用品",
RevenueCode: "1090515010000000000",
AmountIncludeTax: 1130.00,
Quantity: 10,
Unit: "个",
TaxRate: 0.13,
TaxSign: 1,
Discount: 0,
},
},
ApplyPerson: "张三",
Payee: "李四",
Reviewer: "王五",
}
resp, err := client.CreateInvoice(context.Background(), req)
if err != nil {
log.Fatalf("创建开票申请失败: %v", err)
}
fmt.Printf("开票状态: %d, 错误信息: %s\n", resp.Status, resp.ErrorMsg)
for i, inv := range resp.DataList {
fmt.Printf("发票%d: 代码=%s, 号码=%s, 金额(含税)=%s\n", i+1, inv.InvoiceCode, inv.InvoiceNo, inv.TotalIncludeTax)
}
}
// ExampleClient_QueryInvoiceStatus 展示了如何查询开票状态
func ExampleClient_QueryInvoiceStatus() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &QueryInvoiceStatusRequest{
OrderID: "ORDER20240101001",
}
resp, err := client.QueryInvoiceStatus(context.Background(), req)
if err != nil {
log.Fatalf("查询开票状态失败: %v", err)
}
fmt.Printf("开票状态: %d, 描述: %s\n", resp.Status, resp.Message)
}
// ExampleClient_CreatePayment 展示了如何创建付款单据
func ExampleClient_CreatePayment() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &CreatePaymentRequest{
Code: "PAY20240101001",
UserID: "user123",
Title: "采购付款-2024年1月",
Amount: "50000.00",
Supplier: &Supplier{
Name: "供应商A",
},
Department: &Department{
Name: "财务部",
},
Company: &Company{
Name: "XX科技有限公司",
},
PaymentDetailList: []PaymentDetail{
{
Amount: "50000.00",
Remark: "1月采购货款",
},
},
}
resp, err := client.CreatePayment(context.Background(), req)
if err != nil {
log.Fatalf("创建付款单据失败: %v", err)
}
fmt.Printf("付款单据编码: %s\n", resp.Code)
}
// ExampleHandlePaymentNotification 展示了如何处理支付完成通知
func ExampleHandlePaymentNotification() {
// 模拟平台回调的请求体
notificationBody := `{
"code": "PAY20240101001",
"instanceId": "instance_001",
"corpId": "dingXXXXXX",
"paymentStatus": "SUCCESS",
"paymentTime": "2024-01-15 10:30:00",
"userId": "user123",
"amount": "50000.00",
"source": "openapi"
}`
result, err := HandlePaymentNotification([]byte(notificationBody))
if err != nil {
log.Printf("处理通知失败: %v", err)
}
fmt.Printf("通知处理结果: %s\n", result)
// 实际业务中,可以在此处解析通知数据并执行后续操作
var notification PaymentNotification
if err := json.Unmarshal([]byte(notificationBody), ¬ification); err == nil {
fmt.Printf("收到支付通知: 单据编码=%s, 支付状态=%s\n", notification.Code, notification.PaymentStatus)
}
}
// ExampleClient_QueryPaymentStatus 展示了如何查询支付状态
func ExampleClient_QueryPaymentStatus() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &QueryPaymentStatusRequest{
Code: "PAY20240101001",
UserID: "user123",
}
resp, err := client.QueryPaymentStatus(context.Background(), req)
if err != nil {
log.Fatalf("查询支付状态失败: %v", err)
}
fmt.Printf("支付状态: %s, 支付时间: %s\n", resp.PaymentStatus, resp.PaymentTime)
}
// ExampleClient_CreateSupplier 展示了如何创建供应商
func ExampleClient_CreateSupplier() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := CreateSupplierBizData{
CorpID: "dingXXXXXX",
Creator: "user123",
SupplierInfo: &SupplierInfo{
Name: "测试供应商有限公司",
CorpID: "dingXXXXXX",
Creator: "user123",
UserDefineCode: "SUP-001",
ContactName: "张三",
ContactTelephone: "13800138000",
ContactEmail: "contact@supplier.com",
ContactAddress: "北京市朝阳区XX路XX号",
},
}
bizDataBytes, _ := json.Marshal(bizData)
req := &CreateSupplierRequest{
InvokeID: "invoke_001",
UserID: "user123",
Data: string(bizDataBytes),
BizType: "create_supplier",
}
resp, err := client.CreateSupplier(context.Background(), req)
if err != nil {
log.Fatalf("创建供应商失败: %v", err)
}
fmt.Printf("创建供应商响应: invokeId=%s, bizType=%s\n", resp.InvokeID, resp.BizType)
}
// ExampleClient_QuerySupplierByName 展示了如何根据名称查询供应商
func ExampleClient_QuerySupplierByName() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := []QuerySupplierByNameBizData{
{
CorpID: "dingXXXXXX",
Name: "测试供应商有限公司",
},
}
bizDataBytes, _ := json.Marshal(bizData)
req := &QuerySupplierByNameRequest{
InvokeID: "invoke_002",
UserID: "user123",
Data: string(bizDataBytes),
BizType: "query_supplier_by_name",
}
resp, err := client.QuerySupplierByName(context.Background(), req)
if err != nil {
log.Fatalf("查询供应商失败: %v", err)
}
fmt.Printf("查询结果: success=%v, result=%s\n", resp.Success, resp.Result)
}
// ExampleClient_UpdateSupplier 展示了如何更新供应商
func ExampleClient_UpdateSupplier() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := UpdateSupplierBizData{
SupplierID: "SUP_XXXXX",
Name: "更新后的供应商名称",
CorpID: "dingXXXXXX",
UserID: "user123",
ContactName: "李四",
ContactTelephone: "13900139000",
ContactEmail: "new@supplier.com",
Description: "长期合作供应商",
}
bizDataBytes, _ := json.Marshal(bizData)
req := &UpdateSupplierRequest{
InvokeID: "invoke_003",
UserID: "user123",
Data: string(bizDataBytes),
BizType: "update_supplier",
}
resp, err := client.UpdateSupplier(context.Background(), req)
if err != nil {
log.Fatalf("更新供应商失败: %v", err)
}
fmt.Printf("更新供应商响应: invokeId=%s, bizType=%s\n", resp.InvokeID, resp.BizType)
}
// ExampleClient_QuerySupplierByUserDefineCode 展示了如何根据自定义编码查询供应商
func ExampleClient_QuerySupplierByUserDefineCode() {
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := QuerySupplierByUserDefineCodeBizData{
CorpID: "dingXXXXXX",
UserDefineCode: "SUP-001",
}
bizDataBytes, _ := json.Marshal(bizData)
req := &QuerySupplierByUserDefineCodeRequest{
InvokeID: "invoke_004",
UserID: "user123",
Data: string(bizDataBytes),
BizType: "query_supplier_by_userDefineCode",
}
resp, err := client.QuerySupplierByUserDefineCode(context.Background(), req)
if err != nil {
log.Fatalf("查询供应商失败: %v", err)
}
fmt.Printf("查询供应商响应: invokeId=%s, bizType=%s\n", resp.InvokeID, resp.BizType)
}
=== SDK 生成完成 ===