intelligence_finance_v1_ga-.../intelligence_finance_v1_ga/generate.md

36 KiB
Raw Permalink Blame History

// File: intelligence_finance_v1_ga/go.mod

module intelligence_finance_v1_ga

go 1.21

// File: intelligence_finance_v1_ga/types.go

package intelligence_finance_v1_ga

import "encoding/json"

// BaseResponse 是平台所有请求接口的通用响应结构。
// code 为业务状态码0 或 200 表示成功msg 为提示信息data 为具体业务数据。
type BaseResponse struct {
	Code int             `json:"code"`
	Msg  string          `json:"msg"`
	Data json.RawMessage `json:"data"`
}

// 发票类型枚举。
const (
	InvoiceTypeSpecial           = 1 // 专用发票
	InvoiceTypeNormal            = 2 // 普通发票
	InvoiceTypeNormalElectronic  = 3 // 普通发票(电子)
	InvoiceTypeSpecialElectronic = 4 // 专用发票(电子)
	InvoiceTypeDigitalSpecial    = 8 // 数电专票
	InvoiceTypeDigitalNormal     = 9 // 数电普票
)

// 开票状态枚举。
const (
	InvoiceStatusNotIssued         = 0 // 未开票
	InvoiceStatusIssuing           = 1 // 开票中
	InvoiceStatusPartialFailed     = 2 // 部分失败
	InvoiceStatusSuccess           = 3 // 开票成功
	InvoiceStatusFailed            = 4 // 开票失败
	InvoiceStatusPartialNotIssued  = 5 // 部分未开
	InvoiceStatusNoDigitalAccount  = 6 // 未配置数电账号
	InvoiceStatusNoAutoConfig      = 7 // 未配置自动开票配置
)

// 支付状态枚举。
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" // 对私银行卡
)

// 通知响应常量。
const (
	NotifySuccess = "SUCCESS" // 通知处理成功
	NotifyFailed  = "FAILED"  // 通知处理失败
)

// InvoiceOrderRequest 是订单开票请求参数。
type InvoiceOrderRequest struct {
	CompanyCode      string           `json:"companyCode"`      // 开票的企业主体编码,不传则默认主体开票
	OrderID          string           `json:"orderId"`          // 订单唯一标识(需保证在贵方系统内唯一)
	InvoiceType      int              `json:"invoiceType"`      // 发票类型枚举
	Products         []InvoiceProduct `json:"products"`         // 货物/服务明细列表,至少一项
	Remark           string           `json:"remark"`           // 订单备注(非发票备注)
	Purchaser        string           `json:"purchaser"`        // 购方企业名称
	TaxNum           string           `json:"taxnum"`           // 购方纳税人识别号
	PurchaserAddress string           `json:"purchaserAddress"` // 购方地址
	PurchaserTel     string           `json:"purchaserTel"`     // 购方电话
	BankName         string           `json:"bankName"`         // 购方开户行名称
	BankAccount      string           `json:"bankAccount"`      // 购方银行账号
	Phone            string           `json:"phone"`            // 收票人手机号(用于接收电票短信)
	Email            string           `json:"email"`            // 收票人邮箱(用于接收电票邮件)
	ApplyPerson      string           `json:"applyPerson"`      // 开票申请人名称
	Payee            string           `json:"payee"`            // 收款人(发票票面)
	Reviewer         string           `json:"reviewer"`         // 复核人(发票票面)
	InvoiceRemark    string           `json:"invoiceRemark"`    // 发票备注栏内容
	NaturalPerson    string           `json:"naturalPerson"`    // 购买方自然人标识Y-是N-否默认N
	AdditionInfo     string           `json:"additionInfo"`     // 附加信息JSON数组字符串
}

// InvoiceProduct 是订单开票的货物/服务明细项。
type InvoiceProduct struct {
	ProductName      string  `json:"productName"`      // 货物或服务名称
	RevenueCode      string  `json:"revenueCode"`      // 19位税收分类编码
	AmountIncludeTax float64 `json:"amountIncludeTax"` // 单条明细含税总金额(单位:元)
	Specs            string  `json:"specs"`            // 规格型号
	Unit             string  `json:"unit"`             // 计量单位(如:台、个、次)
	Quantity         float64 `json:"quantity"`         // 数量
	Discount         float64 `json:"discount"`         // 折扣金额无折扣传0
	TaxSign          int     `json:"taxSign"`          // 是否含税0-不含税1-含税默认建议传1
	TaxRate          float64 `json:"taxRate"`          // 税率小数形式如0.13表示13%
}

