This commit is contained in:
邹宗楠
2025-11-10 09:51:45 +08:00
parent ab98ad1cd0
commit d2996db7cf
9 changed files with 221 additions and 13 deletions

View File

@@ -0,0 +1,101 @@
package jdapi
import "time"
// InvoiceDetailResult 发票申请
type InvoiceDetailResult struct {
ApplyId int64 `json:"applyId"` // 申请单号
OrderId int64 `json:"orderId"` // 订单号
InvoiceType int `json:"invoiceType"` // 发票类型 1:电子发票自开, 2:电子发票代开, 3:普通发票, 4:增值税专用发票
SourceId int `json:"sourceId"` // 申请单来源 10000:来自下单消息, 10010:电子发票系统补开, 10020:自助发票系统补开, 10030:交易纠纷系统补开, 10040:JOS平台
InvoiceStatus int `json:"invoiceStatus"` // 发票状态 1:待开票, 3:开票中, 4:开票成功, 5:开票失败, 6:冲红中, 7:冲红成功, 8:冲红失败, 9:已驳回, 11:蓝票审核失败, 12:红票审核失败, 13:待换开, 14:换开中, 15:换开驳回, 16:退款关闭, 17:驳回关闭
InvoiceTitleType int `json:"invoiceTitleType"` // 发票抬头类型 4:个人, 5:企业
InvoiceTitle string `json:"invoiceTitle"` // 发票抬头
ConsumerTaxId string `json:"consumerTaxId"` // 买家税号
ConsumerAddress string `json:"consumerAddress"` // 购买方公司地址
ConsumerPhone string `json:"consumerPhone"` // 购买方公司电话
ConsumerBankName string `json:"consumerBankName"` // 购买方公司开户行信息
ConsumerBankAccount string `json:"consumerBankAccount"` // 购买方公司银行账号
LogisticsReceiverName string `json:"logisticsReceiverName"` // 收票人姓名
LogisticsReceiverPhone string `json:"logisticsReceiverPhone"` // 收票人电话
LogisticsReceiverAddress string `json:"logisticsReceiverAddress"` // 收货地址信息
ApplyTime string `json:"applyTime"` // 发票申请时间
RejectReason string `json:"rejectReason"` // 驳回原因
AuditTime string `json:"auditTime"` // 审核时间
OrderCompleteTime string `json:"orderCompleteTime"` // 订单完成时间
CustomerTaxNo string `json:"customerTaxNo"` // 纳税人识别号
IvcContentType int `json:"ivcContentType"` // 发票内容类型 1:明细 2:类别
IvcContentName string `json:"ivcContentName"` // 发票内容名称
CustomerEmail string `json:"customerEmail"` // 消费者邮箱
ShouldInvoiceAmount float64 `json:"shouldInvoiceAmount"` // 该订单按照京东规则计算出的应开票金额,商家也可以根据自己的规则使用金额项明细自己计算应开票金额
AmountDetail interface{} `json:"amountDetail"` // 订单的金额项
CompanyId int64 `json:"companyId"` // 公司主体id
CompanyName string `json:"companyName"` // 公司主体名称
StoreId int64 `json:"storeId"` // 到家门店ID
StoreName string `json:"storeName"` // 到家门店名称
}
// InvoiceListResult 查询发票列表
type InvoiceListResult struct {
InvoiceTypeName string `json:"invoiceTypeName"` // 开票类型
SourceId int64 `json:"sourceId"` // 10000下单, 10010商家主动补开, 10020消费者申请补开, 10021消费者申请修改, 10022消费者申请换开, 10030交易纠纷, 10040宙斯平台, 10050开普勒平台
InvoiceStatusName string `json:"invoiceStatusName"` // 申请单开票状态
LogisticsReceiverAddress string `json:"logisticsReceiverAddress"` // 收货地址信息
InvoiceContentTypeName string `json:"invoiceContentTypeName"` // 发票内容编号
OrderId int64 `json:"orderId"` // 订单号
InvoiceContentType int64 `json:"invoiceContentType"` // 发票内容编号 1明细2类别
CompanyName string `json:"companyName"` // 公司名称
StoreId int64 `json:"storeId"` // 到家门店ID
StoreName string `json:"storeName"` // 到家门店名称
ConsumerPhone string `json:"consumerPhone"` // 购买方公司电话
InvoiceAmount float64 `json:"invoiceAmount"` // 建议开票金额
OrderCompleteTime int64 `json:"orderCompleteTime"` // 订单完成时间
RejectReason string `json:"rejectReason"` // 驳回原因
InvoiceTitleType int64 `json:"invoiceTitleType"` // 发票抬头类型 4:个人, 5:企业
ConsumerTaxId string `json:"consumerTaxId"` // 买家税号
InvoiceType int64 `json:"invoiceType"` // 开票类型 1普票, 2增票, 3电票自开, 4电票代开
InvoiceTitleTypeName string `json:"invoiceTitleTypeName"` // 发票抬头类型
IvcContentType int64 `json:"ivcContentType"` // 发票内容类型 1明细 2类别
ApplyTime int64 `json:"applyTime"` // 申请时间
InvoiceTitle string `json:"invoiceTitle"` // 发票抬头
ConsumerAddress string `json:"consumerAddress"` // 购买方公司地址
LogisticsReceiverName string `json:"logisticsReceiverName"` // 收票人姓名
IvcContentName string `json:"ivcContentName"` // 发票内容类型
CompanyId int64 `json:"companyId"` // 公司Id
ConsumerBankAccount string `json:"consumerBankAccount"` // 购买方公司银行账号
LogisticsReceiverPhone string `json:"logisticsReceiverPhone"` // 收票人电话
AuditTime time.Time `json:"auditTime"` // 审核时间
AmountDetail interface{} `json:"amountDetail"` // 发票内容明细
SourceName string `json:"sourceName"` // 10000下单, 10010商家主动补开, 10020消费者申请补开, 10021消费者申请修改, 10022消费者申请换开, 10030交易纠纷, 10040宙斯平台, 10050开普勒平台
UserType int64 `json:"userType"` // 用户类型 1企业用户 2个人用户
InvoiceStatus int64 `json:"invoiceStatus"` // 申请单开票状态 1待开票, 3开票中, 4开票成功, 5开票失败, 6冲红中, 7冲红成功, 8冲红失败, 9已驳回, 11蓝票审核失败, 12红票审核失败, 13待换开, 14换开中, 15换开驳回, 16退款关闭, 17驳回关闭
ConsumerBankName string `json:"consumerBankName"` // 购买方公司开户行
Oaid string `json:"oaid"` // 收件人唯一标识长度为256
}
// QueryInvoiceListParam 查询发票列表
type QueryInvoiceListParam struct {
InvoiceStatusList []int `json:"invoiceStatusList"` // 发票状态列表--发票状态 1:待开票, 3:开票中, 4:开票成功, 5:开票失败, 6:冲红中, 7:冲红成功, 8:冲红失败, 9:已驳回, 11:蓝票审核失败, 12:红票审核失败, 13:待换开, 14:换开中, 15:换开驳回, 16:退款关闭, 17:驳回关闭
OrderId int64 `json:"orderId"` // 订单编号
ApplyTimeOrder string `json:"applyTimeOrder"` // 否 DESC倒叙 ASC正序 按申请时间排序规则
OrderCompleteTimeStart *time.Time `json:"orderCompleteTimeStart"` // 订单完成时间-开始
OrderCompleteTimeEnd *time.Time `json:"orderCompleteTimeEnd"` // 订单完成时间-结束
ApplyTimeStart *time.Time `json:"applyTimeStart"` // 申请时间-开始(仅支持查询申请时间在两年内的发票申请记录)
ApplyTimeEnd *time.Time `json:"applyTimeEnd"` // 申请时间-结束(仅支持查询申请时间在两年内的发票申请记录)
StoreId int64 `json:"storeId"` // 到家门店ID
PageSize int `json:"pageSize"` // 每页行数最大20
PageIndex int `json:"pageIndex"` // 页码
}
// BlueTicketParam 上传蓝票
type BlueTicketParam struct {
OrderId string `json:"orderId"` // 订单编号
ReceiverTaxNo string `json:"receiverTaxNo"` // 销货方识别号(税号)
ReceiverName string `json:"receiverName"` // 销货方公司名称
InvoiceCode string `json:"invoiceCode"` // (不传为电子发票、传为普通发票) 发票代码
IvcTitle string `json:"ivcTitle"` // 个人 发票抬头
TotalPrice string `json:"totalPrice"` // 开票金额
InvoiceTime string `json:"invoiceTime"` // 开票时间
PdfInfo string `json:"pdfInfo"` // PDF文件二进制流base64
FullEleInvoiceNo string `json:"fullEleInvoiceNo"` // 普通发票号码/全电发票号码
}

