Documentation
¶
Overview ¶
Package pay360 封装 360 联运(软件管家)开放平台 OPENAPI 的服务端接口。
它面向需要对接 360 联运支付/退款/订单/代扣/签约/发票的 Go 服务端程序, 统一处理签名生成、access_token 生命周期、Header-Tid 排障头与错误码语义。
快速开始:
c, err := pay360.New("your-appid", 123456, "your-appsecret")
if err != nil {
// 处理构造错误
}
tid, err := c.Refund(ctx, pay360.RefundRequest{
OrderID: "order-1",
OrderAmount: 100, // 单位:分
UserID: "user-1",
RefundReason: "用户申请退款",
})
access_token 由 Client 内部缓存并按需刷新;默认实现为无锁内存缓存, 多实例部署可通过 WithTokenCache 注入共享存储实现,详见 TokenCache。
Client 构造后字段只读,可安全地在多个 goroutine 间共享。
Index ¶
- Constants
- Variables
- type APIError
- type Ack
- type Callback
- type CancelSignRequest
- type Client
- func (c *Client) CancelSign(ctx context.Context, req CancelSignRequest) (headerTid string, err error)
- func (c *Client) DoPost(ctx context.Context, req DoPostRequest) (headerTid string, err error)
- func (c *Client) PlainInvoice(ctx context.Context, req PlainInvoiceRequest) (PlainInvoiceResult, error)
- func (c *Client) PlainInvoiceCancel(ctx context.Context, orderID string) (headerTid string, err error)
- func (c *Client) QueryOrder(ctx context.Context, req OrderQueryRequest) (OrderQuery, error)
- func (c *Client) QuerySpecialInvoice(ctx context.Context, requestType, sourceID string) (SpecialInvoiceQueryResult, error)
- func (c *Client) Refund(ctx context.Context, req RefundRequest) (headerTid string, err error)
- func (c *Client) SpecialInvoice(ctx context.Context, req SpecialInvoiceRequest) (SpecialInvoiceResult, error)
- func (c *Client) SpecialInvoiceCancel(ctx context.Context, req SpecialInvoiceCancelRequest) (headerTid string, err error)
- func (c *Client) VerifyCallback(body []byte) (*Callback, error)
- type CreateOrderParams
- type DoPostRequest
- type Option
- type OrderExtra
- type OrderQuery
- type OrderQueryRequest
- type PlainInvoiceRequest
- type PlainInvoiceResult
- type RefundRequest
- type SpecialInvoiceCancelRequest
- type SpecialInvoiceQueryResult
- type SpecialInvoiceRequest
- type SpecialInvoiceResult
- type TokenCache
Examples ¶
Constants ¶
const ( CallbackOrderStatus = 1 // 订单状态变更(普通下单扣款、退款) CallbackAutopay = 2 // 代扣推送(自动扣款),需厂商据 order_extra 创建订单 CallbackSign = 3 // 签约/取消签约状态通知,无需下发或取消权益 )
回调类型。
const ( AutoPayStatusOpen = 1 // 开通签约 AutoPayStatusCancel = 2 // 取消签约 )
签约状态(OrderExtra.AutoPayStatus / callback_type=3)。
const ( OrderStatusPending = 10 // 待付款(初始状态) OrderStatusPaid = 20 // 付款完成(待通知厂商) OrderStatusNotified = 30 // 待厂商发权益(已通知厂商) OrderStatusAfterSale = 40 // 售后中(厂商发起退款) OrderStatusCompleted = 50 // 交易完成(厂商已发放) OrderStatusCanceled = 60 // 已取消(支付超时、过期等) OrderStatusClosed = 70 // 交易关闭(退款完成) )
订单状态码(order_status,用于订单查询响应与订单推送回调)。
其中 20、30、50 均视为支付成功状态(见 OrderQuery.IsPaid)。
const ( PayChannelTask = -1 // 任务单 PayChannelWechat = 1 // 微信 PayChannelAlipay = 2 // 支付宝 PayChannelAlipayAutopay = 3 // 支付宝代扣单 )
支付渠道(pay_channel / pay_chanel)。
const ( PeriodTypeDay = 0 // 扣款周期按天计 PeriodTypeMonth = 1 // 扣款周期按自然月计 )
代扣周期类型(period_type)。
const ( OrderPayTypeNormal = 0 // 付费单 OrderPayTypeTask = 3 // 任务单 )
订单类型(order_pay_type)。
const ( AutoPayDisabled = 0 // 不开启代扣 AutoPayEnabled = 1 // 开启代扣 )
是否开启代扣(createOrder 的 auto_pay_status)。
注意:与回调 order_extra 中的 auto_pay_status(AutoPayStatusOpen/AutoPayStatusCancel, 表示签约/取消签约)语义不同。
const ( AutopayModeManager = 0 // 管家侧发起代扣续费订单(需固定扣款周期) AutopayModeVendor = 1 // 厂商侧发起代扣续费订单(厂商完全可控,经服务端代扣接口发起) )
代扣发起方(ext.autopay_mode)。
const ( SpecialInvoiceQueryIssue = "1" // 开票查询 SpecialInvoiceQueryCancel = "2" // 红冲查询 )
专票查询请求类型。
const Version = "v0.1.1"
Variables ¶
var ( ErrParam = &APIError{Code: 10001, Msg: "参数错误"} ErrInternal = &APIError{Code: 10002, Msg: "服务内部错误"} ErrSign = &APIError{Code: 10006, Msg: "sign 错误"} ErrRequestExpired = &APIError{Code: 10007, Msg: "请求过期"} ErrAccessToken = &APIError{Code: 10012, Msg: "access_token 错误"} ErrIllegalAccess = &APIError{Code: 10014, Msg: "非法访问"} ErrContentType = &APIError{Code: 10015, Msg: "不支持的 content_type"} ErrParamType = &APIError{Code: 10016, Msg: "参数类型错误"} ErrAppNotFound = &APIError{Code: 100001, Msg: "应用信息不存在"} ErrAppOffline = &APIError{Code: 100002, Msg: "应用信息已下线"} ErrVendorNotFound = &APIError{Code: 100003, Msg: "厂商信息不存在"} ErrVendorOffline = &APIError{Code: 100004, Msg: "厂商信息已下线"} ErrOrderNotFound = &APIError{Code: 100005, Msg: "订单不存在"} ErrAppCategoryNotFound = &APIError{Code: 100006, Msg: "应用分类不存在"} ErrAuthInfo = &APIError{Code: 100008, Msg: "认证信息错误"} ErrOrderStatusInvalid = &APIError{Code: 100009, Msg: "订单状态有误,不允许进行此操作"} )
文档《360联运JSSDK集成说明》第四章错误码表对应的哨兵值。 仅携带 Code,用于 errors.Is 判定。
var ErrCallbackSign = errors.New("pay360: callback sign mismatch")
ErrCallbackSign 表示回调验签失败。
Functions ¶
This section is empty.
Types ¶
type APIError ¶
APIError 表示 360 平台返回的业务错误(errno 非 0,或部分网关接口的 code 非 0)。
可用 errors.Is 与本包导出的错误码哨兵比较,例如:
if errors.Is(err, pay360.ErrAccessToken) { /* token 失效,触发重试 */ }
HeaderTid 为本次响应头 Header-Tid 的值,便于向 360 反馈问题时快速定位。
type Ack ¶
type Ack struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
}
Ack 为厂商对订单推送回调的响应体。
func AckResponse ¶
AckResponse 返回自定义响应体(成功时 code 应为 200)。
Example ¶
out, _ := json.Marshal(AckResponse(500, "retry later", "job-1")) fmt.Println(string(out))
Output: {"code":500,"message":"retry later","data":"job-1"}
func AckSuccess ¶
func AckSuccess() Ack
AckSuccess 返回标准成功响应 {"code":200,"message":"success","data":""}。 360-Server 收到此响应后会将 order_status 由 30 变更为 50。
Example ¶
out, _ := json.Marshal(AckSuccess()) fmt.Println(string(out))
Output: {"code":200,"message":"success","data":""}
type Callback ¶
type Callback struct {
AppID string `json:"app_id"`
BankTradeCode string `json:"bank_trade_code"`
CallbackType int `json:"callback_type"`
MfrOrderAmount int64 `json:"mfr_order_amount"`
MfrOrderID string `json:"mfr_order_id"`
MfrProductID string `json:"mfr_product_id"`
MfrProductName string `json:"mfr_product_name"`
OrderCode string `json:"order_code"`
OrderExtra string `json:"order_extra"`
OrderStatus int `json:"order_status"`
PayChannel int `json:"pay_channel"`
Qid int64 `json:"qid"`
Sign string `json:"sign"`
Timestamp int64 `json:"timestamp"`
TransTime string `json:"trans_time"`
// Extra 为 OrderExtra 字段解析后的结构(callback_type 为 2/3 时有意义)。
Extra OrderExtra `json:"-"`
}
Callback 为厂商订单推送回调的解析结果。
func ParseCallback ¶
ParseCallback 解析厂商订单推送回调的请求体,并解析内嵌的 order_extra。 它不做验签;如需验签请使用 Client.VerifyCallback。
Example ¶
body := `{"callback_type":2,"mfr_order_id":"parent1","order_extra":"{\"mfr_order_id\":\"child1\"}"}`
cb, _ := ParseCallback([]byte(body))
fmt.Println(cb.CallbackType, cb.Extra.MfrOrderID)
Output: 2 child1
type CancelSignRequest ¶
CancelSignRequest 为厂商侧取消签约的参数。
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 是 360 联运 OPENAPI 的服务端客户端。
构造后所有字段只读(token 缓存内部自带并发安全),可在多个 goroutine 间共享。
func New ¶
New 创建客户端。appid 与 appsecret 必填,qid 为厂商 ID。
默认使用官方域名、进程内内存 token 缓存与带连接池的默认 HTTP 客户端。 构造期不发起任何网络请求,也不启动后台 goroutine。
func (*Client) CancelSign ¶
func (c *Client) CancelSign(ctx context.Context, req CancelSignRequest) (headerTid string, err error)
CancelSign 厂商侧取消用户代扣签约。返回本次响应的 Header-Tid。
func (*Client) PlainInvoice ¶
func (c *Client) PlainInvoice(ctx context.Context, req PlainInvoiceRequest) (PlainInvoiceResult, error)
PlainInvoice 开具普通发票。
func (*Client) PlainInvoiceCancel ¶
func (c *Client) PlainInvoiceCancel(ctx context.Context, orderID string) (headerTid string, err error)
PlainInvoiceCancel 普票红冲(红冲对应订单的普通发票)。返回本次响应的 Header-Tid。
此接口响应采用 {code,msg} 信封(code 0 表示成功),与多数接口的 errno 信封不同。
func (*Client) QueryOrder ¶
func (c *Client) QueryOrder(ctx context.Context, req OrderQueryRequest) (OrderQuery, error)
QueryOrder 查询订单详情。
注意:请勿通过客户端轮询此接口;SDK 本身会通过订单推送通知状态变更。
func (*Client) QuerySpecialInvoice ¶
func (c *Client) QuerySpecialInvoice(ctx context.Context, requestType, sourceID string) (SpecialInvoiceQueryResult, error)
QuerySpecialInvoice 查询专票开票或红冲进度。 requestType 取 SpecialInvoiceQueryIssue 或 SpecialInvoiceQueryCancel。
func (*Client) SpecialInvoice ¶
func (c *Client) SpecialInvoice(ctx context.Context, req SpecialInvoiceRequest) (SpecialInvoiceResult, error)
SpecialInvoice 申请开具专用发票,返回 source_id。建议保存返回信息以便后续查询/红冲。
func (*Client) SpecialInvoiceCancel ¶
func (c *Client) SpecialInvoiceCancel(ctx context.Context, req SpecialInvoiceCancelRequest) (headerTid string, err error)
SpecialInvoiceCancel 申请专票红冲。返回本次响应的 Header-Tid。
func (*Client) VerifyCallback ¶
VerifyCallback 验签并解析厂商订单推送回调。
验签规则与出站一致(空值不参与),签名盐为本客户端的 appsecret。 验签失败返回 ErrCallbackSign。务必在发放权益前完成验签与数据一致性校验。
type CreateOrderParams ¶
type CreateOrderParams struct {
OrderID string // 厂商订单号,需保证应用内唯一
OrderAmount int64 // 订单金额,单位:分
CreateTime string // 厂商创建订单的时间戳(10 位,秒级)
UserID string // 用户 ID
ProductID string // 商品 ID
ProductName string // 商品描述
AutoPayStatus int // 是否开启代扣,见 AutoPayDisabled / AutoPayEnabled
OrderPayType int // 订单类型,见 OrderPayTypeNormal / OrderPayTypeTask
PeriodType int // 代扣周期类型,见 PeriodTypeDay / PeriodTypeMonth
Period int // 代扣周期值(与 PeriodType 组合,如 PeriodTypeDay+90 表示 90 天)
ExecuteTime string // 首次扣款时间,格式 yyyy-MM-dd
AutoPayAmount int64 // 代扣金额,单位:分
AutopayMode int // 代扣发起方,见 AutopayModeManager / AutopayModeVendor
TaskID string // 任务 ID,OrderPayType == OrderPayTypeTask 时必填
}
CreateOrderParams 是前端 SDK360.createOrder 所需的订单参数。
360 联运的下单由前端 JSSDK 直连完成,但订单数据应由厂商服务端生成唯一 order_id、 组装并留存后下发给前端。本结构提供类型化构造、条件校验与序列化,不发起任何请求。
代扣字段(AutoPayStatus 起的一组)仅当开启代扣(AutoPayStatus == AutoPayEnabled)时 生效且必填,校验由 CreateOrderParams.Validate 强制。
func (CreateOrderParams) MarshalForSDK ¶
func (p CreateOrderParams) MarshalForSDK() ([]byte, error)
MarshalForSDK 校验并序列化为前端 SDK360.createOrder 所需的 JSON。
非代扣订单只输出基础字段;开启代扣时附带代扣字段及 ext(autopay_mode 的 JSON 字符串)。 数字字段以 JSON number 输出,与 360 前端约定一致。
Example ¶
p := CreateOrderParams{
OrderID: "order-1", OrderAmount: 1, CreateTime: "1700000000",
UserID: "user-1", ProductID: "vip-1", ProductName: "会员月卡",
}
data, _ := p.MarshalForSDK()
fmt.Println(string(data))
Output: {"create_time":"1700000000","order_amount":1,"order_id":"order-1","product_id":"vip-1","product_name":"会员月卡","user_id":"user-1"}
func (CreateOrderParams) Validate ¶
func (p CreateOrderParams) Validate() error
Validate 校验参数。基础字段恒校验;开启代扣时强制校验代扣相关字段。
type DoPostRequest ¶
type DoPostRequest struct {
OrderID string // 签约的订单 ID
AgreementNumber string // 签约的协议号
AutopayAmount int64 // 代扣金额,单位:分
AutopayOrderID string // 本次代扣的订单 ID,须保证唯一
}
DoPostRequest 为厂商侧发起代扣的参数。
本接口仅用于厂商服务端主动发起代扣,代扣发起日期与周期由厂商自行设定。 注意:若上一笔代扣失败需重新发起,必须使用一个全新的 AutopayOrderID, 复用旧值可能出现“代扣失败但显示成功”的异常。
type Option ¶
type Option func(*Client)
Option 配置 Client。
func WithBaseURL ¶
WithBaseURL 覆盖接口域名(默认 https://api.openstore.360.cn)。主要用于测试。
func WithHTTPClient ¶
WithHTTPClient 注入自定义的 httpc 客户端(用于自定义超时、传输等)。 如需请求日志,可在构造该客户端时通过 httpc.WithTransport 注入带日志的 RoundTripper。
func WithTokenCache ¶
func WithTokenCache(tc TokenCache) Option
WithTokenCache 注入自定义的 access_token 缓存实现(如基于 Redis 的多实例共享)。
func WithTokenRefreshAhead ¶
WithTokenRefreshAhead 设置 token 提前刷新的安全边界(默认 5 分钟)。 剩余有效期不足该值时,下一次取 token 会触发刷新。
type OrderExtra ¶
type OrderExtra struct {
MfrOrderID string `json:"mfr_order_id"`
AgreementNumber string `json:"agreement_number"`
AutoPayStatus int `json:"auto_pay_status"`
}
OrderExtra 为回调中 order_extra 字段(JSON 字符串)解析后的内容。
type OrderQuery ¶
type OrderQuery struct {
MfrOrderID string `json:"mfr_order_id"` // 厂商订单编号
MfrOrderAmount int64 `json:"mfr_order_amount"` // 厂商订单金额,单位:分
MfrCreateTime string `json:"mfr_create_time"` // 厂商订单创建时间
MfrProductID string `json:"mfr_product_id"` // 厂商商品 ID
MfrProductName string `json:"mfr_product_name"` // 厂商商品名称
OrderStatus int `json:"order_status"` // 订单状态,见文档状态码
PayChannel int `json:"pay_chanel"` // 支付渠道 1-微信 2-支付宝(沿用文档查询响应字段名 pay_chanel)
OrderCode string `json:"order_code"` // 360 订单编号
BankTradeCode string `json:"bank_trade_code"` // 银行流水号
OrderPayTime string `json:"order_pay_time"` // 付款时间
OrderRefundTime string `json:"order_refund_time"` // 退款时间
HeaderTid string `json:"-"` // 本次响应的 Header-Tid
}
OrderQuery 为订单查询返回的订单详情。
func (OrderQuery) IsPaid ¶
func (o OrderQuery) IsPaid() bool
IsPaid 报告订单是否处于支付成功状态(order_status 为 20、30 或 50)。
type OrderQueryRequest ¶
OrderQueryRequest 为订单查询参数。
type PlainInvoiceRequest ¶
type PlainInvoiceRequest struct {
OrderID string // 厂商调用 SDK 传入的订单 ID
InvoiceTitle string // 发票抬头
UserEmail string // 用户邮箱
TaxRegisterNo string // 纳税人识别号
Address string // 地址
Phone string // 电话
BankName string // 银行名称
BankAccount string // 银行账号
Remarks string // 备注
}
PlainInvoiceRequest 为普票开具参数。OrderID、InvoiceTitle、UserEmail 必填,其余可选。
type PlainInvoiceResult ¶
type PlainInvoiceResult struct {
DownloadURL string `json:"download_url"` // PDF 下载地址
InvoiceCode string `json:"invoice_code"` // 发票代码
InvoiceNo string `json:"invoice_no"` // 发票号码
ReceiptURL string `json:"receipt_url"` // 收票地址,可据此生成二维码
SuccessTime string `json:"success_time"` // 开票日期
VerifyCode string `json:"verify_code"` // 校验码
HeaderTid string `json:"-"`
}
PlainInvoiceResult 为普票开具返回结果。
type RefundRequest ¶
type RefundRequest struct {
OrderID string // 厂商调用 SDK 传入的订单 ID
OrderAmount int64 // 订单金额,单位:分
UserID string // 用户 ID(厂商的用户唯一标识)
RefundReason string // 申请退款说明,长度不超过 200 个字符
}
RefundRequest 为订单退款申请参数。
type SpecialInvoiceCancelRequest ¶
type SpecialInvoiceCancelRequest struct {
Category string // 红冲类别,1 销方红冲
InvoiceNum string // 发票号码
RedReason string // 红冲原因,如 INVOICE_MISTAKE
SourceID string // 蓝票申请单来源 ID
OrderID string // 厂商调用 SDK 传入的订单 ID
}
SpecialInvoiceCancelRequest 为专票红冲参数(销方红冲)。
type SpecialInvoiceQueryResult ¶
type SpecialInvoiceQueryResult struct {
DownloadURL string `json:"download_url"` // PDF 下载地址
InvoiceCode string `json:"invoice_code"` // 发票代码
InvoiceNum string `json:"invoice_num"` // 发票号码
ReceiptURL string `json:"receipt_url"` // 收票地址
Status string `json:"status"` // 状态,如 SUCCESS_END
SuccessTime string `json:"success_time"` // 开票/红冲日期
HeaderTid string `json:"-"`
}
SpecialInvoiceQueryResult 为专票查询返回结果(开票或红冲)。
type SpecialInvoiceRequest ¶
type SpecialInvoiceRequest struct {
OrderID string // 厂商调用 SDK 传入的订单 ID
InvoiceTitle string // 发票抬头(不支持个人抬头)
UserEmail string // 用户邮箱
TaxRegisterNo string // 纳税人识别号
Address string // 地址
Phone string // 电话
BankName string // 银行名称
BankAccount string // 银行账号
CustomType string // 商户类型,1 企业
Remarks string // 备注
}
SpecialInvoiceRequest 为专票开具参数。除 Remarks 外均为必填。 专票申请后需人工审核(一般 5 个工作日内),可通过 Client.QuerySpecialInvoice 查询进度。
type SpecialInvoiceResult ¶
type SpecialInvoiceResult struct {
SourceID string `json:"source_id"` // 蓝票申请单来源 ID,红冲时需要
HeaderTid string `json:"-"`
}
SpecialInvoiceResult 为专票开具返回结果。
type TokenCache ¶
type TokenCache interface {
// Load 返回当前缓存的 token 及其过期时间;ok 为 false 表示无缓存。
Load(ctx context.Context) (token string, expireAt time.Time, ok bool, err error)
// Store 写入新的 token 及其过期时间。
Store(ctx context.Context, token string, expireAt time.Time) error
}
TokenCache 抽象 access_token 的持久化,供多实例部署共享 token。
默认实现为进程内无锁内存缓存,适用于单实例。多实例(多进程)场景下, 由于“新申请 token 会使旧 token 失效”,应注入基于共享存储(如 Redis)的实现, 并在刷新处自行加分布式锁或采用单点刷新,避免实例间互相作废 token。