// InvoiceOrderData 是订单开票接口的响应数据。
type InvoiceOrderData struct {
	Status   int           `json:"status"`   // 开票状态
	ErrorMsg string        `json:"errorMsg"` // 错误信息(开票失败时返回原因)
	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"`            // 开票类型0-正数票1-负数票(红冲)
	ListFlag             string          `json:"listFlag"`             // 清单标识0-无清单1-有清单
	Mobile               string          `json:"mobile"`               // 手机号(购方手机)
	OriginalInvCode      string          `json:"originalInvCode"`      // 红冲时对应的原蓝票代码
	OriginalInvNo        string          `json:"originalInvNo"`        // 红冲时对应的原蓝票号码
	AdditionInfo         string          `json:"additionInfo"`         // 数电发票备注栏的附加信息部分
	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"`        // 购买方自然人标识Y-是N-否
	Remark               string          `json:"remark"`               // 备注
	Reviewer             string          `json:"reviewer"`             // 复核人
	SellerAddress        string          `json:"sellerAddress"`        // 销方地址
	SellerBankAccount    string          `json:"sellerBankAccount"`    // 销方开户账号
	SellerBankName       string          `json:"sellerBankName"`       // 销方开户行
	SellerName           string          `json:"sellerName"`           // 销方名称
	CheckCode            string          `json:"checkCode"`            // 校验码
	CipherText           string          `json:"cipherText"`           // 密码区
	DrewDate             string          `json:"drewDate"`             // 开票日期格式yyyy-MM-dd HH:mm:ss
	InvoiceCode          string          `json:"invoiceCode"`          // 发票代码
	InvoiceNo            string          `json:"invoiceNo"`            // 发票号码
	InvoiceStatus        string          `json:"invoiceStatus"`        // 发票状态1-正常2-已红冲3-已作废
	LayoutFileURL        string          `json:"layoutFileUrl"`        // 电子发票地址PDF/OFD
	PDFURL               string          `json:"pdfUrl"`               // 电子发票PDF地址
	OFDURL               string          `json:"ofdUrl"`               // 电子发票OFD地址
	XMLURL               string          `json:"xmlUrl"`               // 电子发票XML数据地址
	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"`             // 金额
	Quantity           string `json:"quantity"`           // 数量
	DeductionAmount    string `json:"deductionAmount"`    // 扣除金额
	TaxAmount          string `json:"taxAmount"`          // 税额
	ItemTitle          string `json:"itemTitle"`          // 商品合并显示名称
	TaxCode            string `json:"taxCode"`            // 税收分类编码19位
	ItemType           string `json:"itemType"`           // 商品行性质0-正常行1-折扣行2-被折扣行
	ItemName           string `json:"itemName"`           // 商品简称
	Specs              string `json:"specs"`              // 商品规格型号
	TaxFreePolicy      string `json:"taxFreePolicy"`      // 免税政策1-免税2-不征税3-普通零税率
	PreferentialPolicy string `json:"preferentialPolicy"` // 优惠政策类型
	TaxRate            string `json:"taxRate"`            // 税率小数形式如0.13
	TaxSign            string `json:"taxSign"`            // 是否含税0-否1-是
	Unit               string `json:"unit"`               // 计量单位(如:台、个、次)
	UnitPrice          string `json:"unitPrice"`          // 单价
}

// QueryInvoiceStatusRequest 是开票状态查询请求参数。
type QueryInvoiceStatusRequest struct {
	OrderID string `json:"orderId"` // 订单唯一标识
}

// QueryInvoiceStatusData 是开票状态查询接口的响应数据。
type QueryInvoiceStatusData struct {
	Status  int           `json:"status"`  // 开票状态
	Message string        `json:"message"` // 状态描述(如"开票成功"
	Data    []InvoiceData `json:"data"`    // 发票详细列表,结构与回调中的 data 字段一致
}

