sdk_generate/test.md

1307 lines
44 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// File: intelligence_finance_v1_ga/go.mod
```go
module intelligence_finance_v1_ga
go 1.21
```
// File: intelligence_finance_v1_ga/errors.go
```go
package intelligence_finance_v1_ga
import "fmt"
// APIError 表示 HTTP 层面的错误(非 200 响应)。
type APIError struct {
// StatusCode HTTP 状态码
StatusCode int
// Body 响应体原始内容
Body string
}
// Error 实现 error 接口。
func (e *APIError) Error() string {
return fmt.Sprintf("api error: status=%d body=%s", e.StatusCode, e.Body)
}
// BusinessError 表示业务层面的错误(通用响应结构中 code 非成功值)。
type BusinessError struct {
// Code 业务错误码
Code int
// Msg 业务错误描述
Msg string
}
// Error 实现 error 接口。
func (e *BusinessError) Error() string {
return fmt.Sprintf("business error: code=%d msg=%s", e.Code, e.Msg)
}
// NotificationError 表示通知处理失败。
type NotificationError struct {
// Reason 失败原因
Reason string
}
// Error 实现 error 接口。
func (e *NotificationError) Error() string {
return fmt.Sprintf("notification error: %s", e.Reason)
}
```
// File: intelligence_finance_v1_ga/crypto.go
```go
package intelligence_finance_v1_ga
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())
}
// GenerateTimestampMillis 生成毫秒级时间戳。
func GenerateTimestampMillis() string {
return fmt.Sprintf("%d", time.Now().UnixMilli())
}
// 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 算法对 data 进行签名,密钥为 key结果 Base64 编码。
// 对应文档中客户应用签名算法HmacSHA256密钥为 client-secret
// 签名数据为 x-bfl-signature-timestamp + x-bfl-signature-nonce。
func HmacSHA256Base64(key, data string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// BuildSignString 方式1字典序排序拼接排除空值与签名字段本身。
func BuildSignString(params map[string]string) string {
keys := make([]string, 0, len(params))
for k, v := range params {
if v != "" && k != "sign" && k != "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 方式2固定顺序拼接排除空值。
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_ga/types.go
```go
package intelligence_finance_v1_ga
import "encoding/json"
// ==================== 通用 ====================
// CommonResponse 通用响应结构。
type CommonResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data json.RawMessage `json:"data"`
}
// ==================== 接口1订单开票 ====================
// InvoiceApplyRequest 提交订单开票申请请求。
type InvoiceApplyRequest struct {
// CompanyCode 开票的企业主体编码,不传则默认主体开票
CompanyCode string `json:"companyCode,omitempty"`
// OrderID 订单唯一标识(需保证在贵方系统内唯一)
OrderID string `json:"orderId"`
// InvoiceType 发票类型枚举1-专用发票2-普通发票3-普通发票(电子)4-专用发票(电子)8-数电专票9-数电普票
InvoiceType int `json:"invoiceType"`
// Products 货物/服务明细列表,至少一项
Products []ProductItem `json:"products"`
// Remark 订单备注(非发票备注)
Remark string `json:"remark,omitempty"`
// Purchaser 购方企业名称
Purchaser string `json:"purchaser"`
// TaxNum 购方纳税人识别号
TaxNum string `json:"taxnum,omitempty"`
// PurchaserAddress 购方地址
PurchaserAddress string `json:"purchaserAddress,omitempty"`
// PurchaserTel 购方电话
PurchaserTel string `json:"purchaserTel,omitempty"`
// BankName 购方开户行名称
BankName string `json:"bankName,omitempty"`
// BankAccount 购方银行账号
BankAccount string `json:"bankAccount,omitempty"`
// Phone 收票人手机号(用于接收电票短信)
Phone string `json:"phone,omitempty"`
// Email 收票人邮箱(用于接收电票邮件)
Email string `json:"email,omitempty"`
// ApplyPerson 开票申请人名称
ApplyPerson string `json:"applyPerson,omitempty"`
// Payee 收款人(发票票面)
Payee string `json:"payee,omitempty"`
// Reviewer 复核人(发票票面)
Reviewer string `json:"reviewer,omitempty"`
// InvoiceRemark 发票备注栏内容
InvoiceRemark string `json:"invoiceRemark,omitempty"`
// NaturalPerson 购买方自然人标识Y-是N-否默认N数电票可选传
NaturalPerson string `json:"naturalPerson,omitempty"`
// AdditionInfo 附加信息JSON数组字符串
AdditionInfo string `json:"additionInfo,omitempty"`
}
// ProductItem 货物/服务明细项。
type ProductItem struct {
// ProductName 货物或服务名称
ProductName string `json:"productName"`
// RevenueCode 19位税收分类编码
RevenueCode string `json:"revenueCode"`
// AmountIncludeTax 单条明细含税总金额(单位:元)
AmountIncludeTax float64 `json:"amountIncludeTax"`
// Specs 规格型号
Specs string `json:"specs,omitempty"`
// Unit 计量单位(如:台、个、次)
Unit string `json:"unit,omitempty"`
// Quantity 数量
Quantity float64 `json:"quantity"`
// Discount 折扣金额无折扣传0
Discount float64 `json:"discount,omitempty"`
// TaxSign 是否含税0-不含税1-含税默认建议传1
TaxSign int `json:"taxSign,omitempty"`
// TaxRate 税率小数形式如0.13表示13%
TaxRate float64 `json:"taxRate,omitempty"`
}
// InvoiceApplyResponse 提交订单开票申请响应。
type InvoiceApplyResponse struct {
// Status 开票状态0-未开票1-开票中2-部分失败3-开票成功4-开票失败5-部分未开6-未配置数电账号7-未配置自动开票配置
Status int `json:"status"`
// ErrorMsg 错误信息(开票失败时返回原因)
ErrorMsg string `json:"errorMsg,omitempty"`
// DataList 发票数据列表(一张订单可能对应多张发票)
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开票状态查询 ====================
// InvoiceStatusQueryRequest 查询订单开票状态请求。
type InvoiceStatusQueryRequest struct {
// OrderID 订单唯一标识(需保证在贵方系统内唯一)
OrderID string `json:"orderId"`
}
// InvoiceStatusQueryResponse 查询订单开票状态响应。
type InvoiceStatusQueryResponse struct {
// Status 开票状态0-未开票3-成功4-失败6-未配置数电账号7-未配置自动开票)
Status int `json:"status"`
// Message 状态描述(如"开票成功"
Message string `json:"message"`
// Data 发票详细列表结构与回调中的data字段一致
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"`
PaymentDetailListJSON 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 单据唯一编码
Code string `json:"code"`
}
// ==================== 接口4支付完成通知 ====================
// PaymentNotifyData 支付完成通知数据。
type PaymentNotifyData 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"`
}
// 支付状态枚举。
const (
PaymentStatusSuccess = "SUCCESS" // 支付成功
PaymentStatusFail = "FAIL" // 支付失败
PaymentStatusTerminate = "TERMINATE" // 支付取消
PaymentStatusWaitPay = "WAIT_PAY" // 待支付
PaymentStatusPaying = "PAYING" // 支付中
PaymentStatusPartSuccess = "PART_SUCCESS" // 部分支付成功
PaymentStatusRefund = "REFUND" // 退款
)
// 来源枚举。
const (
SourceApproval = "approval" // 审批单
SourceOpenAPI = "openapi" // 开发接口
)
// 账户类型枚举。
const (
AccountTypeAlipay = "ALIPAY" // 支付宝
AccountTypeBankCard = "BANKCARD" // 银行卡
AccountTypeCorpBankCard = "CORP_BANK_CARD" // 对公银行卡
AccountTypePersonalBankCard = "PERSONAL_BANK_CARD" // 对私银行卡
)
// ==================== 接口5支付状态查询 ====================
// PaymentStatusQueryRequest 查询支付状态请求。
type PaymentStatusQueryRequest struct {
Code string `json:"code"`
UserID string `json:"userId"`
}
// ==================== 通用通知机制 ====================
// Notification 通用通知数据。
type Notification struct {
BizType string `json:"bizType"`
BizID string `json:"bizId"`
Data string `json:"data,omitempty"`
}
// 通知响应常量。
const (
NotifyResultSuccess = "SUCCESS" // 成功
NotifyResultFailed = "FAILED" // 失败
)
// ==================== 接口6创建供应商 ====================
// CreateSupplierRequest 创建供应商请求。
type CreateSupplierRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// SupplierBizData 供应商业务数据。
type SupplierBizData 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"`
}
// SupplierResponseData 供应商响应数据。
type SupplierResponseData struct {
Result string `json:"result,omitempty"`
Success bool `json:"success"`
}
// SupplierResult 供应商信息(响应)。
type SupplierResult 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"`
InvoiceName string `json:"invoiceName,omitempty"`
InvoiceTaxNo string `json:"invoiceTaxNo,omitempty"`
CreateTime int64 `json:"createTime,omitempty"`
ModifiedTime int64 `json:"modifiedTime,omitempty"`
Code string `json:"code,omitempty"`
ID int64 `json:"id,omitempty"`
Status string `json:"status,omitempty"`
}
// ==================== 接口7根据名称查询供应商 ====================
// QuerySupplierByNameRequest 根据名称查询供应商请求。
type QuerySupplierByNameRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// QueryByName 按名称查询业务数据。
type QueryByName 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"`
}
// ==================== 接口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"`
}
// ==================== 接口9根据用户自定义编码查询供应商 ====================
// QuerySupplierByUserDefineCodeRequest 根据用户自定义编码查询供应商请求。
type QuerySupplierByUserDefineCodeRequest struct {
InvokeID string `json:"invokeId,omitempty"`
UserID string `json:"userId"`
Data string `json:"data,omitempty"`
BizType string `json:"bizType"`
}
// QueryByUserDefineCode 按用户自定义编码查询业务数据。
type QueryByUserDefineCode 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"`
}
```
// File: intelligence_finance_v1_ga/client.go
```go
package intelligence_finance_v1_ga
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
// 供应商业务类型常量。
const (
BizTypeCreateSupplier = "create_supplier"
BizTypeQuerySupplierByName = "query_supplier_by_name"
BizTypeUpdateSupplier = "update_supplier"
BizTypeQuerySupplierByUserDefine = "query_supplier_by_userDefineCode"
)
// Client 业财连接接口客户端。
type Client struct {
baseURL string
tenantID string
clientID string
clientSecret string
signEnabled bool
httpClient *http.Client
// 各接口路径(可通过 Option 覆盖)
pathSubmitInvoiceApply string
pathQueryInvoiceStatus string
pathCreatePayment string
pathQueryPaymentStatus string
pathCreateSupplier string
pathQuerySupplierByName string
pathUpdateSupplier string
pathQuerySupplierByUserDefineCode string
}
// Option 客户端配置项。
type Option func(*Client)
// WithHTTPClient 自定义 http.Client。
func WithHTTPClient(c *http.Client) Option {
return func(cli *Client) { cli.httpClient = c }
}
// WithSignEnabled 是否启用请求签名钉钉AI表格场景可关闭签名由AI表格自动完成
func WithSignEnabled(enabled bool) Option {
return func(cli *Client) { cli.signEnabled = enabled }
}
// WithPathSubmitInvoiceApply 设置提交订单开票申请接口路径。
func WithPathSubmitInvoiceApply(path string) Option {
return func(cli *Client) { cli.pathSubmitInvoiceApply = path }
}
// WithPathQueryInvoiceStatus 设置开票状态查询接口路径。
func WithPathQueryInvoiceStatus(path string) Option {
return func(cli *Client) { cli.pathQueryInvoiceStatus = path }
}
// WithPathCreatePayment 设置创建付款单据接口路径。
func WithPathCreatePayment(path string) Option {
return func(cli *Client) { cli.pathCreatePayment = path }
}
// WithPathQueryPaymentStatus 设置支付状态查询接口路径。
func WithPathQueryPaymentStatus(path string) Option {
return func(cli *Client) { cli.pathQueryPaymentStatus = path }
}
// WithPathCreateSupplier 设置创建供应商接口路径。
func WithPathCreateSupplier(path string) Option {
return func(cli *Client) { cli.pathCreateSupplier = path }
}
// WithPathQuerySupplierByName 设置根据名称查询供应商接口路径。
func WithPathQuerySupplierByName(path string) Option {
return func(cli *Client) { cli.pathQuerySupplierByName = path }
}
// WithPathUpdateSupplier 设置更新供应商接口路径。
func WithPathUpdateSupplier(path string) Option {
return func(cli *Client) { cli.pathUpdateSupplier = path }
}
// WithPathQuerySupplierByUserDefineCode 设置根据用户自定义编码查询供应商接口路径。
func WithPathQuerySupplierByUserDefineCode(path string) Option {
return func(cli *Client) { cli.pathQuerySupplierByUserDefineCode = path }
}
// NewClient 创建业财连接接口客户端。
//
// baseURL 为平台接口根地址tenantID 为平台分配的租户唯一标识;
// clientID 为平台分配的应用标识钉钉AI表格固定为 "dd-ai-table"
// clientSecret 为平台分配的密钥,用于请求签名。
func NewClient(baseURL, tenantID, clientID, clientSecret string, opts ...Option) *Client {
c := &Client{
baseURL: strings.TrimRight(baseURL, "/"),
tenantID: tenantID,
clientID: clientID,
clientSecret: clientSecret,
signEnabled: true,
httpClient: &http.Client{Timeout: 30 * time.Second},
pathSubmitInvoiceApply: "/invoice/apply",
pathQueryInvoiceStatus: "/invoice/status",
pathCreatePayment: "/payment/create",
pathQueryPaymentStatus: "/payment/status",
pathCreateSupplier: "/supplier/create",
pathQuerySupplierByName: "/supplier/queryByName",
pathUpdateSupplier: "/supplier/update",
pathQuerySupplierByUserDefineCode: "/supplier/queryByUserDefineCode",
}
for _, opt := range opts {
opt(c)
}
return c
}
// doRequest 发送 POST 请求并解析响应。
func (c *Client) doRequest(ctx context.Context, path string, reqBody, respBody interface{}) error {
body, err := json.Marshal(reqBody)
if err != nil {
return fmt.Errorf("marshal request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+path, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("new request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("tenant-id", c.tenantID)
httpReq.Header.Set("client-id", c.clientID)
if c.signEnabled {
timestamp := GenerateTimestamp()
nonce, err := GenerateNonce(32)
if err != nil {
return fmt.Errorf("generate nonce: %w", err)
}
sign := HmacSHA256Base64(c.clientSecret, timestamp+nonce)
httpReq.Header.Set("x-bfl-signature-timestamp", timestamp)
httpReq.Header.Set("x-bfl-signature-nonce", nonce)
httpReq.Header.Set("x-bfl-signature", sign)
}
httpResp, err := c.httpClient.Do(httpReq)
if err != nil {
return fmt.Errorf("do request: %w", err)
}
defer httpResp.Body.Close()
respData, err := io.ReadAll(httpResp.Body)
if err != nil {
return fmt.Errorf("read response: %w", err)
}
if httpResp.StatusCode != http.StatusOK {
return &APIError{StatusCode: httpResp.StatusCode, Body: string(respData)}
}
if err := json.Unmarshal(respData, respBody); err != nil {
return fmt.Errorf("unmarshal response: %w", err)
}
return nil
}
// checkBusinessCode 校验通用响应结构中的业务 code。
func checkBusinessCode(code int, msg string) error {
if code != 0 && code != 200 {
return &BusinessError{Code: code, Msg: msg}
}
return nil
}
// SubmitInvoiceApply 提交订单开票申请接口1
func (c *Client) SubmitInvoiceApply(ctx context.Context, req *InvoiceApplyRequest) (*InvoiceApplyResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *InvoiceApplyResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathSubmitInvoiceApply, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// QueryInvoiceStatus 查询订单开票状态接口2
func (c *Client) QueryInvoiceStatus(ctx context.Context, req *InvoiceStatusQueryRequest) (*InvoiceStatusQueryResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *InvoiceStatusQueryResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathQueryInvoiceStatus, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// CreatePayment 创建付款单据接口3
func (c *Client) CreatePayment(ctx context.Context, req *CreatePaymentRequest) (*CreatePaymentResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *CreatePaymentResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathCreatePayment, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// QueryPaymentStatus 查询支付状态接口5响应数据与支付通知一致。
func (c *Client) QueryPaymentStatus(ctx context.Context, req *PaymentStatusQueryRequest) (*PaymentNotifyData, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *PaymentNotifyData `json:"data"`
}
if err := c.doRequest(ctx, c.pathQueryPaymentStatus, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// CreateSupplier 创建供应商接口6
func (c *Client) CreateSupplier(ctx context.Context, req *CreateSupplierRequest) (*CreateSupplierResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *CreateSupplierResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathCreateSupplier, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// QuerySupplierByName 根据名称查询供应商接口7
func (c *Client) QuerySupplierByName(ctx context.Context, req *QuerySupplierByNameRequest) (*QuerySupplierByNameResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *QuerySupplierByNameResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathQuerySupplierByName, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// UpdateSupplier 更新供应商接口8
func (c *Client) UpdateSupplier(ctx context.Context, req *UpdateSupplierRequest) (*UpdateSupplierResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *UpdateSupplierResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathUpdateSupplier, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// QuerySupplierByUserDefineCode 根据用户自定义编码查询供应商接口9
func (c *Client) QuerySupplierByUserDefineCode(ctx context.Context, req *QuerySupplierByUserDefineCodeRequest) (*QuerySupplierByUserDefineCodeResponse, error) {
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *QuerySupplierByUserDefineCodeResponse `json:"data"`
}
if err := c.doRequest(ctx, c.pathQuerySupplierByUserDefineCode, req, &envelope); err != nil {
return nil, err
}
if err := checkBusinessCode(envelope.Code, envelope.Msg); err != nil {
return nil, err
}
return envelope.Data, nil
}
// ==================== 通知机制辅助 ====================
// ParseNotification 解析通用通知数据。
func ParseNotification(body []byte) (*Notification, error) {
var n Notification
if err := json.Unmarshal(body, &n); err != nil {
return nil, fmt.Errorf("parse notification: %w", err)
}
return &n, nil
}
// ParsePaymentNotify 解析支付完成通知数据接口4
func ParsePaymentNotify(body []byte) (*PaymentNotifyData, error) {
var n PaymentNotifyData
if err := json.Unmarshal(body, &n); err != nil {
return nil, fmt.Errorf("parse payment notify: %w", err)
}
return &n, nil
}
// VerifyNotificationSignature 校验通知签名。
//
// 平台使用客户提供的验签密钥对原始请求体进行 HmacSHA256 签名并 Base64 编码,
// 通过请求头 x-bfl-signature 传递。verifyKey 为客户在平台配置的验签密钥。
func VerifyNotificationSignature(verifyKey string, rawBody []byte, signature string) (bool, error) {
if signature == "" {
return false, &NotificationError{Reason: "empty signature"}
}
expected := HmacSHA256Base64(verifyKey, string(rawBody))
return hmacEqual(expected, signature), nil
}
// hmacEqual 常量时间比较两个 Base64 签名是否一致。
func hmacEqual(a, b string) bool {
if len(a) != len(b) {
return false
}
var v byte
for i := 0; i < len(a); i++ {
v |= a[i] ^ b[i]
}
return v == 0
}
```
// File: intelligence_finance_v1_ga/example_test.go
```go
package intelligence_finance_v1_ga
import (
"context"
"encoding/json"
"fmt"
"testing"
)
// ExampleClient_SubmitInvoiceApply 演示提交订单开票申请。
func ExampleClient_SubmitInvoiceApply() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &InvoiceApplyRequest{
OrderID: "ORDER-20240101-001",
InvoiceType: 9, // 数电普票
Purchaser: "某某科技有限公司",
TaxNum: "91330100XXXXXXXXXX",
Email: "finance@example.com",
Phone: "13800000000",
Products: []ProductItem{
{
ProductName: "软件服务",
RevenueCode: "3040201000000000000",
AmountIncludeTax: 11300,
Quantity: 1,
TaxRate: 0.13,
TaxSign: 1,
},
},
}
resp, err := client.SubmitInvoiceApply(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("status=%d errorMsg=%s\n", resp.Status, resp.ErrorMsg)
// Output:
}
// ExampleClient_CreatePayment 演示创建付款单据。
func ExampleClient_CreatePayment() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
req := &CreatePaymentRequest{
Code: "PAY-20240101-001",
UserID: "04221***",
Title: "供应商货款",
Amount: "11300.00",
Supplier: &Supplier{
Name: "某某供应商",
},
PaymentDetailList: []PaymentDetail{
{
Amount: "11300.00",
Tax: "1300.00",
},
},
}
resp, err := client.CreatePayment(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("code=%s\n", resp.Code)
// Output:
}
// ExampleClient_CreateSupplier 演示创建供应商。
func ExampleClient_CreateSupplier() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := []SupplierBizData{
{
CorpID: "dingXXXXXX",
Creator: "04221***",
SupplierInfo: &SupplierInfo{
Name: "某某供应商",
CorpID: "dingXXXXXX",
Creator: "04221***",
ContactName: "张三",
ContactTelephone: "18888888888",
InvoiceName: "某某供应商",
InvoiceTaxNo: "91330100XXXXXXXXXX",
},
},
}
dataBytes, _ := json.Marshal(bizData)
req := &CreateSupplierRequest{
InvokeID: "REQ-001",
UserID: "04221***",
Data: string(dataBytes),
BizType: BizTypeCreateSupplier,
}
resp, err := client.CreateSupplier(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("bizType=%s data=%s\n", resp.BizType, resp.Data)
// Output:
}
// ExampleClient_QuerySupplierByName 演示根据名称查询供应商。
func ExampleClient_QuerySupplierByName() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
queries := []QueryByName{
{CorpID: "dingXXXXXX", Name: "某某供应商"},
}
dataBytes, _ := json.Marshal(queries)
req := &QuerySupplierByNameRequest{
InvokeID: "REQ-002",
UserID: "04221***",
Data: string(dataBytes),
BizType: BizTypeQuerySupplierByName,
}
resp, err := client.QuerySupplierByName(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("success=%v result=%s\n", resp.Success, resp.Result)
// Output:
}
// ExampleClient_UpdateSupplier 演示更新供应商。
func ExampleClient_UpdateSupplier() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := UpdateSupplierBizData{
SupplierID: "SUP_XXXXX",
Name: "某某供应商",
CorpID: "dingXXXXXX",
UserID: "04221***",
ContactName: "李四",
ContactTelephone: "18888888888",
AccountType: AccountTypeCorpBankCard,
}
dataBytes, _ := json.Marshal(bizData)
req := &UpdateSupplierRequest{
InvokeID: "REQ-003",
UserID: "04221***",
Data: string(dataBytes),
BizType: BizTypeUpdateSupplier,
}
resp, err := client.UpdateSupplier(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("bizType=%s\n", resp.BizType)
// Output:
}
// ExampleClient_QuerySupplierByUserDefineCode 演示根据用户自定义编码查询供应商。
func ExampleClient_QuerySupplierByUserDefineCode() {
ctx := context.Background()
client := NewClient(
"https://api.example.com",
"your-tenant-id",
"dd-ai-table",
"your-client-secret",
)
bizData := QueryByUserDefineCode{
CorpID: "dingXXXXXX",
UserDefineCode: "SUP-CODE-001",
}
dataBytes, _ := json.Marshal(bizData)
req := &QuerySupplierByUserDefineCodeRequest{
InvokeID: "REQ-004",
UserID: "04221***",
Data: string(dataBytes),
BizType: BizTypeQuerySupplierByUserDefine,
}
resp, err := client.QuerySupplierByUserDefineCode(ctx, req)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("bizType=%s data=%s\n", resp.BizType, resp.Data)
// Output:
}
// TestVerifyNotificationSignature 演示通知验签。
func TestVerifyNotificationSignature(t *testing.T) {
verifyKey := "customer-verify-secret"
rawBody := []byte(`{"bizType":"payment","bizId":"PAY-001","data":"{}"}`)
sign := HmacSHA256Base64(verifyKey, string(rawBody))
ok, err := VerifyNotificationSignature(verifyKey, rawBody, sign)
if err != nil {
t.Fatalf("verify error: %v", err)
}
if !ok {
t.Fatal("signature mismatch")
}
}
// TestParsePaymentNotify 演示解析支付完成通知。
func TestParsePaymentNotify(t *testing.T) {
body := []byte(`{
"code":"PAY-001",
"instanceId":"inst-001",
"corpId":"dingXXXXXX",
"paymentStatus":"SUCCESS",
"paymentTime":"2024-01-01 10:00:00",
"userId":"04221***",
"amount":"11300.00"
}`)
n, err := ParsePaymentNotify(body)
if err != nil {
t.Fatalf("parse error: %v", err)
}
if n.PaymentStatus != PaymentStatusSuccess {
t.Fatalf("unexpected status: %s", n.PaymentStatus)
}
}
```
=== SDK 生成完成 ===