Просмотр исходного кода

fix: 按印章列表 sealId 拉图,避免印章名不一致

Co-authored-by: Cursor <cursoragent@cursor.com>
郭铭泽 5 дней назад
Родитель
Сommit
7a5a1882fb
2 измененных файлов с 123 добавлено и 1 удалено
  1. 2 0
      errors.go
  2. 121 1
      seal.go

+ 2 - 0
errors.go

@@ -11,6 +11,8 @@ var (
 	ErrSealCreatePageUnavailable = errors.New("qiyuesuo: seal create page unavailable")
 	ErrSealCreatePageUnavailable = errors.New("qiyuesuo: seal create page unavailable")
 	// ErrSealImageUnavailable 未获取到印章图片。
 	// ErrSealImageUnavailable 未获取到印章图片。
 	ErrSealImageUnavailable = errors.New("qiyuesuo: seal image unavailable")
 	ErrSealImageUnavailable = errors.New("qiyuesuo: seal image unavailable")
+	// ErrSealNotFound 法人单位下未找到可用电子公章。
+	ErrSealNotFound = errors.New("qiyuesuo: seal not found")
 )
 )
 
 
 type apiResponse struct {
 type apiResponse struct {

+ 121 - 1
seal.go

@@ -2,6 +2,7 @@ package qiyuesuosdk
 
 
 import (
 import (
 	"encoding/base64"
 	"encoding/base64"
+	"errors"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
@@ -63,6 +64,122 @@ func (c *Client) CompanySealImageBase64(company CompanyLocateParams, sealName st
 	return base64.StdEncoding.EncodeToString(data), contentType, nil
 	return base64.StdEncoding.EncodeToString(data), contentType, nil
 }
 }
 
 
+// CompanySealSummary 法人单位电子印章摘要(来自 /seal/customparam/cert/list)。
+type CompanySealSummary struct {
+	ID            string
+	Name          string
+	Type          string
+	SealAttribute string
+	StatusKey     string
+}
+
+type sealCertListItem struct {
+	ID            string `json:"id"`
+	Name          string `json:"name"`
+	Type          string `json:"type"`
+	SealAttribute string `json:"sealAttribute"`
+	Status        *struct {
+		Key string `json:"key"`
+	} `json:"status"`
+}
+
+type sealCertListResp struct {
+	apiResponse
+	List []sealCertListItem `json:"list"`
+}
+
+// ListCompanyElectronicSeals 查询法人单位下状态正常的电子印章列表。
+func (c *Client) ListCompanyElectronicSeals(company CompanyLocateParams) ([]CompanySealSummary, error) {
+	companyReq, err := company.toCompanyRequest()
+	if err != nil {
+		return nil, err
+	}
+	var resp sealCertListResp
+	if err := c.postJSON("/seal/customparam/cert/list", map[string]any{
+		"companyRequest":  companyReq,
+		"sealAttribute":   "ELECTRONIC",
+		"sealQueryStatus": "NORMAL",
+	}, &resp); err != nil {
+		return nil, err
+	}
+	if err := resp.err(); err != nil {
+		return nil, err
+	}
+	out := make([]CompanySealSummary, 0, len(resp.List))
+	for _, item := range resp.List {
+		statusKey := ""
+		if item.Status != nil {
+			statusKey = item.Status.Key
+		}
+		if statusKey != "" && statusKey != "NORMAL" {
+			continue
+		}
+		out = append(out, CompanySealSummary{
+			ID:            item.ID,
+			Name:          item.Name,
+			Type:          item.Type,
+			SealAttribute: item.SealAttribute,
+			StatusKey:     statusKey,
+		})
+	}
+	return out, nil
+}
+
+func pickCompanySeal(seals []CompanySealSummary, preferredName string) (*CompanySealSummary, error) {
+	if len(seals) == 0 {
+		return nil, ErrSealNotFound
+	}
+	preferredName = strings.TrimSpace(preferredName)
+	if preferredName != "" {
+		for i := range seals {
+			if seals[i].Name == preferredName {
+				return &seals[i], nil
+			}
+		}
+	}
+	for i := range seals {
+		if seals[i].Type == "COMPANY" {
+			return &seals[i], nil
+		}
+	}
+	return &seals[0], nil
+}
+
+// SealImageByID 按印章 id 下载电子章图片。
+func (c *Client) SealImageByID(sealID string) ([]byte, string, error) {
+	sealID = strings.TrimSpace(sealID)
+	if sealID == "" {
+		return nil, "", ErrInvalidParams
+	}
+	return c.postForImageBytes("/seal/customparam/image", map[string]any{
+		"sealId":        sealID,
+		"sealAttribute": "ELECTRONIC",
+		"sealImageFormatRequest": map[string]any{
+			"imageFormat": "png",
+		},
+	})
+}
+
+// ResolveCompanySealImageBase64 先列出法人单位电子章,再按 sealId 拉图(避免印章名不一致)。
+func (c *Client) ResolveCompanySealImageBase64(company CompanyLocateParams, preferredSealName string) (string, string, string, error) {
+	seals, err := c.ListCompanyElectronicSeals(company)
+	if err != nil {
+		return "", "", "", err
+	}
+	seal, err := pickCompanySeal(seals, preferredSealName)
+	if err != nil {
+		return "", "", "", err
+	}
+	data, contentType, err := c.SealImageByID(seal.ID)
+	if err != nil {
+		return "", "", "", err
+	}
+	if len(data) == 0 {
+		return "", "", "", ErrSealImageUnavailable
+	}
+	return seal.Name, base64.StdEncoding.EncodeToString(data), contentType, nil
+}
+
 // CompanySignQualifications 法人单位签章资质(是否已有可用电子章等)。
 // CompanySignQualifications 法人单位签章资质(是否已有可用电子章等)。
 type CompanySignQualifications struct {
 type CompanySignQualifications struct {
 	ElectronicSeal bool `json:"electronicSeal"`
 	ElectronicSeal bool `json:"electronicSeal"`
@@ -155,11 +272,14 @@ func (c *Client) CompanySealCreatePageURL(company CompanyLocateParams, companyDi
 	return url, nil
 	return url, nil
 }
 }
 
 
-// IsSealNotFoundError 静默授权时「查询的印章不存在」。
+// IsSealNotFoundError 静默授权或查章时「查询的印章不存在」。
 func IsSealNotFoundError(err error) bool {
 func IsSealNotFoundError(err error) bool {
 	if err == nil {
 	if err == nil {
 		return false
 		return false
 	}
 	}
+	if errors.Is(err, ErrSealNotFound) {
+		return true
+	}
 	msg := err.Error()
 	msg := err.Error()
 	return strings.Contains(msg, "查询的印章不存在") || strings.Contains(msg, "无可授权的印章")
 	return strings.Contains(msg, "查询的印章不存在") || strings.Contains(msg, "无可授权的印章")
 }
 }