// CreatePaymentRequest 是创建付款单据请求参数。
type CreatePaymentRequest struct {
	Code                     string             `json:"code"`                     // 单据编码
	YidaAppType              string             `json:"yidaAppType"`              // 宜搭应用类型
	EmpAccountUserID         string             `json:"empAccountUserId"`         // 员工账号用户ID
	Department               *Department        `json:"department"`               // 部门信息
	Usage                    string             `json:"usage"`                    // 用途
	PaymentUserID            string             `json:"paymentUserId"`            // 付款用户ID
	Customer                 *Customer          `json:"customer"`                 // 客户信息
	PrincipalID              string             `json:"principalId"`              // 负责人ID
	Remark                   string             `json:"remark"`                   // 备注
	Supplier                 *Supplier          `json:"supplier"`                 // 供应商信息
	Title                    string             `json:"title"`                    // 标题
	Project                  *Project           `json:"project"`                  // 项目信息
	PaymentUserIDListStr     string             `json:"paymentUserIdListStr"`     // 付款用户ID列表字符串
	NeedPayment              bool               `json:"needPayment"`              // 是否需要付款
	PaymentDetailListJsonStr string             `json:"paymentDetailListJsonStr"` // 付款明细列表JSON字符串
	PaymentDetailList        []PaymentDetail    `json:"paymentDetailList"`        // 付款明细列表
	Company                  *Company           `json:"company"`                  // 企业主体信息
	Amount                   string             `json:"amount"`                   // 金额
	RecipientAccountInfo     *RecipientAccount  `json:"recipientAccountInfo"`     // 收款账户信息
	EnterpriseAccount        *EnterpriseAccount `json:"enterpriseAccount"`        // 企业账号信息
	Category                 []Category         `json:"category"`                 // 收支类别信息
	UserID                   string             `json:"userId"`                   // 用户ID
	OccurDate                int64              `json:"occurDate"`                // 发生日期(时间戳)
	Product                  *Product           `json:"product"`                  // 商品信息
	YidaFormUUID             string             `json:"yidaFormUuid"`             // 宜搭表单UUID
	CanEditPaymentInfo       bool               `json:"canEditPaymentInfo"`       // 是否可编辑付款信息
	PaymentUserIDList        []string           `json:"paymentUserIdList"`        // 付款用户ID列表
	YidaProcInsID            string             `json:"yidaProcInsId"`            // 宜搭流程实例ID
	SyncPaymentOrder         bool               `json:"syncPaymentOrder"`         // 是否同步付款单据
}

// Department 是部门信息。
type Department struct {
	Code string `json:"code"` // 部门编码
	Name string `json:"name"` // 部门名称
}

// Customer 是客户信息。
type Customer struct {
	Code string `json:"code"` // 客户编码
	Name string `json:"name"` // 客户名称
}

// Supplier 是供应商信息。
type Supplier struct {
	Code string `json:"code"` // 供应商编码
	Name string `json:"name"` // 供应商名称
}

// Project 是项目信息。
type Project struct {
	Code string `json:"code"` // 项目编码
	Name string `json:"name"` // 项目名称
}

// Category 是收支类别信息。
type Category struct {
	Code string `json:"code"` // 类别编码
	Name string `json:"name"` // 类别名称
}

// Product 是商品信息。
type Product struct {
	Code string `json:"code"` // 商品编码
	Name string `json:"name"` // 商品名称
}

// Company 是企业主体信息。
type Company struct {
	Code string `json:"code"` // 企业编码
	Name string `json:"name"` // 企业名称
}

// EnterpriseAccount 是企业账号信息。
type EnterpriseAccount struct {
	EnterpriseAccountCode string `json:"enterpriseAccountCode"` // 企业账号编码
	AccountCategory       string `json:"accountCategory"`       // 账户类别
	AccountType           string `json:"accountType"`           // 账户类型
	CardNo                string `json:"cardNo"`                // 卡号
	AccountName           string `json:"accountName"`           // 账户名称
	OfficialNumber        string `json:"officialNumber"`        // 对公账号
	OfficialName          string `json:"officialName"`          // 对公账户名称
	Name                  string `json:"name"`                  // 名称
	Code                  string `json:"code"`                  // 编码
	City                  string `json:"city"`                  // 城市
	Province              string `json:"province"`              // 省份
}