View File

@@ -1,7 +1,11 @@
package jdapi
import (
"fmt"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/globals"
"io/ioutil"
"net/http"
"strings"
@@ -95,8 +99,9 @@ const (
CallbackMsgOrderInfoChange = "orderInfoChange" //订单售前用户改变收货地址电话等
// 账务
CallbackMsgEndOrderFinance = "endOrderFinance" // 订单金额拆分完成消息
CallbackMsgFinanceAdjustment = "financeAdjustment" // 财务调整单消息
CallbackMsgEndOrderFinance = "endOrderFinance" // 订单金额拆分完成消息
CallbackMsgFinanceAdjustment = "financeAdjustment" // 财务调整单消息
CallbackMsgApplyInvoice = "applyOrderInvoiceStatus" // 发票消息
// 售后
CallbackMsgNewApplyAfterSaleBill = "newApplyAfterSaleBill" // 新建售后单申请消息
@@ -196,6 +201,15 @@ type CallbackStoreStockMsg struct {
OperSource int `json:"operSource"`
}
type CallbackInvoiceMsg struct {
*CallbackMsg
BillID string `json:"billId"` // 消息单据ID
Id string `json:"id"` // 主键id
InvoiceStatus string `json:"invoiceStatus"` // 更新后的发票状态 1:待开票 3:开票中 4:开票成功 5:开票失败 6:冲红中 7:冲红成功 8:冲红失败 9:已驳回 11:蓝票审核失败 12:红票审核失败 13:待换开 14:换开中 15:换开驳回 16:退款关闭 17:协商关闭
Modified string `json:"modified"` // 发票状态更新时刻
StoreId string `json:"storeId"` // 门店id非必需当状态变化来自秒送门店的时候才会携带
}
const (
OpenSourceJDLSP = 1
OpenSourceJDMedicineCity = 2
@@ -262,6 +276,10 @@ func GetCallbackMsg(request *http.Request) (callbackMsg *CallbackMsg, mapData ma
if err != nil {
return nil, nil, Err2CallbackResponse(err, "")
}
if msgURL == CallbackMsgApplyInvoice {
globals.SugarLogger.Debugf("-jd-----Invoice:= %s", utils.Format4Output(data, false))
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "2452A93EEB9111EC9B06525400E86DC0", "jdController发票推送", utils.Format4Output(data, false))
}
values, err := utils.HTTPBody2Values(data, needDecodeMap[msgURL])
if err != nil {
@@ -295,6 +313,14 @@ func GetCallbackMsg(request *http.Request) (callbackMsg *CallbackMsg, mapData ma
callbackMsg.Param = orderInfoMsg
orderInfoMsg.CallbackMsg = callbackMsg
}
} else if msgURL == CallbackMsgApplyInvoice {
var orderInfoMsg *CallbackInvoiceMsg
if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderInfoMsg); err == nil {
callbackMsg.Param = orderInfoMsg
orderInfoMsg.CallbackMsg = callbackMsg
}
fmt.Println(orderInfoMsg)
} else {
var orderMsg *CallbackOrderMsg
if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderMsg); err == nil {

View File

@@ -0,0 +1,53 @@
package jdapi
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
)
// QueryInvoiceDetail 发票申请详情查询
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=182&apiid=38559b4a4fc34c8b8d3223d43c731d70
func (a *API) QueryInvoiceDetail(orderID string) (invoice *InvoiceDetailResult, err error) {
jdParams := map[string]interface{}{
"orderId": orderID,
}
result, err := a.AccessAPINoPage("JdInvoiceService/getInvoiceApplyDetail", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "0"))
if err != nil {
return nil, err
}
if err = utils.Map2StructByJson(result, &invoice, false); err != nil {
return nil, err
}
return invoice, err
}
// QueryInvoiceList 查询发票列表
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=182&apiid=55f36649c0d642d8aa0cd8949729a124
func (a *API) QueryInvoiceList(param *QueryInvoiceListParam) (invoice []*InvoiceListResult, err error) {
jdParams := utils.Struct2MapByJson(param)
result, err := a.AccessAPINoPage("JdInvoiceService/pageInvoiceApply", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "0"))
if err != nil {
return nil, err
}
if result.(map[string]interface{})["list"] != nil {
data := make([]*InvoiceListResult, 0, 0)
if err = json.Unmarshal(utils.MustMarshal(result.(map[string]interface{})["list"]), &data); err != nil {
return nil, err
}
return data, nil
}
return nil, fmt.Errorf("未查询到发票数据")
}
// UploadBlueTicket 上传蓝票
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=182&apiid=1eb09fa07adf4243b14b2193fdf7154d
func (a *API) UploadBlueTicket(param *BlueTicketParam) (err error) {
jdParams := utils.Struct2MapByJson(param)
_, err = a.AccessAPINoPage("JdInvoiceService/applyInvoiceForOwn", jdParams, nil, nil, genNoPageResultParser("code", "msg", "", "0"))
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,32 @@
package jdapi
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
"testing"
)
func TestQueryInvoiceList(t *testing.T) {
param := &QueryInvoiceListParam{
InvoiceStatusList: nil,
OrderId: 0,
ApplyTimeOrder: "",
OrderCompleteTimeStart: utils.Time2Pointer(utils.Str2Time("2025-05-01 00:00:00")),
OrderCompleteTimeEnd: utils.Time2Pointer(utils.Str2Time("2025-05-31 23:00:00")),
ApplyTimeStart: nil,
ApplyTimeEnd: nil,
StoreId: 11906384,
PageSize: 20,
PageIndex: 1,
}
data, err := api.QueryInvoiceList(param)
globals.SugarLogger.Debugf("data = %s", utils.Format4Output(data, false))
globals.SugarLogger.Debugf("data = %v", err)
}
func TestQueryInvoiceDetail(t *testing.T) {
result, err := api.QueryInvoiceDetail("315229256506")
globals.SugarLogger.Debugf("data = %s", utils.Format4Output(result, false))
globals.SugarLogger.Debugf("data = %v", err)
}

