diff --git a/business/jxutils/jxutils.go b/business/jxutils/jxutils.go index 386c2e465..a24657e59 100644 --- a/business/jxutils/jxutils.go +++ b/business/jxutils/jxutils.go @@ -144,7 +144,11 @@ func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) { // vendorID = model.VendorIDELM vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位,和饿了么订单ID“eleme_order_id”字段格式保持一致。 } else if orderIDLen == len("15380342248732") { - vendorID = model.VendorIDEBAI + if vendorOrderID[:2] == "88" { + vendorID = model.VendorIDJX + } else { + vendorID = model.VendorIDEBAI + } } else if orderIDLen == len("33437032333978492") { vendorID = model.VendorIDMTWM } else if orderIDLen == len("5287873015048") { diff --git a/business/model/order.go b/business/model/order.go index 3f1e4427f..9eb767f6b 100644 --- a/business/model/order.go +++ b/business/model/order.go @@ -8,6 +8,14 @@ const ( OrderDeliveryTypeSelfTake = "self" // 用户自提 ) +const ( + PayTypeWX = 1 // 微信支付 + + PayStatusNo = 0 + PayStatusYes = 1 + PayStatusRefund = 2 +) + type ModelTimeInfo struct { CreatedAt time.Time `orm:"auto_now_add;type(datetime)"` UpdatedAt time.Time `orm:"auto_now;type(datetime)"` @@ -260,6 +268,29 @@ type OrderComment struct { UpdatedOriginalMsg string `orm:"type(text)" json:"-"` } +type OrderPay struct { + ModelIDCULD + + VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` + VendorID int `orm:"column(vendor_id)" json:"vendorID"` + PayType int `json:"payType"` + VendorPayType string `orm:"size(48)" json:"vendorPayType"` + Status int `json:"status"` + PayCreatedAt time.Time `orm:"type(datetime);index" json:"payCreatedAt"` + PayFinishedAt *time.Time `orm:"type(datetime);null" json:"payFinishedAt"` + + PrepayID string `orm:"column(prepay_id);unique;size(48)" json:"prepayID"` + CodeURL string `orm:"column(code_url);size(256)" json:"codeURL"` + PayOrderID string `orm:"column(pay_order_id);size(48)" json:"payOrderID"` + OriginalData string `orm:"type(text)" json:"-"` +} + +func (v *OrderPay) TableIndex() [][]string { + return [][]string{ + []string{"VendorOrderID", "VendorID", "PayType", "DeletedAt"}, + } +} + // 判断是否是购买平台自有物流 // 对于京东,饿百来说,就是其自有的物流,对于微商城来说,是达达 func IsWaybillPlatformOwn(bill *Waybill) bool { diff --git a/business/partner/purchase/jd/store_sku2.go b/business/partner/purchase/jd/store_sku2.go index c426169f5..db58ccfac 100644 --- a/business/partner/purchase/jd/store_sku2.go +++ b/business/partner/purchase/jd/store_sku2.go @@ -103,9 +103,9 @@ func isErrPartialFailed(err error) bool { func getStrOutSkuIDs(l []*jdapi.StoreSkuBatchUpdateResponse, isSuccess bool) (outSkuIDs []string) { for _, v := range l { - if isSuccess && v.Code == 0 { + if isSuccess && jdapi.IsCodeSuccess(v.Code) { outSkuIDs = append(outSkuIDs, v.OutSkuID) - } else if !isSuccess && v.Code != 0 { + } else if !isSuccess && !jdapi.IsCodeSuccess(v.Code) { outSkuIDs = append(outSkuIDs, v.OutSkuID) } } diff --git a/business/partner/purchase/jx/localjx/order.go b/business/partner/purchase/jx/localjx/order.go index 6abc2cb0e..1810b92ad 100644 --- a/business/partner/purchase/jx/localjx/order.go +++ b/business/partner/purchase/jx/localjx/order.go @@ -3,6 +3,7 @@ package localjx import ( "crypto/md5" "fmt" + "math" "time" "git.rosy.net.cn/baseapi/utils" @@ -16,6 +17,8 @@ import ( const ( OrderCreateTypePre = 0 // 预创建 OrderCreateTypeNormal = 1 // 正常创建 + + PayWaitingTime = 10 * time.Minute // 等待支付的最长时间 ) type JxSkuInfo struct { @@ -42,7 +45,14 @@ type JxOrderInfo struct { OrderID int64 `json:"orderID"` StoreName string `json:"storeName"` - PayID string `json:"payID"` +} + +var ( + orderNoBeginTimestamp int64 +) + +func init() { + orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix() } func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, createType int) (outJxOrder *JxOrderInfo, err error) { @@ -54,7 +64,7 @@ func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, if outJxOrder.TotalPrice != jxOrder.TotalPrice { return nil, fmt.Errorf("商品或配送信息发生改变,请重新下单") } - outJxOrder.OrderID = GenOrderNo() + outJxOrder.OrderID = GenOrderNo(ctx) order, err2 := jxOrder2GoodsOrder(ctx, outJxOrder, deliveryAddress) if err = err2; err == nil { partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) @@ -63,14 +73,45 @@ func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, return outJxOrder, err } -func GenOrderNo() (orderNo int64) { - orderNo = time.Now().Unix()*100000 + 88000000000000000 +func Pay4Order(ctx *jxcontext.Context, orderID int64, payType int, vendorPayType string) (orderPay *model.OrderPay, err error) { + order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(orderID), model.VendorIDJX) + if err == nil { + switch payType { + case model.PayTypeWX: + orderPay, err = pay4OrderByWX(ctx, order, vendorPayType) + default: + err = fmt.Errorf("支付方式:%d当前不支持", payType) + } + } + return orderPay, err +} + +func OnPayFinished(orderPay *model.OrderPay) (err error) { + order, err := partner.CurOrderManager.LoadOrder(orderPay.VendorOrderID, orderPay.VendorID) + if err == nil { + db := dao.GetDB() + dao.UpdateEntity(db, orderPay) + order.Status = model.OrderStatusNew + order.StatusTime = *orderPay.PayFinishedAt + // OnOrderNew逻辑需要修改 + // err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order)) + } + return err +} + +func GenOrderNo(ctx *jxcontext.Context) (orderNo int64) { + const randPartNum = 1000 + orderNo = time.Now().Unix() - orderNoBeginTimestamp + // fmt.Println(orderNo) + orderNo = orderNo * randPartNum md5Bytes := md5.Sum([]byte(utils.GetUUID())) randPart := 0 for k, v := range md5Bytes { randPart += int(v) << ((k % 3) * 8) } - return orderNo + int64(randPart%10000) + orderNo += int64(randPart % randPartNum) + orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * 88 + return orderNo } func formalizeSkus(skus []*JxSkuInfo) (outSkus []*JxSkuInfo) { @@ -140,6 +181,9 @@ func generateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64 } } else { checkTime = *jxOrder.ExpectedDeliveredTime + if utils.Time2Date(time.Now()).Sub(utils.Time2Date(checkTime)) > 24*time.Hour { + return nil, nil, fmt.Errorf("预订单只能预定当天或第二天") + } } if !isTimeInOpTime(storeDetail.OpenTime1, storeDetail.CloseTime1, storeDetail.OpenTime2, storeDetail.CloseTime2, checkTime) { return nil, nil, fmt.Errorf("门店:%s不在营业时间范围", storeDetail.Name) diff --git a/business/partner/purchase/jx/localjx/order_test.go b/business/partner/purchase/jx/localjx/order_test.go index 10cd279f4..d9ee64cb1 100644 --- a/business/partner/purchase/jx/localjx/order_test.go +++ b/business/partner/purchase/jx/localjx/order_test.go @@ -1,8 +1,12 @@ package localjx -import "testing" +import ( + "testing" -func TestSyncStoreSkus(t *testing.T) { - orderNo := GenOrderNo() + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" +) + +func TestGenOrderNo(t *testing.T) { + orderNo := GenOrderNo(jxcontext.AdminCtx) t.Log(orderNo) } diff --git a/business/partner/purchase/jx/localjx/wxpay.go b/business/partner/purchase/jx/localjx/wxpay.go new file mode 100644 index 000000000..3e2f8620e --- /dev/null +++ b/business/partner/purchase/jx/localjx/wxpay.go @@ -0,0 +1,70 @@ +package localjx + +import ( + "time" + + "git.rosy.net.cn/baseapi/platformapi/wxpay" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" + "git.rosy.net.cn/jx-callback/globals/api" +) + +func vendorPayType2WxpayType(vendorPayType string) string { + return vendorPayType +} + +func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayType string) (orderPay *model.OrderPay, err error) { + payCreatedAt := time.Now() + param := &wxpay.CreateOrderParam{ + Body: "", + NotifyURL: "http://callback.test.jxc4.com/wxpay/msg/", + OutTradeNo: order.VendorOrderID, + SpbillCreateIP: ctx.GetRealRemoteIP(), + TradeType: vendorPayType2WxpayType(vendorPayType), + TotalFee: int(order.ActualPayPrice), + + TimeStart: wxpay.Time2PayTime(payCreatedAt), + // TimeExpire: wxpay.Time2PayTime(payCreatedAt.Add(PayWaitingTime)), + } + result, err := api.WxpayAPI.CreateUnifiedOrder(param) + if err == nil { + orderPay = &model.OrderPay{ + VendorOrderID: order.VendorOrderID, + VendorID: order.VendorID, + PayType: model.PayTypeWX, + VendorPayType: vendorPayType, + Status: 0, + PayCreatedAt: payCreatedAt, + PrepayID: result.PrepayID, + CodeURL: result.CodeURL, + } + dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName()) + err = dao.CreateEntity(dao.GetDB(), orderPay) + } + return orderPay, err +} + +func OnWxPayCallback(msg *wxpay.CallbackMsg) (err error) { + return err +} + +func onWxpayFinished(msg *wxpay.PayResultMsg) (err error) { + orderPay := &model.OrderPay{ + VendorOrderID: msg.OutTradeNo, + VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(msg.OutTradeNo), + PayType: model.PayTypeWX, + } + orderPay.DeletedAt = utils.DefaultTimeValue + db := dao.GetDB() + if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "DeletedAt"); err == nil { + orderPay.VendorPayType = msg.TradeType + orderPay.PayFinishedAt = utils.Time2Pointer(wxpay.PayTime2Time(msg.TimeEnd)) + orderPay.Status = model.PayStatusYes + dao.UpdateEntity(db, orderPay) + err = OnPayFinished(orderPay) + } + return err +} diff --git a/conf/app.conf b/conf/app.conf index 608ab9764..8e6d243f5 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -50,6 +50,10 @@ weixinPageSecret = "c7a84ed3ef3ae04ac78e02fb593ffbe5" weixinMiniAppID = "wx08a5c2a8581414ff" weixinMiniSecret = "e7ec67c86cbd4dfa531af7af7533cdc9" +wxpayAppID = "wx4b5930c13f8b1170" +wxpayAppKey = "XKJPOIHJ233adf01KJIXlIeQDSDKFJAD" +wxpayAppMchID = "1390686702" + backstageHost = "http://www.jxc4.com" wxBackstageHost = "http://wx.jxc4.com" diff --git a/controllers/jx_order2.go b/controllers/jx_order2.go index 738f6df1f..c82145403 100644 --- a/controllers/jx_order2.go +++ b/controllers/jx_order2.go @@ -28,3 +28,19 @@ func (c *JxOrderController) CreateOrder() { return retVal, "", err }) } + +// @Title 请求支付京西商城订单 +// @Description 请求支付京西商城订单 +// @Param token header string true "认证token" +// @Param vendorOrderID formData string true "订单ID" +// @Param payType formData int true "支付类型" +// @Param vendorPayType formData string true "平台支付类型" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /Pay4Order [post] +func (c *JxOrderController) Pay4Order() { + c.callPay4Order(func(params *tJxorderPay4OrderParams) (retVal interface{}, errCode string, err error) { + retVal, err = localjx.Pay4Order(params.Ctx, utils.Str2Int64(params.VendorOrderID), params.PayType, params.VendorPayType) + return retVal, "", err + }) +} diff --git a/controllers/wxpay_callback.go b/controllers/wxpay_callback.go index 3de328fc0..dfdbd5f19 100644 --- a/controllers/wxpay_callback.go +++ b/controllers/wxpay_callback.go @@ -4,6 +4,8 @@ import ( "net/http" "git.rosy.net.cn/baseapi/platformapi/wxpay" + "git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx" + "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" ) @@ -13,8 +15,14 @@ type WXPayController struct { func (c *WXPayController) Msg() { if c.Ctx.Input.Method() == http.MethodPost { - var callbackResponse *wxpay.CallbackResponse - + msg, callbackResponse := api.WxpayAPI.GetCallbackMsg(c.Ctx.Request) + if callbackResponse == nil { + if err := localjx.OnWxPayCallback(msg); err != nil { + if msg.MsgType != wxpay.MsgTypeUnkown { + callbackResponse = wxpay.Err2CallbackResponse(err, "") + } + } + } if callbackResponse == nil { callbackResponse = wxpay.SuccessResponse } diff --git a/globals/api/api.go b/globals/api/api.go index ff4a9529d..eb4aed297 100644 --- a/globals/api/api.go +++ b/globals/api/api.go @@ -19,6 +19,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/showapi" "git.rosy.net.cn/baseapi/platformapi/weimobapi" "git.rosy.net.cn/baseapi/platformapi/weixinapi" + "git.rosy.net.cn/baseapi/platformapi/wxpay" "git.rosy.net.cn/baseapi/platformapi/xiaowmapi" "git.rosy.net.cn/baseapi/platformapi/yilianyunapi" "git.rosy.net.cn/baseapi/platformapi/zhongwuapi" @@ -41,6 +42,7 @@ var ( WeixinMiniAPI *weixinapi.API // 小程序 WeixinMiniAPI2 *weixinapi.API // 小程序2 WeixinMiniAppID2 string + WxpayAPI *wxpay.API // 微信支付API WeixinPageAPI *weixinapi.API // 用户微信扫码登录 @@ -141,6 +143,7 @@ func Init() { WeixinMiniAPI2 = weixinapi.New(WeixinMiniAppID2, beego.AppConfig.String("weixinMiniSecret2")) } WeixinPageAPI = weixinapi.New(beego.AppConfig.String("weixinPageAppID"), beego.AppConfig.String("weixinPageSecret")) + WxpayAPI = wxpay.New(beego.AppConfig.String("wxpayAppID"), beego.AppConfig.String("wxpayAppKey"), beego.AppConfig.String("wxpayAppMchID")) AutonaviAPI = autonavi.New(beego.AppConfig.String("autonaviKey")) BaiDuNaviAPI = baidunavi.New(beego.AppConfig.String("baidunaviAK"), beego.AppConfig.String("baidunaviSK")) diff --git a/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go index a46fcf679..8b200cec3 100644 --- a/globals/beegodb/beegodb.go +++ b/globals/beegodb/beegodb.go @@ -61,6 +61,7 @@ func Init() { orm.RegisterModel(&model.UserDeliveryAddress{}) orm.RegisterModel(&model.UserCartItem{}) + orm.RegisterModel(&model.OrderPay{}) // create table orm.RunSyncdb("default", false, true) } diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 92ec70584..175ed53e9 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -592,6 +592,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JxOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JxOrderController"], + beego.ControllerComments{ + Method: "Pay4Order", + Router: `/Pay4Order`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JxShopController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JxShopController"], beego.ControllerComments{ Method: "JxMsg",