// RecipientAccount 是收款账户信息。
type RecipientAccount struct {
	AccountCategory string `json:"accountCategory"` // 账户类别
	AccountType     string `json:"accountType"`     // 账户类型
	CardNo          string `json:"cardNo"`          // 卡号
	AccountName     string `json:"accountName"`     // 账户名称
}

// PaymentDetail 是付款明细。
type PaymentDetail struct {
	Amount       string       `json:"amount"`       // 金额
	InvoiceInfo  *InvoiceInfo `json:"invoiceInfo"`  // 发票信息
	ProductCode  string       `json:"productCode"`  // 商品编码
	ProjectCode  string       `json:"projectCode"`  // 项目编码
	Remark       string       `json:"remark"`       // 备注
	PrincipalID  string       `json:"principalId"`  // 负责人ID
	Tax          string       `json:"tax"`          // 税额
}

// InvoiceInfo 是付款明细中的发票信息。
type InvoiceInfo struct {
	InvoiceNo   string `json:"invoiceNo"`   // 发票号码
	InvoiceCode string `json:"invoiceCode"` // 发票代码
}

// CreatePaymentData 是创建付款单据接口的响应数据。
type CreatePaymentData struct {
	Code string `json:"code"` // 单据唯一编码
}

// QueryPaymentStatusRequest 是支付状态查询请求参数。
type QueryPaymentStatusRequest struct {
	Code   string `json:"code"`   // 单据编码
	UserID string `json:"userId"` // 用户ID
}

// PaymentInfo 是支付信息,用于支付完成通知和支付状态查询。
type PaymentInfo struct {
	Code                 string             `json:"code"`                 // 单据编码
	InstanceID           string             `json:"instanceId"`           // 实例ID
	CorpID               string             `json:"corpId"`               // 企业ID
	PaymentStatus        string             `json:"paymentStatus"`        // 支付状态
	PaymentTime          string             `json:"paymentTime"`          // 支付时间
	UserID               string             `json:"userId"`               // 用户ID
	FailReason           string             `json:"failReason"`           // 失败原因
	PayerAccountInfo     *PayerAccountInfo  `json:"payerAccountInfo"`     // 付款账户信息
	PayeeAccountInfo     *PayeeAccountInfo  `json:"payeeAccountInfo"`     // 收款账户信息
	RelatedRowNumberList []string           `json:"relatedRowNumberList"` // 关联行号列表
	Source               string             `json:"source"`               // 来源
	Template             string             `json:"template"`             // 模板
	Amount               string             `json:"amount"`               // 金额
}

// PayerAccountInfo 是付款账户信息。
type PayerAccountInfo struct {
	BankOpenDTO           *BankOpenDTO `json:"bankOpenDTO"`           // 银行信息
	EnterpriseAccountCode string       `json:"enterpriseAccountCode"` // 企业账号编码
	AccountType           string       `json:"accountType"`           // 账户类型
}

// PayeeAccountInfo 是收款账户信息。
type PayeeAccountInfo struct {
	BankOpenDTO *BankOpenDTO `json:"bankOpenDTO"` // 银行信息
}

// BankOpenDTO 是银行信息。
type BankOpenDTO struct {
	BankCode       string `json:"bankCode"`       // 银行编码
	BankName       string `json:"bankName"`       // 银行名称
	BankBranchCode string `json:"bankBranchCode"` // 银行支行编码
	BankBranchName string `json:"bankBranchName"` // 银行支行名称
	AccountName    string `json:"accountName"`    // 账户名称
	BankCardNo     string `json:"bankCardNo"`     // 银行卡号
	Type           string `json:"type"`           // 账户类型
}

// NotifyRequest 是通用通知机制的通知数据。
type NotifyRequest struct {
	BizType string `json:"bizType"` // 业务类型
	BizID   string `json:"bizId"`   // 业务ID
	Data    string `json:"data"`    // 业务数据
}

