diff --git a/intelligence_finance_v1/generate.md b/intelligence_finance_v1/generate.md new file mode 100644 index 0000000..6d3f680 --- /dev/null +++ b/intelligence_finance_v1/generate.md @@ -0,0 +1,1307 @@ +// File: intelligence_finance_v1/go.mod +``` +module intelligence_finance_v1 + +go 1.21 +``` + +// File: intelligence_finance_v1/crypto.go +```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 +```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 +```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 +```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 +```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 生成完成 === \ No newline at end of file