From d2996db7cf03cf310f28ff5d8869acb5f0d96ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E5=AE=97=E6=A5=A0?= Date: Mon, 10 Nov 2025 09:51:45 +0800 Subject: [PATCH] 1 --- platformapi/jdapi/Invoice_model.go | 101 ++++++++++++++++++++++++++++ platformapi/jdapi/callback.go | 30 ++++++++- platformapi/jdapi/invoice.go | 53 +++++++++++++++ platformapi/jdapi/invoice_test.go | 32 +++++++++ platformapi/jdapi/jdapi_test.go | 4 +- platformapi/jdapi/store_test.go | 2 +- platformapi/mtwmapi/mtwmapi_test.go | 7 +- platformapi/mtwmapi/retail_test.go | 2 +- platformapi/platformapi.go | 3 +- 9 files changed, 221 insertions(+), 13 deletions(-) create mode 100644 platformapi/jdapi/Invoice_model.go create mode 100644 platformapi/jdapi/invoice.go create mode 100644 platformapi/jdapi/invoice_test.go diff --git a/platformapi/jdapi/Invoice_model.go b/platformapi/jdapi/Invoice_model.go new file mode 100644 index 00000000..4a4cc7e1 --- /dev/null +++ b/platformapi/jdapi/Invoice_model.go @@ -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"` // 普通发票号码/全电发票号码 +} diff --git a/platformapi/jdapi/callback.go b/platformapi/jdapi/callback.go index 9b867e9d..8f34bc03 100644 --- a/platformapi/jdapi/callback.go +++ b/platformapi/jdapi/callback.go @@ -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 { diff --git a/platformapi/jdapi/invoice.go b/platformapi/jdapi/invoice.go new file mode 100644 index 00000000..a68a632c --- /dev/null +++ b/platformapi/jdapi/invoice.go @@ -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 +} diff --git a/platformapi/jdapi/invoice_test.go b/platformapi/jdapi/invoice_test.go new file mode 100644 index 00000000..61914ae5 --- /dev/null +++ b/platformapi/jdapi/invoice_test.go @@ -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) +} diff --git a/platformapi/jdapi/jdapi_test.go b/platformapi/jdapi/jdapi_test.go index 0a7a8186..2156d185 100644 --- a/platformapi/jdapi/jdapi_test.go +++ b/platformapi/jdapi/jdapi_test.go @@ -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") diff --git a/platformapi/jdapi/store_test.go b/platformapi/jdapi/store_test.go index f16e28e5..2b0a1f67 100644 --- a/platformapi/jdapi/store_test.go +++ b/platformapi/jdapi/store_test.go @@ -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) } diff --git a/platformapi/mtwmapi/mtwmapi_test.go b/platformapi/mtwmapi/mtwmapi_test.go index 60dec1eb..b03f61c5 100644 --- a/platformapi/mtwmapi/mtwmapi_test.go +++ b/platformapi/mtwmapi/mtwmapi_test.go @@ -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) { - -} diff --git a/platformapi/mtwmapi/retail_test.go b/platformapi/mtwmapi/retail_test.go index 3224c1fd..ee9812c2 100644 --- a/platformapi/mtwmapi/retail_test.go +++ b/platformapi/mtwmapi/retail_test.go @@ -394,7 +394,7 @@ func TestRetailRecommendTag(t *testing.T) { // 删除商品 func TestRetailDelete(t *testing.T) { - poiCode := "20849656" + poiCode := "30400128" i := 0 count := 0 diff --git a/platformapi/platformapi.go b/platformapi/platformapi.go index 861680ab..e56eebda 100644 --- a/platformapi/platformapi.go +++ b/platformapi/platformapi.go @@ -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 // 读取数据错误,或数据格式错误认为是偶发情况,重试