// File: intelligence_finance_v1_ga/crypto.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 进行签名,并返回 Base64 编码结果。
// 密钥为 client-secret签名数据为 timestamp + nonce。
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 方式1字典序排序拼接。
// 空值会被排除,且自动排除 sign / signature 字段本身。
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/errors.go

package intelligence_finance_v1_ga

import "fmt"

// SDKError 表示 SDK 内部错误(网络、编解码等)。
type SDKError struct {
	Op  string // 发生错误的操作名称
	Err error  // 底层错误
}

// Error 实现 error 接口。
func (e *SDKError) Error() string {
	if e.Op != "" {
		return fmt.Sprintf("intelligence_finance_v1_ga: %s: %v", e.Op, e.Err)
	}
	return fmt.Sprintf("intelligence_finance_v1_ga: %v", e.Err)
}

// Unwrap 返回底层错误,支持 errors.Is / errors.As。
func (e *SDKError) Unwrap() error {
	return e.Err
}

// APIError 表示平台返回的业务错误或非 200 的 HTTP 响应。
type APIError struct {
	HTTPStatus int    // HTTP 状态码(非 200 时设置)
	Code       int    // 平台业务错误码
	Msg        string // 平台错误信息
	Body       string // 原始响应体HTTP 非 200 时设置)
}

// Error 实现 error 接口。
func (e *APIError) Error() string {
	if e.HTTPStatus != 0 {
		return fmt.Sprintf("intelligence_finance_v1_ga: http status %d: %s", e.HTTPStatus, e.Body)
	}
	return fmt.Sprintf("intelligence_finance_v1_ga: api error code=%d msg=%s", e.Code, e.Msg)
}

// File: intelligence_finance_v1_ga/client.go

package intelligence_finance_v1_ga

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

// 默认接口路径(实际路径以接口对接时分配的短码为准,可通过 Option 覆盖)。
const (
	DefaultInvoiceOrderPath       = "/invoice/order"
	DefaultQueryInvoiceStatusPath = "/invoice/status/query"
	DefaultCreatePaymentPath      = "/payment/create"
	DefaultQueryPaymentStatusPath = "/payment/status/query"
)

// Client 是业财连接接口的客户端。
type Client struct {
	baseURL      string
	tenantID     string
	clientID     string
	clientSecret string
	httpClient   *http.Client
	signEnabled  bool

	invoiceOrderPath       string
	queryInvoiceStatusPath string
	createPaymentPath      string
	queryPaymentStatusPath string
}

// Option 定义客户端配置选项。
type Option func(*Client)

// WithHTTPClient 设置自定义 HTTP 客户端。
func WithHTTPClient(c *http.Client) Option {
	return func(cli *Client) {
		cli.httpClient = c
	}
}

// WithTimeout 设置请求超时时间。
func WithTimeout(d time.Duration) Option {
	return func(cli *Client) {
		cli.httpClient.Timeout = d
	}
}

// WithSignEnabled 设置是否启用签名。
// 客户应用需启用签名默认启用钉钉AI表格无需配置签名可设置为 false。
func WithSignEnabled(enabled bool) Option {
	return func(cli *Client) {
		cli.signEnabled = enabled
	}
}

// WithInvoiceOrderPath 覆盖订单开票接口路径。
func WithInvoiceOrderPath(p string) Option {
	return func(cli *Client) { cli.invoiceOrderPath = p }
}

// WithQueryInvoiceStatusPath 覆盖开票状态查询接口路径。
func WithQueryInvoiceStatusPath(p string) Option {
	return func(cli *Client) { cli.queryInvoiceStatusPath = p }
}

// WithCreatePaymentPath 覆盖创建付款单据接口路径。
func WithCreatePaymentPath(p string) Option {
	return func(cli *Client) { cli.createPaymentPath = p }
}

// WithQueryPaymentStatusPath 覆盖支付状态查询接口路径。
func WithQueryPaymentStatusPath(p string) Option {
	return func(cli *Client) { cli.queryPaymentStatusPath = p }
}