View File

@@ -30,7 +30,7 @@ func init() {
// 天天果园
//api = New("c45e6510-00ba-4be2-977e-bcb9c9792cc7", "5d5577a2506f41b8b4ec520ba83490f5", "0b01b9eeb15b41dab1c3d05d95c17a26")
// 京东果园 320406
//api = New("de4a9818-b171-41ed-ba37-0b060cad001f", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
api = New("de4a9818-b171-41ed-ba37-0b060cad001f", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
// 京东白货
//api = New("9053e4fd-4e0e-4e9e-8ab1-f348e5cbf3e7", "4602bd4b84984186815dbc03299c7094", "386ab19719d9470487011217d0c57349")
// 果切 379599
@@ -38,7 +38,7 @@ func init() {
// 李氏水果 346254
//api = New("c7c41cb6-6db4-4f67-a864-ca5f524653d0", "13493b4a951945f689dcc989b6693631", "7e28a37be43a430bb5928c835e482fe2")
// 381564
api = New("4d0c707a-54eb-4f05-8187-6cedf95827c7", "d2d1e2e3213d4320bc2712a684307831", "1750f5b9848d4a6492c1c20b487074da")
//api = New("4d0c707a-54eb-4f05-8187-6cedf95827c7", "d2d1e2e3213d4320bc2712a684307831", "1750f5b9848d4a6492c1c20b487074da")
// 390558
//api = New("9053e4fd-4e0e-4e9e-8ab1-f348e5cbf3e7", "4602bd4b84984186815dbc03299c7094", "386ab19719d9470487011217d0c57349")

View File

@@ -41,7 +41,7 @@ func TestGetStationsByVenderId(t *testing.T) {
}
func TestGetStoreInfoByStationNo(t *testing.T) {
result, err := api.GetStoreInfoByStationNo2("12691999")
result, err := api.GetStoreInfoByStationNo2("21103071")
if err != nil {
t.Fatal(err)
}

View File

@@ -2,11 +2,10 @@ package mtwmapi
import (
"fmt"
"testing"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"go.uber.org/zap"
"testing"
)
var (
@@ -82,7 +81,3 @@ func TestRefreshAccessToken(t *testing.T) {
fmt.Println(utils.Format4Output(result, false))
t.Log(utils.Format4Output(result, false))
}
func Test22(t *testing.T) {
}

View File

@@ -394,7 +394,7 @@ func TestRetailRecommendTag(t *testing.T) {
// 删除商品
func TestRetailDelete(t *testing.T) {
poiCode := "20849656"
poiCode := "30400128"
i := 0
count := 0

View File

@@ -5,6 +5,7 @@ import (
"compress/gzip"
"errors"
"fmt"
"git.rosy.net.cn/jx-callback/globals"
"io/ioutil"
"math"
"net"
@@ -173,7 +174,7 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
} else {
bodyData, getDataErr = ioutil.ReadAll(response.Body)
}
globals.SugarLogger.Debugf("%s", utils.Format4Output(time.Now(), false))
if getDataErr != nil {
baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, url:%v, error:%v", trackInfo, request.URL, err)
errLevel = ErrLevelRecoverableErr // 读取数据错误,或数据格式错误认为是偶发情况,重试