package weixinmsg import ( "encoding/json" "fmt" "git.rosy.net.cn/baseapi/platformapi/weixinapi" "math" "strings" "time" beego "github.com/astaxie/beego/server/web" "git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin" "git.rosy.net.cn/jx-callback/business/authz/autils" "git.rosy.net.cn/jx-callback/business/jxstore/permission" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/netprinter" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/model/legacymodel" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api2" ) const ( WX_TO_ORDER_PAGE_URL = "/#/?jxStoreId=" WX_TO_STORE_SKU_PAGE_URL = "/#/shop?jxStoreId=" WX_TO_SHOW_COMMENTS_DETAIL_URL = "/#/assess-list?jxStoreId=" //展示差评详情的页面 WX_TO_SHOW_MSG = "/#/message-detail?msgID=%d&msgStatusID=%d" WX_MINI_TO_ORDER_PAGE_URL = "pages/order-manager/main" WX_MINI_TO_STORE_SKU_PAGE_URL = "pages/goods-manager/main" WX_MINI_TO_SHOW_COMMENTS_DETAIL_URL = "pages/pagesStore/store-comment/main" WX_MINI_TO_SHOW_MSG = "pages/pagesStore/msg-page/main?msgID=%d&msgStatusID=%d" //新订单模板消息文字颜色 WX_NEW_ORDER_TEMPLATE_COLOR = "#173177" WX_HIGHLEVEL_TEMPLATE_COLOR = "#FF0000" //红色 WX_HIGHLEVEL_TEMPLATE_COLOR2 = "#333333" //黑色 WX_TEMPLATE_VENDERCOLOR_JDDJ = "#47B34F" WX_TEMPLATE_VENDERCOLOR_MT = "#F4A800" WX_TEMPLATE_VENDERCOLOR_ELM = "#0191EA" //蓝色 WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS = "#4F4DA0" WX_NEWORDER_TEMPLATE_ID = "_DtNGwmOeR6TkkTVUblxLIlkV2MAPOX57TkvfdqG6nY" //微信新订单推送 WX_ADJUSTORDER_TEMPLATE_ID = "N5rmV2-PDf3opjkv23IdLc76VnFThr_uOKSh5FzT13M" //微信调整订单推送 WX_MTPS_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信美团配送员接单推送 WX_MTPS_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信美团配送员配送完成推送 WX_MTPS_UNABLE_DELIVER_TEMPLATE_ID = "ZFph5Hp7oLlrzVRXbsKIC_StmaBeB9Dlp4tlHeAmUQ8" //微信美团配送配送能力不足推送 WX_MTPS_DELIVERY_EXCEPTION_TEMPLATE_ID = "RkfOFHgR1N75L4-a6Gv0DljpCsVfOHhLm_vyXh8MR-w" //微信美团配送异常推送 WX_BAD_COMMENT_PUSH_TEMPLATE_ID = "NaMEzjctvVPQ9ishTI1dKpp5QSYV2FWcWftSSjDrpN8" //微信中差评消息推送 WX_DADA_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信达达众包配送员接单推送 WX_DADA_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信达达众包配送员配送完成推送 WX_SALE_BILL_TEMPLATE_ID = "eTUuFZMWH7IsVBfcxNMpmaHYaxRkUaD6zG8wSGJDcic" WX_NORMAL_STORE_ACT_MSG_TEMPLATE_ID = "eXsfOMvDOKVSht0Q0v4IsDrx3MBlRCVYwYl7Hi2uuuI" WX_NORMAL_STORE_MSG_TEMPLATE_ID = "EUeIJEz2TLUAn4TU2EffOGYLd3dEaYndD_y6Sw9FcSU" WX_CHANGE_APPROVED_TEMPLATE_ID = "gIG2olBZtQbjXmp6doNB_dESu60By5xuXYOGxksLv3Y" WX_CHANGE_REJECTED_TEMPLATE_ID = "OBF4-d5inK95epHcUltpdb1zq9boVp2HESpASVRh1Oo" WX_ORDER_APPLY_CANCEL_TEMPLATE_ID = "e6urTtcm4PL0rgDMG_1qWNOwrE3Qxqcm_dx0kWWCmEI" WX_ORDER_ORDER_CANCELED_TEMPLATE_ID = "HXjuSAbIk77Xh18hjgwoxHzbciR9jX3Rn2CpLJz9dZw" WX_ORDER_CHANGE_INFO_TEMPLATE_ID = "cjmEQFEpvcOuBNqQpTfMU5FeBpGRbQh_gWKz-WPW8Ro" WX_AFS_ORDER_WAIT4APPROVE_TEMPLATE_ID = "X29udtANvhX6x1Lyh-T40NGNjRXBbUj5oSBTfDhZAqU" WX_AFS_ORDER_STATUS_CHANGED_TEMPLATE_ID = "99T33rrXX0VboO1hljs4x8dDoLiSj3QX_rOikPHIXkg" WS_NOTIFY_STORE_STATUS_CHHANGED_TEMPLATE_ID = "Fl0vOnBKTQqRFx3-shGKxdCnxMdQXNeODzgkuwd7oxw" WX_STORE_ALERT_TEMPLATE_ID = "0AjzVl1wPl6iO4nFOS4IEsJYSzBymlT37DciIvcCOxE" WX_KNOWLEDGE_BASE_TEMPLATE_ID = "1Fc703r13L3KQ6r_jdql2em_YhQ9CyOXTnqtDx-6Hx8" //知识库模板 ) var ( VendorColors = map[int]string{ model.VendorIDJD: WX_TEMPLATE_VENDERCOLOR_JDDJ, model.VendorIDMTWM: WX_TEMPLATE_VENDERCOLOR_MT, model.VendorIDELM: WX_TEMPLATE_VENDERCOLOR_ELM, model.VendorIDEBAI: WX_TEMPLATE_VENDERCOLOR_ELM, } testMiniProgramStoreMap = map[int]int{ 101089: 1, 100888: 1, 100204: 1, 100205: 1, 100147: 1, } debugOpenIDMap = map[string]int{ "oYN_usk0AeGc_C6VEZfmFQP5VHMQ": 1, // 周小扬 "oYN_ust9hXKEvEv0X6Mq6nlAWs_E": 1, // me "oYN_usqnpGVQ4xxlao_yybsbYJh4": 1, // 朱丹 } ) func GetWeixinOpenIDsFromStoreID(storeID int) (retVal []string) { db := dao.GetDB() openIDMap := make(map[string]int) if globals.EnableWXAuth2 { if userIDList, err2 := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(storeID)); err2 == nil { for _, v := range userIDList { if authList, err2 := dao.GetUserBindAuthInfo(db, v, model.AuthBindTypeAuth, []string{weixin.AuthTypeMP}, "", "", nil); err2 == nil { for _, v := range authList { retVal = append(retVal, v.AuthID) openIDMap[v.AuthID] = 1 } } } } } retVal = jxutils.StringMap2List(openIDMap) if !globals.ReallyCallPlatformAPI { // todo,调试,只发给我 globals.SugarLogger.Debugf("GetWeixinOpenIDsFromStoreID store:%d, openids:%v", storeID, retVal) if storeID == 100146 { retVal = []string{"oYN_ust9hXKEvEv0X6Mq6nlAWs_E"} } else { retVal = nil } } return retVal } func SendMsgToStore(storeID int, templateID, downloadURL, miniPageURL string, data interface{}) (err error) { globals.SugarLogger.Debugf("SendMsgToStore storeID:%d, templateID:%s, downloadURL:%s, miniPageURL:%s", storeID, templateID, downloadURL, miniPageURL) if storeID == 0 { // 测试,只发给我 // SmartMessageTemplateSend("oYN_ust9hXKEvEv0X6Mq6nlAWs_E", templateID, downloadURL, miniPageURL, data) } else { openIDs := GetWeixinOpenIDsFromStoreID(storeID) successCount := 0 for _, openID := range openIDs { realMiniPageURL := miniPageURL // if testMiniProgramStoreMap[storeID] == 0 && debugOpenIDMap[openID] == 0 { // realMiniPageURL = "" // } globals.SugarLogger.Debugf("SendMsgToStore storeID:%d, openID:%s, templateID:%s, downloadURL:%s, realMiniPageURL:%s", storeID, openID, templateID, downloadURL, realMiniPageURL) if err2 := SmartMessageTemplateSend(openID, templateID, downloadURL, realMiniPageURL, data); err2 == nil { successCount++ } else { err = err2 } } if successCount > 0 { err = nil // 只要成功一个都当成成功 } if err != nil { globals.SugarLogger.Debugf("SendMsgToStore all failed storeID:%d, templateID:%s, error:%v", storeID, templateID, err) } } return err } func SmartMessageTemplateSend(userOpenID, templateID, downloadURL, miniPageURL string, data interface{}) (err error) { var miniProgram map[string]interface{} if miniPageURL != "" { miniProgram = map[string]interface{}{ "appid": api.WeixinMiniAPI.GetAppID(), "pagepath": miniPageURL, } } globals.SugarLogger.Debugf("SmartMessageTemplateSend openID:%s, templateID:%s, downloadURL:%s, miniProgram:%s", userOpenID, templateID, downloadURL, utils.Format4Output(miniProgram, true)) if globals.ReallySendWeixinMsg || debugOpenIDMap[userOpenID] == 1 { if err = api.WeixinAPI.CBMessageTemplateSend(userOpenID, templateID, downloadURL, miniProgram, data); err != nil { globals.SugarLogger.Debugf("SmartMessageTemplateSend openID:%s, templateID:%s, downloadURL:%s, miniProgram:%s, failed with error:%v", userOpenID, templateID, downloadURL, utils.Format4Output(miniProgram, true), err) } } return err } func MediaMessageSendGroup(openIDs []string, mediaID string) (err error) { return api.WeixinAPI.CBMassSend(openIDs, mediaID) } func getOrderDetailBrief(order *model.GoodsOrder) (brief string) { sb := new(strings.Builder) sb.WriteString(order.Skus[0].SkuName) sb.WriteString("等共") sb.WriteString(utils.Int2Str(order.Skus[0].Count)) sb.WriteString("份(") sb.WriteString(jxutils.IntPrice2StandardString(order.Skus[0].SalePrice)) sb.WriteString("元/份)等,点击查看详情。") //,预计收入") //TODO 2020-07-20 果园和菜市不同 //TODO 2021-06-15 都不显示钱了 //var price int64 //if beego.BConfig.RunMode == "jxgy" { // price = order.NewEarningPrice //} else { // if order.EarningType == model.EarningTypePoints { // price = order.ActualPayPrice // } else { // price = order.EarningPrice // } //} //sb.WriteString(jxutils.IntPrice2StandardString(price)) //sb.WriteString("元") return sb.String() } func NotifyNewOrder(order *model.GoodsOrder) (err error) { globals.SugarLogger.Debugf("NotifyNewOrder orderID:%s", order.VendorOrderID) if order.VendorID == model.VendorIDELM { return nil } if len(order.Skus) == 0 { return nil } if !model.IsOrderSolid(order) { globals.SugarLogger.Infof("NotifyNewOrder orderID:%s is not solid", order.VendorOrderID) return nil } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } sb := new(strings.Builder) sb.WriteString(suffix + "老板,") sb.WriteString(order.ConsigneeName) sb.WriteString("购买了商品") sb.WriteString(getOrderDetailBrief(order)) data := map[string]interface{}{ "first": map[string]interface{}{ "value": sb.String(), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "Day": map[string]interface{}{ "value": FormatDeliveryTime(order), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderId": map[string]interface{}{ "value": order.VendorOrderID, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderType": map[string]interface{}{ "value": fmt.Sprintf("%s 第%d号订单", model.VendorChineseNames[order.VendorID], order.OrderSeq), "color": VendorColors[order.VendorID], }, "customerName": map[string]interface{}{ "value": order.ConsigneeName, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "customerPhone": map[string]interface{}{ "value": order.ConsigneeMobile, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromOrder(order) //return SendMsgToStore(storeID, WX_NEWORDER_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL+fmt.Sprintf("?jxStoreId=%v", storeID), data) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeID, dataStore) return SendMsgToStore(storeID, WX_NEWORDER_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) } func NotifyWaybillStatus(bill *model.Waybill, order *model.GoodsOrder, isBillAlreadyCandidate bool) (err error) { globals.SugarLogger.Debugf("NotifyWaybillStatus orderID:%s bill:%v", order.VendorOrderID, bill) if order.VendorID == model.VendorIDELM { return nil } if !model.IsOrderSolid(order) { globals.SugarLogger.Infof("NotifyWaybillStatus orderID:%s is not solid", order.VendorOrderID) return nil } var title string suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } templateID := "" remark := "" titleColor := "" switch bill.Status { case model.WaybillStatusAccepted: if bill.WaybillVendorID == model.VendorIDMTPS { templateID = WX_MTPS_DELIVERY_GRABDONE_TEMPLATE_ID } else if bill.WaybillVendorID == model.VendorIDDada { templateID = WX_DADA_DELIVERY_GRABDONE_TEMPLATE_ID } remark = FormatDeliveryTime(order) if isBillAlreadyCandidate { titleColor = WX_HIGHLEVEL_TEMPLATE_COLOR title = fmt.Sprintf("%s 第%d号订单由于之前安排的配送员长时间没有取货,我们已重新安排%s配送员%s负责配送。^_^", model.VendorChineseNames[bill.OrderVendorID], order.OrderSeq, model.VendorChineseNames[bill.WaybillVendorID], bill.CourierName) } else { titleColor = WX_HIGHLEVEL_TEMPLATE_COLOR2 title = fmt.Sprintf("%s 第%d号订单长时间无人配送,我们已安排%s配送员%s负责配送。^_^", model.VendorChineseNames[bill.OrderVendorID], order.OrderSeq, model.VendorChineseNames[bill.WaybillVendorID], bill.CourierName) } case model.WaybillStatusDelivered: if bill.WaybillVendorID == model.VendorIDMTPS { templateID = WX_MTPS_DELIVERY_DONE_TEMPLATE_ID } else if bill.WaybillVendorID == model.VendorIDDada { templateID = WX_DADA_DELIVERY_DONE_TEMPLATE_ID } titleColor = VendorColors[bill.OrderVendorID] title = fmt.Sprintf("%s 第%d号订单的配送完成", model.VendorChineseNames[bill.OrderVendorID], order.OrderSeq) } if templateID != "" { data := map[string]interface{}{ "first": map[string]interface{}{ "value": suffix + title, "color": titleColor, }, "keyword1": map[string]interface{}{ "value": bill.VendorOrderID, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword2": map[string]interface{}{ "value": fmt.Sprintf("%s(%s)", bill.CourierName, model.VendorChineseNames[bill.WaybillVendorID]), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ "value": bill.CourierMobile, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "remark": map[string]interface{}{ "value": remark, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } //err = SendMsgToStore(jxutils.GetSaleStoreIDFromOrder(order), templateID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeDetail.ID), WX_MINI_TO_ORDER_PAGE_URL+fmt.Sprintf("?jxStoreId=%v", storeDetail.ID), data) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) err = SendMsgToStore(jxutils.GetSaleStoreIDFromOrder(order), templateID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeDetail.ID), WX_MINI_TO_ORDER_PAGE_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, title) } return err } func NotifyUserApplyCancel(order *model.GoodsOrder, cancelReason string) (err error) { globals.SugarLogger.Debugf("NotifyUserApplyCancel orderID:%s", order.VendorOrderID) if order.VendorID == model.VendorIDELM { return nil } if !model.IsOrderSolid(order) { globals.SugarLogger.Infof("NotifyUserApplyCancel orderID:%s is not solid", order.VendorOrderID) return nil } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } title := suffix + "老板,您有订单申请取消!请及时联系客户处理!" data := map[string]interface{}{ "first": map[string]interface{}{ "value": title, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword1": map[string]interface{}{ // 订单编号 "value": fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID), "color": VendorColors[order.VendorID], }, "keyword2": map[string]interface{}{ // 订单日期 "value": utils.Time2Str(order.OrderCreatedAt), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ // 订单内容 "value": cancelReason, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "remark": map[string]interface{}{ "value": order.ConsigneeMobile, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromOrder(order) //err = SendMsgToStore(storeID, WX_ORDER_APPLY_CANCEL_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL+fmt.Sprintf("?jxStoreId=%v", storeID), data) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) err = SendMsgToStore(storeID, WX_ORDER_APPLY_CANCEL_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, title) return err } func NotifyOrderChanged(order *model.GoodsOrder) (err error) { globals.SugarLogger.Debugf("NotifyOrderChanged orderID:%s", order.VendorOrderID) if order.VendorID == model.VendorIDELM { return nil } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } title := fmt.Sprintf("您有订单的信息已被修改") data := map[string]interface{}{ "first": map[string]interface{}{ "value": suffix + title, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword1": map[string]interface{}{ "value": order.VendorOrderID, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword2": map[string]interface{}{ "value": "用户修改订单", "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ "value": order.ConsigneeAddress + "," + order.ConsigneeName + "," + order.ConsigneeMobile + "," + order.BuyerComment, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword4": map[string]interface{}{ "value": utils.Time2Str(order.OrderCreatedAt), "color": VendorColors[order.VendorID], }, "remark": map[string]interface{}{ "value": "请及时处理", "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromOrder(order) //err = SendMsgToStore(storeID, WX_ORDER_CHANGE_INFO_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL+fmt.Sprintf("?jxStoreId=%v", storeID), data) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) err = SendMsgToStore(storeID, WX_ORDER_CHANGE_INFO_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, title) return err } func NotifyOrderCanceled(order *model.GoodsOrder) (err error) { globals.SugarLogger.Debugf("NotifyOrderCanceled orderID:%s", order.VendorOrderID) if order.VendorID == model.VendorIDELM { return nil } if !model.IsOrderSolid(order) { globals.SugarLogger.Infof("NotifyOrderCanceled orderID:%s is not solid", order.VendorOrderID) return nil } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } title := fmt.Sprintf(suffix+"老板,您的订单%s第%d号订单, %s被取消了!", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID) var price int64 if beego.BConfig.RunMode == "jxgy" { price = order.NewEarningPrice } else { if order.EarningType == model.EarningTypePoints { price = order.ActualPayPrice } else { price = order.EarningPrice } } data := map[string]interface{}{ "first": map[string]interface{}{ "value": title, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderProductPrice": map[string]interface{}{ "value": jxutils.IntPrice2StandardCurrencyString(price), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderProductName": map[string]interface{}{ "value": getOrderDetailBrief(order), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderAddress": map[string]interface{}{ "value": order.ConsigneeAddress, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "orderName": map[string]interface{}{ "value": fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID), "color": VendorColors[order.VendorID], }, "remark": map[string]interface{}{ "value": order.ConsigneeMobile, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromOrder(order) //err = SendMsgToStore(storeID, WX_ORDER_ORDER_CANCELED_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL+fmt.Sprintf("?jxStoreId=%v", storeID), data) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) err = SendMsgToStore(storeID, WX_ORDER_ORDER_CANCELED_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, title) return err } func PushJDBadCommentToWeiXin(comment *legacymodel.JxBadComments, isBadComment bool, order *model.GoodsOrder) (err error) { globals.SugarLogger.Debugf("PushJDBadCommentToWeiXin orderID:%s", comment.OrderId) suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } sb := new(strings.Builder) sb.WriteString(fmt.Sprintf(suffix+"你收到了%s客户(", model.VendorChineseNames[int(utils.Str2Int64WithDefault(comment.OrderFlag, 0))])) sb.WriteString(comment.Userphone) sb.WriteString(")的一条") sb.WriteString(utils.Int2Str(comment.Score)) if isBadComment { sb.WriteString("星差评,请商家在1小时内及时联系客户处理!") } else { sb.WriteString("星中评,如有必要,请商家在1小时内及时联系客户处理!") } title := sb.String() var orderInfo string consigneeName := comment.Userphone if order != nil { orderInfo = fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[int(utils.Str2Int64WithDefault(comment.OrderFlag, 0))], order.OrderSeq, comment.OrderId) consigneeName = order.ConsigneeName } else { orderInfo = fmt.Sprintf("%s订单, %s", model.VendorChineseNames[int(utils.Str2Int64WithDefault(comment.OrderFlag, 0))] /*comment.OrderId*/, "") } data := map[string]interface{}{ "first": map[string]interface{}{ "value": title, "color": WX_HIGHLEVEL_TEMPLATE_COLOR, }, "keyword1": map[string]interface{}{ "value": genJdCommentRemark(comment), "color": WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS, }, "keyword2": map[string]interface{}{ "value": comment.Score, "color": WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS, }, "keyword3": map[string]interface{}{ "value": orderInfo, "color": WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS, }, "keyword4": map[string]interface{}{ "value": consigneeName, "color": WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS, }, "keyword5": map[string]interface{}{ "value": comment.Userphone, "color": WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS, }, } storeID := int(utils.Str2Int64(comment.Jxstoreid)) err = SendMsgToStore(storeID, WX_BAD_COMMENT_PUSH_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_SHOW_COMMENTS_DETAIL_URL, storeID), WX_MINI_TO_SHOW_COMMENTS_DETAIL_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, int(utils.Str2Int64(comment.Jxstoreid)), comment.OrderId, title) return err } func NotifySaleBill(storeID int, title, shopName, fileURL string) (err error) { globals.SugarLogger.Debugf("NotifySaleBill storeID:%d, fileURL:%s", storeID, fileURL) if title == "" { title = "当期账单" } if shopName == "" { shopName = globals.StoreName } data := map[string]interface{}{ "first": map[string]interface{}{ "value": "新的账单上传成功!", "color": "#00008B", }, "keyword1": map[string]interface{}{ "value": title, }, "keyword2": map[string]interface{}{ "value": "点击查看详情", "color": "#00008B", }, "keyword3": map[string]interface{}{ "value": shopName, }, "keyword4": map[string]interface{}{ "value": utils.GetCurTimeStr(), }, "remark": map[string]interface{}{ "value": "手机买菜上京西,极速到家送惊喜", }, } return SendMsgToStore(storeID, WX_SALE_BILL_TEMPLATE_ID, fileURL, "", data) } func NotifyStoreOpRequestStatus(isAccepted bool, storeID, nameID int, spuName string, originalUnitPrice, unitPrice int, rejectReason string) (err error) { globals.SugarLogger.Debugf("NotifyStoreOpRequestStatus isAccepted:%t, storeID:%d, nameID:%d, spuName:%s, originalUnitPrice:%d, unitPrice:%d, rejectReason:%s", isAccepted, storeID, nameID, spuName, originalUnitPrice, unitPrice, rejectReason) templateID := "" fileURL := globals.WxBackstageHost + fmt.Sprintf("%s%d", WX_TO_STORE_SKU_PAGE_URL, storeID) data := make(map[string]interface{}) if isAccepted { templateID = WX_CHANGE_APPROVED_TEMPLATE_ID data = map[string]interface{}{ "first": map[string]interface{}{ "value": fmt.Sprintf("%s%s元,修改为%s元,已经通过审核。^_^", spuName, jxutils.IntPrice2StandardString(int64(originalUnitPrice)), jxutils.IntPrice2StandardString(int64(unitPrice))), "color": "#333333", }, "keyword1": map[string]interface{}{ "value": "审核通过", "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": utils.Time2Str(time.Now()), "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "点击查看详情", }, } } else { templateID = WX_CHANGE_REJECTED_TEMPLATE_ID data = map[string]interface{}{ "first": map[string]interface{}{ "value": fmt.Sprintf("您好!抱歉的通知您。%s%s元,修改为%s元,未通过审核。原因:%s", spuName, jxutils.IntPrice2StandardString(int64(originalUnitPrice)), jxutils.IntPrice2StandardString(int64(unitPrice)), rejectReason), "color": "#E80000", }, "keyword1": map[string]interface{}{ "value": "1", "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": "审核不通过", "color": "#2E408E", }, "keyword3": map[string]interface{}{ "value": utils.Time2Str(time.Now()), "color": "#2E408E", }, "keyword4": map[string]interface{}{ "value": "审核不通过", "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "请您及时到商品管理修改价格,修改后请重新提交。", }, } } err = SendMsgToStore(storeID, templateID, fileURL, WX_MINI_TO_STORE_SKU_PAGE_URL, data) return err } func NotifyStoreMessage(storeID, msgID, msgStatusID int, msg *model.Message) (err error) { globals.SugarLogger.Debugf("NotifyStoreMessage storeID:%d, msgID:%d, title:%s, content:%s", storeID, msgID, msg.Title, msg.Content) templateID := "" fileURL := globals.WxBackstageHost + fmt.Sprintf(WX_TO_SHOW_MSG, msgID, msgStatusID) data := make(map[string]interface{}) switch msg.Type { case model.MessageTypeStore: templateID = WX_NORMAL_STORE_MSG_TEMPLATE_ID data = map[string]interface{}{ "first": map[string]interface{}{ "value": msg.Content, "color": "#333333", }, "keyword1": map[string]interface{}{ "value": msg.Title, "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": utils.GetCurTimeStr(), "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "", }, } case model.MessageTypeStoreAct: actMap := &model.MessageActInfo{} err = json.Unmarshal([]byte(msg.ActInfo), &actMap) templateID = WX_NORMAL_STORE_ACT_MSG_TEMPLATE_ID data = map[string]interface{}{ "first": map[string]interface{}{ "value": "即将开展[" + msg.Title + "]活动,详情点击", "color": "#333333", }, "keyword1": map[string]interface{}{ "value": msg.Title, "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": actMap.BeginAt + "-" + actMap.EndAt, "color": "#2E408E", }, "keyword3": map[string]interface{}{ "value": model.VendorNames[int(utils.Interface2Float64WithDefault((actMap.VendorID), 0))], "color": "#2E408E", }, "remark": map[string]interface{}{ "value": msg.Content, }, } } return SendMsgToStore(storeID, templateID, fileURL, fmt.Sprintf(WX_MINI_TO_SHOW_MSG, msgID, msgStatusID), data) } func NotifyAfsOrderStatus(afsOrder *model.AfsOrder) (err error) { globals.SugarLogger.Debugf("NotifyAfsOrderStatus orderID:%s", afsOrder.VendorOrderID) if afsOrder.VendorID == model.VendorIDELM { return nil } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromAfsOrder(afsOrder), afsOrder.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } var templateID, comment string if afsOrder.Status == model.AfsOrderStatusWait4Approve { templateID = WX_AFS_ORDER_WAIT4APPROVE_TEMPLATE_ID comment = "您有新售后单,请尽快处理" } else if afsOrder.Status == model.AfsOrderStatusWait4ReceiveGoods { templateID = WX_AFS_ORDER_STATUS_CHANGED_TEMPLATE_ID comment = "商家您好!如顾客商品已成功退回,请点击确认收货" } else { return err } order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID) if err != nil { return err } data := map[string]interface{}{ "first": map[string]interface{}{ "value": suffix + fmt.Sprintf("%s 第%d号订单, %s", model.VendorChineseNames[afsOrder.VendorID], order.OrderSeq, afsOrder.VendorOrderID), "color": WX_HIGHLEVEL_TEMPLATE_COLOR2, }, "keyword1": map[string]interface{}{ "value": afsOrder.AfsOrderID, "color": WX_TEMPLATE_VENDERCOLOR_JDDJ, }, "keyword2": map[string]interface{}{ "value": model.OrderStatusName[afsOrder.Status], "color": WX_HIGHLEVEL_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ "value": utils.Time2Str(afsOrder.AfsCreatedAt), "color": VendorColors[order.VendorID], }, "remark": map[string]interface{}{ "value": comment, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromAfsOrder(afsOrder) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) err = SendMsgToStore(storeID, templateID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) netprinter.NofityOrderMsg(jxcontext.AdminCtx, jxutils.GetSaleStoreIDFromAfsOrder(afsOrder), afsOrder.VendorOrderID, comment) return err } func FormatDeliveryTime(order *model.GoodsOrder) string { var tmpTime time.Time if order.ExpectedDeliveredTime == utils.DefaultTimeValue { tmpTime = order.OrderCreatedAt.Add(1 * time.Hour) } else { tmpTime = order.ExpectedDeliveredTime } left := tmpTime.Sub(time.Now()) / time.Minute leftHours := left / 60 leftMinutes := left % 60 return fmt.Sprintf("请于%s前送达(剩余时间%d小时%d分钟)", utils.Time2Str(tmpTime), leftHours, leftMinutes) } func genJdCommentRemark(comment *legacymodel.JxBadComments) string { sb := new(strings.Builder) sb.WriteString("评价标签:") sb.WriteString(comment.Vendertags) sb.WriteString(" 评价内容:") sb.WriteString(comment.Scorecontent) return sb.String() } func NotifyStoreStatusChanged(openUserID, title, content string) (err error) { SmartMessageTemplateSend(openUserID, WS_NOTIFY_STORE_STATUS_CHHANGED_TEMPLATE_ID, "", "", map[string]interface{}{ "first": map[string]interface{}{ "value": title, "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword1": map[string]interface{}{ "value": "", "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword2": map[string]interface{}{ "value": utils.Time2Str(time.Now()), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ "value": content, "color": WX_HIGHLEVEL_TEMPLATE_COLOR, }, "keyword4": map[string]interface{}{ "value": "", "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "remark": map[string]interface{}{ "value": "", "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, }) return err } func NotifyStoreAlertMessage(storeID int, storeName, title, content string) (err error) { globals.SugarLogger.Debugf("NotifyStoreAlertMessage storeID:%d, storeName:%d, title:%s, content:%s", storeID, storeName, title, content) templateID := WX_STORE_ALERT_TEMPLATE_ID data := map[string]interface{}{ "first": map[string]interface{}{ "value": "", "color": "#333333", }, "keyword1": map[string]interface{}{ "value": storeName, "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": utils.GetCurTimeStr(), "color": "#2E408E", }, "keyword3": map[string]interface{}{ "value": content, "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "", }, } if false { err = SendMsgToStore(storeID, templateID, "", "", data) } return err } func SendStoreMessage(ctx *jxcontext.Context, title, content string, storeIDs []int, imgs []string, actInfo string, messageType int, isAsync, isContinueWhenError bool) (hint string, err error) { db := dao.GetDB() //权限 if permission.IsRoled(ctx) { if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil { var storeIDs2 []int if len(storeIDs) > 0 { for _, v := range storeIDs { if storeIDsMap[v] != 0 { storeIDs2 = append(storeIDs2, v) } } if len(storeIDs2) == 0 { storeIDs2 = append(storeIDs2, -1) } } else { for k, _ := range storeIDsMap { storeIDs2 = append(storeIDs2, k) } } storeIDs = nil storeIDs = storeIDs2 } } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() msg := &model.Message{ Title: title, Content: content, Type: int8(messageType), ActInfo: actInfo, Imgs: strings.Join(imgs, ","), } dao.WrapAddIDCULDEntity(msg, ctx.GetUserName()) if err = dao.CreateEntity(db, msg); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList := make([]*model.MessageStatus, len(storeIDs)) for k, storeID := range storeIDs { msgStatus := &model.MessageStatus{ MessageID: msg.ID, StoreID: storeID, Status: model.MessageStatusNew, } dao.WrapAddIDCULDEntity(msgStatus, ctx.GetUserName()) if err = dao.CreateEntity(db, msgStatus); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList[k] = msgStatus } dao.Commit(db, txDB) rootTask := tasksch.NewParallelTask("SendStoreMessage", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { db := dao.GetDB() msgStatus := batchItemList[0].(*model.MessageStatus) if err = NotifyStoreMessage(msgStatus.StoreID, msgStatus.MessageID, msgStatus.ID, msg); err == nil { msgStatus.Status = model.MessageStatusSendAllSuccess } else { msgStatus.Status = model.MessageStatusSendAllFailed } dao.WrapUpdateULEntity(msgStatus, ctx.GetUserName()) // globals.SugarLogger.Debug(utils.Format4Output(msgStatus, false)) _, err = dao.UpdateEntity(db, msgStatus) return nil, err }, msgStatusList) tasksch.HandleTask(rootTask, nil, len(msgStatusList) > 5).Run() if !isAsync { _, err = rootTask.GetResult(0) } else { hint = rootTask.ID } return "", err } func NotifyAdjustOrder(order *model.GoodsOrder) (err error) { globals.SugarLogger.Debugf("NotifyAdjustOrder orderID:%s", order.VendorOrderID) if order.VendorID == model.VendorIDELM { return nil } if len(order.Skus) == 0 { return } suffix := "" storeDetail, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err == nil && storeDetail != nil { suffix = storeDetail.CityName + "," + storeDetail.Name } if !model.IsOrderSolid(order) { globals.SugarLogger.Infof("NotifyAdjustOrder orderID:%s is not solid", order.VendorOrderID) return nil } sb := new(strings.Builder) sb.WriteString(suffix + "老板,") sb.WriteString(order.ConsigneeName) sb.WriteString("调整了订单商品,请及时查看!") sb.WriteString(getOrderDetailBrief(order)) data := map[string]interface{}{ "first": map[string]interface{}{ "value": sb.String(), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword1": map[string]interface{}{ "value": math.Round(jxutils.IntPrice2Standard(order.NewEarningPrice)), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword2": map[string]interface{}{ "value": utils.Time2Str(order.CreatedAt), "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, "keyword3": map[string]interface{}{ "value": model.OrderStatusName[order.Status], "color": WX_NEW_ORDER_TEMPLATE_COLOR, }, } storeID := jxutils.GetSaleStoreIDFromOrder(order) //dataStore := fmt.Sprintf(`{"address":"%s","cityName":"%s","id":%d,"name":"%s","payeeName":"%s","status":%d,"tel1":"%s","tel2":"%s"}`, storeDetail.Address, storeDetail.CityName, storeDetail.ID, storeDetail.Name, storeDetail.PayeeName, storeDetail.Status, storeDetail.Tel1, storeDetail.Tel2) //url := WX_MINI_TO_ORDER_PAGE_URL + fmt.Sprintf("?jxStoreId=%v&data=%v", storeDetail.ID, dataStore) return SendMsgToStore(storeID, WX_ADJUSTORDER_TEMPLATE_ID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data) } func SendStoreMessageKnowledge(ctx *jxcontext.Context, title string, knowIDs, storeIDs []int) (hint string, err error) { var ( db = dao.GetDB() content string ) knows, err := dao.GetKnowledgeDepotNoPage(db, knowIDs) for k, v := range knows { if k != 0 { content += weixinapi.SNSCutLine } content += v.Content } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() msg := &model.Message{ Title: title, Content: content, Type: 4, } dao.WrapAddIDCULDEntity(msg, ctx.GetUserName()) if err = dao.CreateEntity(db, msg); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList := make([]*model.MessageStatus, len(storeIDs)) for k, storeID := range storeIDs { msgStatus := &model.MessageStatus{ MessageID: msg.ID, StoreID: storeID, Status: model.MessageStatusNew, } dao.WrapAddIDCULDEntity(msgStatus, ctx.GetUserName()) if err = dao.CreateEntity(db, msgStatus); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList[k] = msgStatus } dao.Commit(db, txDB) rootTask := tasksch.NewParallelTask("SendStoreMessageKnowledge", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { db := dao.GetDB() msgStatus := batchItemList[0].(*model.MessageStatus) if err = NotifyKnowledge(msgStatus.StoreID, title); err == nil { msgStatus.Status = model.MessageStatusSendAllSuccess } else { msgStatus.Status = model.MessageStatusSendAllFailed } dao.WrapUpdateULEntity(msgStatus, ctx.GetUserName()) // globals.SugarLogger.Debug(utils.Format4Output(msgStatus, false)) _, err = dao.UpdateEntity(db, msgStatus) return nil, err }, msgStatusList) tasksch.HandleTask(rootTask, nil, true).Run() //if !isAsync { // _, err = rootTask.GetResult(0) //} else { hint = rootTask.ID //} return "", err } func NotifyKnowledge(storeID int, title string) (err error) { globals.SugarLogger.Debugf("NotifyKnowledge storeID:%d, title:%s", storeID, title) templateID := WX_KNOWLEDGE_BASE_TEMPLATE_ID data := map[string]interface{}{ "first": map[string]interface{}{ "value": "今日每日一词已更新!", "color": "#333333", }, "keyword1": map[string]interface{}{ "value": time.Now().Format("2006-01-02"), "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": title, "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "", }, } return SendMsgToStore(storeID, templateID, "", "", data) } func SendUserMessage(ctx *jxcontext.Context, title, content string, userIDs []string, isAsync, isContinueWhenError bool) (hint string, err error) { db := dao.GetDB() txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() msg := &model.Message{ Title: title, Content: content, Type: model.MessageTypeUser, } dao.WrapAddIDCULDEntity(msg, ctx.GetUserName()) if err = dao.CreateEntity(db, msg); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList := make([]*model.MessageStatus, len(userIDs)) for k, userID := range userIDs { msgStatus := &model.MessageStatus{ MessageID: msg.ID, UserID: userID, Status: model.MessageStatusNew, } dao.WrapAddIDCULDEntity(msgStatus, ctx.GetUserName()) if err = dao.CreateEntity(db, msgStatus); err != nil { dao.Rollback(db, txDB) return "", err } msgStatusList[k] = msgStatus } dao.Commit(db, txDB) rootTask := tasksch.NewParallelTask("SendUserMessage", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { db := dao.GetDB() msgStatus := batchItemList[0].(*model.MessageStatus) if err = NotifyUserMessage(msgStatus.UserID, msg.Title, msg.Content); err == nil { msgStatus.Status = model.MessageStatusSendAllSuccess } else { msgStatus.Status = model.MessageStatusSendAllFailed } dao.WrapUpdateULEntity(msgStatus, ctx.GetUserName()) _, err = dao.UpdateEntity(db, msgStatus) return nil, err }, msgStatusList) tasksch.HandleTask(rootTask, nil, len(msgStatusList) > 5).Run() if !isAsync { _, err = rootTask.GetResult(0) } else { hint = rootTask.ID } return "", err } func NotifyUserMessage(userID string, title, content string) (err error) { globals.SugarLogger.Debugf("NotifyUserMessage userID:%d, title:%s, content:%s", userID, title, content) templateID := WX_NORMAL_STORE_MSG_TEMPLATE_ID data := map[string]interface{}{ "first": map[string]interface{}{ "value": content, "color": "#333333", }, "keyword1": map[string]interface{}{ "value": title, "color": "#2E408E", }, "keyword2": map[string]interface{}{ "value": utils.GetCurTimeStr(), "color": "#2E408E", }, "remark": map[string]interface{}{ "value": "", }, } return SendMsgToUser(userID, templateID, data) } func SendMsgToUser(userID string, templateID string, data interface{}) (err error) { globals.SugarLogger.Debugf("SendMsgToUser userID:%d, templateID:%s", userID, templateID) authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, []string{"weixinsns"}, "", "", []string{"wx2bb99eb5d2c9b82c"}) if err != nil { return err } successCount := 0 if len(authBinds) == 0 { return fmt.Errorf("此用户未找到微信认证方式!userID: %v", userID) } globals.SugarLogger.Debugf("SendMsgToUser userID:%d, openID:%s, templateID:%s", userID, authBinds[0].AuthID, templateID) if err2 := SmartMessageTemplateSend(authBinds[0].AuthID, templateID, "", "", data); err2 == nil { successCount++ } else { err = err2 } if successCount > 0 { err = nil // 只要成功一个都当成成功 } if err != nil { globals.SugarLogger.Debugf("SendMsgToUser all failed userID:%d, templateID:%s, error:%v", userID, templateID, err) } return err }