// 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,
		httpClient:             &http.Client{Timeout: 30 * time.Second},
		signEnabled:            true,
		invoiceOrderPath:       DefaultInvoiceOrderPath,
		queryInvoiceStatusPath: DefaultQueryInvoiceStatusPath,
		createPaymentPath:      DefaultCreatePaymentPath,
		queryPaymentStatusPath: DefaultQueryPaymentStatusPath,
	}
	for _, opt := range opts {
		opt(c)
	}
	return c
}

// doRequest 发送 POST 请求并处理通用响应结构,返回 data 字段的原始字节。
func (c *Client) doRequest(ctx context.Context, path string, reqBody interface{}) (json.RawMessage, error) {
	bodyBytes, err := json.Marshal(reqBody)
	if err != nil {
		return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("marshal request: %w", err)}
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+path, bytes.NewReader(bodyBytes))
	if err != nil {
		return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("new request: %w", err)}
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("tenant-id", c.tenantID)
	req.Header.Set("client-id", c.clientID)

	if c.signEnabled {
		timestamp := GenerateTimestamp()
		nonce, err := GenerateNonce(16)
		if err != nil {
			return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("generate nonce: %w", err)}
		}
		// 签名算法HmacSHA256密钥为 client-secret签名数据为 timestamp + nonce结果 Base64 编码。
		signature := HmacSHA256Base64(c.clientSecret, timestamp+nonce)
		req.Header.Set("x-bfl-signature-timestamp", timestamp)
		req.Header.Set("x-bfl-signature-nonce", nonce)
		req.Header.Set("x-bfl-signature", signature)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("do request: %w", err)}
	}
	defer resp.Body.Close()

	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("read response: %w", err)}
	}

	if resp.StatusCode != http.StatusOK {
		return nil, &APIError{HTTPStatus: resp.StatusCode, Body: string(respBytes)}
	}

	var base BaseResponse
	if err := json.Unmarshal(respBytes, &base); err != nil {
		return nil, &SDKError{Op: "doRequest", Err: fmt.Errorf("unmarshal base response: %w", err)}
	}
	if base.Code != 0 && base.Code != 200 {
		return nil, &APIError{Code: base.Code, Msg: base.Msg}
	}
	return base.Data, nil
}

// InvoiceOrder 提交订单开票请求。
func (c *Client) InvoiceOrder(ctx context.Context, req *InvoiceOrderRequest) (*InvoiceOrderData, error) {
	data, err := c.doRequest(ctx, c.invoiceOrderPath, req)
	if err != nil {
		return nil, err
	}
	var out InvoiceOrderData
	if len(data) > 0 {
		if err := json.Unmarshal(data, &out); err != nil {
			return nil, &SDKError{Op: "InvoiceOrder", Err: fmt.Errorf("unmarshal data: %w", err)}
		}
	}
	return &out, nil
}

// QueryInvoiceStatus 查询订单开票状态。
func (c *Client) QueryInvoiceStatus(ctx context.Context, req *QueryInvoiceStatusRequest) (*QueryInvoiceStatusData, error) {
	data, err := c.doRequest(ctx, c.queryInvoiceStatusPath, req)
	if err != nil {
		return nil, err
	}
	var out QueryInvoiceStatusData
	if len(data) > 0 {
		if err := json.Unmarshal(data, &out); err != nil {
			return nil, &SDKError{Op: "QueryInvoiceStatus", Err: fmt.Errorf("unmarshal data: %w", err)}
		}
	}
	return &out, nil
}

// CreatePayment 创建付款单据。
func (c *Client) CreatePayment(ctx context.Context, req *CreatePaymentRequest) (*CreatePaymentData, error) {
	data, err := c.doRequest(ctx, c.createPaymentPath, req)
	if err != nil {
		return nil, err
	}
	var out CreatePaymentData
	if len(data) > 0 {
		if err := json.Unmarshal(data, &out); err != nil {
			return nil, &SDKError{Op: "CreatePayment", Err: fmt.Errorf("unmarshal data: %w", err)}
		}
	}
	return &out, nil
}

