intelligence_finance_v1-202.../intelligence_finance_v1/valid.md

45 KiB
Raw Blame History

// 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

import "encoding/json"

// ============================================================ // 通用请求/响应结构 // ============================================================

// CommonResponse 通用API响应结构 type CommonResponse struct { Code int json:"code" Msg string json:"msg,omitempty" Data json.RawMessage 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 json.RawMessage 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 json.RawMessage 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 json.RawMessage 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 json.RawMessage 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)
}

// 如果response不为nil将commonResp.Data反序列化到response
if response != nil {
	if err := json.Unmarshal(commonResp.Data, 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 // 注意:平台回调时,请求体为 NotificationRequest 结构,其中 Data 字段为 PaymentNotification 的JSON字符串 func HandlePaymentNotification(body []byte) (string, error) { // 先解析外层通知结构 var notificationReq NotificationRequest if err := json.Unmarshal(body, &notificationReq); err != nil { return "FAILED", NewSDKError(ErrCodeInvalidParam, "解析通知请求失败", err) }

// 根据bizType处理不同业务
switch notificationReq.BizType {
case "payment_notification":
	// 解析内部支付通知数据
	var paymentNotification PaymentNotification
	if err := json.Unmarshal([]byte(notificationReq.Data), &paymentNotification); err != nil {
		return "FAILED", NewSDKError(ErrCodeInvalidParam, "解析支付通知数据失败", err)
	}
	// 业务处理由调用方自行实现,此处仅返回成功
	// 调用方应在此函数基础上扩展业务逻辑
	_ = paymentNotification
default:
	// 未知业务类型,记录日志后返回失败
	return "FAILED", NewSDKError(ErrCodeInvalidParam, "未知业务类型: "+notificationReq.BizType, nil)
}

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() { // 模拟平台回调的请求体符合NotificationRequest格式 notificationBody := { "bizType": "payment_notification", "bizId": "instance_001", "data": "{\"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 notificationReq NotificationRequest
json.Unmarshal([]byte(notificationBody), &notificationReq)
var paymentNotification PaymentNotification
json.Unmarshal([]byte(notificationReq.Data), &paymentNotification)
fmt.Printf("收到支付通知: 单据编码=%s, 支付状态=%s\n", paymentNotification.Code, paymentNotification.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)
// 如果需要解析响应数据,可以进一步处理 resp.Data
var responseData CreateSupplierResponseData
if err := json.Unmarshal(resp.Data, &responseData); err == nil {
	fmt.Printf("响应数据: success=%v, result=%s\n", responseData.Success, responseData.Result)
}

}

// 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)
// 解析响应数据
var results []QuerySupplierByNameResult
if err := json.Unmarshal(resp.Data, &results); err == nil {
	for _, r := range results {
		fmt.Printf("供应商: %s, ID: %s\n", r.SupplierName, r.SupplierID)
	}
}

}

// 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)
// 解析响应数据
var responseData QuerySupplierByUserDefineCodeResponseData
if err := json.Unmarshal(resp.Data, &responseData); err == nil {
	fmt.Printf("响应数据: success=%v\n", responseData.Success)
}

}