// QueryPaymentStatus 查询支付状态。
// 响应数据与支付完成通知的数据结构一致。
func (c *Client) QueryPaymentStatus(ctx context.Context, req *QueryPaymentStatusRequest) (*PaymentInfo, error) {
	data, err := c.doRequest(ctx, c.queryPaymentStatusPath, req)
	if err != nil {
		return nil, err
	}
	var out PaymentInfo
	if len(data) > 0 {
		if err := json.Unmarshal(data, &out); err != nil {
			return nil, &SDKError{Op: "QueryPaymentStatus", Err: fmt.Errorf("unmarshal data: %w", err)}
		}
	}
	return &out, nil
}

// ParsePaymentNotify 解析支付完成通知请求体。
// 该接口由客户提供、平台调用,用于在支付完成后接收平台回调。
func ParsePaymentNotify(body []byte) (*PaymentInfo, error) {
	var info PaymentInfo
	if err := json.Unmarshal(body, &info); err != nil {
		return nil, &SDKError{Op: "ParsePaymentNotify", Err: fmt.Errorf("unmarshal notify: %w", err)}
	}
	return &info, nil
}

// ParseNotify 解析通用通知请求体bizType / bizId / datafunc ParseNotify(body []byte) (*NotifyRequest, error) {
	var req NotifyRequest
	if err := json.Unmarshal(body, &req); err != nil {
		return nil, &SDKError{Op: "ParseNotify", Err: fmt.Errorf("unmarshal notify: %w", err)}
	}
	return &req, nil
}

// File: intelligence_finance_v1_ga/example_test.go

package intelligence_finance_v1_ga

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
)

// TestInvoiceOrder 演示订单开票接口的调用。
func TestInvoiceOrder(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			t.Errorf("expected POST, got %s", r.Method)
		}
		if got := r.Header.Get("tenant-id"); got != "tenant-001" {
			t.Errorf("tenant-id = %q", got)
		}
		if got := r.Header.Get("client-id"); got != "dd-ai-table" {
			t.Errorf("client-id = %q", got)
		}
		if got := r.Header.Get("x-bfl-signature"); got == "" {
			t.Error("missing x-bfl-signature header")
		}
		if got := r.Header.Get("x-bfl-signature-timestamp"); got == "" {
			t.Error("missing x-bfl-signature-timestamp header")
		}
		if got := r.Header.Get("x-bfl-signature-nonce"); got == "" {
			t.Error("missing x-bfl-signature-nonce header")
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"code":0,"msg":"ok","data":{"status":1,"errorMsg":"","dataList":[]}}`))
	}))
	defer server.Close()

	client := NewClient(server.URL, "tenant-001", "dd-ai-table", "test-secret")

	resp, err := client.InvoiceOrder(context.Background(), &InvoiceOrderRequest{
		OrderID:     "ORDER-001",
		InvoiceType: InvoiceTypeDigitalNormal,
		Purchaser:   "测试购方企业",
		TaxNum:      "91310000MA1FL00000",
		Email:       "buyer@example.com",
		Products: []InvoiceProduct{
			{
				ProductName:      "测试服务",
				RevenueCode:      "3040101000000000000",
				AmountIncludeTax: 113,
				Quantity:         1,
				TaxSign:          1,
				TaxRate:          0.13,
			},
		},
	})
	if err != nil {
		t.Fatalf("InvoiceOrder: %v", err)
	}
	if resp.Status != InvoiceStatusIssuing {
		t.Errorf("status = %d, want %d", resp.Status, InvoiceStatusIssuing)
	}
}

// TestQueryInvoiceStatus 演示开票状态查询接口的调用。
func TestQueryInvoiceStatus(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"code":0,"msg":"ok","data":{"status":3,"message":"开票成功","data":[]}}`))
	}))
	defer server.Close()

	client := NewClient(server.URL, "tenant-001", "dd-ai-table", "test-secret")

	resp, err := client.QueryInvoiceStatus(context.Background(), &QueryInvoiceStatusRequest{
		OrderID: "ORDER-001",
	})
	if err != nil {
		t.Fatalf("QueryInvoiceStatus: %v", err)
	}
	if resp.Status != InvoiceStatusSuccess {
		t.Errorf("status = %d, want %d", resp.Status, InvoiceStatusSuccess)
	}
	if resp.Message != "开票成功" {
		t.Errorf("message = %q", resp.Message)
	}
}

// TestCreatePayment 演示创建付款单据接口的调用。
func TestCreatePayment(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"code":0,"msg":"ok","data":{"code":"PAY-001"}}`))
	}))
	defer server.Close()

	client := NewClient(server.URL, "tenant-001", "dd-ai-table", "test-secret")

	resp, err := client.CreatePayment(context.Background(), &CreatePaymentRequest{
		Code:   "PAY-001",
		UserID: "user-001",
		Title:  "测试付款单",
		Amount: "1000.00",
		Department: &Department{
			Name: "财务部",
		},
		Supplier: &Supplier{
			Name: "测试供应商",
		},
		PaymentDetailList: []PaymentDetail{
			{
				Amount: "1000.00",
				InvoiceInfo: &InvoiceInfo{
					InvoiceNo:   "12345678",
					InvoiceCode: "011001900111",
				},
			},
		},
	})
	if err != nil {
		t.Fatalf("CreatePayment: %v", err)
	}
	if resp.Code != "PAY-001" {
		t.Errorf("code = %q, want PAY-001", resp.Code)
	}
}

// TestQueryPaymentStatus 演示支付状态查询接口的调用。
func TestQueryPaymentStatus(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"code":0,"msg":"ok","data":{"code":"PAY-001","instanceId":"inst-001","corpId":"corp-001","paymentStatus":"SUCCESS","paymentTime":"2024-01-01 10:00:00","userId":"user-001","source":"openapi","amount":"1000.00"}}`))
	}))
	defer server.Close()

	client := NewClient(server.URL, "tenant-001", "dd-ai-table", "test-secret")

	resp, err := client.QueryPaymentStatus(context.Background(), &QueryPaymentStatusRequest{
		Code:   "PAY-001",
		UserID: "user-001",
	})
	if err != nil {
		t.Fatalf("QueryPaymentStatus: %v", err)
	}
	if resp.PaymentStatus != PaymentStatusSuccess {
		t.Errorf("paymentStatus = %q, want %q", resp.PaymentStatus, PaymentStatusSuccess)
	}
}

// TestParsePaymentNotify 演示解析支付完成通知。
func TestParsePaymentNotify(t *testing.T) {
	body := []byte(`{"code":"PAY-001","instanceId":"inst-001","corpId":"corp-001","paymentStatus":"SUCCESS","paymentTime":"2024-01-01 10:00:00","userId":"user-001","source":"openapi","amount":"1000.00","payerAccountInfo":{"accountType":"BANKCARD","bankOpenDTO":{"bankName":"交通银行","bankCardNo":"6222000000000000"}}}`)

	info, err := ParsePaymentNotify(body)
	if err != nil {
		t.Fatalf("ParsePaymentNotify: %v", err)
	}
	if info.Code != "PAY-001" {
		t.Errorf("code = %q", info.Code)
	}
	if info.PaymentStatus != PaymentStatusSuccess {
		t.Errorf("paymentStatus = %q", info.PaymentStatus)
	}
	if info.PayerAccountInfo == nil || info.PayerAccountInfo.BankOpenDTO == nil {
		t.Error("payerAccountInfo.bankOpenDTO is nil")
	}
}

// TestParseNotify 演示解析通用通知。
func TestParseNotify(t *testing.T) {
	body := []byte(`{"bizType":"invoice","bizId":"ORDER-001","data":"{\"status\":3}"}`)

	req, err := ParseNotify(body)
	if err != nil {
		t.Fatalf("ParseNotify: %v", err)
	}
	if req.BizType != "invoice" {
		t.Errorf("bizType = %q", req.BizType)
	}
	if req.BizID != "ORDER-001" {
		t.Errorf("bizId = %q", req.BizID)
	}
}

// TestHmacSHA256Base64 演示签名算法的正确性。
func TestHmacSHA256Base64(t *testing.T) {
	// 使用固定输入验证签名结果可复现。
	sig := HmacSHA256Base64("secret", "1700000000abc123")
	if sig == "" {
		t.Error("signature is empty")
	}
}

=== SDK 生成完成 ===